问题描述
我对Bokeh和Javascript都是陌生的,我正在尝试在Bokeh中实现一个简单的multiselect小部件.这个想法只是根据用户选择的字母(A,B,C)在散点图上显示x和y数据.用户选择选项之前,该图应为空.问题在于Javascript回调:当我使用MultiSelect小部件选择一个条目时,什么也没有发生.代码如下.
I am new to both Bokeh and Javascript and I am trying to implement a simple multiselect widget in Bokeh. The idea is simply to display the x and y data on a scatterplot depending on the letter or letters chosen by the user (A, B, C). The graph should be empty before the user selects a choice. The problem lies with the Javascript callback: nothing happens when I select an entry with the MultiSelect widget. The code is below.
from bokeh.models import CustomJS, ColumnDataSource, MultiSelect, Column
from bokeh.plotting import figure, show
import pandas as pd
data = dict(letter = ['A','A','B','C','B','B','A','C','C','B'],
x = [1, 2, 1, 2, 3, 2, 2, 3, 2, 3],
y = ['10','20','10','30','10','40','10','30','10','40'])
data = pd.DataFrame(data)
data_source = ColumnDataSource(data)
source = ColumnDataSource(dict(letter = [], x = [], y = []))
plot = figure()
plot.circle('x', 'y', line_width = 2, source = source)
callback = CustomJS(args = {'source': source, 'data_source': data_source},
code = """
var data = data_source
source.data = data[cb_obj.value];
""")
multiselect = MultiSelect(title = 'Choose', value = [], options = ['A', 'B', 'C'])
multiselect.js_on_change('value', callback)
layout = Column(multiselect, plot)
show(layout)
有什么想法吗?
推荐答案
您处在正确的轨道上.如果要过滤数据,通常最好有一个主"数据源,以便在过滤值更改时仅从中提取所需的元素.我发现使用循环执行此操作最简单(请参见下面的代码).另外,别忘了总是在回调结束时向源发出更改.
You're on the right track. If you'd like to filter data it is generally a good idea to have a "master" data source from which to extract only the required elements as the filtered value changes. I find it easiest to do this using loops (see code below). Also, don't forget to always emit the changes to the source at the end of the callback.
from bokeh.models import CustomJS, ColumnDataSource, MultiSelect, Column
from bokeh.plotting import figure, show
import pandas as pd
data = dict(letter = ['A','A','B','C','B','B','A','C','C','B'],
x = [1, 2, 1, 2, 3, 2, 2, 3, 2, 3],
y = ['10','20','10','30','10','40','10','30','10','40'])
data = pd.DataFrame(data)
data_source = ColumnDataSource(data)
source = ColumnDataSource(dict(x = [], y = []))
plot = figure()
plot.circle('x', 'y', line_width = 2, source = source)
callback = CustomJS(args = {'source': source, 'data_source': data_source},
code = """
var data = data_source.data;
var s_data = source.data;
var letter = data['letter'];
var select_vals = cb_obj.value;
var x_data = data['x'];
var y_data = data['y'];
var x = s_data['x'];
x.length = 0;
var y = s_data['y'];
y.length = 0;
for (var i = 0; i < x_data.length; i++) {
if (select_vals.indexOf(letter[i]) >= 0) {
x.push(x_data[i]);
y.push(y_data[i]);
}
}
source.change.emit();
""")
multiselect = MultiSelect(title = 'Choose', value = [], options = ['A', 'B', 'C'])
multiselect.js_on_change('value', callback)
layout = Column(multiselect, plot)
show(layout)
一般评论:我-和您一样-最近才开始使用Bokeh,我也是JS新手.我在Bokeh 用户指南中找到了示例,非常有帮助.
General comment: I - like you - only started using Bokeh recently and I'm a JS novice, too. I found the examples in the Bokeh user guide, very helpful.
这篇关于如何在Bokeh中为多选小部件实现Javascript回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!