If you’re using pure HoloViews objects to display charts in a Jupyter notebook, you might run into problems when trying to convert your notebook into a script to run directly in a Bokeh or Voila server.
This post explains what goes wrong, and provides a workaround. The screenshots are from ContainDS Dashboards running in JupyterHub, but the same approach works for a plain Jupyter notebook and the regular Voila or Bokeh serving commands.
Here is a simple HoloViews-only notebook, cut down from the example given on the HoloViews DynamicMap user guide. You can download the full ipynb file from there.
When run, you should get an interactive graph like this:
That’s great, but how can you share this in a user-friendly way with a colleague or client?
HoloViews is running with the Bokeh back-end, so maybe the
bokeh serve command is an option. Or since it’s a Jupyter notebook, maybe
voila is the best way to go?
You can try running
voila notebook.ipynb directly, or since I have the Voila extension for JupyterHub installed, I can just click the Voila preview button directly from the notebook:
It looks like it worked, but if I move the sliders the graph doesn’t change…
It turns out there is an incompatibility between Voila and Bokeh – Voila uses ipywidgets to sync the front-end and back-end, but Bokeh doesn’t.
There is an issue recorded on the Voila GitHub repo about this. It sounds like the Voila team is keen to support Bokeh natively, but there is some translation work required.
What about serving through
bokeh serve? Since I am trying this on a JupyterHub with ContainDS Dashboards, I can simply create a new dashboard specifying the ‘bokeh’ framework. This uses
bokeh serve internally:
However, when the dashboard runs it seems to think everything is fine (no errors are reported) but there is nothing visible on the page – it’s completely empty!
Clearly HoloViews needs a bit more support to fall under Bokeh’s radar.
Panel to the Rescue
It turns out that things can be fixed simply by wrapping our HoloViews DynamicMap in a Panel pane. In place of just outputting
dmap in a cell, do this:
p = pn.Pane(dmap) p.servable()
Somehow this fixes our
bokeh serve dashboard! Not only is everything visible, but this time we can interact with it as expected:
Unfortunately this trick doesn’t fix the display in Voila at the time of writing. (The graph and sliders appear, but the graph doesn’t update when the sliders slide.)
This is just a little trick to bridge the gap between some of the different visualization, serving, and widget frameworks out there in the Python data science ecosystem. But it also exposes some of the overlap and dependencies that they bring.
To try to understand these interactions between the components, I asked Philipp Rudiger, creator of Panel and HoloViews, and also a core developer of Bokeh.
His insightful answer about the technical details can be found on the HoloViews forum.
Ultimately, Panel does a great deal of work behind the scenes to ensure it adapts to its environment and also to the widgets it contains.
His response also explains how to enable HoloViews within Voila, and how work is currently underway to improve that integration.