Reputation: 121
I'm trying to plot several circles using bokeh sliders. I know there is an example on the page https://docs.bokeh.org/en/latest/docs/gallery/slider.html but when I try to implement it I get a graphic and the sliders but the graphic is not updated. I guess it's a problem with the callback.
Here is't my code:
import numpy as np
from bokeh.layouts import row, widgetbox
from bokeh.models import CustomJS, Slider
from bokeh.plotting import figure, output_file, show, ColumnDataSource
L_1 = 150
L_2 = 100
w = 0
h = 250
r1 = L_1 + L_2
r2 = L_1 - L_2
t = np.linspace(0, 2 * np.pi, 200)
sint = np.sin(t)
cost = np.cos(t)
x1 = r1 * cost
y1 = r1 * sint
x2 = r2 * cost
y2 = r2 * sint
x3 = r1 * cost + w
y3 = r1 * sint + h
x4 = r2 * cost + w
y4 = r2 * sint + h
source = ColumnDataSource(data=dict(x1=x1,y1=y1,x2=x2,y2=y2,x3=x3,y3=y3,x4=x4,y4=y4,t=t))
plot = figure(plot_width=400, plot_height=400)
plot.line('x1', 'y1', source=source, line_width=3, line_alpha=0.6)
plot.line('x2', 'y2', source=source, line_width=3, line_alpha=0.6)
plot.line('x3', 'y3', source=source, line_width=3, line_alpha=0.6)
plot.line('x4', 'y4', source=source, line_width=3, line_alpha=0.6)
callback = CustomJS(args=dict(source=source), code="""
var data = source.data;
var L_1 = l1.value;
var L_2 = l2.value;
var w = w.value;
var h = h.value;
var r1 = L_1 + L_2;
var r2 = L_1 - L_2;
t = data['t'];
for (i = 0; i < t.length; i++) {
sint = Math.sin(t[i]);
cost = Math.cos(t[i]);
y1[i] = r1 * sint;
x1[i] = r1 * cost;
y2[i] = r2 * sint;
x2[i] = r2 * cost;
y3[i] = r1 * sint + w;
x3[i] = r1 * cost + h;
y4[i] = r2 * sint + w;
x4[i] = r2 * cost + h;
}
source.change.emit();
""")
L_1_slider = Slider(start=0, end=300, value=200, step=1,
title="L1", callback=callback)
callback.args["l1"] = L_1_slider
L_2_slider = Slider(start=0, end=300, value=150, step=1,
title="L2", callback=callback)
callback.args["l2"] = L_2_slider
w_slider = Slider(start=0, end=600, value=0, step=1,
title="w", callback=callback)
callback.args["w"] = w_slider
h_slider = Slider(start=0, end=600, value=0, step=.1,
title="h", callback=callback)
callback.args["h"] = h_slider
layout = row(
plot,
widgetbox(L_1_slider, L_2_slider, w_slider, h_slider),
)
output_file("slider2.html", title="slider.py example")
show(layout)
Upvotes: 1
Views: 1457
Reputation: 3364
You are correct it is an issue with the callback. In its current state, you can inspect the browser console - it will display that y1 is undefined. That is because there are no variables defined within the callback as y1 (and y2 etc...). It is however stored within the column data source; so you can update the callback as follows: (or define all variables before assignment in the for loop).
callback = CustomJS(args=dict(source=source), code="""
var data = source.data;
var L_1 = l1.value;
var L_2 = l2.value;
var w = w.value;
var h = h.value;
var r1 = L_1 + L_2;
var r2 = L_1 - L_2;
t = data['t'];
for (i = 0; i < t.length; i++) {
sint = Math.sin(t[i]);
cost = Math.cos(t[i]);
data.y1[i] = r1 * sint;
data.x1[i] = r1 * cost;
data.y2[i] = r2 * sint;
data.x2[i] = r2 * cost;
data.y3[i] = r1 * sint + w;
data.x3[i] = r1 * cost + h;
data.y4[i] = r2 * sint + w;
data.x4[i] = r2 * cost + h;
}
source.change.emit();
""")
Upvotes: 3