我有一个普遍的问题,当小部件触发回调时,应如何使用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)
但是,如果可以替换的话(对于与该代码无关的更大项目)会有用得多
for (var i = 0; i < old_x.length; i++) {
old_x[i] = new_x[i];
old_y[i] = new_y[i];
}
像这样
old_x = new_x
old_y = new_y
我尝试这样做,但是数据没有更新。有人可以解释为什么,以及如何实现这种更高级别的数据更改(即不必一一更改列表的值)吗?
编辑: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();
""")
答案 0 :(得分:0)
首先,要纠正误解:
var old_x = data_curr['x'] // This is a numpy.ndarray
这是在不存在NumPy的浏览器中执行的JavaScript,因此它要么是JS类型数组,要么是纯JS数组,但绝对不是numpy.ndarray
。
您必须实际更新源中的值。当您这样做时:
var old_x = data_curr['x']
您创建一个新的局部变量。如果您这样做:
old_x = new_x
然后,您要做的就是为局部变量分配一个新值。这完全不会影响数据源 。
相反,您需要以下内容:
source_curr.data['x'] = new_x
这实际上修改了数据源的内容。