Jun 10, 2024

Create Interactive Revit Reports with pyRevit Linkify

Learn how to use pyRevit's Linkify to create linkable buttons to select elements, open views or even find elements in the active view

pyRevit Linkify

pyRevit Linkify is a great feature that can create a linkable buttons to your elements and it can do 3 things:
- Select Elements
- Open Views
- Find Elements in the ActiveView (Zoom on it)

And it's super easy to use! Let's have a look at the documentation first to understand how to use it.

pyRevit Docs

There are 2 places you can check:

1. pyRevit Dev Docs - Effective Outputs

2. pyRevit ReadTheDocs - Linkify

Import Linkify

Before we dive into the examples, I want you to understand that you need to import script from pyRevit and then get the output so we can use linkify function. Here is the example:

#⬇️ Import and Variable
from pyrevit import script
output = script.get_output()

#👉 Get An Element
el = ... # Get Your Element

#🔗 Create Linkify
el_linkify = output.linkify(el.Id) 

#👀 Print Linkify Button
print(el_linkify)

Now let's have a look at a few examples.

Example 1 - Linkify Single Elements

Let's begin by looking at the examples.

Here is an example to create Linkify for a single element. We will grab all walls in a view and then create linkify button for each wall. Also notice that I've provided wall.Name as the second argument, and that will be the title of our linkify button.

Here is the code:

# 1️⃣ Linkify Single - Walls
all_walls = FilteredElementCollector(doc, doc.ActiveView.Id).OfClass(Wall).ToElements()

for wall in all_walls:
    linkify_wall = output.linkify(wall.Id, wall.Name)
    print(linkify_wall)

Example 2 - Linkify Multiple Elements

We can also provide a list of Element Ids if we want to create a linkable button for many elements at once.

#2️⃣ Linkify Multiple - Walls
all_walls     = FilteredElementCollector(doc, doc.ActiveView.Id).OfClass(Wall).ToElements()
wall_ids      = [wall.Id for wall in all_walls]
linkify_walls = output.linkify(wall_ids, 'Walls {}'.format(len(wall_ids)))
print(linkify_walls)


Example 3 - Linkify Limitation

But keep in mind that Linkify has a limit on how many elements can be included in a single button. Usually you will notice it somewhere around 100-150 elements.

Let's put hundreds of walls into a single linkify button to see what kind of an issue we might encounter.

#3️⃣ Limit ~100-150 elements
all_walls     = FilteredElementCollector(doc).OfClass(Wall).ToElements()
wall_ids      = [wall.Id for wall in all_walls]
linkify_walls = output.linkify(wall_ids, 'Walls {}'.format(len(wall_ids)))
print('Here are all the walls in the project: {}'.format(linkify_walls))

This will still create the button without any issues, however, when you try to use it you will see the following error:

Example 4 - Linkify Views

You will also notice that you can linkify views. And by clicking on suck a linkify button it will open that specific view.

It's great if you want to quickly create a list of views and easily jump between them. This is especially useful if you work on a large project and you have hundreds of views, and sometimes it gets tedious to open the right ones for the day.

So here is a simple sample:

4️⃣ Linkify - Views
all_views_and_vt = FilteredElementCollector(doc).OfClass(ViewPlan).ToElements()
all_views        = [view for view in all_views_and_vt if not view.IsTemplate]

for view in all_views:
    linkify_view = output.linkify(view.Id, 'View: {}'.format(view.Name))
    print(linkify_view)

Example 5 - Analyze Warnings

Alright, now let's put this to use.

You've seen various example of using Linkify, but probably it wasn't that impressive. Now I want to show you a simple tool that can be extremely useful when you work with Revit Warnings.

This example will:
1. Get all warnings in the project,
2. Find elements related to these warnings
3. Find out who was the last person to modify them.
4. Print out the table that will have
- Warning Description
- Username of LastChangedBy
- Linkable Button to select and find these elements

#5️⃣ Bonus Example: Analyze Warnings
def get_sorted_warnings():
    """Function to get All Warnings in the project and sort them by their description
    :return: dict of warnings {warn_description : list_of_warnings}"""
    from collections import defaultdict

    dict_all_warnings = defaultdict(list)
    for w in doc.GetWarnings():
        description = w.GetDescriptionText()
        dict_all_warnings[description].append(w)
    return dict_all_warnings

# Get + Sort Warnings
dict_all_warnings = get_sorted_warnings()

for descr, list_warnings in dict_all_warnings.items():
    table_data = []

    for warn in list_warnings:

        # print(warn)
        element_ids      = list(warn.GetFailingElements()) + list(warn.GetAdditionalElements())
        last_modified_by = {WorksharingUtils.GetWorksharingTooltipInfo(doc, el_id).LastChangedBy for el_id in element_ids}
        last_modified_by = ', '.join(last_modified_by)

        # Linkify
        title = 'Select'
        warn_linkify = output.linkify(element_ids, title)

        # Create a Row of Data
        row = [descr, last_modified_by, str(len(element_ids)), warn_linkify]
        table_data.append(row)
    output.print_table(table_data=table_data,
                       title  =descr,
                       columns=['Warning Description', 'Last Modified By:', 'Elements', 'Linkify'],
                       formats=['**{}**', '*{}*', '', ''])

Overall it's not that complicated, and it gives you great results like this:

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.