BIM Data Visualization with pyRevit & Streamlit
1. What is pyRevit
pyRevit (with lowercase py) is a Rapid Application Prototyping (RAD) environment for Autodesk Revit®. It helps you quickly sketch out your automation and add-on ideas, in whichever language that you are most comfortable with, inside the Revit environment and using its APIs. It also ships with an extensive set of powerful tools that showcase its capabilities as a development environment. Download and install pyRevit, launch Revit, and note the new pyRevit tab that includes these tools. pyRevit also ships with a handy CLI utility for customized configuration and deployment of your tools, and a telemetry server to monitor pyRevit usage across your teams. - pyRevit Official Doc
2. What is Streamlit
Streamlit allows you to develop the web data visualizization tool without front-end knowledge.
The command to install and execute streamlit in a sec.
As of May 2021, streamlit suports 3.6-3.8 verion of Python.
Before you run the streamlit command, make sure your python version with python3 --version
in your terminal.
pip install streamlit
streamlit hello
3. What is pyRevit Routes
Let's say we want to create a web application that would display a list of doors in a model. The web application would be split into two parts.
- Front-end: the part that runs in the browser and acts as the user interface, and
- Back-end: the part that the front-end contacts to send and receive data
While you are free to select whatever toolchain and GUI framework (React, Vue.js, etc) you are comfortable with for the front-end, the challenge has always been on how to create a back-end that has access to Revit contexts and can query or modify Revit documents. What we really needed is to run a HTTP web server over a running Revit instance and manage the HTTP calls in a way that would be executed in Revit context.
The new Routes python module, is an HTTP micro-framework to create web APIs running over Revit instances. This means that you can create functionality that could be triggerd from remote. This framework provides the necessary mechanism to create a back-end that has access to Revit context. - pyRevit Developer Docs
4. pyRevit Route Step-by-step
folder structure for pyRevit Extension
pyRevit already has a fuction to create your custom addin with creating folder as below. After creating the folder, set up the file, whose name should be startup.py
.
pyRevit-Sample-Extensions/
|----pyRevitRoute.Extension/
|----startup.py
5. Show Project Name in your browser
5.1 pyRevit-side
At first, we would like to get the project title under document class.
doc = __revit__.ActiveUIDocument.Document
title = doc.Title
After that, we need to specify the location to store the information.
At this time, we'd like to use /title
under route-sample
.
pyRevit Roputes is like flask that is web application library for python. If you've already experienced, it's more easy to understand what the script does.
from pyrevit import routes
api = routes.API('route-sample')
@api.route('/title')
def get_title(doc):
return routes.make_response(data=doc.Title)
This is pretty difference from pyRevit Addin development but we need to reload in each time.
Then let's try to open your browser and url is http://localhost:48884/route-sample/title.
If your browser shows like below, it's all you have to do from pyRevit side.
Let's move to streamlit side.
5.2 Streamlit side
Let's read the Json data from pyRevit.
I'd like to use requests
library to get the data.
Before you develop the streamlit app, please try the command to use requests library.
pip requests
To create Streamlit app, you need to prepare fot the app and create the file, app.py
The script for the app, it looks like below.
import streamlit as st
import requests
BASE_URL = 'http://localhost:48884/route-sample/'
def get_title():
url = BASE_URL + 'title'
res= requests.get(url)
if res.status_code == 200:
return res.json()
st.title(get_title())
To run your application, please type the below command.
streamlit run app.py
If success, your browser shows like this.
6. Create Level table with pandas
6.1 pyRevit side
To create the table, we need to get the all levels in the projefct.
At this moment, I'm using Revit Python Wrapper
to get all levels with ease.
And it's better to sort the revels by elevation using sorted
method.
One minor note: I would like to use metric units world so I converted the Elevation unit from feet to mm. If you customize the unit, please change this line int the one you wish. level_dict['Elevation']= level.Elevation * 304.8
@api.route('/levels')
def get_levels(doc):
level_list = []
levels = db.Collector(
of_category='Levels',
is_not_type=True).get_elements()
for level in levels:
level_dict = {}
level_dict['name'] = level.name
level_dict['Elevation']= level.Elevation * 304.8
level_list.append(level_dict)
sorted_level_list = sorted(level_list, key=lambda x:x['Elevation'])
return routes.make_response(data=sorted_level_list)
##6.2 Streamlit side
To show the table in your browser, the scripts need to update like below.
def get_levels():
name_list = []
elevation_list = []
url = BASE_URL + 'levels'
res= requests.get(url)
if res.status_code == 200:
for l in res.json():
name_list.append(l['name'])
elevation_list.append(l['Elevation'])
level_tuple = list(zip(name_list, elevation_list))
chart_data = pd.DataFrame(
level_tuple,
columns = ['Level Name','Elevation'])
return chart_data
st.subheader(" Levels ")
st.dataframe(get_levels())
If success, your browser shows like this.
7. Making Bar chart to count furniture family instance by family type
pyRevit side
Let's make bar chart for furniture family
To prepare the data, pyRevit side script should update like below.
@api.route('/furniture')
def get_furnitures(doc):
furnitures = db.Collector(
of_category='Furniture',
is_not_type=True).get_elements()
furniture_dict = {}
for w in furnitures:
if w.Symbol.FamilyName in furniture_dict.keys():
furniture_dict[w.Symbol.FamilyName] += 1
else:
furniture_dict[w.Symbol.FamilyName] = 1
return routes.make_response(data=furniture_dict)
Streamlit Side
Let's use st.bar_chart
to show the bar chart.
def get_furnitures():
url = BASE_URL + 'furniture'
res= requests.get(url)
if res.status_code == 200:
furniture_dict = res.json()
chart_data = pd.DataFrame(
furniture_dict.values(),
index=furniture_dict.keys())
return chart_data
st.subheader(" Furniture Type ")
st.bar_chart(get_furnitures())
If success, your browser shows like this.
Thank you to read the article, I'm very happy to hear your comment/question.
Please feel free to reach out to me.
Discussion