matplotlibtooltipscatter-plotpoint

matplotlib display a tooltip when the mouse is over a point


How to display a tooltip with a specific information for each point in this program ? I found examples doing that on this forum, but it was not easy to reproduce for this example, with plt.scatter created in a "for boucle"

It is supposed to return for each point a different info (for example a numbern from 1 to 50 here), but how to get the value of the point where the mouse is over ? And here only the last point got the tooltip when the mouse is over

import matplotlib.pyplot as plt

fig,ax=plt.subplots()

for i in range(0,50):scatter=ax.scatter(i+1,i+1)

annot=ax.annotate("",xy=(0,0),xytext=(10,10),textcoords="offset points",bbox=dict(boxstyle="round",fc="white"))
annot.set_visible(False)

def update_annot(ind):
    pos = scatter.get_offsets()[ind["ind"][0]]
    annot.xy = pos
    text = "TEST"
    annot.set_text(text)

def hover(event):
    vis = annot.get_visible()
    if event.inaxes == ax:
        cont, ind = scatter.contains(event)
        if cont:
            update_annot(ind)
            annot.set_visible(True)
            fig.canvas.draw_idle()
        else:
            if vis:
                annot.set_visible(False)
                fig.canvas.draw_idle()

fig.canvas.mpl_connect("motion_notify_event", hover)

plt.show()

'


Solution

  • The mplcursors library encapsulates this kind of functionality at a higher level.

    It's easiest if the x and y are in a list (or a numpy array) so the scatterplot can be drawn in one go. You can maintain a parallel list with labels that go together with these xy positions.

    Here is an example:

    import matplotlib.pyplot as plt
    import mplcursors
    
    def show_annotation(sel):
        x, y = sel.target
        ind = sel.index
        sel.annotation.set_text(f'{x:.0f}, {y:.0f}: {labels[ind]}')
    
    fig, ax = plt.subplots()
    
    xs = [i + 1 for i in range(50)]
    ys = [i + 1 for i in range(50)]
    labels = [f'text{i + 1}' for i in range(50)]
    
    scatter = ax.scatter(xs, ys)
    
    cursor = mplcursors.cursor(scatter, hover=True)
    cursor.connect('add', show_annotation)
    
    plt.show()
    

    scatter plot with hovering labels