submit to reddit
Benjamin Zaitlen

Painless Streaming Plots with Bokeh

Bokeh is quickly proving to be the easiest plotting toolkit for web-enabled graphs. Continuum recently released version 0.2 , with 0.3 coming shortly. One of the distinguishing features of Bokeh compared to other web-based plotting toolkits is that streaming, as a feature, is not an afterthought. Animated as well as streaming realtime plots on the web should be nearly as easy as static plots — and with Bokeh, it really is that easy. It’s good to remind yourself that Bokeh is built with Python as a first-class citizen — in other words, all of the plotting commands are in Python and NOT Javascript. Bokeh is open-source and our documentation has loads of beautiful interactive plots.

The Physical World and Realtime Plotting

In this post I’m going to show you a few of the fun and exciting things that can be done with Bokeh. Given the recent MakerFaire events in New York and Italy, I thought it would be fun to bring a bit of hardware into the mix rather than simply simulate streaming data. I decided to incorporate some XBee Modules, which are wireless devices popular among hardware enthusiasts and wireless sensor network (WSN) developers.

Hardware

I set up a WSN with two XBees: one acts as the base station and the second is a mobile unit. The base station records the signal strength (RSSI) of the incoming packets from the mobile unit and dumps the data into a database. The closer the mobile unit is to the base station, the stronger the signal will be. I recorded several minutes of myself (with the mobile unit attached) running around the base station in order to generate a wide landscape of values. My plotting script can then ask for the last X points of data or a slice of rows within the DB.

Bokeh Plotting

After pulling the data, plotting a line plot should be quite familiar to other plotting libraries.

line(x,rssi, color="#0000FF", x_axis_type = "datetime", 
tools="pan,zoom,resize", width=1200,height=300,
title = 'Streaming RSSI Values',
legend='XBee %s Raw' % (xbee_id))
 
xaxis()[0].axis_label = "Time"
yaxis()[0].axis_label = "Signal Strength"

Python

Below is a screenshot—you can see that the while signal is noisy, the farther the mobile unit is from the base station, the smaller the signal strength is:

Static Bokeh RSSI Plot

I’ve added a few other plot elements in addition to plotting the data (x,rssi): height/width, title, legend, and pan/zoom/resize (more on this later)

The above plot is merely an image. But because Bokeh is a web-enabled plotting toolkit, if I render my plot in Bokeh I can interact with my data in exciting and novel ways. Below is the sample plot above but rendered with Bokeh:

You can manipulate this plot: zooming, panning, and resizing all in the browser! To achieve this level of interactivity, I added the additional arguments to the line function tools="pan,zoom,resize". Bokeh gives us the option of saving a single plot as an HTML file OR we can output an embeddable javascript plot:

line_snippet =  line_plot.inject_snippet()
print line_snippet
'''
<script src="xbee_plot.embed.js" bokeh_plottype="embeddata" bokeh_modelid="xbee_plot" bokeh_modeltype="Plot" async="true"></script>
'''

Python

The above code delivers a javascript file which we can embed in a webpage (as I am doing here), an example HTML file with the Javascript called, and a printout of the appropriate code snippet for later use. Again, this is all done with Python!

Painless Realtime Plotting

Lastly, with Bokeh we can easily animate our plot and view the RSSI signal in realtime. For this we will need a server — and luckily enough, Bokeh ships with its own server. Calling bokeh-server instantiates everything we need to serve up streaming plots.

#Code will be significantly simplified in the 0.4 release
import time
from bokeh.objects import GlyphRenderer
renderer = [r for r in curplot().renderers if isinstance(r, GlyphRenderer)][0]
ds = renderer.data_source
while True:
df = pd.io.json.read_json(url+json_call)
ds.data["x"] = x+N*i
ds.data["y"] = df.rssi
ds._dirty = True
session().store_obj(ds)
time.sleep(1.5)
i+=1

Python

With less than 15 lines of code, we’ve animated the plot and can serve it on the web. Below is a captured GIF and you can also see the plots live here. Note: more streaming/animation improvements are coming in 0.4 release

Bokeh GIF RSSI Plot

Code and Install

The example code can be found in my xbee-bokeh example repository and installing dependencies can either be done through conda or pip. For use with a Raspberry Pi or BeagleBone download the minimal anaconda installer for ARM architectures.

Conda is quite easy — simply add the following binstar channels to your .condarc file:

  • https://conda.binstar.org/quasiben
  • https://conda.binstar.org/asmeurer

Then create an new environment:

conda create -n bokeh_rssi python=2.7 pip sqlite pyserial xbee flask-restful bokeh

Similarly, pip can also install all the necessary packages.

Pushing Ahead

Interactivity through the web is more than just a novel feature. For many, it means changing their entire workflow. If I no longer have to take/generate a snapshot, this means my colleagues and collaborators can see analysis as it happens — no photo uploads or emails of static plots. And, as the data changes the plots similarly should update as well. Additionally, building a tool with the Python analyst/developer as our target audience means not having to reach for another language and stack of technologies to learn and manage.

Bokeh is open-source and fully supported by Continuum Analytics. See our Roadmap for more details.

Tags: Bokeh
submit to reddit
comments powered by Disqus