I am working with Python 3.6.2
and Bokeh 1.0.4
to create a custom JavaScript callback in my plot.
By tapping on one of the points in the plot, I'd like all points sharing the same attribute in the id-column to be highlighted.
Iterating over all datapoints with JavaScript and manipulating the respective 'selected'-attribute in the ColumnDataSource-object should do the trick. Unfortunately I can not figure out how to correct this code.
# Import packages
from bokeh.plotting import figure, show
from bokeh.models import ColumnDataSource, CustomJS, HoverTool, TapTool
# Create the data for the points
x = [0, 1, 2, 3]
y = [0, 1, 0, 1]
ids = ['A','B','A','B']
data = {'x':x, 'y':y, 'id':ids}
source = ColumnDataSource(data)
# Add tools to the plot
tap = TapTool()
hover = HoverTool(tooltips=[("X", "@x"),
("Y", "@y"),
("ID", "@id")])
# Create a plotting figure
p = figure(plot_width=400, plot_height=400, tools=[tap,hover])
# Code for the callback
code = """
// Set column name to select similar glyphs
var column = 'id';
// Get data from ColumnDataSource
var data = source.data;
// Get indices array of all selected items
var selected = source.selected.indices;
// Array to store glyph-indices to highlight
var select_inds = [];
// Check if only a single glyph is selected
if(selected.length==1){
// Get the value of the column to find similar attributes/glyphs
attribute_value = data[column][selected[0]];
// Iterate over all entries in the ColumnDataSource
for (var i=0; i<data[column].length; ++i){
// Check if items have the same attribute
if(data[column][i]==attribute_value){
// Add index to selected list
select_inds.push(i);
}
}
}
// Set selected glyphs in ColumnDataSource
source.selected.indices = select_inds;
// Save changes to ColumnDataSource
source.change.emit();
"""
# Create a CustomJS callback with the code and the data
callback = CustomJS(args={'source':source}, code=code)
# Add the callback to the ColumnDataSource
source.callback=callback
# Plots circles
p.circle('x', 'y', source=source, size=25, color='blue', alpha=1, hover_color='black', hover_alpha=1)
# Show plot
show(p)
An older version of this problem with Bokeh 0.13.0
could not solve my problem.
You were almost there! The callback has to be added to the TapTool
instead of the ColumnDataSource
.
# Import packages
from bokeh.plotting import figure, show
from bokeh.models import ColumnDataSource, CustomJS, HoverTool, TapTool
# Create the data for the points
x = [0, 1, 2, 3]
y = [0, 1, 0, 1]
ids = ['A','B','A','B']
# Generate data source for the visualization
data = {'x':x, 'y':y, 'id':ids}
source = ColumnDataSource(data)
# Add tools to the plot
tap = TapTool()
hover = HoverTool(tooltips=[("X", "@x"),
("Y", "@y"),
("ID", "@id")])
# Create a plotting figure
p = figure(plot_width=400, plot_height=400, tools=[tap,hover])
# Code for the callback
code = """
// Set column name to select similar glyphs
var column = 'id';
// Get data from ColumnDataSource
var data = source.data;
// Get indices array of all selected items
var selected = source.selected.indices;
// Array to store glyph-indices to highlight
var select_inds = [];
// Check if only a single glyph is selected
if(selected.length==1){
// Get the value of the column to find similar attributes/glyphs
var attribute_value = data[column][selected[0]];
// Iterate over all entries in the ColumnDataSource
for (var i=0; i<data[column].length; ++i){
// Check if items have the same attribute
if(data[column][i]==attribute_value){
// Add index to selected list
select_inds.push(i);
}
}
}
// Set selected glyphs in ColumnDataSource
source.selected.indices = select_inds;
// Save changes to ColumnDataSource
source.change.emit();
"""
# Create a CustomJS callback with the code and the data
callback = CustomJS(args={'source':source}, code=code)
# Add the callback to the taptool
tap.callback=callback
# Plots circles
p.circle('x', 'y', source=source, size=25, color='blue', alpha=1, hover_color='black', hover_alpha=1)
# Show plot
show(p)