OKPy vs Dynamo / Python Discrepancy

I’m testing out the OKPy workflow and hit a roadblock that perhaps someone could help me with.
The objective of what I’m testing is a simple script that will take in a model category , color override , and fill pattern input and then locate all untagged elements and override their color / pattern to match the inputs. Below is what is in OKPy and you can see the printed output looks correct.

import clr, System
clr.AddReference("RevitNodes")
import Revit
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import*

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

def OverrideColorPattern(e, c, f):
	gSettings = OverrideGraphicSettings()
	#gSettings.SetSurfaceForegroundPatternColor(c)
	#gSettings.SetSurfaceForegroundPatternId(f.Id)
	gSettings.SetCutForegroundPatternColor(c)
	gSettings.SetCutForegroundPatternId(f.Id)
	doc.ActiveView.SetElementOverrides(e.Id, gSettings)
	return e

#The current uidoc, doc, uiapp, and app are stored in the following variables
doc = __currentdoc__
app = __app__
uidoc = __uidoc__
uiapp = __uiapp__

#The inputs are stored in the __inputs__ dictionray
inputs = __inputs__
modCat = inputs["modCat"]
fillPat = inputs["fillPat"]
colorOverride = inputs["colorOverride"]
print(modCat)
print(annoCat)
print(fillPat)
print(colorOverride)
####Create Annotation Dictionary to Pair Model Cat with Tag###
annoList = ["Door Tags","Wall Tags" , "Window Tags"]
modList = ["Doors", "Walls", "Windows"]
annoDict = {}
for x , y in zip(annoList,modList):
    annoDict[y] = x
    
bic = System.Enum.GetValues(BuiltInCategory) 

for i in bic:
    try:
        cat = Revit.Elements.Category.ById(ElementId(i).IntegerValue)
        modelCat = Revit.Elements.Category.ById(ElementId(modCat).IntegerValue)
        if str(cat) == annoDict[str(modelCat)]:
            annoCat = i
    except:
        pass
        
###Collect Elements  & Tags in the project####
elements = FilteredElementCollector(doc).OfCategory(BuiltInCategory(modCat)).WhereElementIsNotElementType().ToElements()
annotations = FilteredElementCollector(doc).OfCategory(BuiltInCategory(annoCat)).WhereElementIsNotElementType().ToElements()


###Get Tagged and Untagged Elements##
taggedElements = []
unTaggedElements = []

for anno in annotations:
   tagElems = anno.GetTaggedLocalElements() 
   for tagElem in tagElems:
        taggedElements.append(tagElem.Id)

for e in elements:
    if e.Id in taggedElements:
        continue
    else:
        unTaggedElements.append(e)
        
##Override Untagged Elements##
TransactionManager.Instance.EnsureInTransaction(doc)

elemOverride = []
for i in unTaggedElements:
    override = OverrideColorPattern(i,colorOverride,fillPat)
    elemOverride.append([i,colorOverride,fillPat])

TransactionManager.Instance.TransactionTaskDone()

print(elemOverride)

When I run this it says success , but I do not get the result I’m looking for. What confuses me is if I replicate the same code within dynamo / python I get the result I’m expecting. Thoughts on why the OKPy version is not working correctly when the code works in dynamo?

1 Like

Dynamo Version

1 Like

Hey @criddell !
Thank you for reaching out through the forum! :grin: Thats an awesome tool!
The main reason why it’s not giving you the expected result is that there are many things that are Dynamo specific in the code. RevitServices and RevitNodes are part of that, as well as the Revit namespace with the Revit.Elements.Category.ById among other things. So I’m not surprised it doesn’t work. I’m verry surprised it says that it was run successully though :thinking: . I’m having a hard time getting it to do that on my side.

I made the changes to make it use “pure” Revit API only and it seems to do the job! :smiley:
Here’s the code :

import clr, System
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import*

def OverrideColorPattern(e, c, f):
	gSettings = OverrideGraphicSettings()
	#gSettings.SetSurfaceForegroundPatternColor(c)
	#gSettings.SetSurfaceForegroundPatternId(f.Id)
	gSettings.SetCutForegroundPatternColor(c)
	gSettings.SetCutForegroundPatternId(f.Id)
	doc.ActiveView.SetElementOverrides(e.Id, gSettings)
	return e

#The current uidoc, doc, uiapp, and app are stored in the following variables
doc = __currentdoc__
app = __app__
uidoc = __uidoc__
uiapp = __uiapp__

#The inputs are stored in the __inputs__ dictionray
inputs = __inputs__
modelCat = inputs["modCat"]
fillPat = inputs["fillPat"]
annotCat = inputs["annotCat"]
colorOverride = inputs["colorOverride"]

print(modCat)
print(fillPat)
print(fillPat)
print(colorOverride)
####Create Annotation Dictionary to Pair Model Cat with Tag###
annoList = ["Door Tags","Wall Tags" , "Window Tags"]
modList = ["Doors", "Walls", "Windows"]
annoDict = {}
for x , y in zip(annoList,modList):
    annoDict[y] = x
    
bicmodelCat = [c for c in System.Enum.GetValues(BuiltInCategory) if ElementId(c) == modelCat.Id][0]
bicannotCat = [c for c in System.Enum.GetValues(BuiltInCategory) if ElementId(c) == annotCat.Id][0]
        
###Collect Elements  & Tags in the project####
elements = FilteredElementCollector(doc).OfCategory(bicmodelCat).WhereElementIsNotElementType().ToElements()
annotations = FilteredElementCollector(doc).OfCategory(bicannotCat).WhereElementIsNotElementType().ToElements()


###Get Tagged and Untagged Elements##
taggedElements = []
unTaggedElements = []

for anno in annotations:
   tagElems = anno.GetTaggedLocalElements() 
   for tagElem in tagElems:
        taggedElements.append(tagElem.Id)

for e in elements:
    if e.Id in taggedElements:
        continue
    else:
        unTaggedElements.append(e)
        
##Override Untagged Elements##
transaction = Transaction(doc)
transaction.Start("OkPy - Highlight untagged elements")
elemOverride = []
for i in unTaggedElements:
    override = OverrideColorPattern(i,colorOverride,fillPat)
    elemOverride.append([i,colorOverride,fillPat])

transaction.Commit()

print(elemOverride)

Here it is in action :
overrideUntagged

And here’s the OkPy tool where I made the changes and added an input that was missing (annotCat):
OverrideUntaggedElements.okpy (6.5 KB)

Let me know when you get a chance to try it out! :slight_smile:

This is great. Thanks for the quick reply. I’m going to test this one out and see how it goes… What is interesting is I closed out of Revit and relaunched and started getting error messages that I was just about to go through addressing. I think what threw me off then was it showed success with no errors.

1 Like

Worked like a charm. Thanks again. I made a few edits for my use case. I reduced my mod cats to a defined list

import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import Category

categories = __currentdoc__.Settings.Categories

outdict = {}
modList = ["Doors", "Walls", "Windows"]

for category in categories:
    if category.Name in modList:
        outdict[category.Name] = category
#The information displayed by the input is stored in the __out__ dictionary
__out__= outdict

Then for my test I had the modCat drive the annotation tag that goes with it so I added this section to get the annotCat

####Create Annotation Dictionary to Pair Model Cat with Tag###
categories = __currentdoc__.Settings.Categories

annoList = ["Door Tags","Wall Tags" , "Window Tags"]
modList = ["Doors", "Walls", "Windows"]
annoDict = {}
for x , y in zip(annoList,modList):
    annoDict[y] = x

for c in categories:
    if c.Name == annoDict[modelCat.Name]:
        annotCat = c

Also , I updated the def color override to account for projection and cut lines for things like doors /windows

def OverrideColorPattern(e, c, f):
	gSettings = OverrideGraphicSettings()
	gSettings.SetSurfaceForegroundPatternColor(c)
	gSettings.SetSurfaceForegroundPatternId(f.Id)
	gSettings.SetCutLineColor(c)
	gSettings.SetCutForegroundPatternColor(c)
	gSettings.SetCutForegroundPatternId(f.Id)
	gSettings.SetProjectionLineColor(c) 
	doc.ActiveView.SetElementOverrides(e.Id, gSettings)
	return e

1 Like

That’s just beautiful :star_struck::star_struck::star_struck:

1 Like