我有一个熊猫数据帧df,其中前两列代表x,y坐标,其余列代表时间片(t0,... tn),其中每个点每个点的存在(1)或不存在(0)时间片(ti)被记录。
我想使用RangeSlider
(而不是Slider
),以便我可以跨越一定范围的时间片并绘制出该范围内的点。
这是我到目前为止得到的,
from bokeh.layouts import column
from bokeh.plotting import figure, show
from bokeh.models import CustomJS, ColumnDataSource
from bokeh.models.widgets import RangeSlider
# pts is a dataframe with columns (x, y, t0, t1,...t19)
src = ColumnDataSource(data = pts)
p = figure(plot_height = 500)
p.circle(source= src, x='x', y= 'y', size=2, color="navy", alpha=0.1)
callback = CustomJS( args = dict(source = src), code="""
var data = source.data;
// changed ti range
var ti_start = cb.obj.value[0] + 2 //offset
var ti_end = cb.obj.value[1] + 2
// change data (how to select columns???????)
data = data[ti_start:ti_end]
source.change.emit()
""")
ti_slider = RangeSlider(start=0, end=19, value=(1,2), step=1, title="Time Period",
callback = callback)
layout = column(ti_slider, p)
show(layout)
上面的代码根本不起作用。将绘制点并显示RangeSlider,但是当我更改范围或滑行时什么也没有发生。我无法限制构成数据源(即数据框)的列。我尝试更改选择列的代码,但我不知道任何JavaScript。
这是我第一次尝试将CustomJS
函数用于bokeh。
答案 0 :(得分:0)
上面的代码中存在许多问题:
cb_obj
而不是cb.obj
js_on_change
,而不是非常老的临时callback
参数data
,然后丢弃结果-需要在某些时候从字面上分配给source.data
,以确保效果。 CDSView
,它使您可以表达可更新的子集视图以应用于恒定数据源。这是一个简化的工作示例:
from bokeh.layouts import column
from bokeh.plotting import figure, show
from bokeh.models import CustomJS, ColumnDataSource, RangeSlider, CDSView, IndexFilter
source = ColumnDataSource(data=dict(
x=[1,2,3,4],
y=[1,1,1,1],
t0=[1,1,0,0],
t1=[0,1,0,0],
t2=[0,1,1,0],
t3=[0,0,1,1],
t4=[0,0,0,1],
t5=[0,0,0,0],
))
p = figure(plot_height=500, x_range=(0,5), y_range=(0,2))
view = CDSView(source=source, filters=[IndexFilter([0, 1])])
p.circle('x', 'y', size=10, color="navy", alpha=0.8,
source=source, view=view)
callback = CustomJS(args=dict(source=source, view=view), code="""
const start = cb_obj.value[0]
const end = cb_obj.value[1]
const indices = []
for (var i=0; i < source.get_length(); i++) {
for (var j=start; j<=end; j++) {
if (source.data["t" + j][i]==1) {
indices.push(i)
break
}
}
}
view.indices = indices
""")
ti_slider = RangeSlider(start=0, end=5, value=(0,1), step=1, title="Time Period")
ti_slider.js_on_change('value', callback)
show(column(ti_slider, p))