bokeh / jupyter_bokeh

An extension for rendering Bokeh content in JupyterLab notebooks
BSD 3-Clause "New" or "Revised" License
249 stars 48 forks source link

'Models must be owned by only a single document' issue #167

Open axil opened 1 year ago

axil commented 1 year ago

The following code that intermixes two BokehModel instances with an ipywidget instance

import bokeh.plotting as bp
import bokeh.models as bm
import ipywidgets as ipw
from jupyter_bokeh import BokehModel
p = bp.figure()
src = bm.ColumnDataSource(data={'x': [1,2], 'y': [3,4]}) 
p.line(source=src)
radio = bm.RadioGroup(labels=['a', 'b'], active=0)
label = ipw.Label('c')
callback = bm.CustomJS(args=dict(data_src=src))
radio.js_on_change('active', callback)
ipw.VBox([
    BokehModel(p),
    BokehModel(radio), 
    label,
])

generates the following error:

RuntimeError: Models must be owned by only a single document, Selection(id='1732', ...) is already in a doc

Supposedly the problem is with jupyter_bokeh because

import bokeh.layouts as bl
bp.show(bl.column(p, radio))

works fine.

It is similar to #154, and I understand that

ipw.VBox([
    BokehModel(bl.column(p, radio)),
    label,
])

is a workaround, but this trick is not always possible, for example, it is not possible for the following layout:

ipw.VBox([
    BokehModel(p),
    ipw.HBox([
          BokehModel(radio), 
          label,
    ]),
])

and the main difference from issue 154 is that I don't understand which model is being 'shared' here.

mattpap commented 1 year ago

There is a potential workaround for the "single document" error:

doc = Document()
doc.add_root(p)
doc.add_root(radio)
ipw.VBox([
    BokehModel(p),
    ipw.HBox([
          BokehModel(radio), 
          label,
    ]),
])

This way p and radio will share a document and BokehModel will not attempt to attach a new one under such setup. However, that only solves part of the problem. The other issue is that each BokehModel(...) is an independent embedding point, which is currently undefined behavior when using the same document. Consider each BokehModel(...) as if calling show() multiple times with the same document. However, I have some ideas how this could be alleviated.

axil commented 1 year ago

@mattpap Yes, it helps with the ownership issue. Yet this code displays both widgets twice and generates the following error

image

for every model (a total of 8 times). Do you know how to deal with it?