How to set familyinstance parameter

python

#1

I have a family which has a instance length parameter name “extend_len”
and I am trying to place this family instance somewhere and set its parameter accordingly.

I coded like below

fmtype = Revit.Elements.FamilyType.ByName(‘S05P’)}

fmins=Revit.Elements.FamilyInstance.ByPoint(fmtype,Point.ByCoordinates(1,2,3))

fmins.setParameterByName(“extend_len”,700)

then I got error like what this thread mentionedhttps://forum.dynamobim.com/t/familyinstance-object-has-no-attribute-setparameterbyname/6310

I don’t quite understand the “implementation” mentioned,I tried something like “fmins.Set”,but no luck.
Then I tried as below,but this is way so ugly and I can’t do it for all my parts in a for loop

any ideas?
Thanks in advance!


#2

Hi @kaeyonbaker,

It is good practice to either upload your script, or at least copy/paste the ALL the Python code so we can advise better (you will get faster help that way and won’t get told off for not giving enough info). :slight_smile:

To begin with, Element.SetParameterByName() is a Dynamo node and isn’t a method on the actual Revit API object. When using Dynamo Nodes in python, the arguments (which are the inputs between the () at the end of the method name) are the same as the IN ports to the node. For instance, to create a simple Line.ByStartPointEndPoint(), you would write is like so…

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

p1 = IN[0]
p2 = IN[1]

l = Line.ByStartPointEndPoint(p1,p2)

OUT = l

which is equivalent to the actual node in Dynamo…
image

So, you can see that the Inputs of the node and Arguments are the same. To use the Element.SetParameterByName() method correctly, look at the following python example…

Example 01

import clr

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

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

# Used to Ensure that object is in a list...
def tolist(obj1):
if hasattr(obj1,"__iter__"): return obj1
else: return [obj1]

### Input Variables ###
# Ensure elems is a list to satisfy For Loop if only one element is passed. NOTE: Element has NOT been Unwrapped using the UnwrapElement conversion method as not using Revit API.
elems = tolist(IN[0])
# List of Parameter Names to find and update...
pNames = tolist(IN[1])
# List of Parameter Values to update to...
pVals = tolist(IN[2])

### Output Variables ###
outList = []

### Main Body ###
# Test if number of Parameter Names is equal to number of values...
if len(pNames) == len(pVals):
# Loop through all the input Elements...
for e in elems:
# Loop through all parameter names and values at once...
for n,v in zip(pNames,pVals):
# using Try/Except statement to handle errors...
try:
# Using Element.SetParameterByName Node. Note that the Revit.Elements.Element.SetParameterByName() is the same as the Library browser location. This is important. ie you can't just call Element.SetParameterByName()...
elem = Revit.Elements.Element.SetParameterByName(e,n,v)
outList.append(elems)
# Report Exception message...
except Exception, ex:
outList.append(ex.message)
# Return Results...
OUT = outList
else:
OUT = "The number of Parameter Names does not match the number of Parameter Values"

Now, you could also do this using the Revit API. The equivalent(ish) python code using Revit API is something like this…

Example 02

import clr

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc =  DocumentManager.Instance.CurrentDBDocument

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

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

# Used to Ensure that object is in a list...
def tolist(obj1):
	if hasattr(obj1,"__iter__"): return obj1
	else: return [obj1]

### Input Variables ###
# Ensure elems is a list to satisfy For Loop if only one element is passed. NOTE: Since we are wanting to use the Revit API, you need to use the UnwrapElement() method. This means that you can use the Revit API methods on the Object.
elems = tolist(UnwrapElement(IN[0]))
# List of Parameter Names to find and update...
pNames = tolist(IN[1])
# List of Parameter Values to update to...
pVals = tolist(IN[2])

### Output Variables ###
outList = []

### Main Body ###
# Get Document Display Unit Type for Length to convert any Parameters of type Length later on...
dut = doc.GetUnits().GetFormatOptions(UnitType.UT_Length).DisplayUnits
# Test if number of Parameter Names is equal to number of values...
if len(pNames) == len(pVals):
	# Transaction required to make change in Revit...
	TransactionManager.Instance.EnsureInTransaction(doc)
	# Loop through all Elements...
	for e in elems:
		# Loop through all parameter names and values at once...
		for n,v in zip(pNames,pVals):
			# using Try/Except statement to handle errors...
			try:
				# Using LookupParameter method since we are searching by Parameter Name...
				p = e.LookupParameter(n)
				
				# Check if the Parameters Type is Length and convert to Revits Internal Units. ie if you are using metric mm, this will convert all length parameters to imperial ft. Revit uses imperial for everything, therefore you need to convert. Add additional logic if you need to convert other Parameter Types ie Forces etc
				if p.Definition.ParameterType == ParameterType.Length:
					v = UnitUtils.ConvertToInternalUnits(v,dut)
				
				# Set the Parameters value. If unit type does not match the Parameters Unit Type, then this will fail. ie passing a string into a parameter that takes an integer will fail...
				p.Set(v)
				outList.append(e)
			# Report Exception message...
			except Exception, ex:
				outList.append(ex.message)
	# Closing current Transaction to commit changes...
	TransactionManager.Instance.TransactionTaskDone()
	# Return results...
	OUT = outList
else:
	OUT = "The number of Parameter Names does not match the number of Parameter Values"

image

I hope this helps you understand the difference between using Revit Nodes and Revit API in your python code. Also note, Example 01 using Revit Nodes in code is much simpler and doesn’t require Transactions and other bits and pieces. This is because the Revit Node itself has all of that already implemented. This is useful to know. I prefer to stick to one or the other and not mix them up, so either pure Revit API or pure Dynamo Revit Nodes. Although, you could wrap/unwrap to make use of both.

This is a very long answer to a quite a simple question, but I thought I would be thorough.

Hope this answers your questions and clarifies the different ways in which you can leverage Revit Nodes or Revit API effectively in python.

Cheers,
Dan


#3

Big Thanks!
I read your so detailed post carefully and thoroughly and found that the key points I missed out is

param = fmins.LookupParameter(name)
param.Set(value)

Besides,your code which takes good care on input inspecting,error handling and unit transfering is also quite inspiring!


#4

You’re welcome @kaeyonbaker. I’m glad this helped! :wink: