Reputation: 1775
Is there a way to activate/deactivate a hovertool in a callback?
I tried to do that at the same time as I toggle line visibility using checkboxes. Each line has a hovertool, when a line has "visible=false" I set the "names" attribute of the corresponding tool to a dummy string; otherwise I set it equal to the initial "name" attribute of the line.
It works for the first time any box is checked, the other two line disappear and the hovertool doesn't show on them. But it doesn't work to reactivate the hovertool.
Here is my attempt:
from bokeh.plotting import figure, output_file
from bokeh.models import CustomJS, HoverTool, CheckboxGroup, ColumnDataSource
from bokeh.layouts import gridplot
from bokeh.resources import CDN
from bokeh.embed import file_html
from collections import OrderedDict
TOOLTIPS = [ ("x", "$~x"), ("y", "$~y") ]
TOOLS = ['crosshair']
source = ColumnDataSource(data={'x':range(10),'y0':range(10),'y1':range(10)[::-1],'y2':[i**0.5 for i in range(10)]})
fig = figure(tools=TOOLS)
fig.tools[0].dimensions = 'height'
plots = []
plots.append( fig.line(x='x',y='y0', name="0", source=source) )
plots.append( fig.line(x='x',y='y1', name="1", source=source) )
plots.append( fig.line(x='x',y='y2', name="2", source=source) )
names = ['first','second','third']
ID=0
for plot in plots:
fig.add_tools( HoverTool(mode='vline',line_policy='interp',renderers=[plot],names=[str(ID)],tooltips=OrderedDict( [('name',names[ID])]+TOOLTIPS )) )
ID+=1
N_plots = range(len(plots))
checkbox = CheckboxGroup(labels=names,active=[],width=200)
checkbox_iterable =[('p'+str(i),plots[i]) for i in N_plots]+[('hover'+str(i),fig.tools[1:][i]) for i in N_plots]+[('checkbox',checkbox)]
checkbox_code = """var indexOf = [].indexOf;"""+''.join(['p'+str(i)+'.visible = indexOf.call(checkbox.active, '+str(i)+') >= 0;' for i in N_plots])
checkbox_code += ''.join(['if(p'+str(i)+'.visible) hover'+str(i)+'.names = ["'+str(i)+'"];' for i in N_plots])+''.join(['if(p'+str(i)+'.visible==false) hover'+str(i)+'.names = ["no"];' for i in N_plots])
checkbox_code += ''.join(['console.log(hover'+str(i)+'.names);' for i in N_plots])
checkbox.callback = CustomJS(args={key: value for key,value in checkbox_iterable}, code=checkbox_code)
grid = gridplot([[fig,checkbox]],toolbar_location='left')
outfile=open('hovtest.html','w')
outfile.write(file_html(grid,CDN,'test'))
outfile.close()
I use bokeh 0.12.4
Upvotes: 3
Views: 2077
Reputation: 1775
Someone from the bokeh discussion group found a nice way to do this (bokeh discussion thread).
We can alter the display property of the hover tool based on the checkbox.active list. Here is an example code:
from bokeh.plotting import figure, output_file
from bokeh.models import CustomJS, HoverTool, CheckboxGroup, ColumnDataSource
from bokeh.layouts import gridplot
from bokeh.resources import CDN
from bokeh.embed import file_html
from collections import OrderedDict
TOOLTIPS = [ ("x", "$~x"), ("y", "$~y") ]
TOOLS = ['crosshair']
data = {'x':range(10),
'y0':range(10),
'y1':range(10)[::-1],
'y2':[i**0.5 for i in range(10)]
}
source = ColumnDataSource(data=data)
fig = figure(tools=TOOLS)
fig.tools[0].dimensions = 'height'
plots = []
plots.append( fig.line(x='x',y='y0', name="first", source=source) )
plots.append( fig.line(x='x',y='y1', name="second", source=source) )
plots.append( fig.line(x='x',y='y2', name="third", source=source) )
checkbox = CheckboxGroup(
labels=[plot.name for plot in plots],
active=[0,1,2],
width=200,
callback = CustomJS( args=dict(p0=plots[0],p1=plots[1],p2=plots[2]),
code = """
p0.visible = cb_obj.active.includes(0);
p1.visible = cb_obj.active.includes(1);
p2.visible = cb_obj.active.includes(2);
"""
)
)
for ID,plot in enumerate(plots):
fig.add_tools(
HoverTool(
mode='vline',
line_policy='interp',
renderers=[plot],
names=[plot.name],
tooltips=OrderedDict( [('name',plot.name)]+TOOLTIPS ),
callback=CustomJS( args=dict(cb=checkbox),
code="""
if(!cb.active.includes(%d)) {
document.getElementsByClassName('bk-tooltip')[%d].style.display = 'none';
}
""" % (ID,ID)
)
)
)
grid = gridplot([[fig,checkbox]],toolbar_location='left')
outfile=open('hovtest.html','w')
outfile.write(file_html(grid,CDN,'hovtest'))
outfile.close()
Upvotes: 2