HoverTool doesn't work for graph drawn in periodic_callback

I am developing bokeh server application.

I want to use hovertool in my appliation.
hovetool doesn’t work for vbar drawn in periodic_calback,
while it works for vbar drawn at first.

Here is my code.

from bokeh.plotting import figure, curdoc
from bokeh.models import HoverTool

n_callback = 0
seq_no = 0

def draw_vbar(color):
    global seq_no
    bottom_data_list = accum_data_list.copy()
    for i in range(15):
        accum_data_list[i] += 10
    vbar = fig_p.vbar(x=idx_list, width=0.9, top=accum_data_list.copy(), bottom =bottom_data_list,color=color)
    vbar.data_source.data["seq_no"] = [seq_no for i in range(15)]
    seq_no += 1

def update():
    global n_callback
    
    print(n_callback)
    if n_callback == 0:
        draw_vbar("green")
    n_callback += 1

idx_list = [i for i in range(1,16)]
accum_data_list = [0 for i in range(15)]

hv_tool = HoverTool()
hv_tool.tooltips=[("Sequence No.","@seq_no")]

fig_p = figure(title="HoverToolTest",x_range=(0.5,15.5))
fig_p.add_tools(hv_tool)

draw_vbar("blue")
draw_vbar("yellow")

curdoc().add_root(fig_p)
curdoc().add_periodic_callback(update,1000)

HoverTool shows “Sequence No:0” for blue vbar and “Sequence No:1” for yellow vbar. However, it doesn’t show anything for green vbar.

How can I tell HoverTool that new vbar is added to the figure?

I used bokeh 2.0.2 and python 3.6.9 on Ubuntu 18.04.
I used Chrome 81.0.4044.138 and FireFox 76.0.1, HoverTool didn’t work for green vbar in both browser.
I run this application like “bokeh serve thiscode.py”

HoverTool has a list of renderers that it works on. If you provide no renderers, by default it will use all the existing ones. If you add new renderers to a hover tool that you want it to work on, be sure to update its renderers property as well.

To add to @p-himik’s response: I ran into a similar situtation recently in a project I’m working on, where a large number of new renderers were added to the plot with each update.

I found it simplest to delete the existing hovertool from the plot’s tools list and re-create it with each call of the callback.

2 Likes

Hi @p-himik. Thank you for your very quick response.

Although I added renderer to hover_tool.renderers using “hv_tool.renderers.append(vbar)”, hovetool still doesn’t work for green vbar.
Did I misunderstand what you told me?

from bokeh.plotting import figure, curdoc
from bokeh.models import HoverTool

n_callback = 0
seq_no = 0

def draw_vbar(color):
    global seq_no
    bottom_data_list = accum_data_list.copy()
    for i in range(15):
        accum_data_list[i] += 10
    vbar = fig_p.vbar(x=idx_list, width=0.9, top=accum_data_list.copy(), bottom =bottom_data_list,color=color)
    vbar.data_source.data["seq_no"] = [seq_no for i in range(15)]
    hv_tool.renderers.append(vbar)  #add renderer
    print(hv_tool.renderers)
    seq_no += 1
    

def update():
    global n_callback
    
    print(n_callback)
    if n_callback == 0:
        draw_vbar("green")
    n_callback += 1

idx_list = [i for i in range(1,16)]
accum_data_list = [0 for i in range(15)]

hv_tool = HoverTool()
hv_tool.tooltips=[("Sequence No.","@seq_no")]
hv_tool.renderers = [] # to avoid renderers to be "auto"
fig_p = figure(title="HoverToolTest",x_range=(0.5,15.5))
fig_p.add_tools(hv_tool)

draw_vbar("blue")
draw_vbar("yellow")

curdoc().add_root(fig_p)
curdoc().add_periodic_callback(update,1000)

Hi @carolyn. Thank you for proposing another solution kindly.
Following code works well. I appriciate for sharing your experience with us.

from bokeh.plotting import figure, curdoc
from bokeh.models import HoverTool

n_callback = 0
seq_no = 0
hv_tool = None

def draw_vbar(color):
    global seq_no
    global hv_tool
    bottom_data_list = accum_data_list.copy()
    for i in range(15):
        accum_data_list[i] += 10
    vbar = fig_p.vbar(x=idx_list, width=0.9, top=accum_data_list.copy(), bottom =bottom_data_list,color=color)
    vbar.data_source.data["seq_no"] = [seq_no for i in range(15)]

    if seq_no != 0:
        fig_p.toolbar.tools.remove(hv_tool) #delete old hover tool
    hv_tool = HoverTool()  #recreate hover tool
    hv_tool.tooltips=[("Sequence No.","@seq_no")]
    fig_p.add_tools(hv_tool) #add new hover tool
    seq_no += 1
    

def update():
    global n_callback
    
    print(n_callback)
    if n_callback == 0:
        draw_vbar("green")
    n_callback += 1

idx_list = [i for i in range(1,16)]
accum_data_list = [0 for i in range(15)]

fig_p = figure(title="HoverToolTest",x_range=(0.5,15.5))

draw_vbar("blue")
draw_vbar("yellow")

curdoc().add_root(fig_p)
curdoc().add_periodic_callback(update,1000)

Your code seems fine to me but maybe there’s some Bokeh “plumbing” missing. I would also try hv_tool.renderers = hv_tool.renderers + [vbar]. But since carolyn’s solution works for you then it’s all good either way.

1 Like

Thank you for following up.
Yes, I have no problem now. I appreciate your help.