A question on Holoview integration in a Bokeh app

hey there,

I have spent some time on making a served dashboard based on bokeh app with callback triggering updates on the figures.

Now comes a point where I feel some limitations of Bokeh, namely for example plotting histograms are not easy, matrices of scatter plots need to be coded by hand…

So I have naturally bent towards the direction of Holoview, which offers this type of more elaborate figures and based on Bokeh. But I am a bit puzzled on how to incorporate the whole holoview machinery in a Bokeh app. Especially the way how I could integrate callbacks to update figures with it…

I would appreciate if somebody could tell me what is the best strategy to include HV figures that updates with click event callbacks — besides telling me to refactor the whole dashboard using Holoviews :slight_smile:


So if you’ve already written a bokeh app I can suggest two options:

  1. Have a look at Panel, it’s written entirely on top of Bokeh and you should be able to just drop your existing Bokeh objects into a Panel app and then combine it with HoloViews components.

  2. Use the HoloViews renderer to convert HoloViews components to bokeh components:

hv_obj = ... # (Some HoloViews object)
renderer = hv.renderer('bokeh').instance(mode='server')
bokeh_model = renderer.get_plot_state(hv_obj, doc=your_bokeh_document)

thanks philipp, it is very helpful, especially 1.

the solution 2. is not compatible with callback and updates, am I correct?

the solution 2. is not compatible with callback and updates, am I correct?

HoloViews is very deliberately written to avoid writing callbacks with side-effects. In theory you could modify the resulting bokeh model yourself using callbacks once you’ve set them up but you lose much of the power of HoloViews that way.

I guess I’d have to know more about what you’re trying to achieve to make concrete recommendations.

1 Like

@philippjfr Would you or anyone else be kind enough to explain this interaction between Panel, HoloViews, and Bokeh?

I have also come across this situation - that HoloViews objects aren’t interactive when run through bokeh serve, even though they work fine in a Jupyter notebook.

Things can be fixed easily by wrapping the HV object in a panel.Pane, but I’m not 100% sure why. I feel this is key to understanding the HoloViz ecosystem so I would really value any insight!

I’ve written up a more detailed example, including trying this with Voila too, on my blog.

Thank you anyone for any thoughts… The contrast between bokeh and Jupyter servers is also important I think.

Would you or anyone else be kind enough to explain this interaction between Panel, HoloViews, and Bokeh?

Sure. So for a very long time HoloViews was an entirely independent project which could render to Bokeh but didn’t treat Bokeh in any special way. We had some options for deploying on Bokeh server but those were somewhat limited. In the HoloViews 1.13 release however we switched HoloViews widgets and rendering entirely over to Panel in the background so now all the widgets you see and all the rendering is done by Panel.

This also simplified the story behind interacting with Jupyter and Bokeh server, all the setting up of bi-directional communication channels could now simply be handled by Panel and HoloViews wouldn’t worry about it. So let’s look at the three scenarios you called out in your blog post:

Jupyter notebook/JupyterLab

In the Jupyter Notebook comms can be globally accessed on the Jupyter.notebook.kernel object making it possible to easily set up bi-directional communication channels. In JupyterLab on the other hand it is not as simple and we proxy the CommManager object using the @pyviz/jupyterlab_pyviz extension. Otherwise things work basically the same, both HoloViews and Panel set up communication channels via this mechanism.

Bokeh/Panel Server

On the bokeh server communication is handled by the Bokeh Websocket. The easiest way to set this up from HoloViews is indeed what you describe, i.e. using pn.panel(hv_obj).servable(). This sets things up so that panel serve ... or bokeh serve ... will work. Alternatively you can also create a simple script which launches a server using the pn.serve function, so you simply run python script_with_pn_serve.py.


Voila currently does not follow the classic notebook API, i.e. making Jupyter.notebook.kernel available, but also does not support JupyterLab extension which means the standard communication channels will not work out of the box. Therefore I initially prototyped ipybokeh as part of a Jupyter dashboarding workshop last year, which eventually migrated to jupyter_bokeh. Using this it is possible to wrap a bokeh (or Panel) object in an ipywidget which is supported in Voila. You can activate this in Panel by doing:

pn.config.comms = 'ipywidget'

or explicitly calling pn.ipywidget(hv_or_panel_obj). However currently throttling is not yet enabled so you will end up with a lot of events being generated. Starting in Panel 0.10.0 throttling will be enabled and you should be able to use Panel/Bokeh objects in Voila just like any other ipywidgets based object.

Thank you so much @philippjfr for taking the time to explain all of this. I think ultimately I was underestimating how much work Panel does under the hood to adapt to different environments.

I’ve updated my post to point to your explanation of course!

1 Like

Don’t get me started on environments like VSCode, nteract or Colab. We’ll be adding a guide explaining all this at some point soon I hope.

I’ve updated my post to point to your explanation of course!