Bokeh & Custom Js - Using A Slider To Update A Multiline Graph
Solution 1:
The other answers are both partially correct, but incomplete or have issues in various ways. The major missing part is that if you slice the original data source every time the slider moves, then the after the first slider move, you are now no longer slicing the original data anymore, so things will not work. You need to send the full original data separately, and always copy the sub-parts you want out of the original. Here is a complete working script:
from bokeh.io import show
from bokeh.layouts import column
from bokeh.models import CustomJS, ColumnDataSource, Slider
from bokeh.plotting import figure
data_dict = {
'lons':[[-1.0, -1.1, -1.2, -1.3, -1.4], [-1.0, -1.1, -1.25, -1.35, -1.45]],
'lats':[[53.0, 53.1, 53.2, 53.3, 53.4], [53.05, 53.15, 53.25, 53.35, 53.45]]
}
full_source = ColumnDataSource(data_dict)
source = ColumnDataSource(data_dict)
p = figure(plot_width=400, plot_height=400, tools="")
p.multi_line(xs='lons', ys='lats', source=source)
callback = CustomJS(args = dict(source=source, full_source=full_source), code = """
const time = cb_obj.value;
const full_lons = full_source.data['lons']
const full_lats = full_source.data['lats']
for(i=0; i<full_lons.length; i++) {
source.data['lons'][i] = full_lons[i].slice(0, time)
source.data['lats'][i] = full_lats[i].slice(0, time)
}
// only need this because source.data is being updated "in place"
source.change.emit()
""")
slider = Slider(start = 0, end = 5, value = 0, step = 1, callback = callback)
slider.js_on_change('value', callback)
layout = column(p, slider)
show(layout)
I've updated the code to use figure
from bokeh.plotting
to be simpler, and also to get default axes, etc. It's also worth noting that a slider value of 0 may not make sense, a plot with that will be (correctly) empty.
Solution 2:
I believe what you are looking for is covered in the documentation - please see : https://hub.mybinder.org/user/bokeh-bokeh-notebooks-ykp39727/notebooks/tutorial/06%20-%20Linking%20and%20Interactions.ipynb#Slider-widget-example
Specifically, something like the following slider.js_on_change('value', calback)
Solution 3:
There were some small problems in your javascript code (You forgot a )
and you forgot to assign the lists with new lons/lats to the source.), a syntax error in the Slider and a typo in the imports.
#!/usr/bin/python3from bokeh.models import CustomJS, ColumnDataSource, Slider, Plot
from bokeh.models.glyphs import MultiLine
from bokeh.io import show
from bokeh.layouts import column
data_dict = {'lons':[[-1.0, -1.1, -1.2, -1.3, -1.4], [-1.0, -1.1, -1.25, -1.35, -1.45]], 'lats':[[53.0, 53.1, 53.2, 53.3, 53.4], [53.05, 53.15, 53.25, 53.35, 53.45]]}
source = ColumnDataSource(data_dict)
p = Plot(title = None, plot_width = 400, plot_height = 400)
glyph = MultiLine(xs = 'lons', ys = 'lats')
p.add_glyph(source, glyph)
callback = CustomJS(args = dict(source = source), code = """
var data = source.data;
var time = time.value;
var lons = data['lons']
var lats = data['lats']
var runners = lons.length
var new_lons = []
var new_lats = []
for(i=0; i<runners; i++){
var runner_lons = lons[i].slice(0, time)
var runner_lats = lats[i].slice(0, time)
new_lons.push(runner_lons)
new_lats.push(runner_lats)
}
lons = new_lons
lats = new_lats
source.attributes.data.lons = new_lons
source.attributes.data.lons = new_lats
source.change.emit();
""")
slider = Slider(start = 0, end = 5, value = 0, step = 1, callback = callback)
layout = column(p, slider)
callback.args["time"] = slider
show(layout)
Post a Comment for "Bokeh & Custom Js - Using A Slider To Update A Multiline Graph"