Barchart hover tool for empty bars

I have a bar chart that uses a few custom hover tools. However, it is very common for some of the bars to be empty (no data), making it impossible to hover over.
Is it possible to activate the hovertool by hovering over the index, or some other work around?

Any help is appreciated, thank you for your time.

No one has ever asked about anything like this and it certainly didn’t occur to me, so there is nothing built in to cater to this use case. My best suggestion for an immediate workaround is to plot some some invisible, but non-zero-sized bars where you want to the hover to activate.

Thanks for your feedback, your workaround worked. For anyone who stumbles over this in the future, here’s how I did it.

First, my data that I want to plot is in the dataframe sa_mw_cumul. I plotted this as you would normally.

source = ColumnDataSource(dict(x=sa_mw_cumul, y=index))
plt.hbar(y='y', right='x',left=0, color=index_cmap, height=.5, source=source, name='real_data')

Then, I created a “dummy” dataframe with all values at 0, unless my real data was set to 0 at that index. Then, I set the value to the max of my real data. (This is so that my fake data wouldn’t stretch my graph.)

force_hover=pd.DataFrame(index=sa_mw_cumul.index, columns=['data'], data=0)
max_span = max(sa_mw_cumul) #Figure out how far you can plot without expanding graph
    
for part in sa_mw_cumul.index:
    if sa_mw_cumul.loc[part] == 0:
        force_hover.loc[part, 'data'] = max_span

Next I plotted this, with fill_alpha set to 0

force_hover_source = ColumnDataSource(dict(x=force_hover['data'], y=index))
plt.hbar(y='y', right='x',left=0, color=None, height=.5, source=force_hover_source, fill_alpha=0, name='force_hover')

I now had a graph that looked good, but I was using @x in my HoverTool’s tooltips to get me this data. This meant that I would get a non-0 value for all the “empty” bars when I hover over them. I fixed this by creating a customjshover that takes a dataframe as an arg. With this I can force it to only read data from the correct dataframe.

(Sorry for the messy code with all the formatting of my dataframe.)

def _create_cumulative_hover(self, df):
    csa = pd.DataFrame(df.sum(axis=1)) #represents total shipped
    csa.rename(index=str, columns={csa.columns[0]:"qty_shipped"}, inplace=True)
    csa = csa.reset_index()
    csa.index = csa.index.astype(str) #CDS must have a string as column header
    csa = csa.transpose()
    source = ColumnDataSource(csa)

    return CustomJSHover(args=dict(source=source),code="""
        var part_index = special_vars.index.toString();
        //I index [part_index][3] because my dataframe was multi-indexed
        return source.data[part_index][3].toFixed(0).toString(); 
    """)

(Finally, create the hover tool.)

def _create_hover_tools(mw_sa):
    return HoverTool(
            tooltips=[
                ('Total Delivered', '$x{dummy_text}'),
            ],
            formatters={
                #every part has an x,y, etc, so everywhere you put the hoverview, you will call custom.
                #The actual variable used is completely irrelevant
                '$x': self._create_cumulative_hover(mw_sa),
            }
    )
1 Like