Javascript 使用bokeh滑块小部件更新绘图数据

Javascript 使用bokeh滑块小部件更新绘图数据,javascript,python,bokeh,Javascript,Python,Bokeh,我有一个一般性的问题,当小部件触发回调时,应该如何在Bokeh中使用CustomJS脚本更新数据 下面的代码对我来说很好 import numpy as np from bokeh.layouts import column, row from bokeh.models import CustomJS, Slider from bokeh.plotting import ColumnDataSource, figure, output_file, output_notebook, show o

我有一个一般性的问题,当小部件触发回调时,应该如何在Bokeh中使用CustomJS脚本更新数据

下面的代码对我来说很好

import numpy as np

from bokeh.layouts import column, row
from bokeh.models import CustomJS, Slider
from bokeh.plotting import ColumnDataSource, figure, output_file, output_notebook, show
output_notebook()

# Define a slider
my_slider = Slider(start=0, end=2, value=0, step=1, title="Amplitude")

# Produce a list of data to be scrolled with the slider
xy_list = []
for a in range(0,3):
    x_list = np.linspace(0, 10, 500)
    y_list = float(a) * np.sin(x_list)
    xy_list.append(
        ColumnDataSource(data=dict(x=x_list, y=y_list))
    )

# Produce the initial data to be displayed
# NOTE: this is like a hard-coded deepcopy,
# since deepcopy doesn't seem to work well 
# with Bokeh objects
xy_current = ColumnDataSource(
    data=dict(
        x=np.linspace(0, 10, 500), 
        y=0.0*np.linspace(0, 10, 500)
    )
)

# Produce a plot
plot = figure(y_range=(-10, 10), plot_width=200, plot_height=200)
plot.line('x', 'y', source=xy_current, line_width=3, line_alpha=0.6)

# Define a callback for the slider
callback = CustomJS(
    args=dict(
#         source_0=xy_source_0, # An instance of ColumnDataSource
        source_curr=xy_current, # An instance of ColumnDataSource
        source_list=xy_list, # A list, with entries of type ColumnDataSource
    ),
    code="""
    var data_curr = source_curr.data; // This is an instance of bokeh.core.property.wrappers.PropertyValueColumnData
    var plot_i = cb_obj.value // This is an int
    var old_x = data_curr['x'] // This is a numpy.ndarray
    var old_y = data_curr['y'] // This is a numpy.ndarray
    var new_x = source_list[plot_i].data['x'] // This is a numpy.ndarray
    var new_y = source_list[plot_i].data['y'] // This is a numpy.ndarray
    // Now update the y-values for each x, based on the slider value
    for (var i = 0; i < old_x.length; i++) {
        old_x[i] = new_x[i];
        old_y[i] = new_y[i];
    }
    source_curr.change.emit();
""")

# Implement the callback
my_slider.js_on_change('value', callback)

# Show 
layout = row(
    plot,
    my_slider,
)

show(layout)
我试过这样做,但是数据没有更新。有人能解释一下为什么,以及如何实现这种更高层次的数据更改(即不必逐个更改列表的值)


编辑:在bigreddot给出答案之后,我将回调脚本更新为以下形式,使用更少的ocal变量

callback = CustomJS(
    args=dict(
        source_curr=xy_current, # An instance of ColumnDataSource
        source_list=xy_list, # A list, with entries of type ColumnDataSource
    ),
    code="""
    var plot_i = cb_obj.value // This is an int
    // Now update the y-values for each x, based on the slider value
    source_curr.data['x'] = source_list[plot_i].data['x']
    source_curr.data['y'] = source_list[plot_i].data['y']

    source_curr.change.emit();
""")

首先,纠正一种误解:

var old\u x=data\u curr['x']//这是一个numpy.ndarray
这是在不存在NumPy的浏览器中执行的JavaScript,因此它要么是JS类型的数组,要么是普通的JS数组,但绝对不是
NumPy.ndarray


您必须实际更新源中的值。当您这样做时:

var old_x = data_curr['x']
创建一个新的局部变量。如果你这样做:

old_x = new_x
然后,您所做的就是为局部变量指定一个新值。这根本不会影响数据源

相反,您需要的是:

source_curr.data['x'] = new_x

这实际上修改了数据源的内容。

感谢您的快速回复!事实上,我知道numpy不是javascript类型,这是一条注释,用来提醒我自己要将什么样的数据传递给回调函数。我真正不知道的是如何跟踪javascript中有关局部变量的规则。来自python的Bokeh强迫人们编写小的js代码段,即使在简单的情况下也可能很棘手。谢谢!
old_x = new_x
source_curr.data['x'] = new_x