Hi there,
just started to work with Bokeh to generate a simple server that allows users on an offine workstation, to load .txt files from a metrology tool to generate plots.
The files can have a variable amount of sections, so I want to generate variable number of plots depending on file content.
I found this question about dynamically adding plots and ported it to the most recent Bokeh version, but it seems I cannot create a reference to the Bokeh.Plotting definitions:
Sample Code:
# myapp.py
from bokeh.layouts import column
from bokeh.models import Button, CustomJS
from bokeh.plotting import figure, curdoc
f1 = figure()# add a line renderer and legend to the plot
f1.line(x=[1,2,3], y=[3,2,3], legend_label="Temp.")
main_row = column(f1)
button2=Button(label='Add plot')
button2.js_on_event('button_click', CustomJS(args=dict(main_row=main_row), code="""
const bok = Bokeh; //works
const plt = Bokeh.Plotting; //does not work
var f = plt.Figure();
f.line({x: [1, 2, 3], y: [3, 2, 1]});
main_row.children.push(f);
main_row.properties.children.change.emit();
"""))
curdoc().add_root(column(button2,main_row))
In the browser’s debugger I get the Error Cannot read properties of undefined (reading 'Figure')
because plt
is indeed undefined. In the Debugging tools of the browser, bok
does not have a Plotting
module.
Assume it has something to do with the separate Bokeh-api.js
- but I could not figure out, how to integrate that - help is appreciated…
I haven’t used Bokeh in years and have no clue about the current state of affairs, but I got notified because you linked to my comment so I did a quick check.
It seems that you can use const f = new (Bokeh.Models.get('Figure'))();
instead of const plt = Bokeh.Plotting; var f = plt.Figure();
. But I haven’t tried actually running the code. Could be that it doesn’t work at all, could be that it just needs a bit of other changes.
1 Like
Hi Eugene, thanks for the ultra-quick reply. Your suggestion indeed generates a Figure instance, but I still get an error calling the methods of the instance - since I need a low code solution, that colleagues working with the machine can understand without digging into JS details, this may get too complex.
Currently looking at another Python Plotting alternative, which has the possibility to use a categorical column to generate a trellis/facet plot - might be exactly what I need, without requiring to write JS code on top of Python.
If anybody has a working example for dynamic plot adding/removing via JS in the recent Bokeh version, I am still interested to see an example.
Just in case - if you can run Bokeh with a server, you don’t need to rely on JS at all and you can do everything via Python. The button would send a message to the server, the server would update its version of the document, and then send the new data to the frontend.
1 Like
This is provided by bokeh-api(.min).js
bundle, which we don’t have a good way of detecting automatically if it’s needed. Here’s an updated version of your example adding that bundle:
from bokeh.layouts import column
from bokeh.models import Button, CustomJS
from bokeh.plotting import figure
from bokeh.io import save
from bokeh.resources import CDN
f1 = figure()# add a line renderer and legend to the plot
f1.line(x=[1,2,3], y=[3,2,3], legend_label="Temp.")
main_row = column(f1)
button2=Button(label='Add plot')
button2.js_on_event('button_click', CustomJS(args=dict(main_row=main_row), code="""
const plt = Bokeh.Plotting;
const f = plt.figure();
f.line({x: [1, 2, 3], y: [3, 2, 1]});
main_row.children.push(f);
main_row.properties.children.change.emit();
"""))
layout = column(button2,main_row)
resources = CDN.clone(components=[*CDN.components, "bokeh-api"])
save(layout, resources=resources)
I use save()
for my own simplicity, but this will work with curdoc()
, etc.
1 Like
It would be good to document this. Can you start an new issue for this?
Thanks to all, the suggested snippet works. Still need to check, if I am better of with the Server version - but since the target system is in a very sensitive IT env with a lot of restrictions, I am not sure yet, if user rights allow to start anything serving actively on localhost - will test next time on the system - the idea of having a standalone html with JS only was charming.
Thanks for getting me going again.
I meanwhile also created an issue - hope it is roughly how you exected it to be… Thanks again!