我使用Bokeh生成交互式时间序列图。可以同时显示n个系列。每个系列将显示从t = 0到t = x,其中x是滑块创建的值。
我正在使用ColumnDataSource来包含它,MultiLine字形用于显示系列,Slider用于滑块,CustomJS用于控制更新交互。
from bokeh.models import CustomJS, ColumnDataSource, Slider, Plot
from bokeh.models.glyph 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.change.emit();
""")
slider = Slider(start = 0, , end = 5, value = 0, step = 1, callback = callback)
layout = column(p, slider)
callback.args["time"] = slider
show(layout)
此代码呈现图形,两条线都绘制在source.data
中的所有点。
移动滑块将按预期更新lons
和lats
中的数据,但图形显示不会更新。
指针,建议,建议,解释都非常感谢!
其他答案部分正确,但不完整或以各种方式存在问题。主要的缺失部分是,如果每次滑块移动时切片原始数据源,那么在第一个滑块移动后,您现在不再再切割原始数据,因此事情将无法工作。您需要单独发送完整的原始数据,并始终从原始数据中复制所需的子部分。这是一个完整的工作脚本:
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)
我更新了代码,使用来自figure
的bokeh.plotting
更简单,并且还获得默认轴等。还值得注意的是,滑块值0可能没有意义,带有它的图将(正确)为空。
我相信您所寻找的内容包含在文档中 - 请参阅:https://hub.mybinder.org/user/bokeh-bokeh-notebooks-ykp39727/notebooks/tutorial/06%20-%20Linking%20and%20Interactions.ipynb#Slider-widget-example
具体来说,像下面的slider.js_on_change('value', calback)
您的javascript代码中存在一些小问题(您忘记了)
,而您忘记为源代码分配新的lons / lats。),Slider中的语法错误和导入中的拼写错误。
#!/usr/bin/python3
from 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)