I am using Bokeh to try and create a figure whose data points when \'hovered\' over by the user will display another graph within the hover tool, showing additional informa
You can use Python callback only in Bokeh server applications. It seems impossible to use Python callbacks for a HoverTool (it must be always a JS callback, or you get this error: ValueError: expected an instance of type Callback, got
).
The following solution uses JS callback and it shows a small "tooltip plot" when hovering the circles on the main plot (works for Bokeh v1.0.4 and only if there are 2 plots in the Bokeh document):
from bokeh.plotting import figure, show
from bokeh.layouts import gridplot, Row
from bokeh.models import ColumnDataSource, CDSView, BooleanFilter, CustomJS, BoxSelectTool, HoverTool
import pandas as pd
data = {'x': [1, 2, 3],
'y':[1, 2, 3],
'xs':[[9, 8, 7], [6, 5, 4], [3, 2, 1]],
'ys':[[29, 28, 29], [27, 28, 27], [25, 25, 20]]}
source = ColumnDataSource(data)
plot = figure(title = 'PLOT IN HOVER TOOLTIP', tools = '')
circles = plot.circle('x', 'y', size = 20, source = source)
plot_tooltip = figure(name = 'plot_tooltip', plot_width = 200, plot_height = 200, x_axis_location = None, y_axis_location = None, title = None, tools = 'hover', tooltips = [("x", "@x"), ("y", "@y")], toolbar_location = None)
lines = plot_tooltip.line('x', 'y', source = ColumnDataSource({'x': [], 'y': []}))
circles2 = plot_tooltip.circle('x', 'y', source = ColumnDataSource({'x': [], 'y': []}))
code = """
var indices = cb_data.index['1d'].indices;
if (indices.length > 0){
if(plot_tooltip.x_range.bounds == null)
{
Bokeh.documents[0].add_root(plot_tooltip)
}
const idx = indices[0]
lines.data_source.data['x'] = source.data['xs'][idx]
lines.data_source.data['y'] = source.data['ys'][idx]
lines.data_source.change.emit();
circles.data_source.data['x'] = source.data['xs'][idx]
circles.data_source.data['y'] = source.data['ys'][idx]
circles.data_source.change.emit();
div = document.getElementsByClassName('bk-root')[1];
div.style = "position:absolute; left:" + cb_data.geometry['sx'] + "px; top:" + cb_data.geometry['sy'] + "px;";
} """
callback = CustomJS(args = dict(source = source, lines = lines, circles = circles2, plot_tooltip = plot_tooltip), code = code)
hover = HoverTool()
hover.callback = callback
hover.tooltips = None
hover.renderers = [circles]
plot.add_tools(hover)
show(plot)
Result: