In my standalone website, a button click by the user updates the text of a bokeh.models.Div via Javascript. Usually, this text only includes, well text, images and some formatting instructions. I wonder whether I’d also be able to include a precomputed bokeh.plotting.figure somewhere in the text in this way as well.
A minimal example is below. My hope was to do this with a json_item embedding. Essentially, precompute the figure in Python, obtain the JSON with json_item()
, save it somewhere later accessible from Javascript. Then in Javascript set the Div’s text field to a div tag with the chosen #id and call Bokeh.embed.embed_item()
on the JSON information. This pretty much works except for the fact that #id is not found, because it is contained in a shadowroot. How could I solve this?
Example:
from bokeh import events
from bokeh.embed import json_item
from bokeh.layouts import layout
from bokeh.models import Button, CustomJS
from bokeh.models import Div
from bokeh.plotting import figure, show
import json
p = figure()
p.line(x=[0, 1], y=[0, 1])
div = Div(text='', name='mydiv')
button = Button(label='Click')
item_text = json.dumps(json_item(p, "myplot"))
button.js_on_event(events.ButtonClick, CustomJS(code=f"""
let div = Bokeh.documents[0].get_model_by_name('mydiv');
div.text = '<div id="myplot"></div>';
let item = JSON.parse(data);
// Raises error "Error rendering Bokeh model: could not find #myplot HTML tag"
Bokeh.embed.embed_item(item);
""", args=dict(data=item_text)))
show(layout([button, div]))
Edit: I now realized that I can pass a html-DOM-reference to embed_item
, as in Bokeh.embed.embed_item(item, dom)
. Still, it would be nice to realize this within the Bokeh components without having to figure out the dom-tree to a component, which can be quite brittle and complicated.