2

Normally, I am able to replace parts of a panel via pop and insert, which updates any existing panels automatically. However, if these are triggered from a bokeh selected.on_change callback, existing panels do not update.

For example, running the following in JupyterLab works

from bokeh.plotting import figure
from bokeh.sampledata.iris import flowers
from bokeh.models import ColumnDataSource
import panel as pn


pn.extension()

def create_figure():
    src = ColumnDataSource(flowers)
    p = figure(height=200, width=200, tools='box_select')
    p.circle("petal_length", "petal_width", source=src)
    return p

pnl = pn.panel(pn.Row(create_figure, create_figure))
pnl

The displayed panel will update as expected when I run the following in the next cell:

pnl.pop(0)
pnl.insert(0, figure)

However, if I do the same thing via a callback when the selection of the column data source changes, the panel does not update as I select data points in the plot:

def replace_plot(attr, old, new):
    pnl.objects.pop(0)
    pnl.objects.insert(0, figure)

def create_figure():
    src = ColumnDataSource(flowers)
    p = figure(height=200, width=200, tools='box_select')
    p.circle("petal_length", "petal_width", source=src)
    src.selected.on_change('indices', replace_plot)
    return p

pnl = pn.panel(pn.Row(create_figure, create_figure))
pnl

What does work is to replace the entire pnl.objects with a new list:

def replace_plot(attr, old, new):
    pnl.objects = [figure]

Strangely, this only work when I call pnl.show() to display the panel in a new browser tab, in the notebook I need to display the panel again in a new cell to see the update. I tried replacing individual items in the objects list via indexing, but this worked the same as pop and insert, the panel did not update automatically.

Is there a way to replace parts of a panel vi a selected.on_change callback and have it refresh automatically (preferably inside the notebook but via show also works)?

Versions:

-----
bokeh       2.0.1
pandas      1.0.3
panel       0.9.5
-----
IPython             6.5.0
jupyter_client      5.2.3
jupyter_core        4.6.3
jupyterlab          2.1.0
notebook            5.6.0
-----
Python 3.7.6 | packaged by conda-forge | (default, Mar 23 2020, 23:03:20) [GCC 7.3.0]
Linux-5.6.13-arch1-1-x86_64-with-arch
4 logical CPU cores
-----
Session information updated at 2020-05-21 18:38
joelostblom
  • 43,590
  • 17
  • 150
  • 159
  • I don't know the answer, but if you get no answer to this question on SO, you can also try posting your question on https://discourse.holoviz.org/ – Sander van den Oord May 23 '20 at 14:27
  • Thanks @SandervandenOord, I opened one at https://discourse.holoviz.org/t/how-can-i-replace-part-of-a-panel-via-a-selection-change-in-a-bokeh-figure/701 previously. – joelostblom May 23 '20 at 20:34

1 Answers1

1

Turns out this is a bug in panel, now being tracked at https://github.com/holoviz/panel/issues/1368. For the time being, the following snippet works around the problem:

from panel.io.notebook import push

def replace_plot(attr, old, new):
    for ref in pnl._models:
        _, _, doc, comm = pn.state._views[ref]
        doc.hold()
        pnl[0] = 1
        push(doc, comm)
    for ref in pnl._models:
        _, _, doc, comm = pn.state._views[ref]
        doc.unhold()
joelostblom
  • 43,590
  • 17
  • 150
  • 159