如何在Bokeh中为多选小部件实现Javascript回调

时间:2019-05-17 13:47:12

标签: javascript bokeh

我对Bokeh和Javascript都是陌生的,我试图在Bokeh中实现一个简单的multiselect小部件。这个想法只是根据用户选择的字母(A,B,C)在散点图上显示x和y数据。用户选择选项之前,该图应为空。问题在于Javascript回调:当我使用MultiSelect小部件选择一个条目时,什么也没有发生。代码如下。

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)

有什么想法吗?

1 个答案:

答案 0 :(得分:0)

您在正确的轨道上。如果您想过滤数据,通常最好有一个“主”数据源,以便在过滤值更改时仅从中提取所需的元素。我发现使用循环执行此操作最简单(请参见下面的代码)。另外,别忘了总是在回调结束时向源发出更改。

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 user guide中发现了示例,非常有帮助。