Search code examples
hovertooltipbokehscatter-plotrunumap

bokeh HoverTool and tooltips not working correctly


Hi there I just got the plot I wanted with some help and tweaks here and there using bokeh; however, I can't figure out how to add information of interest to my tooltips navigation/hover tool.

Specifically this is what my df looks like:enter image description here

with ID as df.index, which is the exact information I want to show when hovering (among others) since it helps to understand what sample we are looking at.

That said,this is the code I'm using with relevant libraries/packages:

import numpy as np
import pandas as pd
import plotly.express as px
import bokeh.plotting as bp

from bokeh.models import CategoricalColorMapper, Legend, HoverTool
from bokeh.plotting im


TOOLS="hover,crosshair,pan,wheel_zoom,zoom_in,zoom_out,box_zoom,undo,redo,reset,tap,save,box_select,poly_select,lasso_select,examine,help"

df = pd.DataFrame({
    'name': df.index,
    'UMAP1': df['UMAP1'],
    'UMAP2': df['UMAP2'],
    'population': df['population'],
    'color': df['color'],
})

#individual_id = bp.ColumnDataSource(df)
#hover_name = HoverTool(
    #tooltips=[('ID', '@name')])

fig = figure(tools=TOOLS, x_axis_label='UMAP1', y_axis_label='UMAP2')
legend = Legend(orientation='horizontal', title='metapopulations')
fig.add_layout(legend, 'below')
#fig.add_tools(hover_name)


grouper = df.groupby('population')
for label, g in grouper:
    fig.scatter(g['UMAP1'], g['UMAP2'], color=g['color'], legend_label=label, fill_alpha=0.6)

#hover = fig.select(dict(type=HoverTool))
#hover.tooltips = [('Name', '@name')]

show(fig)

As you can see I tried some options but all of them returned ??? instead of the sample's ID... also, for some reason, in this specific context the ColumnDataSource, when used, returns an error. If anyone has any idea how to link samples' ID to data points in the UMAP, it will be greatly appreciated. Thanks!


Solution

  • I take the example from your last question to adapt it to your new requirements.

    In this example the initial DataFrame is extended by a column named "name". As bigreddot mentioned in the comment, you have to pass the information for the HoverTool to the source of the figure some how. In the old example the plot took the data directly from the columns of a DataFrame and got no additional data. This time I transfer the DataFrame per group to a ColumnDataSource and use only the names of the columns to address the data from the source. Doing so I can pass additional columns like "name".

    Before showing the plot I add a HoverTool to the figure with a collection of all renderers I collected while looping over the groups.

    import pandas as pd
    from bokeh.plotting import show, figure, output_notebook
    from bokeh.models import ColumnDataSource, Legend, HoverTool
    output_notebook()
    
    df = pd.DataFrame({
        'name': ['foo', 'bar', 'bla']*2,
        'UMAP1': [1,2,3,4,5,6],
        'UMAP2': [1,2,3,4,5,6],
        'population':['EUR', 'SIB', 'AME']*2,
        'color':['#1e90ff', '#bdb76b', '#eeaeee']*2,
    })
    
    p = figure()
    legend = Legend(orientation='horizontal')
    p.add_layout(legend, 'below')
    
    grouper = df.groupby('population')
    circles = []
    for label, g in grouper:
        source = ColumnDataSource(g)
        c = p.scatter('UMAP1', 'UMAP2', color='color', legend_label=label, source=source)
        circles.append(c)
    
    hover = HoverTool(tooltips = [('Name', '@name')], renderers=circles)
    p.add_tools(hover)
    show(p)
    

    figure with HoverTool