Eduardo Vieira
Eduardo Vieira

Reputation: 121

Multiple sliders on bokeh plot

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

Answers (1)

Anthonydouc
Anthonydouc

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

Related Questions