Saturday, February 9, 2019

Line graphs in JupyterLab

Recently I've been doing quite a bit of work on climate solution models, using Jupyter Notebook to interact with the backend model. The Jupyter Notebook is a way to allow front-end code running in a browser to interact with backend code running as kernels managed by Jupyter. Though Jupyter evolved from iPython, there are now kernels available for many languages including Java, R, and even C++. All of my work with Jupyter is in Python, however.

I spent time investigating various graphing and charting packages which support interactive use in a JupyterLab notebook. The demo code for the different charting packages is available on github for reference. Note that github will render this file in a way which looks nice, but it is not actually running Jupyter and the graphs are just static snapshots.

The notebook can be run for keepsies using, which creates a container to run user code. Clicking on the button below will open Jupyter in a new browser window, albeit after a perhaps lengthy pause while initializing a container to run it.

At launch an error dialog may appear, about jupiterlab_pyviz. I think that is a false alarm as jupiterlab_pyviz is installed in the container and the Altair-viz chart does work, but I haven't figured out how to suppress the popup.

For those who have not used Jupyter before: each numbered block of code in the Notebook is a cell, and can be run using the right-pointing triangle button at the top. When the Notebook is first opened there will likely be no graphs displayed. Clicking the run button in each cell (and twice in the matplotlib cell to get it to render) will run each one and allow the graphs to be interacted with.

Matplotlib + ipympl

matplotlib is one of the oldest plotting packages for Python still in active development. Its primary design point is static graphs, but it does provide interactive features with a suitable renderer. In addition to Jupyter notebooks matplotlib supports renderers for many GUI environments like PyTk and Qt.

Instructions on the web will generally say to include a "%matplotlib inline" statement for use in Jupyter notebooks, but inline graphs are completely static. Instead, this example uses ipympl and "%matplotlib ipympl" which allows interactive features to work. A toolbar at the bottom allows panning and zooming.

However, matplotlib's interactive features are quite limited. Only one chart at a time can be interactive, and the user must click a power button in the upper right to deactivate it before another can be activated. The overall experience isn't great, matplotlib is much stronger when producing purely static graphs.



Bokeh is a charting and dashboarding package. Though it supports use within Jupyter, bokeh appears to be mainly aimed at creation of dashboards and larger collections of visualizations. For example it doesn't always cooperate with Jupyter widgets, preferring bokeh server's layout functions.

Bokeh's interactive features include a tooltip showing exact values when hovering over a datapoint, plus zoom and panning within the chart.



hvplot is built atop bokeh and looks quite similar in operation, with tooltips and pan-and-zoom. hvplot's programming interface is integrated with Pandas, adding an hvplot() method to the dataframe.



Beaker/Xs a collection of extensions for Jupyter Notebook, spanning the gamut from computation kernels to a graphing package. Its interactive features include tooltips on hover plus panning and zooming, with double-click to return to the original zoom level.

The charts in Bokeh are implemented in Groovy. The Python APIs are a direct transfer of the Groovy APIs. They aren't Python bindings in a Pythonic interface, Beaker/X provides a mechanism for different language kernels to call into each other. This did not make it very easy to code for in Python, for example I could not figure out how to set up a Tooltips object and had to leave it with the default.



bqplot was released by Bloomberg, and is a charting package used in producing various Bloomberg media properties. It is a thin Python layer which passes through most commands to D3.js for implementation.

bqplot has ways to support both tooltips on hover and zoom-and-pan features, but I was not able to get both to work at the same time. The video shows a quick edit and re-running the cell in order to demonstrate one and the other. There may well be a way to do so, but I didn't figure it out.

Additionally, the tooltips for Line charts are currently not able to retrieve data values and always print NaN.



Altair is somewhat different from the other packages described here in that it is a declarative API, not imperative. That is, instead of a series of operations to produce a graph, Altair instead provides a way to declare what elements of data should be graphed and how to transform the data while doing so. In that sense, Altair aspires to be more like SQL for fetching data or Prolog for transforming data than it does to be a more traditional API.

Altair-Viz emits a Vega-Lite description of the desired graphic, which is expanded to Vega, which ultimately sits atop D3.js in the browser. JupyterLab, an early access release for the next major Jupyter version, supports Vega-Lite and Vega natively. Altair does not require installation of a Jupyter extension to work, the only charting package in this post which does not need one.

For interactive use, Altair charts support tooltips on hover and pan-and-zoom of the graph. is a plotting-as-a-service provider. The main service is hosted online, but the basic functionality of the implementation is also available as an open source package which is run locally. charts support tooltips and zoom-and-pan, as well as a mode which prints the X/Y coordinates as the pointer moves over the chart.


My intention at this point is to focus on Altair-Viz as it is working well and shows promise for future capabilities, with Jupyterlab having native support for the Vega graphics grammar.