如何创建一个Bokeh Tap工具来选择ColumnDataSource中在给定列

时间:2017-07-07 01:29:32

标签: bokeh

我使用ColumnDataSource在散点图中绘制了一堆数据,一列是X坐标,另一列是Y坐标。第三列的患者ID可能有重复。我想创建一个Tap派生工具,它将选择在患者ID列中共享相同值的所有其他x,y坐标。

'x'  'y' 'ID'
 1    2   'p1'
 2    3   'p1'
 2    5   'p2'
 0    1   'p2'

所以基本上如果我在我的散景散点图中点击坐标(1,2),我会得到(1,2)和(2,3)点的选择,而其他所有选择都未被选中,就像你如何找到套索和boxselect工具表现。

1 个答案:

答案 0 :(得分:5)

以下是使用带有散景0.12.6的CustomJS的示例解决方案。基本上当用户选择一个字形时,你知道哪一行对应。查找关联的id值,然后将具有相同id的所有其他数据点添加到ColumnDataSource的selected属性。

您也可以仅使用python创建等效回调。但是,这将需要使用散景服务器。代码也非常相似。

from bokeh.plotting import figure, output_file, show
from bokeh.models import ColumnDataSource, CustomJS

# output to static HTML file
output_file("line.html")

p = figure(plot_width=400, plot_height=400,tools=["tap"])

x =[1,2,2,0]
y = [2,3,5,1]
n_id = ['p1','p1','p2','p2']
data = {'x':x,'y':y,'id':n_id}
source = ColumnDataSource(data)

# source callback
code = """
    var data = source.data,
        selected = source.selected['1d']['indices'],
        select_inds = [selected[0]];
    if(selected.length == 1){
        // only consider case where one glyph is selected by user
        selected_id = data['id'][selected[0]]
        for (var i = 0; i < data['x'].length; ++i){
            if(data['id'][i] == selected_id){
                // add all points to selected if their ids coincide with original
                // glyph that was clicked.
                select_inds.push(i)
            }
        }
    }
    source.selected['1d']['indices'] = select_inds 
    source.change.emit();
"""
callback = CustomJS(args={'source':source},code=code)
source.callback=callback
p.circle('x','y',source=source, size=20, color="navy", alpha=0.5)
# show the results
show(p)

在最近的散景版本中,用于访问所选索引的符号已经有所简化。为了与bokeh 0.13.0兼容,JS回调可能变为:

code = """
    var data = source.data,
        selected = source.selected.indices,
        select_inds = [];
    if(selected.length == 1){
        // only consider case where one glyph is selected by user
        selected_id = data['id'][selected[0]]
        for (var i = 0; i < data['x'].length; ++i){
            if(data['id'][i] == selected_id){
                // add all points to selected if their ids coincide with original
                // glyph that was clicked.
                select_inds.push(i)
            }
        }
    }
    source.selected.indices = select_inds 
    source.change.emit();
"""