Issues when passing figures to ColumnDataSource

I am passing a ColumnDataSource, which contains references to Bokeh figures, as an argument to a js_on_change function . This works fine if the CDS is static and not changed later on. However if the CDS is updated right before the js code is run, the CDS data seems to become corrupted and will trigger the following JS error. Full example is below. Any idea what is going on here?

Uncaught Error: reference {“id”:“1002”} isn’t known (not in Document?)

from bokeh.io import output_notebook, curdoc

from bokeh.layouts import row, column
from bokeh.plotting import figure

from bokeh.models import ColumnDataSource, CustomJS
from bokeh.models.widgets import Button

p = figure(width=600, height=200, title="Fruit counts by year", tools="save", css_classes=["test"])

button = Button(label="Click me", button_type="success")

plot_cds = ColumnDataSource({})


def trigger_js_change():
    plot_cds.data = {"test": [p]}  # updating the cds with bokeh models at runtime will trigger an error
    button.disabled = True


button.on_click(trigger_js_change)

button.js_on_change("disabled", CustomJS(
    args=dict(plot_cds=plot_cds),
    code="""
        console.log(plot_cds) // triggers error
       """))

curdoc().add_root(column(p, button))

This is 100% not intended usage, CDS are intended for arrays of data, e.g. numbers or in some cases strings. It’s not meant to be a container for plot objects or any other Bokeh models in general [1]. Recent Bokeh versions added a DataModel class that can be used to synchronize custom/abitrary data fields, which seems more like what you want. There is an example here:

bokeh/data_models.py at branch-3.0 · bokeh/bokeh · GitHub

E.g. in this case you could define an Instance(Plot) property to hold a Plot object.


  1. And there is nothing in any docs or examples to suggest this usage as far as I know. But if that’s not the case please let us know where so we can update and/or remove any content that is misleading. ↩︎

Thanks for your reply, I am fully aware of that my approach is not a intended use case of CDS.

The DataModel class seems offer what I need. However I am not sure how to utilize sequences of plots.
Instance(Plot) works only for 1 plot object, what kind of interface should be used to support a list of plots?

All of Bokeh’s property types, including various containers are documented in the reference guide:

In this case, perhaps List(Instance(...))

1 Like