Widget troubles with the Panel/Voila integration

I’d like to serve panel objects, including holoviews graphs, with Voila, following instructions in the deployment guide. However, HoloMap/DynamicMap widgets seem to lose their interactivity when I do so.

To front load the MRE, this works fine in JupyterLab (I get an interactive dmap with widgets):

import panel as pn
import numpy as np
import pandas as pd
import holoviews as hv
import hvplot.pandas

df = pd.DataFrame(np.random.rand(300).reshape((100,3)), columns=['a','b','c'])
df['c'] = df['c'] > 0.5

pn.ipywidget(df.hvplot.line(groupby='c'))

The JupyterLab Voila preview as well as the Voila command also display this fine, but the widgets no longer update the plot. I’m not seeing any errors Python-side that would indicate problems. Same deal if I try pn.extension(comms='ipywidgets')

My env was pretty clean - a fresh Python 3.7 conda env on Ubuntu in which I installed jupyterlab, hvplot, voila, and jupyter_bokeh from conda-forge. According to jupyter labextension list this gave me:

JupyterLab v3.0.16
/home/jokasinski/miniconda3/envs/voila/share/jupyter/labextensions
        @bokeh/jupyter_bokeh v3.0.0 enabled OK (python, jupyter_bokeh)
        @voila-dashboards/jupyterlab-preview v2.0.2 enabled OK (python, voila)
        @pyviz/jupyterlab_pyviz v2.0.1 enabled OK (python, pyviz_comms)
        @jupyter-widgets/jupyterlab-manager v3.0.0 enabled OK (python, jupyterlab_widgets)

Which should be okay, if I understand the docs.

I tried installing jupyter_bokeh from bokeh instead of conda-forge, but then that example stopped working in the notebook. I tried to install everything (including nodejs) from bokeh instead, and then run the labextension commands in the panel documentation, but it fails to build jupyter_bokeh - looks like it can’t find a node_modules directory.

There are other permutations I could try, but unless I misunderstand I think this contradicts the Panel documentation and is a bug. However, there are a lot of moving parts I haven’t chased down yet, so the real problem could be elsewhere.

Am I not installing these packages properly/have bad version combinations? Is this functionality intended to be supported? Let me know if there’s any other info I can provide - any help would be greatly appreciated. Thanks!

It’s a regression in Bokeh unfortunately [BUG] Layout regression in panel introduced by PR #11123 · Issue #11188 · bokeh/bokeh · GitHub

Update: answer for another post.

Sorry I don’t quite understand - the widget & all the graphs are present, it’s just that sliding the widgets no longer updates the graph. How does the layout regression cause this?

Sorry.My answer was for another post.

I cannot get Voila working either. See Enable serving notebook as interactive docs with static code cells · Issue #2241 · holoviz/panel · GitHub

@philippjfr . Should @nitrocalcite create a specific “Voila not working” bug report?

Happy to do so, just let me know which library. To me it looks a panel bug because it contradicts panel docs, but I would figure that the underlying issue is in jupyter_bokeh. However, having not yet reproduced without holoviews/hvplot, I can’t really exclude them either.

1 Like

I had this problem too. Previously, I mainly used Voila to serve the dashboard with the combination of Panel and Ipywidgets. However, after I updated both (Panel and Voila) packages recently, it stopped to work. In my case, last combinations that worked was Panel==0.11.0 and voila==0.2.7.

1 Like

@philippjfr are you aware of this issue?

Looking into it now.

2 Likes

Okay, figured it out, for some reason the dist bundle wasn’t included when uploading the jupyter_bokeh 3.0.0 bundle to NPM. I’ll try to release 3.0.1 as soon as I get a chance.

1 Like

Fix is here: Bundle dist directory by philippjfr · Pull Request #132 · bokeh/jupyter_bokeh · GitHub

1 Like

I’ve released jupyter_bokeh 3.0.2 to NPM and PyPI now. Will follow up with conda-forge once the bot updates the recipe.

2 Likes

@philippjfr . This made Panel work in VS Code again. But it does not get Voila working

Notes from test


$ "C:\Python38\python.exe" -m venv .venv
$ source .venv/Scripts/activate
$ pip install -r requirements.txt
Collecting panel==0.11.3
  Using cached panel-0.11.3-py2.py3-none-any.whl (9.0 MB)
Collecting jupyter_bokeh==3.0.2
  Downloading jupyter_bokeh-3.0.2-py3-none-any.whl (1.4 MB)
     |████████████████████████████████| 1.4 MB 2.2 MB/s
Collecting jupyterlab
  Using cached jupyterlab-3.0.16-py3-none-any.whl (8.2 MB)
Collecting voila
  Downloading voila-0.2.10-py3-none-any.whl (1.6 MB)
     |████████████████████████████████| 1.6 MB 6.4 MB/s

test_voila.ipynb (43.2 KB)

It’s not working if I run it from the command line either

voila test_voila.ipynb

Yeah thanks a lot for looking into this promptly, but like Marc I can confirm that the widgets are still not interactive with voila under jupyter_bokeh 3.0.2. Was just in the process of triple checking I’ve got my env set up right.

1 Like

I added a bug report here Voila cannot serve Panel Apps · Issue #2351 · holoviz/panel (github.com)

Thanks, will have to dig into this further.

2 Likes

Hi all,

has there been an update on this point? I believe I’m having the same issue: widgets update the plot via a function bound via hvplot.bind() if run locally but once deployed to Heroku via Voila (or even running a local test using voila notebook.ipynb) adjusting the widgets doesn’t do anything.

You can find a sample Panel/Voila app deployed on Heroku here (adjusting the building_weight slider normally has the largest visual effect but no change here).

Notebook:

from typing import List
import numpy as np
import rioxarray
import hvplot.xarray
import panel as pn
import cartopy.crs as ccrs

array1 = rioxarray.open_rasterio('raster1.tif')
array2 = rioxarray.open_rasterio('raster2.tif')
array3 = rioxarray.open_rasterio('raster3.tif')
array4 = rioxarray.open_rasterio('raster4.tif')

# add arrays to list to make the function definition a bit more succinct
arrays = [array1, array2, array3, array4]

widget1 = pn.widgets.IntSlider(start=0, end=10, step=1, value=5, name='Name 1')
widget2 = pn.widgets.IntSlider(start=0, end=10, step=1, value=5, name='Name 2')
widget3 = pn.widgets.IntSlider(start=0, end=10, step=1, value=5, name='Name 3')
widget4 = pn.widgets.IntSlider(start=0, end=10, step=1, value=5, name='Name 3')

def func(arrays: List[np.ndarray], widget1, widget2, widget3, widget4):
    
    # dummy formula
    data = (arrays[0] * widget1 + arrays[1] * widget2) * (arrays[2] * widget3 + arrays[3] * widget4)
    
    # normalise to float values between 0 and 1
    data = (data - np.min(data)) / (np.max(data) - np.min(data))
    
    # name the array, so we can mask 0 as nodata below via .redim.nodata(final=0)
    # this way the 0 values won't be color-mapped and the underlying basetiles will show
    data.name = 'Risk'
    
    output_ds = data.to_dataset(dim=None)
    
    return output_ds

xri = hvplot.bind(func, arrays, widget1, widget2, widget3, widget4).interactive()

interactive = (
    # x and y flipped in xarray: https://github.com/holoviz/hvplot/issues/668
    xri.hvplot(x='x', y='y', groupby='band', geo=True, project=True, crs=ccrs.epsg(32631), tiles='ESRI', 
               frame_width=800, data_aspect=1, xaxis=None, yaxis=None,
              cmap='fire_r'
               
               # redim to mask out no data: https://discourse.holoviz.org/t/rasterize-displaying-nodata-missing-value-fillvalue-for-integer-uint16-data/1517/8

              ).redim.nodata(Risk=0).opts(active_tools=['wheel_zoom'])
)

pn.Column(
    interactive.widgets(),
    interactive.panel(),
).servable()

heroku logs -t

Starting process with command `voila --port=35790 --Voila.ip=0.0.0.0 --no-browser --strip_sources=True --enable_nbextensions=True --show_tracebacks=True --NotebookClient.iopub_timeout=30 notebooks/s2_raster_calc_0_3.ipynb`
2022-10-09T08:48:56.276029+00:00 app[web.1]: [Voila] Using /tmp to store connection files
2022-10-09T08:48:56.276575+00:00 app[web.1]: [Voila] Storing connection files in /tmp/voila_6500j6yo.
2022-10-09T08:48:56.276625+00:00 app[web.1]: [Voila] Serving static files from /app/.heroku/python/lib/python3.10/site-packages/voila/static.
2022-10-09T08:48:57.218309+00:00 heroku[web.1]: State changed from starting to up
2022-10-09T08:48:57.018640+00:00 app[web.1]: [Voila] Voilà is running at:
2022-10-09T08:48:57.018668+00:00 app[web.1]: http://2ea27d3f-1842-4924-97a2-a15d11d5e42b:35790/
2022-10-09T08:48:59.507204+00:00 heroku[router]: at=info method=GET path="/api/kernels/bb65158a-60d2-4747-9a34-edb5331984ee/channels?session_id=18716c64-4499-4ca9-b3eb-65e9ef05466c" host=dynamic-weight-matrix.herokuapp.com request_id=18f09b89-5701-4bff-a7dc-af9200010fa5 fwd="95.90.196.195" dyno=web.1 connect=0ms service=19ms status=404 bytes=1095 protocol=https
2022-10-09T08:48:59.998652+00:00 heroku[router]: at=info method=POST path="/voila/api/shutdown/bb65158a-60d2-4747-9a34-edb5331984ee" host=dynamic-weight-matrix.herokuapp.com request_id=7b73e6cc-c4e1-4978-833b-1a16f3a83009 fwd="95.90.196.195" dyno=web.1 connect=0ms service=2ms status=404 bytes=390 protocol=https
2022-10-09T08:48:59.491539+00:00 app[web.1]: /app/.heroku/python/lib/python3.10/site-packages/jupyter_server/base/handlers.py:197: UserWarning: The Tornado web application does not 
have an 'authorizer' defined in its settings. In future releases of jupyter_server, this will be a required key for all subclasses of `JupyterHandler`. For an example, see the jupyter_server source code for how to add an authorizer to the tornado settings: https://github.com/jupyter-server/jupyter_server/blob/653740cbad7ce0c8a8752ce83e4d3c2c754b13cb/jupyter_server/serverapp.py#L234-L256
2022-10-09T08:48:59.491584+00:00 app[web.1]: warnings.warn(
2022-10-09T08:48:59.492196+00:00 app[web.1]: 404 GET /api/kernels/bb65158a-60d2-4747-9a34-edb5331984ee/channels?session_id=18716c64-4499-4ca9-b3eb-65e9ef05466c (10.1.83.187): Kernel does not exist: bb65158a-60d2-4747-9a34-edb5331984ee
2022-10-09T08:48:59.508086+00:00 app[web.1]: 404 GET /api/kernels/bb65158a-60d2-4747-9a34-edb5331984ee/channels?session_id=18716c64-4499-4ca9-b3eb-65e9ef05466c (10.1.83.187) 18.79ms2022-10-09T08:48:59.998336+00:00 app[web.1]: 404 POST /voila/api/shutdown/bb65158a-60d2-4747-9a34-edb5331984ee (10.1.34.191): Kernel does not exist: bb65158a-60d2-4747-9a34-edb5331984ee
2022-10-09T08:48:59.998448+00:00 app[web.1]: [Voila] WARNING | wrote error: 'Kernel does not exist: bb65158a-60d2-4747-9a34-edb5331984ee'
2022-10-09T08:48:59.998871+00:00 app[web.1]: 404 POST /voila/api/shutdown/bb65158a-60d2-4747-9a34-edb5331984ee (10.1.34.191) 1.37ms
2022-10-09T08:49:00.051518+00:00 app[web.1]: [Voila] Writing notebook-signing key to /app/.local/share/jupyter/notebook_secret
2022-10-09T08:49:00.054630+00:00 app[web.1]: [Voila] WARNING | Notebook s2_raster_calc_0_3.ipynb is not trusted
2022-10-09T08:49:00.587232+00:00 app[web.1]: 404 GET /voila/templates/lab/static/voila.js.map (10.1.0.66) 1.49ms
2022-10-09T08:49:00.597252+00:00 app[web.1]: [Voila] Kernel started: af95c20a-d247-48f3-9469-eaa9987ecfb3
2022-10-09T08:49:00.586834+00:00 heroku[router]: at=info method=GET path="/voila/templates/lab/static/voila.js.map" host=dynamic-weight-matrix.herokuapp.com request_id=1b49757d-81ce-4def-b9f3-5e1b207ca590 fwd="95.90.196.195" dyno=web.1 connect=0ms service=507ms status=404 bytes=238 protocol=https
2022-10-09T08:49:14.328343+00:00 heroku[router]: at=info method=GET path="/" host=dynamic-weight-matrix.herokuapp.com request_id=1055273f-c190-45cc-9557-bc5c284a91c1 fwd="95.90.196.195" dyno=web.1 connect=0ms service=14331ms status=200 bytes=4519553 protocol=https
2022-10-09T08:49:14.296639+00:00 app[web.1]: /app/.heroku/python/lib/python3.10/site-packages/nbconvert/filters/datatypefilter.py:41: UserWarning: Your element with mimetype(s) dict_keys([]) is not able to be represented.
2022-10-09T08:49:14.296667+00:00 app[web.1]: warn(
2022-10-09T08:49:17.898076+00:00 heroku[router]: at=info method=GET path="/voila/templates/lab/static/voila.js?v=4c82c2283cae785353d94b03ebcd62800b93598b39300642e9810298f553b16214caf74db5a26c1ce26e51911387d275462c0dbe057e2a19cc0319ddc6be3fc2" host=dynamic-weight-matrix.herokuapp.com request_id=fa04baeb-b22a-400c-a70e-64f24505c21c fwd="95.90.196.195" dyno=web.1 connect=0ms service=48ms status=200 bytes=4243716 protocol=https
2022-10-09T08:49:23.954834+00:00 heroku[router]: at=info method=GET path="/api/kernels/af95c20a-d247-48f3-9469-eaa9987ecfb3?1665305366858" host=dynamic-weight-matrix.herokuapp.com request_id=bdd94d60-d787-4d36-9451-968b7ddf4476 fwd="95.90.196.195" dyno=web.1 connect=0ms service=1ms status=200 bytes=502 protocol=https
2022-10-09T08:49:24.650789+00:00 app[web.1]: [IPKernelApp] ERROR | No such comm target registered: jupyter.widget.control
2022-10-09T08:49:24.653906+00:00 app[web.1]: [IPKernelApp] WARNING | No such comm: 4b8142d5-8d14-4ee8-9496-dab4fad30a94

JS Console

Firefox can’t establish a connection to the server at wss://dynamic-weight-matrix.herokuapp.com/api/kernels/bb65158a-60d2-4747-9a34-edb5331984ee/channels?session_id=18716c64-4499-4ca9-b3eb-65e9ef05466c. [voila.js:61:568484](https://dynamic-weight-matrix.herokuapp.com/voila/templates/lab/static/voila.js?v=4c82c2283cae785353d94b03ebcd62800b93598b39300642e9810298f553b16214caf74db5a26c1ce26e51911387d275462c0dbe057e2a19cc0319ddc6be3fc2)

POSThttps://dynamic-weight-matrix.herokuapp.com/voila/api/shutdown/bb65158a-60d2-4747-9a34-edb5331984ee[HTTP/1.1 404 Not Found 347ms]

Source map error: Error: request failed with status 404 Resource URL: https://dynamic-weight-matrix.herokuapp.com/voila/templates/lab/static/voila.js?v=4c82c2283cae785353d94b03ebcd62800b93598b39300642e9810298f553b16214caf74db5a26c1ce26e51911387d275462c0dbe057e2a19cc0319ddc6be3fc2 Source Map URL: voila.js.map

GEThttps://dynamic-weight-matrix.herokuapp.com/favicon.ico[HTTP/1.1 503 Service Unavailable 0ms]

Error: Promised response from onMessage listener went out of scope [background.js:841:170](moz-extension://e4992c4a-b9d8-4628-9086-47b96033c016/dist/background.js)

Bokeh: BokehJS not loaded, scheduling load and callback at

Date Sun Oct 09 2022 10:49:13 GMT+0200 (Central European Summer Time)

[dynamic-weight-matrix.herokuapp.com:30:15](https://dynamic-weight-matrix.herokuapp.com/)

Bokeh: injecting link tag for BokehJS stylesheet: https://cdn.jsdelivr.net/npm/notyf@3/notyf.min.css [dynamic-weight-matrix.herokuapp.com:30:15](https://dynamic-weight-matrix.herokuapp.com/)

Bokeh: injecting link tag for BokehJS stylesheet: https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.1/css/all.min.css [dynamic-weight-matrix.herokuapp.com:30:15](https://dynamic-weight-matrix.herokuapp.com/)

Bokeh: all BokehJS libraries/stylesheets loaded [dynamic-weight-matrix.herokuapp.com:30:15](https://dynamic-weight-matrix.herokuapp.com/)

Bokeh: BokehJS plotting callback run at

Date Sun Oct 09 2022 10:49:13 GMT+0200 (Central European Summer Time)

[dynamic-weight-matrix.herokuapp.com:30:15](https://dynamic-weight-matrix.herokuapp.com/)

[bokeh] setting log level to: 'info' [dynamic-weight-matrix.herokuapp.com:689:1366](https://dynamic-weight-matrix.herokuapp.com/)

Bokeh: all callbacks have finished [dynamic-weight-matrix.herokuapp.com:30:15](https://dynamic-weight-matrix.herokuapp.com/)

Use of mozImageSmoothingEnabled is deprecated. Please use the unprefixed imageSmoothingEnabled property instead. [dynamic-weight-matrix.herokuapp.com:919:270](https://dynamic-weight-matrix.herokuapp.com/)

[bokeh] document idle at 291 ms [dynamic-weight-matrix.herokuapp.com:35:14](https://dynamic-weight-matrix.herokuapp.com/)

Starting WebSocket: wss://dynamic-weight-matrix.herokuapp.com/api/kernels/af95c20a-d247-48f3-9469-eaa9987ecfb3 [dynamic-weight-matrix.herokuapp.com:30:15](https://dynamic-weight-matrix.herokuapp.com/)

Failed to fetch ipywidgets through the "jupyter.widget.control" comm channel, fallback to fetching individual model state. Reason: Control comm was closed too early [dynamic-weight-matrix.herokuapp.com:40:14](https://dynamic-weight-matrix.herokuapp.com/)

Error: Promised response from onMessage listener went out of scope

Versions

voila==0.3.6
geoviews==1.9.5
hvplot==0.8.0
panel==0.13.1