Bokeh
In this last entry on Python plotting libraries, we will review Bokeh, a library for plotting interactive graphics based on HTML/JS. These plots can then be used in a web application or website to display results.
Bokeh is included in some distributions, but it can be installed using pip. Unlike the libraries that we reviewed in earlier entries, Bokeh is not meant for use in the analysis stage of a study, but on the final dissemination of results, or as part of data based applications (such as dashboards, database viewers, etc).
In this entry, we will create a simple interactive graphic using the sine plot shown in the entry on Matplotlib. Then, we will add the optional server component included in Bokeh to create a graphic that is recalculated dynamically.
import bokeh.plotting as bp
from bokeh.models import CustomJS, Slider
from bokeh.io import output_notebook, vplot
import numpy as np
x = np.arange(0,2*np.pi,0.01)
y = np.sin(x)
We start by creating a figure with a title and axis labels:
fig = bp.figure(title='sin(x) function', x_axis_label='x', y_axis_label='sin(x)')
The next step is creating the actual line graph on the figure:
figline = fig.line(x, y, line_width=2)
Finally, we must save the output as an HTML file. We now have an interactive graphic.
bp.curdoc().add_root(vplot(fig))
bp.save(fig,'out.html')
We can preview the result also in the IPython Notebook:
output_notebook()
bp.show(fig)
You can actually interact with the plot shown above! But the interactions are limited to zooming, panning, saving ... In some scenarios this might not be enough. Let's say we want to change the frequency of the sinus function shown above. We can do so by adding a Slider widget:
callback = CustomJS(args=dict(source=figline.data_source), code="""
var data = source.get('data');
var f = cb_obj.get('value')
x = data['x']
y = data['y']
for (i = 0; i < x.length; i++) {
y[i] = Math.sin(f*x[i])
}
source.trigger('change');
""")
slider = Slider(start=0.1, end=4, value=1, step=.1, title="Frequency", callback=callback)
layout = vplot(slider, fig)
bp.show(layout)
Now, let's say we have a data source that changes over time, or that depends on heavy processing of user input. There are ways to do this using the JS (or Python by using the CustomJS.from_py_func()) callback to update the plot. But Bokeh also provides both a server and client side functions for this scenario. We must create a Python script that creates a view (the figure and input widgets) and a callback function that updates the view. This script is then fed to the server, which must be running while the graphic is online. We are going to create a sine graphic that shows the variations when frequency changes. We need to create a file with the following contents:
# sineserver.py
# Imports
import bokeh.plotting as bp
from bokeh.models import Slider
from bokeh.io import vplot
import numpy as np
# Original dataset
x = np.arange(0,2*np.pi,0.01)
y = np.sin(x)
# Create figure
fig = bp.figure(title='sin(x) function', x_axis_label='x', y_axis_label='sin(x)')
figline = fig.line(x, y, line_width=2)
# Callback function
def update_sin(attr, old, new):
f = int(new)
x = np.arange(0,2*np.pi,0.01)
y = np.sin(f*x)
figline.data_source.data["y"] = y
# Add slider
slider = Slider(start=1, end=10, title='Freq')
slider.on_change('value', update_sin)
# Create view
bp.curdoc().add_root(vplot(slider, fig))
To run this code, we must open a terminal and run bokeh serve --show sineserver.py
. Then we must open a browser and go to http://localhost:5008/sineserver.
Bokeh is a great platform for showing graphics on a website or web app; specially for applications with dynamic data sources. As a library, it is not as developed as Matplotlib and there is not as much documentation. It is under development so there are some edges. It is not very practical for its use in daily work, but it definitely beats other solutions for interactive graphics.