Select callback using BokehJS in a static React site #12099
-
For reference, this was originally posted on the discourse site; https://discourse.bokeh.org/t/select-callback-using-bokehjs-in-a-static-react-site. Please visit the site for more context, and thanks to @bryevdv for linking to here so we can continue the discussion. Brief overviewI am attempting to write a Bokeh figure that updates with a Select widget in a static React site. I have created a Python version of the figure/widget and a JavaScript version that mirrors the Python version closely. Results/Expected results
ExampleThe code to reproduce user interactions working fine in Python (and not working in JavaScript) can be found in a GH repo, https://github.com/ndmlny-qs/bokeh-docusaurus-widgets. The readme explains how to get the environment running for both Python and JavaScript and how to start both for debugging. Example code (also found in the repo)Excuse any typos below. The linked GH repo was tested to ensure the two apps run. from bokeh.io.showing import show
from bokeh.layouts import column
from bokeh.models.sources import ColumnDataSource
from bokeh.models.widgets.inputs import Select
from bokeh.plotting.figure import figure
class BKApp:
def modify_doc(self, doc):
# Initialize the widget value.
init_value = 1
# Compute data using the initial widget value, and create a Bokeh source.
x = range(10)
y = [init_value * pt for pt in x]
source = ColumnDataSource({"x": x, "y": y})
# Create the figure, and attach the data to it.
fig = figure()
glyph = fig.line(x="x", y="y", source=source)
# Create the widget.
select = Select(
value=str(init_value), options=list(map(str, range(3))), title="slope"
)
# Callback for the widget.
def update(attr, old, new):
# Calculate new data.
new_y = [int(new) * pt for pt in x]
# Update the source with the new data.
source.data = {"x": x, "y": new_y}
# Listen for changes from the widget.
select.on_change("value", update)
# Add the widget and plot to the doc.
layout = column([select, fig])
doc.add_root(layout)
def show(self):
# Visualize the widget in Jupyter.
show(self.modify_doc)
BKApp().show() import React, { useRef } from "react";
import BrowserOnly from "@docusaurus/BrowserOnly";
export const BkApp = () => {
const containerRef = useRef(null);
return (
<BrowserOnly fallback={<div>loading...</div>}>
{() => {
const Bokeh = require("@bokeh/bokehjs");
// Initialize the widget value.
const init_value = 1;
// Compute data using the initial widget value, and create a Bokeh source.
const x = [...Array(10).keys()];
let y = [];
for (let i = 0; i < x.length; i++) {
y.push(init_value * x[i]);
}
const source = new Bokeh.ColumnDataSource({ data: { x: x, y: y } });
// Create the figure, and attach the data to it.
const fig = Bokeh.Plotting.figure();
fig.line({
x: { field: "x" },
y: { field: "y" },
source: source,
});
// Create the widget.
const select = new Bokeh.Widgets.Select({
value: init_value.toString(),
options: [...Array(3).keys()].map((value) => {
return value.toString();
}),
title: "slope",
});
// Callback for the widget.
const update = (select, source, fig) => {
let value = select.value;
let x = source.data.x;
// Calculate new data.
const newY = [];
for (let i = 0; i < y.length; i++) {
newY.push(parseInt(value) * x[i]);
}
// Update the source with the new data.
source.data.y = newY;
// Emit changes to the figure.
fig.change.emit();
};
// Listen for changes from the widget.
select.js_event_callbacks["menu_item_click"] = [
new Bokeh.CustomJS({
args: { select, source, fig },
code: update(select, source, fig),
}),
];
// Visualize.
const layout = new Bokeh.Column({ children: [select, fig] });
if (containerRef && containerRef.current) {
containerRef.current.innerHTML = "";
Bokeh.Plotting.show(layout, containerRef.current);
}
return <div ref={containerRef} style={{ width: "100%" }}></div>;
}}
</BrowserOnly>
);
}; |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
@mattpap what is the current status of supplying callbacks directly from BokehJS? I thought I recalled some places that would condition on a callback being a https://github.com/bokeh/bokeh/blob/branch-3.0/bokehjs/examples/tap/tap.ts#L50 which employs a fairly non-standard / undocumented / not-discoverable technique. @ndmlny-qs Hi Andy? I didn't realize this was you 👋 |
Beta Was this translation helpful? Give feedback.
-
The handling for the change to the widget was solved by |
Beta Was this translation helpful? Give feedback.
The handling for the change to the widget was solved by
stas-sl
on the discourse site; https://discourse.bokeh.org/t/select-callback-using-bokehjs-in-a-static-react-site/9103/7. I will be using his suggestions with the other widgets in the tool. If I encounter further issues, I will post on the discourse site. Thanks again @bryevdv !