pyRevit Outputs

Similar to the forms we explored in the previous lesson, pyRevit has a lot of useful functionality for displaying results to users in various ways. Let's have a look

pyRevit Outputs

Similar to the forms we explored in the previous lesson, pyRevit has a lot of useful functionality for displaying results to users in various ways. Let's have a look

Summary

pyRevit Outputs

Let's continue exploring pyRevit Dev Docs and look at pyRevit Outputs.

This provides a lot of different examples to create better outputs for the users. We can structure our data in tables or charts, create linkable elements and even make it much better looking by using markdown or HTML prints.

But to use them, we need to import script module from pyrevit and use get_output() like this:

#⬇️ Imports
from Autodesk.Revit.DB import *
from pyrevit           import script

#📦 Variables
uidoc  = __revit__.ActiveUIDocument
doc    = __revit__.ActiveUIDocument.Document #type:Document
output = script.get_output()

Let's go through it and test different options we get, but before we do, we need to get an output instance from pyRevit.

Linkify - Crete Linkable Element

This is by far the most impressive thing in pyRevit output in my opinion.

It allows us to create a clickable object in the menu that can:

  • select the element

  • open a view

  • and even find where element is the best visible, and zoom on it.

Let's explore how to use it in multiple examples:

It's very simple to use, we need to provide ElementId or a list of ElementIds and a title. And this will create this clickable badge that can:

  • Select an Element

  • Find and Zoom to Element on a plan

  • Open a View (if View provided)

Let's create a few examples

Linkify Single Elements

Let's start by creating linkify for a single element.

We will simply get all_views and all_walls and create output prints for them.


# Linkify - Views
all_views = FilteredElementCollector(doc).OfClass(ViewPlan).ToElements()
for view in all_views:
    view_linkify = output.linkify(view.Id, view.Name)
    print(view_linkify)

# Linkify - Walls
all_walls = FilteredElementCollector(doc).OfClass(Wall).ToElements()
for wall in all_walls:
    wall_linkify = output.linkify(wall.Id, wall.Name)
    print(wall_linkify)
Linkify - Multiple Elements (List Warning Elements)


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():
    print('\n{}'.format(descr))

    for warn in list_warnings:
        # print(warn)
        element_ids = list(warn.GetFailingElements()) + list(warn.GetAdditionalElements())

        # Linkify
        title = '{} Elements'.format(len(element_ids))
        warn_linkify = output.linkify(element_ids, title)
        print(warn_linkify)
# Linkify Has Limit!
all_wall_ids = FilteredElementCollector(doc).OfClass(Wall).ToElementIds()
test_linkify = output.linkify(all_wall_ids)
print(test_linkify)
Table - List Elements with Warnings


= [['结构', '结构', '结构结构', 80],
        ['结构', '结构', '结构', 45],
        ['row3', 'data', 'data', 45],
        ['结构结构', 'data', '结构', 45]]

# formats contains formatting strings for each column
# last_line_style contains css styling code for the last line
output.print_table(table_data=data,
                   title="Example Table",
                   columns=["Row Name", "Column 1", "Column 2", "Percentage"],
                   formats=['', '', '', '{}%'],
                   last_line_style='color:red;')
# 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)

        # last_modified_by = []
        # for el_id in element_ids:
        #     wti = WorksharingUtils.GetWorksharingTooltipInfo(doc, el_id)
        #     last = wti.LastChangedBy
        #     if last not in last_modified_by:
        #         last_modified_by.append(last)

        # 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=['**{}**', '*{}*', '', ''])
Print Markdown



# HEADINGS (Make space after #!)
output.print_md('# Heading 1')
output.print_md('## Heading 2')
output.print_md('### Heading 3')
output.print_md('#### Heading 4')
output.print_md('##### Heading 5')
output.print_md('###### Heading 6')

# Formatting
output.print_md('*Italic Text*')
output.print_md('**Bold Text**')
output.print_md('***Bold Italic Text***')

# Bullet Points
output.print_md('- Bullet Point 1')
output.print_md('* Bullet Point 2')
output.print_md('+ Bullet Point 3')

# Hyperlinks
output.print_md('![LearnRevitAPI Logo](https://raw.githubusercontent.com/ErikFrits/EF-Tools/main/media/EF%20Logo%20-%20LearnRevitAPI.png)')
output.print_md('[LearnRevitAPI Website](https://learnrevitapi.com)')

# Horizontal Line
output.print_md('---')
output.print_md('***')
output.print_md('___')

# To-Do
output.print_md('[x] Task 1')
output.print_md('[ ] Task 2')
output.print_md('[ ] Task 3')
Print HTML


html_code = """<div style="width: 500px; background: linear-gradient(to right, purple, orange); border: 3px solid orange; border-radius: 10px; padding: 10px; text-align: center; box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.5); margin: 0 auto;">
    <h3 style="color: white;">Your Text Here</h3>
</div>"""

output.print_html(html_code)
# Get + Sort Warnings
dict_all_warnings = get_sorted_warnings()

for descr, list_warnings in dict_all_warnings.items():
    print('\n{}'.format(descr))

    html_code = """<div style="width: 500px; background: linear-gradient(to right, purple, orange); border: 3px solid orange; border-radius: 10px; padding: 10px; text-align: center; box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.5); margin: 0 auto;">
        <h3 style="color: white;">{}</h3>
    </div>""".format(descr)
    output.print_html(html_code)

    for warn in list_warnings:
        # print(warn)
        element_ids = list(warn.GetFailingElements()) + list(warn.GetAdditionalElements())

        # Linkify
        title = '{} Elements'.format(len(element_ids))
        warn_linkify = output.linkify(element_ids, title)
        print(warn_linkify)
Print Code


output.print_code("""
#include <iostream>
using namespace std;

int main()
{
    cout << "Hello world!" << endl;
    return 0;
}
""")

Progress Bar - Output Window


for i in range(10):
    import time
    time.sleep(1)

    print(i)
    output.update_progress(i+1, 10)
print('Started')
# output.indeterminate_progress(True)
output.unhide_progress()
print('Working!')
import time
time.sleep(3)

# output.indeterminate_progress(False)
output.hide_progress()

print('Finished')
Progress Bar - Application



from pyrevit.forms import ProgressBar

max_value = 100
with ProgressBar() as pb:
    for counter in range(0, max_value):
        pb.update_progress(counter, max_value)

max_value = 1000
with ProgressBar(title='My Process... ({value} of {max_value})') as pb:
    for counter in range(0, max_value):
        pb.update_progress(counter, max_value)
from pyrevit.forms import ProgressBar

max_value = 1000
with ProgressBar(cancellable=True) as pb:
    for counter in range(0, max_value):
        if pb.cancelled:
            break
        else:
            pb.update_progress(counter, max_value)
max_value = 1000
with ProgressBar(indeterminate=True, cancellable=True) as pb:
    # split the work in chunks and run pb.update_progress
    # periodically
    for counter in range(0, max_value):
        if pb.cancelled:
            break
        else:
            pb.update_progress(counter, max_value)
Logging Messages in Output


output.log_warning('Some message')
output.log_success('Some message')
output.log_info('Some message')
output.log_debug('Some message')
output.log_error('Some message')

for i in range(3):
    try:
        print('Trying to divide by 0.')
        print(1/0)
    except:
        print('Failed')
        import traceback
        output.log_error(traceback.format_exc())
Visualize Data - Charts


# get pie chart object
chart = output.make_pie_chart()

# Set the labels for the circumference axis
chart.data.labels = ['A', 'B', 'C']

# Create new data sets
set_a = chart.data.new_dataset('set_a')
set_a.data = [100, 20, 50]

# You can set a different color for each pie of the chart
set_a.backgroundColor = ["#560764", "#1F6CB0", "#F98B60"]
set_b = chart.data.new_dataset('set_b')
set_b.data = [50, 30, 80]
set_b.backgroundColor = ["#913175", "#70A3C4", "#FFC057"]
set_c = chart.data.new_dataset('set_c')
set_c.data = [40, 20, 10]
set_c.backgroundColor = ["#DD5B82", "#E7E8F5", "#FFE084"]

chart.draw()
get line chart object
chart = output.make_line_chart()

# this is a list of labels for the X axis of the line graph
chart.data.labels = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']

# Let's add the first dataset to the chart object
# we'll give it a name: set_a
set_a = chart.data.new_dataset('set_a')

# And let's add data to it.
# These are the data for the Y axis of the graph
# The data length should match the length of data for the X axis
set_a.data = [12, 19, 3, 17, 6, 3, 7]

# Set the color for this graph
set_a.set_color(0xFF, 0x8C, 0x8D, 0.8)


# Same as above for a new data set: set_b
set_b = chart.data.new_dataset('set_b')

# You can also set custom options for this graph
# See the Charts.js documentation for all the options
set_b.fill = False

# Obviously a different set of data and a different color
set_b.data = [2, 29, 5, 5, 2, 3, 10]
set_b.set_color(0xFF, 0xCE, 0x56, 0.8)

# Same as above for a new data set: set_c
set_c = chart.data.new_dataset('set_c')

# Obviously a different set of data and a different colorset_c.data = [55, 12, 2, 20, 18, 6, 22]
set_c.set_color(0x36, 0xA2, 0xEB, 0.8)

chart.draw()

pyRevit Output Examples


Summary


HomeWork

Now it's time for you to create your own reports with what you've learnt in this lesson.

👀 Have a look at your previous tools, and think where you could improve them by adding a more appealing outputs. Users will certainly appreciate it a lot.


😉 Bonus point for sharing your forms with the community

⌨️ Happy Coding!

Discuss the lesson:

P.S. Sometimes this chat might experience connection issues.
Please be patient or join via Discord app so you can get the most out of this community and get access to even more chats.

P.S. Sometimes this chat might experience connection issues.
Please be patient or join via Discord app so you can get the most out of this community and get access to even more chats.

© 2023-2024 EF Learn Revit API

© 2023-2024 EF Learn Revit API

© 2023-2024 EF Learn Revit API