散景 source.change.emit() 仅适用于第一次更改

Bokeh source.change.emit() only works on first change

我正在尝试创建一个交互式堆叠条形图来显示给定滑块值的数据。整个数据存储在基础数据集中,显示的数据是该基础数据集的子集。我面临的问题是代码基本上可以工作,但只有第一次发出更改。

这是一个最小的例子:

from bokeh.layouts import column
from bokeh.models import CustomJS, Slider
from bokeh.plotting import ColumnDataSource, figure, output_file, show

import pandas as pd

base = pd.DataFrame({'a': [1, 2, 3, 4, 5, 6],
                     'b': [10, 20, 30, 40, 50, 60],
                     'c': ['x', 'y', 'x', 'y', 'x', 'y']})
edit = pd.DataFrame({'a': [1, 2],
                     'b': [10, 20],
                     'c': ['x', 'y']})

sbase = ColumnDataSource(data=base)
sedit = ColumnDataSource(data=edit)

p = figure(x_range=['x', 'y'], width=200, height=200)
p.vbar_stack(stackers=['a', 'b'], x='c', width=0.9, color=['#7570b3', '#1b9e77'], source=sedit)

slider = Slider(start=1, end=3, value=1, step=1, title='slider')
slider_callback = CustomJS(args=dict(sbase=sbase, sedit=sedit), code="""
    const sid = cb_obj.value;
    const bs = sbase.data;
    const ed = sedit.data;
    
    var ix = sid*2-2;
    var iy = sid*2-1;    
    
    ed['a'] = [bs['a'][ix], bs['b'][ix]];
    ed['b'] = [bs['a'][iy], bs['b'][iy]];
    
    console.log(ed)
    console.log(sedit.data)
    sedit.change.emit();
    console.log(sedit.data)
""")
slider.js_on_change('value', slider_callback)

output_file('test.html')
show(column(p, slider))

我有点不知所措,因为根据日志,基础数据确实随着后续输入而改变,但图表仍然保持冻结状态。

source.change.emit 可能应该是内部的,但在一些地方提到它是目前唯一的选择。但是,通常(包括这种情况)推荐的最佳做法始终是进行真正的分配以立即更新整个 属性 值(例如 .data),而不是更改内容“in-place ".

slider_callback = CustomJS(args=dict(sbase=sbase, sedit=sedit), code="""
    const sid = cb_obj.value;
    const bs = sbase.data;
    const ix = sid*2-2;
    const iy = sid*2-1;

    sedit.data = {
        a: [bs['a'][ix], bs['b'][ix]],
        b: [bs['a'][iy], bs['b'][iy]],
        c: bs.c
    }
""")