Data scientists use data visualization to communicate data and generate insights. It’s essential for data scientists to know how to create meaningful visualization dashboards, especially real-time dashboards. This article talks about two ways to get your real-time dashboard in Python:
- First, we use streaming data and create an auto-updated streaming dashboard.
- Second, we use a “Refresh” button to refresh the dashboard whenever we need the dashboard to be refreshed.
For demonstration purposes, the plots and dashboards are very basic, but you will get the idea of how we do a real-time dashboard.
The code for this article can be found here: realtime_dashboard.ipynb and realtime_dashboard.py. The content of these two files is completely the same, just in different formats.
Data source
To show how we create this dashboard with a real-world API, we use weather data from the OpenWeather API as an example in this article.
If you would like to try out the code mentioned in this article, you will need to get access to the OpenWeather weather API. You can sign up at the Open Weather website and then get the API keys.
Set up
Before going into the code, let’s install the needed packages:
conda install datashader holoviews hvplot notebook numpy pandas panel param requests streamz
Import packages
Here we import the packages used for this article:
import operator as op import numpy as npimport pandas as pd import requests import param import panel as pn import hvplot.pandas import hvplot.streamz import holoviews as hv from holoviews.element.tiles import EsriImagery from holoviews.selection import link_selections from datashader.utils import lnglat_to_meters from streamz.dataframe import PeriodicDataFrame
Streaming data and dashboard
First, we make a function ‘weather_data’ to get weather data for a list of cities using the OpenWeather API. The output is a pandas dataframe with each row representing each city.
def weather_data(cities, openweathermap_api_key=openweathermap_api_key): """ Get weather data for a list of cities using the openweathermap API """ L = [] for c in cities: res = requests.get(f'http://api.openweathermap.org/data/2.5/weather?q={c}&appid={openweathermap_api_key}&units=imperial') L.append(res.json()) df = pd.DataFrame(L) df['lon'] = df['coord'].map(op.itemgetter('lon')) df['lat'] = df['coord'].map(op.itemgetter('lat')) df['Temprature'] = df['main'].map(op.itemgetter('temp')) df['Humidity'] = df['main'].map(op.itemgetter('humidity')) df['Wind Speed'] = df['wind'].map(op.itemgetter('speed')) return df[['name','lon', 'lat','Temprature','Humidity','Wind Speed']]
Second, we use ‘streamz’ to create a streaming dataframe based on San Francisco’s weather data. The function ‘streaming_weather_data’ is used as a callback function by the PeriodicDataFrame function to create a ‘streamz’ streaming dataframe ‘df’. ‘streamz’ docs documented how ‘PeriodicDataFrame’ works:
streamz provides a high-level convenience class for this purpose, called a PeriodicDataFrame. A PeriodicDataFrame uses Python’s asyncio event loop (used as part of Tornado in Jupyter and other interactive frameworks) to call a user-provided function at a regular interval, collecting the results and making them available for later processing.
def streaming_weather_data(**kwargs): """ callback function get San Francisco weather data """ df = weather_data(['San Francisco']) df['time'] = [pd.Timestamp.now()] return df.set_index('time') Make a streaming dataframe df = PeriodicDataFrame(streaming_weather_data, interval='30s')
The ‘streamz’ streaming dataframe ‘df’ looks like this, with values updated every 30s (since we set interval=’30′).
Third, we make some very basic plots using ‘hvPlot’ to plot the ‘streamz’ dataframe, and then we use ‘panel’ to organize the plots and put everything in a dashboard. If you would like to know more about how to use ‘hvPlot’ to plot ‘streamz’ dataframe, please see hvPlot docs.
# panel dashboard for streaming data pn_realtime = pn.Column( pn.Row( df[['Temprature']].hvplot.line(title='Temprature', backlog=1000), df[['Humidity']].hvplot.line(title='Humidity', backlog=1000)), df[['Wind Speed']].hvplot.line(title='Wind Speed', backlog=1000))
Here is what the dashboard looks like. Since the streaming dataframe updates every 30s, this dashboard will automatically update every 30s as well. Here we see that Temperature changed, while humidity and wind speed did not.
Great, now you know how to make a streaming dataframe and a streaming dashboard.
Refresh dashboard
Sometimes, we don’t really need a streaming dashboard. Instead, we might just like to refresh the dashboard whenever we see it. In this section, I am going to show you how to make a “Refresh” button in your dashboard and refresh the dashboard with new data whenever you click “Refresh.”
First, let’s make a simple function ‘weather_plot’ to plot weather data on a map given city names and return both the plot and the data.
cities = ['San Francisco', 'Los Angeles', 'Santa Barbara', 'Sacramento', 'Fresno','San Diego', 'San Luis Obispo'] def weather_plot(col, cities=cities): """ plot weather data on a map col: 'Temprature', 'Humidity', 'Wind Speed' """ df = weather_data(cities) df['x'], df['y'] = lnglat_to_meters(df['lon'], df['lat']) table = hv.Table(df[['name', col]]).opts(width=800) points = df.hvplot.scatter('x','y', c=col, cmap='bkr', hover_cols=['name']) map_tiles = EsriImagery().opts(alpha=0.5, width=900, height=480, bgcolor='white') return pn.Column(points * map_tiles, table)
With the plotting function ready, we can start making the refreshable dashboard. I use the ‘param.Action’ function to trigger an update whenever we click on the button ‘Refresh’. In addition, I use the ‘param.ObjectSelector’ function to create a dropdown menu of the dataframe columns we are interested in plotting and ‘param.ObjectSelector’ trigger an update whenever we select a different option in the dropdown menu. Then the ‘@param.depends(‘action’, ‘select_column’)’ decorator tells the ‘get_plot’ function to rerun whenever we click the Refresh button or select another column.
class refresh_weather_dashboard(param.Parameterized): action = param.Action(lambda x: x.param.trigger('action'), label='Refresh') select_column = param.ObjectSelector(default='Temprature', objects=['Temprature', 'Humidity', 'Wind Speed']) @param.depends('action', 'select_column') def get_plot(self): return weather_plot(self.select_column) weather_dashboard = refresh_weather_dashboard() pn_weather = pn.Column( pn.panel(weather_dashboard.param, show_labels=True, show_name=False, margin=0),
weather_dashboard.get_plot, width=400 )
Here is what the refresh dashboard looks like:
Finally, we can use ‘panel’ to combine the two dashboards we created.
pane = pn.Tabs( ('Real Time', pn_realtime), ('Refresh Weather Dashboard', pn_weather) ).servable() pane
Deployment
Our final dashboard ‘pane’ is a ‘panel’ object, which can be served by running:
panel serve realtime_dashboard.py
or
panel serve realtime_dashboard.ipynb
For more information on ‘panel’ deployment, please refer to the ‘panel’ docs.
Now you know how to make a real-time streaming dashboard and a refreshable dashboard in python using ‘hvplot’ , ‘panel’ and ‘streamz’. Hope you find this article helpful!
References
https://openweathermap.org/api
https://panel.holoviz.org/gallery/param/action_button.html
https://streamz.readthedocs.io/en/latest/dataframes.html
https://hvplot.holoviz.org/user_guide/Streaming.html
https://panel.holoviz.org/user_guide/Deploy_and_Export.html
About the Author
Sophia Yang
Sophia Yang is a Senior Data Scientist at Anaconda, Inc., where she uses data science to facilitate decision making for various departments across the company. She volunteers as a Project Incubator at NumFOCUS to help Open Source Scientific projects grow. She is also the author of multiple Python open-source libraries such as condastats, cranlogs, PyPowerUp, intake-stripe, and intake-salesforce. She holds an MS in Statistics and Ph.D. in Educational Psychology from The University of Texas at Austin.