HoverTool callback only works on some renderers

Hi All,

I have been using vbar_stack to generate a bar plot with Bokeh 1.4.0. There are quite a few columns, but a lot of the values are zero, and I wanted to have the tooltip only display the columns which are non-zero, for that index. I couldn’t see a way of doing this with the standard tooltips, and the CustomJSHover also didn’t seem right, so I tried a generic JS callback.

What I’m finding is that the HoverTool will display correctly, but it only updates when the cursor is over the most recent GlyphRenderer (i.e. the uppermost bar element). The callback is triggered on every bar element, but there are no tooltip indices in cb_data. A regular tooltip updates fine, so I don’t know if I am not configuring the callback correctly?

One HoverTool per glyph does work, but gets messy if there are a lot of elements.

Simplified example below - can anyone offer any advice?

import pandas as pd
import numpy as np

from bokeh.io import output_notebook, show
from bokeh.models import ColumnDataSource, HoverTool, CustomJS
from bokeh.plotting import figure
from bokeh.palettes import viridis

output_notebook()

df = pd.DataFrame(np.random.randint(-30, 10, (10,40)))
df[df < 0] = 0
df.columns = [str(c) for c in df.columns]


p = figure(plot_height=600, plot_width=1600, title="Bars",
        toolbar_location="above", tools="save,pan,wheel_zoom")

cmap = viridis(df.shape[1])

source = ColumnDataSource(df)
bars = p.vbar_stack(df.columns, x="index", width=0.95, fill_color=cmap, line_color="white", muted_alpha=0.2, source=source, legend_label=list(df.columns))

tip_js = """
if (cb_data.index.indices.length == 0) {
    return;
}

var ind = cb_data.index.indices[0];
var tips = [["index", source.data["index"][ind].toString()]];

var total = 0;
for (const col in source.data) {
    if (col == "index") {
        continue;
    }
    var val = source.data[col][ind];
    if (val > 0) {
        var new_tip = [col, val.toString()];
        tips.push(new_tip);
        total += val;
    }
}
tips.push(["total", total.toString()]);
cb_obj.tooltips = tips;
"""

p.add_tools(HoverTool(tooltips=None, renderers=bars, callback=CustomJS(code=tip_js, args={"source":source})))
# p.add_tools(HoverTool(tooltips=[(col, "@"+col) for col in df.columns], renderers=bars))

show(p)