Create multiple filters and visibility graphic overrides by filter rules from Excel File

Hi people on the Dynamo forum,

First of all, Sorry for my bad english, because it’s not my native language. I’m trying to create a filter and visibility graphic override by filter rules from an Excel file in Dynamo / Revit with Python.

Thanks to Ben_Osborne, Konrad_K_Sobon and David Dória

At this moment my Dynamo script creates the filter and overrides the visibility graphics in Revit for 1 Excel imported row of data. Now I would like to make some kind of `for loop’ in python to create multiple filter elements and visibility graphic overrides by multiple rows of data in Excel for a specific view in Revit.

image

My idea of achieving this: I changed my Excel file from 1 row to 2 rows of data and manipulated my Dynamo nodes and my python code in a way I thought it should have worked, but an Error occurs. The error is pritty straight forward, because the inputs, which were strings in the 1 row of data script', became a list of two strings in the 2 rows data script’.

image

I know, by `hard coding’ of the indexes of the inputs in the script I can make the script work for multiple filters and visibility overrides, but I would like to have the computer to run the code by itself. Because in the end I would like to make 100 filters and overrides.

My inputs in the Python script are the strings and doubles from Excel.

Here is my dynamo script:
Python-script-Filters.dyn (225.1 KB)

This is the python code for one filter and visibility override for 1 row of Excel data:

import clr

import sys
sys.path.append('C:\Program Files (x86)\IronPython 2.7\Lib')

import System
from System import Array
from System.Collections.Generic import *

clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

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

clr.AddReference("RevitAPI")
clr.AddReference("RevitAPIUI")
import Autodesk 
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import *

uiapp = DocumentManager.Instance.CurrentUIApplication 
app = uiapp.Application 
uidoc = uiapp.ActiveUIDocument
### Gets the active document your working in
doc = DocumentManager.Instance.CurrentDBDocument

### INputs
view = IN[0]
filter_name = IN[1]
catlist = IN[2]
pattern_name = IN[3]
foreColor = IN[4]
transparency = IN[5]

### Create INput - IN[0] - Categories for BIM-Protocol row
catName = []
for cat in catlist:
	catName.append(Revit.Elements.Category.ByName(cat))	    	
# Revit Categories
cats = UnwrapElement(catName)

cat_id = []
for catid in cats:
	cat_id.append(catid.Id)
# Revit Categorie Id's
cat_ids_list = List[ElementId](cat_id)

### Create INput - IN[2]
# Create fill pattern - <Solid fill>
target = FillPatternTarget.Drafting
orientation = FillPatternHostOrientation.ToView
pattern = FillPattern(pattern_name, target, orientation)

# Create fill pattern element - <Solid fill>
TransactionManager.Instance.EnsureInTransaction(doc)
fpelement = FillPatternElement.Create(doc, pattern)
TransactionManager.Instance.TransactionTaskDone()

### Create INput - IN[0] - Filter element
# Get Built-in Parameters 
pWorkSet=ParameterValueProvider(ElementId(BuiltInParameter.ELEM_PARTITION_PARAM))
pFamType=ParameterValueProvider(ElementId(BuiltInParameter.SYMBOL_NAME_PARAM))
	
# Create Filter rules
xWorkS=FilterStringRule(pWorkSet,FilterStringEquals(),"BL_New_Structural",False)
xFamT=FilterStringRule(pFamType,FilterStringContains(),"2",False)

# Create operators within the filter rule
filt1=[]
filt1.Add(ElementParameterFilter(xWorkS))
filt1.Add(ElementParameterFilter(xFamT))
icolfilt1=List[ElementFilter](filt1)
andfilt1=LogicalAndFilter(icolfilt1)

# Create filter and convert to an element in Revit
TransactionManager.Instance.EnsureInTransaction(doc)

pfeelem=ParameterFilterElement.Create(doc,filter_name, cat_ids_list, andfilt1)

TransactionManager.Instance.TransactionTaskDone()

### Avoid instance INput problem
if isinstance(pfeelem, list):
	pfeelem = pfeelem
else: pfeelem = [pfeelem]

if isinstance(view, list):
	view = view
else: view = [view]

if isinstance(fpelement, list):
	fpelement = fpelement
else: fpelement = [fpelement]

if isinstance(foreColor, list):
	foreColor = foreColor
else: foreColor = [foreColor]

if isinstance(transparency, list):
	transparency = transparency
else: transparency = [transparency]

### Function
def ToRevitColor(dynamoColor):
	return Color(dynamoColor.Red, dynamoColor.Green, dynamoColor.Blue)
	
### Overriding graphic settings
try:
	for v, filt, fP, fC, ts in zip(view, pfeelem, fpelement, foreColor, transparency):
		TransactionManager.Instance.EnsureInTransaction(doc)
		over = OverrideGraphicSettings()
		over.SetSurfaceForegroundPatternId(UnwrapElement(fP).Id)
		over.SetSurfaceForegroundPatternColor(ToRevitColor(fC))
		over.SetSurfaceTransparency(ts)
		v = UnwrapElement(v)
		v.SetFilterOverrides(UnwrapElement(filt).Id, over)
		TransactionManager.Instance.TransactionTaskDone()
	OUT = "Graphics overriden!"
except:
	OUT = "Oops! Something went wrong"

Why not wrap the python in a custom node so you can just make use of list levels and lacing?

Okay thanks for your reply to my first problem ever on the Dynamo Forum haha, so I tried to create the custom node, but the only thing it returns is a `null’. :frowning:
I’m quiet new to dynamo so any help is greatly appriciated. Furthermore I have never used a custom node before aswell.

Maybe a little bit of a weird question, but can you sketch some kind of example, in that way I think I will understand the solution better.

Does it have something to do with the list ‘levels’ of the inputs?
I don’t really understand why it’s going wrong. Every input is in the same list ‘level’ except the view input. Maybe that’s the problem?

Custom node as follows:

I fixed it in the python node itself by using a while loop which iterates through the data.

Big thanks to Ben_Osborne, Konrad_K_Sobon and David Dória

# code by JDynamo 15-03-2021
import clr

import sys
sys.path.append('C:\Program Files (x86)\IronPython 2.7\Lib')

import System
from System import Array
from System.Collections.Generic import *

clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

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

clr.AddReference("RevitAPI")
clr.AddReference("RevitAPIUI")
import Autodesk 
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import *

uiapp = DocumentManager.Instance.CurrentUIApplication 
app = uiapp.Application 
uidoc = uiapp.ActiveUIDocument
### Gets the active document you're working in
doc = DocumentManager.Instance.CurrentDBDocument

### Function
def ToRevitColor(dynamoColor):
	return Color(dynamoColor.Red, dynamoColor.Green, dynamoColor.Blue)

### INputs
view = IN[0]

filter_name = IN[1]
catlist = IN[2]
pattern_name = IN[3]
foreColor = IN[4]
transparency = IN[5]

inputs = filter_name, catlist, pattern_name, foreColor, transparency

begin = 0
eind = len(filter_name)

inputs_lists = []
while begin < len(filter_name):
	inputs_lists.append(inputs[0][begin][0])
	inputs_lists.append(inputs[1][begin])
	inputs_lists.append(inputs[2][begin][0])
	inputs_lists.append(inputs[3][begin])
	inputs_lists.append(inputs[4][begin][0])
	
	begin = begin + 1

filterdata = inputs_lists

start = 0
end = len(inputs)

while end <= len(filterdata):
	### Create INput - IN[1] - Categories for BIM-Protocol row
	catName = []
	for cat in filterdata[1+start]: # [1] wordt [6] via while loop (filterdata[1+start])?
		catName.append(Revit.Elements.Category.ByName(cat))	    	
	
	# Revit Categories
	cats = UnwrapElement(catName)
	
	cat_id = []
	for catid in cats:
		cat_id.append(catid.Id)
	# Revit Categorie Id's
	cat_ids_list = List[ElementId](cat_id)
	
	### Create INput - IN[2]
	# Create fill pattern - <Solid fill>
	target = FillPatternTarget.Drafting
	orientation = FillPatternHostOrientation.ToView
	pattern = FillPattern(filterdata[2+start], target, orientation)
	
	# Create fill pattern element - <Solid fill>
	TransactionManager.Instance.EnsureInTransaction(doc)
	fpelement = FillPatternElement.Create(doc, pattern)
	TransactionManager.Instance.TransactionTaskDone()
	
	### Create INput - IN[1] - Filter element
	# Get Built-in Parameters 
	pWorkSet=ParameterValueProvider(ElementId(BuiltInParameter.ELEM_PARTITION_PARAM))
	pFamType=ParameterValueProvider(ElementId(BuiltInParameter.SYMBOL_NAME_PARAM))
		
	# Create Filter rules
	xWorkS=FilterStringRule(pWorkSet,FilterStringEquals(),"BL_New_Structural",False)
	xFamT=FilterStringRule(pFamType,FilterStringContains(),"2",False)
	
	# Create operators within the filter rule
	filt1=[]
	filt1.Add(ElementParameterFilter(xWorkS))
	filt1.Add(ElementParameterFilter(xFamT))
	icolfilt1=List[ElementFilter](filt1)
	andfilt1=LogicalAndFilter(icolfilt1)
	
	# Create filter and convert to an element in Revit
	TransactionManager.Instance.EnsureInTransaction(doc)
	
	pfeelem=ParameterFilterElement.Create(doc,filterdata[0+start], cat_ids_list, andfilt1)
	# filter_name wordt filterdata[0] en via while loop moet dat [5] worden.
	TransactionManager.Instance.TransactionTaskDone()
	
	### Avoid instance INput problem
	if isinstance(pfeelem, list):
		pfeelem = pfeelem
	else: pfeelem = [pfeelem]
	
	if isinstance(view, list):
		view = view
	else: view = [view]
	
	if isinstance(fpelement, list):
		fpelement = fpelement
	else: fpelement = [fpelement]
	
	if isinstance(filterdata[3+start], list):
		filterdata[3+start] = filterdata[3+start]
	else: filterdata[3+start] = [filterdata[3+start]]
	
	if isinstance(filterdata[4+start], list):
		filterdata[4+start] = filterdata[4+start]
	else: filterdata[4+start] = [filterdata[4+start]]
	

	### Overriding graphic settings
	try:
		for v, filt, fP, fC, ts in zip(view, pfeelem, fpelement, filterdata[3+start], filterdata[4+start]):
			TransactionManager.Instance.EnsureInTransaction(doc)
			over = OverrideGraphicSettings()
			over.SetSurfaceForegroundPatternId(UnwrapElement(fP).Id)
			over.SetSurfaceForegroundPatternColor(ToRevitColor(fC))
			over.SetSurfaceTransparency(ts)
			v = UnwrapElement(v)
			v.SetFilterOverrides(UnwrapElement(filt).Id, over)
			TransactionManager.Instance.TransactionTaskDone()
		OUT = "Graphics overschreven!"
	except:
		OUT = "Oops! Er gaat iets mis"
	
	start = start + 5
	end = end + 5