I am wanting to write a python script that generates panel schedules for all the electrical panels in a model. I took a look at revitapi docs and see that the ‘PanelScheduleSheetInstance’ Class has the tools necessary to accomplish this. My problem is that I am having difficulty putting the pieces together.
I have identified the method that gives me what I want
but I am not fully understanding how to incorporate this method into the python script. Still fairly new to python in dynamo so any help is appreciated!
Here is what I have so far. Basically I just need someone to show me how to correctly incorporate this create method into the python script. Thanks!
Are you trying to create the panel schedule itself or place an existing schedule on a sheet? You have the method for placing an existing panel schedule on a sheet (which takes the active document, the existing schedule Id, and the sheet.) If you’re wanting to create a new schedule from a panel you’ll want to use one of these Create methods. CreateInstanceView (using default template) CreateInstanceView (using specific template)
For now it sounds like the CreateInstanceView method is the one I need. I see that the method takes Document and ElementId as inputs, but what exactly is this ‘Document’? Is that just the revit file in which I am working?
Yes. It’s the Revit “document” (file) that you’re working in. Document.Current is a standard node you can use but you can also pull it directly from Python. A lot of custom nodes include the document.
import clr
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument
OUT = doc
It looks like you are inputting multiple panels, thus the “TypeError: expected ElementId, got List[object]”-warning. In order for this to work with multiple panels, you need to loop through your list of panel id’s.
You could set it up as shown below:
import clr
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
panels = UnwrapElement(IN[0])
output = []
for i in panels:
TransactionManager.Instance.EnsureInTransaction(doc)
output.append(Electrical.PanelScheduleView.CreateInstanceView(doc, i.Id))
TransactionManager.Instance.TransactionTaskDone()
#Assign your output to the OUT variable.
OUT = output
I’ve commented the code here, and now taken into account, that the input may be a single item or a list of items:
import clr
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
#Import ToDSType(bool) extensions method
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)
doc = DocumentManager.Instance.CurrentDBDocument
#Input should be the elements and not the element id's
#Use the ifinstance() built in python function to check if the input is a list or a single object.
#This is a common way to solidify the code incase inputs can be either a list of items or a single item:
#Read more here: https://docs.python.org/2/library/functions.html#isinstance
#if its a list object, iterate through it, and unwrap the elements.
if isinstance(IN[0], list):
panels = [UnwrapElement(i) for i in IN[0]]
#if its a single item, it will be unwrapped in a list with a single item
else:
panels = [UnwrapElement(IN[0])]
#Create an empty list to hold the output
output = []
#Iterate through the list with a for loop
for i in panels:
TransactionManager.Instance.EnsureInTransaction(doc) #We're making changes to the document, thus a transaction is needed
output.append(Electrical.PanelScheduleView.CreateInstanceView(doc, i.Id).ToDSType(False))
#The create method used takes the document and an element ID as inputs.
#So we're iterating through each panel and call the Id property of the family instance by using dot notation.
#Use the .ToDSType(False) as we're creating new non-Revit owned elements
#See here for family instance properties http://www.revitapidocs.com/2018.1/9235095b-b7ae-b6e5-6cc2-2b8d397644de.htm
#See here for Dynamo python migration https://github.com/DynamoDS/Dynamo/wiki/Python-0.6.3-to-0.7.x-Migration#revitapi
TransactionManager.Instance.TransactionTaskDone()
#Assign your output to the OUT variable.
OUT = output
Personally, I’d always use the actual element as input, and the call the ID from inside the code, but it can ofcause also be set up with the element ID as input.
You need to be careful here. You are still inputting a list of a single item. You can see in your output that you have a List of a single item (at index 0) and that you have two levels available, not just one. There is definitely a difference between a singleton and a list containing only one item.
@stedel, thank you! I’ve been working and supporting Revit for almost 10 years now…I never knew about the PS shortcut. And here I was preparing to get into Dynamo to solve the issue.