How to create a Bokeh Tap tool to select all points of the ColumnDataSource sharing the same value in a given column

最后都变了- 提交于 2020-01-17 07:48:04

问题


I have a bunch of data plotted in a scatter plot using a ColumnDataSource and one column is the X coordinates another the Y coordinates. There's a third column with a patient ID that may have duplicates. I'd like to create a Tap derived tool that would select all other x,y coordinates that share the same value in the patient ID column.

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

So basically if I click in my bokeh scatter plot the coordinate (1,2) I'd get points at (1,2) and (2,3) selected with all others unselected much like how you find the lasso and boxselect tools behaving.


回答1:


Here is an example solution using CustomJS with bokeh 0.12.6. Essentially when the user selects a glyph, you know which row that corresponds to. Look up the associated id value and then add all other data points with the same id to the selected attribute of a ColumnDataSource.

You can also create an equivalent call back using python only. However that will require the use of a bokeh server. The code will also be quite similar.

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)

In recent versions of bokeh the notation for accessing the selected indices has been simplified somewhat. For compatibility with bokeh 0.13.0, the JS callback could become:

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();
"""


来源:https://stackoverflow.com/questions/44961192/how-to-create-a-bokeh-tap-tool-to-select-all-points-of-the-columndatasource-shar

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!