У меня есть общий вопрос о том, как данные должны обновляться с помощью пользовательских JS сценариев в Bokeh, когда виджет запускает обратный вызов.
Следующий код прекрасно работает для меня
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();
""")