I am trying to write a script that applies overrides to a drafting view based on a list of layers.
I have started a script but it doesn’t work. I am hopping someone could point me in the right direction.
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import *
from pyrevit import forms, revit, script
# Get the current document
doc = revit.doc
# Define a dictionary of category names and their corresponding override settings
category_overrides = {
"s-hatch8": Color(192, 192, 192), # LIGHT GREY
"s-rein": Color(128, 128, 128), # DARK GREY
"e-hid2": Color(192, 192, 192), # LIGHT GREY
# I plan adding more categories and their corresponding colors when these work
}
# Here I collect all drafting views in the document
drafting_views = FilteredElementCollector(doc) \
.OfClass(ViewDrafting) \
.ToElements()
# Start a transaction
with Transaction(doc, "Modify Graphic Overrides in Drafting Views") as t:
t.Start()
# Iterate through drafting views
for drafting_view in drafting_views:
print("Processing drafting view:", drafting_view.Name)
# Get imported CAD files
imported_instances = FilteredElementCollector(doc) \
.OfClass(ImportInstance) \
.ToElements()
# Iterate through the imported instances
for import_instance in imported_instances:
# Get the category of the import instance
category = import_instance.Category
if category and category.Name.lower() in category_overrides:
# Create an override settings instance
override_settings = OverrideGraphicSettings()
# Set the projection line color based on the category match
override_settings.SetProjectionLineColor(category_overrides[category.Name.lower()])
# Apply the graphic override settings to the current drafting view
drafting_view.SetCategoryOverrides(category.Id, override_settings)
print("Applied override for %s in %s" % (category.Name, drafting_view.Name))
#else:
#print("Skipping category for import instance:", import_instance) # For debugging
t.Commit()
forms.alert("Graphic Overrides updated successfully for drafting views!")
Thank you for your replies. I guess “it doesn’t work” is a little vague. But, so is the result. When I run the code it doesn’t give me a error, but it doesn’t do anything either.
At the Object Styles level. This affects all view in th project and if you are indeed iterating through all views and doing the same thing, then the setting is best applied here. Set it. Forget it. Additional imports will respect the preset object styles. (You could in fact set this in your template and then not need a program at all if it is always the same layers and settings.)
At the view level by category. This is if each view iis a little different.
At the element level. This would be used if elements of the same category need different graphics. View filters could possibly be used here.
Thank you for the detailed explanation. The projects I work on can have up to 100 details attached and placed in their own drafting view. I would love to use the insert presets, except they only control line thickness not color, making shading impossible. I didn’t know you could change it at the object level and affect each view that a linked file is placed.
I would suggest for the long term; you look at converting these over to Revit detail elements and views. It is much faster to copy sheets and views over from a template or other project than it is to link in AutoCAD drawings. In the end you would save considerable time.
That isn’t an option because we still do projects in AutoCAD and use those same details. Also having to worry about how each new version of Revit will convert the (insert object here) i.e. text, families and such. Keeping the details in cad lets us avoid that problem.
Thanks for all the help and I have the code almost done, but I am getting error:
“Exception: Attempting to create an ExternalEvent outside of a standard API execution”
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import *
from pyrevit import forms, revit
with revit.Transaction("Convert Layers"):
uidoc = __revit__.ActiveUIDocument
doc = __revit__.ActiveUIDocument.Document
data = {
"S-HATCH8": "255,0,0", # Red
"S-HATCH6": "0,255,0", # Green
"S-HATCH14": "0,0,255" # Blue
}
# Get all linked CAD files
import_instances = FilteredElementCollector(doc) \
.OfClass(ImportInstance) \
.ToElements()
# Loop through each ImportInstance
for instance in import_instances:
layers = sorted(instance.Category.SubCategories, key=lambda x: x.Name)
for layer in layers:
lname = layer.Name
if lname in data:
# Get the layer name
cad_color = data[lname]
print(cad_color)
if "," in cad_color:
cad_color_list = cad_color.split(",")
with revit.Transaction("cadlayer_override"):
layer.LineColor = revit.DB.Color(int(cad_color_list[0]), int(cad_color_list[1]), int(cad_color_list[2]))
output_success.append("{} \t {},{},{}".format(lname, layer.LineColor.Red, layer.LineColor.Green, layer.LineColor.Blue))
else:
print("No ImportInstances found.")
At which line you get that exception? You should always give us the full context of the errors to have as much info as possible to help you.
That being said, I believe the transaction at the start is useless, and it might be what’s causing the error.
Other unsolicited advice:
import as little modules as needed, here the revit api can be skipped by using pyrevit.revit.DB for FilteredElementCollector
the “else” of the “for” loop doesn’t do what you think it triggers if the loop completed without an early exit with “break”. I know, this can feel not intuitive, and I never use it because of that.
If you invert the if condition and jump to the next loop, you can avoid to indent the code too much
from pyrevit import revit, DB
def main():
uidoc = __revit__.ActiveUIDocument
doc = __revit__.ActiveUIDocument.Document
data = {
"S-HATCH8": "255,0,0", # Red
"S-HATCH6": "0,255,0", # Green
"S-HATCH14": "0,0,255" # Blue
}
# Get all linked CAD files
import_instances = DB.FilteredElementCollector(doc) \
.OfClass(ImportInstance) \
.ToElements()
if not import_instances:
print("No ImportInstances found.")
return
# Loop through each ImportInstance
for instance in import_instances:
layers = sorted(instance.Category.SubCategories, key=lambda x: x.Name)
for layer in layers:
lname = layer.Name
if lname not in data:
continue
# Get the layer color
cad_color = data[lname]
print(cad_color)
if "," not in cad_color:
continue
cad_color_list = cad_color.split(",")
with revit.Transaction("cadlayer_override"):
layer.LineColor = DB.Color(int(cad_color_list[0]), int(cad_color_list[1]), int(cad_color_list[2]))
print("{} \t {},{},{}".format(lname, layer.LineColor.Red, layer.LineColor.Green, layer.LineColor.Blue))
main()