Python >> Tutoriel Python >  >> Python Tag >> Matplotlib

Matplotlib Cursor - Comment ajouter un curseur et annoter votre tracé

Cet article explique comment insérer un curseur dans votre tracé , comment le personnaliser et comment stocker les valeurs que vous avez sélectionnées dans la fenêtre de tracé. Dans de nombreuses situations, nous pouvons vouloir sélectionner et stocker les coordonnées de points spécifiques dans notre graphique ; est-ce juste pour évaluer leur valeur ou parce que nous pouvons vouloir utiliser certaines valeurs spécifiques pour le traitement successif des données. Comme vous le verrez, ce n'est pas une tâche difficile, mais cela ajoutera beaucoup de valeur à vos parcelles. Nous verrons également comment faire apparaître un petit cadre contenant les coordonnées du point sélectionné, à chaque fois que nous cliquons dessus.

Voici notre objectif final :un tracé interactif qui annote le point sur lequel vous cliquez :

Et voici le code dont nous parlerons dans cet article qui mène à cette sortie :

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Cursor

#x and y arrays for definining an initial function
x = np.linspace(0, 10, 100)
y = np.exp(x**0.5) * np.sin(5*x)

# Plotting
fig = plt.figure()
ax = fig.subplots()
ax.plot(x,y, color = 'b')
ax.grid()

# Defining the cursor
cursor = Cursor(ax, horizOn=True, vertOn=True, useblit=True,
                color = 'r', linewidth = 1)

# Creating an annotating box
annot = ax.annotate("", xy=(0,0), xytext=(-40,40),textcoords="offset points",
                    bbox=dict(boxstyle='round4', fc='linen',ec='k',lw=1),
                    arrowprops=dict(arrowstyle='-|>'))
annot.set_visible(False)

# Function for storing and showing the clicked values
coord = []
def onclick(event):
    global coord
    coord.append((event.xdata, event.ydata))
    x = event.xdata
    y = event.ydata
    
    # printing the values of the selected point
    print([x,y]) 
    annot.xy = (x,y)
    text = "({:.2g}, {:.2g})".format(x,y)
    annot.set_text(text)
    annot.set_visible(True)
    fig.canvas.draw() #redraw the figure

    
fig.canvas.mpl_connect('button_press_event', onclick)
plt.show()

# Unzipping the coord list in two different arrays
x1, y1 = zip(*coord)
print(x1, y1)

Importer des bibliothèques

Pour commencer, nous importons les bibliothèques et les packages qui seront utilisés dans cet exemple. Nous utiliserons NumPy pour définir une fonction initiale qui sera ensuite affichée à l'aide de matplotlib.pyplot . Enfin, à partir du matplotlib.widget package, nous importons la fonction Curseur, qui servira à la création du curseur interactif.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Cursor

Définir une fonction initiale à tracer

Afin d'utiliser notre curseur sur un tracé réel, nous introduisons une première fonction en définissant deux NumPy tableaux, "x" et "y". Le tableau "x" est défini en exploitant le NumPy fonction .linspace() , qui générera un tableau de 100 nombres équidistants de 0 à 10. Le tableau "y" est défini par la fonction suivante :

Le sin() et la fonction exponentielle sont introduites en utilisant NumPy. Bien sûr, ce n'est qu'un exemple possible, toute fonction est bonne pour le but final de cet article. Toutes ces procédures sont décrites dans les lignes de code suivantes.

#x and y arrays
x = np.linspace(0, 10, 100)
y = np.exp(x**0.5) * np.sin(5*x)

Tracé de la fonction

Dans l'étape suivante, nous définissons la fenêtre de traçage et traçons notre fonction. Pour cela, nous nous appuyons entièrement sur le matplotlib.pyplot paquet.

#Plotting
fig = plt.figure()
ax = fig.subplots()
ax.plot(x,y, color = 'red')
ax.grid()

Définir le curseur

useblit (bool)
Curseur
Syntaxe : Cursor()
Paramètres : ax (variable) Axes définissant l'espace dans lequel sera situé le bouton
horizOn (bool) Tracer la ligne horizontale
vertOn (bool) Tracer la ligne verticale
Utiliser le blitting pour améliorer les performances
color (chaîne ou flottant) La couleur des lignes
linewidth (flotter) Largeur des lignes du curseur
Valeur de retour None

Pour introduire un curseur dans notre tracé, nous devons d'abord définir toutes ses propriétés; pour cela, on exploite la fonction Curseur, du matplotlib.widget forfait.

La fonction prend en entrée les axes dans lesquels nous voulons afficher le curseur ("ax" dans ce cas) et d'autres propriétés du curseur lui-même ; à savoir horizOn et vertOn , qui génèrent une ligne horizontale et une ligne verticale qui identifient de manière univoque le curseur lorsqu'il survole le tracé ; leur valeur peut être fixée à True ou False , selon la façon dont nous voulons identifier le curseur.

Il est également possible de spécifier certaines propriétés de la ligne, comme la couleur et l'épaisseur (en utilisant linewidth ) .

Le dernier paramètre d'entrée est useblit , nous l'avons défini sur True puisqu'il améliore généralement les performances des figures interactives en "ne refaisant pas le travail que nous n'avons pas à faire" (si vous êtes intéressé par le processus de Blitting, veuillez visiter :https://matplotlib.org/3.3.1/tutorials/advanced/blitting.html ).

Tous les paramètres d'entrée de la fonction Cursor sont résumés dans le tableau 1 et une documentation supplémentaire peut être trouvée à :https://matplotlib.org/3.3.3/api/widgets_api.html.

Toutes les propriétés définies dans la fonction Curseur, sont affectés à la variable "curseur".

#defining the cursor
cursor = Cursor(ax, horizOn = True, vertOn=True, color='red', linewidth=1, 
                useblit=True)

À ce stade, nous avons terminé la définition de notre curseur, si nous devions montrer le tracé, nous obtiendrions le résultat affiché dans la figure 1.

Dans les prochaines étapes, nous verrons comment définir le cadre, contenant les coordonnées du point sélectionné, qui apparaîtra à chaque clic de souris. Si cette fonctionnalité ne vous intéresse pas, vous pouvez passer à la section suivante dans laquelle nous verrons comment stocker et imprimer les valeurs sélectionnées par le curseur.

Création des cadres d'annotation

Annoter
Syntaxe : annotate()
Paramètres : text (str) Le texte de l'annotation
xy (flotter, flotter) Le point à annoter
xytext (flotter, flotter) La position où placer le texte
textcoords Le système de coordonnées dans lequel xytext est donné
bbox Instanciation d'un cadre
arrowprops Instanciation d'une flèche
Valeur de retour None

Tableau 2 : Le .annotate() fonction et tous les paramètres d'entrée utilisés dans le présent exemple.

Comme prévu dans l'introduction, nous voulons améliorer le rendu graphique et l'efficacité de notre curseur en faisant apparaître un petit cadre, contenant les coordonnées du point sélectionné, à chaque clic de souris.

Pour cela, nous exploitons la fonction matplotlib .annotate() , qui fournit de nombreuses fonctionnalités différentes pour personnaliser les annotations dans un tracé (une documentation supplémentaire peut être trouvée ici :https://matplotlib.org/3.2.1/api/_as_gen/matplotlib.axes.Axes.annotate.html).

Le premier paramètre d'entrée du .annotate() fonction est le texte qui apparaîtra dans l'annotation ; nous entrons une chaîne vide, car nous ajouterons le texte plus tard (il changera à chaque clic de souris).

On précise alors les propriétés « xy ”, “xytext ” et “textcoords " avec lequel nous définissons un point de référence, la distance du texte à partir de ce point et comment la distance est calculée (dans notre cas en comptant les valeurs numériques en points, le pixel est également disponible), respectivement.

Pour mieux mettre en évidence l'annotation dans le tracé, nous ajoutons également un cadre externe, en utilisant bbox et en passant toutes les propriétés du cadre (comme la couleur de remplissage, la couleur de bord et la largeur de ligne) en tant que clés et valeurs d'un dictionnaire.

Enfin, nous générons une flèche, partant de "xy ” à “xytext ” de manière similaire (toutes les propriétés des flèches se trouvent dans le . annotate Documentation). Les propriétés d'annotation qui viennent d'être définies sont alors affectées à la variable "annot ”; en exploitant la méthode .set_visible() , la visibilité du cadre d'annotation est initialement définie sur False (il n'apparaîtra qu'après le clic de la souris).

Tous les paramètres entrant dans la définition du .annotate() fonction sont résumées dans le tableau 2.

#Creating the annotation framework
annot = ax.annotate("", xy=(0,0), xytext=(-40,40),textcoords="offset points",
                    bbox=dict(boxstyle="round4", fc="grey", ec="k", lw=2),
                    arrowprops=dict(arrowstyle="-|>"))
annot.set_visible(False)

Stocker et afficher les coordonnées du point sélectionné

Le curseur fonctionne maintenant mais rien ne se passe encore lorsque nous cliquons sur le tracé. Dans cette section, nous définissons une fonction qui imprimera et stockera les coordonnées du point cliqué sur le tracé ; il affichera également la boîte d'annotation précédemment définie.

Stocker les valeurs en dehors de la fonction

On définit une liste vide, appelée « coord », dans laquelle seront stockées les coordonnées de tous les points cliqués.

Après cela, nous commençons à définir la nouvelle fonction, elle s'appellera "onclick". L'entrée de la fonction est définie sur événement, pour accéder à la position de l'indicateur sur le tracé.

Dans la fonction, une variable globale appelée "coord" est définie, ceci est fait afin de stocker les valeurs générées dans la fonction et de les avoir également disponibles dans la variable "coord" en dehors de la fonction. Pour stocker les coordonnées du point sélectionné, nous ajoutons les variables event.xdata et event.ydata , comme un tuple, à la liste coord ; de cette façon, les valeurs seront accessibles même en dehors de la fonction. Par souci de simplicité, nous les affectons ensuite à deux variables locales différentes "x" et "y".

Imprimer les valeurs des coordonnées

À ce stade, nous pouvons également imprimer leur valeur en tapant simplement le print() commande.

Affichage des coordonnées du point dans la zone d'annotation

La prochaine fonctionnalité que nous pouvons ajouter à la fonction est d'afficher la boîte d'annotation, contenant les valeurs "x" et "y". Pour cette tâche, les valeurs "x" et "y" sont d'abord utilisées pour définir la position de la boîte d'annotation, en changeant le xy propriété de la variable « annot » puis de définir la variable « text », une chaîne qui contient le texte de l'annotation. Pour changer le texte de la variable « annot », on utilise la méthode .set_text(), en saisissant comme seul paramètre d'entrée la variable "texte".

Nous concluons en changeant la visibilité de la fonction « annot » à True et en redessinant la figure. Les lignes de code suivantes affichent la définition complète de la fonction, en suivant le même ordre que celui utilisé dans la description ci-dessus.

#Function for storing and showing the clicked values
coord = []
def onclick(event):
    global coord
    coord.append((event.xdata, event.ydata))
    x = event.xdata
    y = event.ydata
    print([x,y])
    annot.xy = (x,y)
    text = "({:.2g},{:.2g})".format( x,y )
    annot.set_text(text)
    annot.set_visible(True)
    fig.canvas.draw() #redraw the figure

Afin de connecter l'événement click avec l'exécution de la fonction "onclick", nous exploitons la méthode matplotlib .mpl_connect(), en le liant à l'événement « button_press_event ». Nous traçons enfin la figure. La figure 2 affiche le résultat final.

Accéder aux valeurs stockées en dehors de la fonction

Les coordonnées des points sélectionnés ayant toutes été stockées dans la liste « coord », il est désormais possible d'avoir accès à leurs valeurs en traitant simplement la liste avec des fonctions standards. Un exemple consiste à utiliser la fonction .zip(*) , dans laquelle on entre le nom de la liste après l'astérisque, afin de décompresser tous les tuples en deux tableaux différents "x1" et "y1".

#unzipping the x and y values of the selected points
x1, y1 = zip(*coord)

Conclusion

Dans cet article, nous avons vu comment introduire un curseur dans une fenêtre matplotlib, comment personnaliser ses propriétés et son apparence. Nous avons également exploré la possibilité de créer une boîte d'annotation et comment l'afficher à chaque clic de souris.

Toutes ces fonctionnalités apporteront une valeur ajoutée à vos tracés tant d'un point de vue esthétique que fonctionnel, les rendant plus agréables et compréhensibles, deux aspects fondamentaux que chaque rapport de science des données devrait toujours posséder.

Humour de programmeur