How to Get Title Blocks from Sheets with Revit API❓
There are multiple ways of getting TitleBlocks from Sheets:
💪Use ElementParameterFilter
👉️ Get visible TitleBlocks with FilteredElementCollector(doc, view.Id) <- Slower
👉️ Get all TitleBlocks and look at their OwnerViewId
I would recommend using a function with ElementParameterFilter
, since it's already written for you and it's a no-brainer.
1️⃣ Get TitleBlock with ElementParameterFilter
For this method we will need to create ElementParameterFilter and use it in FilteredElementCollector. This is probably the most efficient way to get TitleBlocks from sheets.
💡 Also notice that there are differences in Revit API for FilterStringRule, but I accounted for it in my snippet.
from Autodesk.Revit.DB import *
doc = __revit__.ActiveUIDocument.Document
app = __revit__.Application
rvt_year = int(app.VersionNumber)
def get_titleblocks_from_sheet(sheet, doc):
"""Function to get TitleBlocks from the given ViewSheet.
:param sheet: ViewSheet that has TitleBlock
:param doc: Document instance of the Project
:return: list of TitleBlocks that are placed on the given Sheet."""
rule_value = sheet.SheetNumber
param_sheet_number = ElementId(BuiltInParameter.SHEET_NUMBER)
f_pvp = ParameterValueProvider(param_sheet_number)
evaluator = FilterStringEquals()
if rvt_year < 2022:
f_rule = FilterStringRule(f_pvp, evaluator, rule_value, True)
else:
f_rule = FilterStringRule(f_pvp, evaluator, rule_value)
tb_filter = ElementParameterFilter(f_rule)
tb = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_TitleBlocks) \
.WhereElementIsNotElementType().WherePasses(tb_filter).ToElements()
return list(tb)
if __name__ == '__main__':
random_sheet = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Sheets)\
.WhereElementIsNotElementType().FirstElement()
title_block = get_titleblocks_from_sheet(random_sheet, doc)
__author__ = '🙋♂️ Erik Frits'
2️⃣ Get visible TitleBlocks with FilteredElementCollector(doc, view.Id)
There is an alternative method to use FilteredElementCollector
and provide ViewSheet.Id
as a second argument to get elements visible in that sheet.
title_blocks = FilteredElementCollector(doc, sheet.Id)\
.OfCategory(BuiltInCategory.OST_TitleBlocks)\
.WhereElementIsNotElementType()\
.ToElements()
💡 This is much easier approach but it will cost in execution time!
Comparison
I was curious about the difference between these two methods, so I put them to the test.
The second method is slower because it has to load up the view to analyze what elements are visible and it comes at a cost!
💡I used a Revit project that is ~500mb and I used similar logic of getting title blocks,
👇 Here are the results.
🧮 As you can see there is a huge difference.
10s
vs 252s
- It's ~2500% difference!
The difference is going to be less on smaller projects. But on large projects where it takes longer times to render views, it might become an issue.
The problem is that whenever you provide View.Id
to FilteredElementCollector
it has to partially render the view. While on a smaller projects this difference can be little, on large projects it might become an issue.
Honestly, though?
I was too lazy to make separate buttons for each method—so my comparison isn't perfect—but with such a huge difference, who cares?
You can take a look at the code below that I quickly wrote to see how I made comparison
👀 Comparison of Get TitleBlock methods
from Autodesk.Revit.DB import *
import time
doc = __revit__.ActiveUIDocument.Document
app = __revit__.Application
rvt_year = int(app.VersionNumber)
def get_titleblocks_from_sheet(sheet, doc):
"""Function to get TitleBlocks from the given ViewSheet.
:param sheet: ViewSheet that has TitleBlock
:param doc: Document instance of the Project
:return: list of TitleBlocks that are placed on the given Sheet."""
rule_value = sheet.SheetNumber
param_sheet_number = ElementId(BuiltInParameter.SHEET_NUMBER)
f_pvp = ParameterValueProvider(param_sheet_number)
evaluator = FilterStringEquals()
if rvt_year < 2022:
f_rule = FilterStringRule(f_pvp, evaluator, rule_value, True)
else:
f_rule = FilterStringRule(f_pvp, evaluator, rule_value)
tb_filter = ElementParameterFilter(f_rule)
tb = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_TitleBlocks) \
.WhereElementIsNotElementType().WherePasses(tb_filter).ToElements()
return list(tb)
if __name__ == '__main__':
all_sheets = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Sheets)\
.WhereElementIsNotElementType().ToElements()
print('Total {} Sheets.'.format(len(all_sheets)))
try: all_sheets = list(all_sheets)[:10]
except: pass
print("Get Titleblocks from {} Sheets:".format(len(all_sheets)))
print('-'*100)
b_start = time.time()
all_tbs = []
for sheet in all_sheets:
tb = get_titleblocks_from_sheet(sheet, doc)
all_tbs += list(tb)
print('*** Get TitleBlocks with ElmenetParameterFilter(rule)')
print('TitleBlocks: {}'.format(len(all_tbs)))
print("It Took {}s to complete with ElementParameterFilter(rule)".format(time.time() - b_start))
print('-'*100)
a_start = time.time()
all_tb = []
for i in all_sheets:
tb = FilteredElementCollector(doc, i.Id).OfCategory(BuiltInCategory.OST_TitleBlocks)\
.WhereElementIsNotElementType().ToElements()
all_tb += list(tb)
print('*** Get TitleBlocks with FilteredElementCollector(doc, View.Id)')
print('TitleBlocks: {}'.format(len(all_tb)))
print("It Took {}s to complete with FEC(doc,View.Id)".format(time.time() - a_start))
__author__ = '🙋♂️Erik Frits'