Bokeh is a powerful data visualization library that allows you to create interactive plots, dashboards, and applications in Python. One of the key features of Bokeh is its ability to handle streaming data and update plots in real time. A real-time data visualization is an essential tool for many fields such as finance, IoT, health monitoring, and many more. Bokeh makes it easy to create real-time data visualizations and dashboards with minimal code.
In this tutorial, we will explain the basics of working with real-time streaming data in Bokeh. We will cover how to create a streaming data source, update a plot in real-time, and create a real-time dashboard. We'll explain how to work with streaming data in jupyter notebook first and then we'll create an independent Bokeh web app as well. We'll be creating a simple line chart that retrieves the latest Bitcoin prices from REST API every second and displays it.
Below, we have included a sample GIF showing how our app will look.
The API returns the current Bitcoin price in USD as JSON data. We'll hit it every second to get the latest price and add it to our line chart.
By the end of this tutorial, you will have a comprehensive understanding of how to work with real-time streaming data in Bokeh and how to create powerful and interactive real-time dashboards and applications.
If you are comfortable learning through videos then please check our video tutorial.
Below, we have imported bokeh and printed the version that we have used in our tutorial.
import bokeh
print("Bokeh Version : {}".format(bokeh.__version__))
Below, we have imported python libraries requests, time, and datetime. The requests will be used to hit REST API and retrieve bitcoin prices.
The output_notebook() function is needed to display bokeh charts in jupyter notebooks.
import requests
import time
from datetime import datetime
from bokeh.io import output_notebook
output_notebook()
Below, we have created a data source that we'll use for creating a chart. We'll be updating this data source with new Bitcoin prices as we retrieve them by hitting REST API.
The code creates a new ColumnDataSource object named data_source and initializes it with an empty dictionary containing two keys, "Close" and "DateTime", with their corresponding values as empty lists.
ColumnDataSource is a fundamental Bokeh data structure used for mapping column-oriented data (like Pandas dataframes or dictionaries) to visual properties of glyphs, such as x and y coordinates, colors, sizes, and so on. It provides a convenient interface to pass data from Python to Bokeh plots and widgets.
In this case, the data_source object is being initialized with empty lists for "Close" and "DateTime" columns.
from bokeh.models import ColumnDataSource
data_source = ColumnDataSource(data = {"Close": [], "DateTime": []})
Below, we have created our line chart using the data source created above. Initially, this chart will be empty. But it'll be populated with values as we update the data source with new values.
In order to update the chart, we have set notebook_handle parameter to True in a call to show() function. This will return a handle which will be used to push changes to the chart.
In the next section, we have written code that updates the data source with new values and pushes changes to the chart to update it every second.
from bokeh.plotting import figure
from bokeh.io import show
fig = figure(x_axis_type="datetime",
plot_width=900, plot_height=450,
tooltips=[("Close", "@Close"),],
title="Bitcoin Close Prices Live (Every Second)"
)
fig.line(x="DateTime", y="Close", line_color="tomato", line_width=3.0, source=data_source)
fig.xaxis.axis_label = "Date Time"
fig.yaxis.axis_label = "Price ($)"
handle_line_chart = show(fig, notebook_handle=True)
Below, we have included code that retrieves bitcoin close prices every second and adds it to data source to update the chart with new values.
The code defines a URL variable that holds a URL for a cryptocurrency API that retrieves the price of Bitcoin in US dollars.
The code then enters into an infinite loop that continuously fetches the latest data from the API, extracts the USD price value and the current datetime, creates a new dictionary new_row containing this data, and appends this new row to an existing ColumnDataSource object named data_source using the stream() method. This ensures that the data in the ColumnDataSource object is continuously updated with the latest values.
The push_notebook() function is then called with the handle_line_chart handle to push the updated data and plot to the notebook.
Finally, the time.sleep(1) function is called to pause the execution of the loop for one second before repeating the process. This creates a continuous stream of updated data and plots in the notebook.
from bokeh.io import push_notebook
url = "https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD"
while True:
resp = requests.get(url)
hist_data = resp.json()
new_row = {"Close": [hist_data["USD"],], "DateTime": [datetime.now(),]}
data_source.stream(new_row)
push_notebook(handle=handle_line_chart)
time.sleep(1)
Below, we have included code that can be saved to a Python file and then bring up an independent bokeh web app that constantly updates Bitcoin prices.
The majority of the code is same as the one we used in jupyter notebook with a few minor changes. The code to retrieve the latest prices every second and update data source is moved to a function named update_chart().
The curdoc() refers to the current document/ web page where the dashboard will be added.
The add_periodic_callback() method calls update_chart() function every second.
We can save the below code to a Python file and bring up a server by calling below command.
## simple_bokeh_dashboard.py
import bokeh
from bokeh.models import ColumnDataSource
from bokeh.io import curdoc
from bokeh.plotting import figure
import requests
import time
from datetime import datetime
data_source = ColumnDataSource(data = {"Close": [], "DateTime": []}) ## Data Source
## Create Line Chart
fig = figure(x_axis_type="datetime",
plot_width=950, plot_height=450,
tooltips=[("Close", "@Close")], title = "Bitcoin Close Price Live (Every Second)")
fig.line(x="DateTime", y="Close", line_color="tomato", line_width=3.0, source=data_source,)
fig.xaxis.axis_label="Date"
fig.yaxis.axis_label="Price ($)"
## Define Callbacks
def update_chart():
global data_source
resp = requests.get("https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD")
hist_data = resp.json()
new_row = {"Close": [hist_data["USD"]], "DateTime": [datetime.now(), ]}
data_source.stream(new_row)
curdoc().add_periodic_callback(update_chart, 1000)
curdoc().add_root(fig)
In today's tutorial, we explained how to work with streaming data when creating charts using Bokeh. We explained how to work with streaming data in jupyter notebook and also as an independent web app.
If you are more comfortable learning through video tutorials then we would recommend that you subscribe to our YouTube channel.
When going through coding examples, it's quite common to have doubts and errors.
If you have doubts about some code examples or are stuck somewhere when trying our code, send us an email at coderzcolumn07@gmail.com. We'll help you or point you in the direction where you can find a solution to your problem.
You can even send us a mail if you are trying something new and need guidance regarding coding. We'll try to respond as soon as possible.
If you want to