在 Bokeh 中使用日期滑块更改数据

Change Data using Date Slider in Bokeh

在 Bokeh 中,我尝试使用滑块更改可视化数据。有趣的是,在滑块更改时,console 会记录预期值,但可视化效果不会按预期更新。

如何获得我想要的功能? 为什么代码记录了正确的数据但图表没有更新?

from bokeh.models import CustomJS, Slider
from bokeh.plotting import ColumnDataSource, figure, output_file, show
from bokeh.embed import file_html
from bokeh.resources import CDN
import pandas as pd

df_str = '''2020-09-10 1 75731 0
2020-09-10 2 71627 0
2020-09-10 3 66972 0
2020-09-10 4 63718 0
2020-09-10 5 61951 0
2020-09-11 1 59380 1
2020-09-11 2 58297 1
2020-09-11 3 57833 1
2020-09-11 4 55669 1
2020-09-11 5 55281 1'''

df = pd.DataFrame([col.split() for col in [row for row in df_str.split('\n')]])
df.columns = ['Date', 'Score', 'ScoreTotal', 'DayNumber']

dates = df.Date.unique()

xs = [[] for _ in range(len(dates))]
ys = [[] for _ in range(len(dates))]
date = [i for i in range(len(dates))]

for _, row in df.iterrows():
  i = int(row.DayNumber)
  xi = row.Score
  yi = row.ScoreTotal
  xs[i].append(xi)
  ys[i].append(yi)

x = xs[0]
y = ys[0]
xs += [[]] * 3
ys += [[]] * 3

source = ColumnDataSource(data=dict(x=x, y=y, xs=xs, ys=ys))

plot = figure(plot_width=500, plot_height=500)
plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6)

date_slider = Slider(start=0, end=2, value=0, step=1, title="Date Slider")

callback = CustomJS(args=dict(source=source, date_slider=date_slider),
                    code="""
    const data = source.data;
    const date = date_slider.value
    const x = data['xs'][date]
    const y = data['ys'][date]
    console.log(y) // CORRECT CONSOLE LOG BUT NO CHANGE
    source.change.emit();
""")

date_slider.js_on_change('value', callback)

from bokeh.layouts import column, row

layout = row(
    plot,
    column(date_slider),
)

show(layout)

Bokeh Discourse website,我能够让用户解释我的 JS 代码没有修改任何东西,正如 Eugene 在上面的评论中提到的那样。需要就地修改原始数据数组。更新 code 参数导致期望的结果:

  code="""
    const data = source.data;
    const date = date_slider.value;
    const old_y = data['y'];
    const x = data['xs'][date];
    const y = data['ys'][date];

    for (var i = 0; i < old_y.length; i++) {
      old_y[i] = y[i]
    }

    source.change.emit();
  """