Oct 15, 2022

Get TitleBlock from Sheet.

Learn how to get TitleBlocks from ViewSheet with ElementParmaeterFilter in Revit API

How to Get Title Blocks from Sheets with Revit API❓

There are multiple ways of getting TitleBlocks from Sheets:

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.

# -*- coding: utf-8 -*-

#⬇️ IMPORTS
from Autodesk.Revit.DB import  *

#📦 VARIABLES
doc      = __revit__.ActiveUIDocument.Document
app      = __revit__.Application
rvt_year = int(app.VersionNumber)

# 👇 FUNCTION
def get_titleblocks_from_sheet(sheet, doc):
    # type:(ViewSheet, Document) -> list
    """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 ARGUMENTS
    rule_value         = sheet.SheetNumber
    param_sheet_number = ElementId(BuiltInParameter.SHEET_NUMBER)
    f_pvp              = ParameterValueProvider(param_sheet_number)
    evaluator          = FilterStringEquals()

    # CREATE A RULE (Method has changed in Revit API in 2022)
    if rvt_year < 2022:
        f_rule = FilterStringRule(f_pvp, evaluator, rule_value, True)  # RVT 2021-
    else:
        f_rule = FilterStringRule(f_pvp, evaluator, rule_value)        # RVT 2022+

    # CREATE A FILTER
    tb_filter = ElementParameterFilter(f_rule)

    # GET TITLEBLOCKS
    tb = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_TitleBlocks) \
        .WhereElementIsNotElementType().WherePasses(tb_filter).ToElements()

    return list(tb)


#🎯 MAIN
if __name__ == '__main__':
    # GET RANDOM SHEET
    random_sheet = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Sheets)\
        .WhereElementIsNotElementType().FirstElement()
 
    # GET TITLEBLOCK
    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.

Get TitleBlocks AB.png

🧮 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

# -*- coding: utf-8 -*-
#⬇️ IMPORTS
from Autodesk.Revit.DB import  *
import time

#📦 VARIABLES
doc   = __revit__.ActiveUIDocument.Document
app   = __revit__.Application
rvt_year = int(app.VersionNumber)

# 👇 FUNCTION
def get_titleblocks_from_sheet(sheet, doc):
    # type:(ViewSheet, Document) -> list
    """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 ARGUMENTS
    rule_value = sheet.SheetNumber
    param_sheet_number = ElementId(BuiltInParameter.SHEET_NUMBER)
    f_pvp = ParameterValueProvider(param_sheet_number)
    evaluator = FilterStringEquals()

    # CREATE A RULE
    if rvt_year < 2022:
        f_rule = FilterStringRule(f_pvp, evaluator, rule_value, True)  # RVT 2021-
    else:
        f_rule = FilterStringRule(f_pvp, evaluator, rule_value)        # RVT 2022+

    # CREATE A FILTER
    tb_filter = ElementParameterFilter(f_rule)

    # GET TITLEBLOCKS
    tb = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_TitleBlocks) \
        .WhereElementIsNotElementType().WherePasses(tb_filter).ToElements()

    return list(tb)

#🎯 MAIN
if __name__ == '__main__':
    all_sheets = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Sheets)\
        .WhereElementIsNotElementType().ToElements()
    print('Total {} Sheets.'.format(len(all_sheets)))

    # Reduce Sheets to run quicker.
    try:     all_sheets = list(all_sheets)[:10]
    except:  pass

    print("Get Titleblocks from {} Sheets:".format(len(all_sheets)))
    print('-'*100)


    #🅱️ OPTION B
    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)

    #🅰️ OPTION A
    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'

Join Newsletter

📩 You will be added to Revit API Newsletter

Join Us!

which is already read by 7400+ people!

Ready to become Revit Hero for your office? Learn Revit API!

Join this comprehensive course that will guide you step by step on how to create your dream tools for Revit that save time.