221 votes

Comment ajouter des annotations de survol dans Matplotlib ?

J'utilise matplotlib pour réaliser des diagrammes de dispersion. Chaque point du nuage de points est associé à un objet nommé. J'aimerais pouvoir voir le nom d'un objet lorsque je passe mon curseur sur le point du nuage de points associé à cet objet. En particulier, il serait agréable de pouvoir voir rapidement le nom des points qui sont des valeurs aberrantes. La chose la plus proche que j'ai pu trouver en cherchant ici est la commande annoter, mais elle semble créer une étiquette fixe sur le graphique. Malheureusement, avec le nombre de points que j'ai, le nuage de points serait illisible si j'étiquetais chaque point. Quelqu'un connaît-il un moyen de créer des étiquettes qui n'apparaissent que lorsque le curseur se trouve à proximité du point en question ?

1voto

Yanarof Foranay Points 11

En me basant sur Markus Dutschke" et "ImportanceOfBeingErnest", j'ai (imo) simplifié le code et l'ai rendu plus modulaire.

De plus, cela ne nécessite pas l'installation de paquets supplémentaires.

import matplotlib.pylab as plt
import numpy as np

plt.close('all')
fh, ax = plt.subplots()

#Generate some data
y,x = np.histogram(np.random.randn(10000), bins=500)
x = x[:-1]
colors = ['#0000ff', '#00ff00','#ff0000']
x2, y2 = x,y/10
x3, y3 = x, np.random.randn(500)*10+40

#Plot
h1 = ax.plot(x, y, color=colors[0])
h2 = ax.plot(x2, y2, color=colors[1])
h3 = ax.scatter(x3, y3, color=colors[2], s=1)

artists = h1 + h2 + [h3] #concatenating lists
labels = [list('ABCDE'*100),list('FGHIJ'*100),list('klmno'*100)] #define labels shown

#___ Initialize annotation arrow
annot = ax.annotate("", xy=(0,0), xytext=(20,20),textcoords="offset points",
                    bbox=dict(boxstyle="round", fc="w"),
                    arrowprops=dict(arrowstyle="->"))
annot.set_visible(False)

def on_plot_hover(event):
    if event.inaxes != ax: #exit if mouse is not on figure
        return
    is_vis = annot.get_visible() #check if an annotation is visible
    # x,y = event.xdata,event.ydata #coordinates of mouse in graph
    for ii, artist in enumerate(artists):
        is_contained, dct = artist.contains(event)

        if(is_contained):
            if('get_data' in dir(artist)): #for plot
                data = list(zip(*artist.get_data()))
            elif('get_offsets' in dir(artist)): #for scatter
                data = artist.get_offsets().data

            inds = dct['ind'] #get which data-index is under the mouse
            #___ Set Annotation settings
            xy = data[inds[0]] #get 1st position only
            annot.xy = xy
            annot.set_text(f'pos={xy},text={labels[ii][inds[0]]}')
            annot.get_bbox_patch().set_edgecolor(colors[ii])
            annot.get_bbox_patch().set_alpha(0.7)
            annot.set_visible(True)
            fh.canvas.draw_idle()
        else:
             if is_vis:
                 annot.set_visible(False) #disable when not hovering
                 fh.canvas.draw_idle()

fh.canvas.mpl_connect('motion_notify_event', on_plot_hover)

Ce qui donne le résultat suivant : Plotting 2 gaussians and 1 scatter

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X