首页 > 解决方案 > 如何在 Bokeh 中为多选小部件实现 Javascript 回调

问题描述

我是 Bokeh 和 Javascript 的新手,我正在尝试在 Bokeh 中实现一个简单的多选小部件。这个想法只是根据用户选择的一个或多个字母(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)

有任何想法吗 ?

标签: javascriptbokeh

解决方案


你在正确的轨道上。如果您想过滤数据,通常最好有一个“主”数据源,以便在过滤值更改时仅从中提取所需元素。我发现使用循环最容易做到这一点(见下面的代码)。此外,不要忘记始终在回调结束时向源发出更改。

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用户指南中找到了示例,非常有帮助。


推荐阅读