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

Widgets Matplotlib - Comment rendre votre tracé interactif avec des boutons

Cet article présente différents types de widgets pouvant être intégrés dans une figure matplotlib, afin de créer et de personnaliser des tracés hautement interactifs. Exploitation du package matplotlib .widget() , il est donc possible de créer des boutons personnalisés qui permettent de contrôler différentes propriétés des graphiques tracés dans la fenêtre principale. Cela représente une solution pratique et créative pour modifier certaines de vos propriétés de tracé pendant qu'il continue d'être affiché dans la fenêtre active de matplotlib. Plus précisément, trois types de widgets différents seront présentés dans cet article :

  • Bouton
  • Boutons radio
  • Boutons de vérification

Matplotlib Widgets :un bloc-notes Jupyter interactif

J'ai créé un Jupyter Notebook interactif pour que vous exécutiez le code décrit dans cet article de manière interactive :

Code d'exemple de widget Matplotlib

Voici le code décrit dans cet article pour le copier-coller :

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Button, RadioButtons, CheckButtons

# x and y arrays definition
x = np.linspace(0, 10, 50)
y = np.sin(x**2)*np.exp(x)

# Plotting
fig = plt.figure()
ax = fig.subplots()
plt.subplots_adjust(left = 0.3, bottom = 0.25)
p, = ax.plot(x, y, color = 'b', label = 'Plot 1')

#---BUTTON-----

# xposition, yposition, width, height
ax_button = plt.axes([0.25, 0.1, 0.08, 0.05])

# properties of the button
grid_button = Button(ax_button, 'Grid', color='white', hovercolor='grey')

# enabling/disabling the grid
def grid(val):
    ax.grid()
    fig.canvas.draw() #redraw the figure


# triggering event is the clicking
grid_button.on_clicked(grid)


#-----RADIO BUTTONS----

ax_color = plt.axes([0.02, 0.5, 0.2, 0.3])
color_button = RadioButtons(ax_color, ['red', 'green', 'blue', 'black'],
                            [False, False, True, False], activecolor= 'r')

# function for changing the plot color
def color(labels):
    p.set_color(labels)
    fig.canvas.draw()
color_button.on_clicked(color)


#----CHECK BUTTONS----

# defining a second function
y1 = -1*np.sin(x**2)*np.exp(x)
p1, = ax.plot(x, y1, color = 'b', label = 'Plot 2', visible = False)
plots =[p, p1]
activated = [True, False]
labels = ['Plot 1', 'Plot 2']

# instance the axes
ax_check = plt.axes([0.7, 0.05, 0.08, 0.1])
plot_button = CheckButtons(ax_check,labels, activated)


# function for displaying/hiding the plots
def select_plot(label):
    
    # get the index that corresponds to the word "label"
    index = labels.index(label)
    
    # set the plot to visible
    plots[index].set_visible(not plots[index].get_visible())
    fig.canvas.draw()

    
plot_button.on_clicked(select_plot)
plt.show()

Importer des packages et des bibliothèques

Comme d'habitude, nous commençons le script en important les différentes bibliothèques et packages qui seront nécessaires à la création de nos tracés interactifs. En plus du classique Numpy et matplotlib.pyplot, il faut aussi importer les fonctions qui comptent pour les boutons qui seront ensuite créés. Comme prévu dans la partie précédente, les fonctions sont Button, RadioButtons et CheckButtons ; tous appartiennent au package matplotlib .widgets.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Button, RadioButtons, CheckButtons

Créer une fonction

Nous commençons par définir une fonction mathématique qui sera tracée dans la fenêtre matplotlib; il est décrit par les tableaux « x » et « y ». Pour la définition du tableau "x", le .linspace() fonction, de Numpy , permet d'obtenir un tableau de 50 nombres équidistants de 0 à 10. Le tableau « y » contient les valeurs de la fonction :

y =sin(x 2 )e x

les lignes de code suivantes décrivent la définition des deux tableaux.

# x and y arrays for function definition
x = np.linspace(0, 10,50)
y = np.sin(x**2) * np.exp(x)

Définir le tracé initial

Une fois que nous avons défini la fonction, nous allons plus loin en créant la fenêtre matplotlib dans laquelle nous allons créer notre tracé; pour ce faire, nous exploitons les fonctions classiques de matplotlib .figure() et .subplots() . Afin d'avoir suffisamment d'espace pour insérer les différents boutons, la taille et la position du tracé sont ajustées en exploitant la fonction .subplots_adjust() et en spécifiant (dans les paramètres d'entrée) l'espace nécessaire le long de chaque bordure du tracé. Dans ce cas, il suffit de créer de l'espace sur les côtés gauche et bas de la parcelle. À la fin, les tableaux « x » et « y » sont tracés sous la forme d'une ligne bleue continue ; le label « Plot 1 » est également attribué à ce premier graphique. L'important est de ne pas oublier de mettre une virgule après le nom de la variable qui fait référence au tracé ("p"), afin de pouvoir modifier ses propriétés dans un second temps.

#Definition of the initial plot
fig = plt.figure()
ax = fig.subplots()
plt.subplots_adjust(left = 0.3, bottom = 0.25)
p, = ax.plot(x,y, color = 'b', label = 'Plot 1')

Widget bouton

Bouton
Syntaxe : Bouton ()
Paramètres : hache (variable) Axes définissant l'espace dans lequel sera situé le bouton
libellé (str) Libellé qui apparaît sur le bouton
couleur (str ou float) La couleur du bouton
hovercolor (str ou float) La couleur du bouton lorsqu'il est cliqué
Valeur de retour Aucun

Tableau 1 : La fonction Bouton() et les paramètres définis dans ce script.

Le premier widget qui sera implémenté dans l'intrigue est un simple bouton. Ce type de boutons offre la possibilité de passer de ON à OFF et inversement, une seule propriété de la parcelle. Cela signifie que ce bouton peut être responsable d'une seule propriété. Si nous voulons contrôler une autre propriété du tracé, nous devons créer un deuxième bouton. Dans cet exemple, le widget Button est créé afin de pouvoir afficher/masquer la grille du tracé. Nous commençons par définir la position et la taille de notre bouton, cela se fait en créant un soi-disant "axes", qui en Python représente un espace qui peut être rempli avec d'autres informations (les propriétés du bouton). La fonction matplotlib qui est exploitée à cette fin s'appelle .axes() et accepte en entrée, une liste de valeurs correspondant à la position horizontale, verticale, largeur et hauteur du bouton.

#---BUTTON----
#Buttons
ax_button = plt.axes([0.25, 0.1, 0.08,0.05]) #xposition, yposition, width and height

Après avoir défini la position et la taille du bouton, ses différentes propriétés peuvent être définies en appelant la fonction spécifique Bouton (). Comme illustré dans le tableau 1, les entrées de cette fonction sont l'endroit où sera créé le bouton, le libellé et la couleur (il est également possible de personnaliser la couleur affichée au survol du bouton avec le curseur). La variable qui fait référence au bouton qui vient d'être défini s'appelle "grid_button".

#Properties of the button
grid_button = Button(ax_button, 'Grid', color = 'white', hovercolor = 'grey')

À ce stade, nous devons spécifier quelle tâche doit être effectuée chaque fois que nous cliquons sur le bouton. Comme dit précédemment, nous voulons utiliser ce bouton pour afficher/masquer la grille ; pour accomplir cette tâche. Nous définissons une fonction appelée grid (), dans lequel nous définissons la commande ax.grid() pour afficher la grille dans la fenêtre de tracé. A la fin, on redessine la figure en utilisant la commande .canvas.draw().

#enabling/disabling the grid
def grid(val):
    ax.grid()
    fig.canvas.draw() #redraw the figure

Pour conclure cette première partie, nous devons spécifier l'événement qui déclenchera l'exécution de la grid() fonction. Nous appliquons la méthode .on_clicked() à la variable "grid_button", en spécifiant en entrée la fonction grid; ainsi, à chaque clic sur le bouton, le script exécute la fonction grid.

#calling the function "grid" when the button gets clicked
grid_button.on_clicked(grid)

La figure 1 affiche la sortie finale de ce premier script (si vous souhaitez obtenir le résultat illustré à la figure 1, ajoutez simplement une autre ligne à votre code, en écrivant "plt.show()", pour afficher le tracé que vous venez de créer ; je vais afficher le tracé à la fin, afin d'avoir tous les widgets inclus).

Illustration 1 : Fenêtre Matplotlib qui apparaît comme le résultat de la première partie du script. L'intrigue a été déplacée vers le haut et vers la bordure gauche afin de créer de l'espace pour les widgets. En bas à gauche de la figure, le widget Button a été inclus ; sa fonction est d'afficher/masquer la grille à chaque clic.

Widget Boutons Radio

Boutons radio
Syntaxe : Boutons radio
Paramètres : hache (variable) Axes définissant l'espace dans lequel seront situés les boutons radio
libellés (liste) Étiquettes de chaque bouton
actif (liste) liste de booléens décrivant l'état de chaque bouton
activecolor (str ou float) La couleur du bouton actif
Valeur de retour Aucun

Tableau 2 : La fonction RadioButtons et les paramètres définis dans ce script.

Le deuxième widget qui sera implémenté dans notre intrigue est ce qu'on appelle les boutons radio . Il se compose d'une série de boutons circulaires qui peuvent être utilisés pour activer/désactiver l'une des différentes propriétés de notre tracé. Dans ce cas, trois boutons radio seront utilisés pour donner à l'utilisateur la possibilité de choisir parmi quatre couleurs différentes pour le tracé affiché. Chaque fois que l'un des boutons radio sera cliqué, le tracé changera de couleur en fonction de celui sélectionné. Comme dans la première partie, la première chose à faire est de définir l'emplacement et la taille de notre widget, en instanciant les soi-disant « axes »; après cela, on définit les propriétés de ces boutons en utilisant la fonction dédiée RadioButtons, et nous les attribuons à la variable "color_button". Comme on peut le voir sur les lignes de code, la fonction RadioButtons prend en entrée les axes dans lesquels on veut placer les boutons, les labels de chaque bouton et leur état d'activation (donné par les opérateurs booléens Vrai ou Faux). Il est également possible de spécifier l'option « activecolor », qui indique la couleur du bouton radio actuellement actif; toutes ces options sont résumées dans le tableau 2.

#---RADIO BUTTONS----
ax_color = plt.axes([0.02, 0.5, 0.2,0.3]) #xposition, yposition, width and height
#Properties of the Radio buttons
color_button = RadioButtons(ax_color, ['red', 'green', 'blue', 'black'], active = [True, False, False, False], activecolor = 'r')

Une fois les boutons radio correctement définis, il faut les lier à la fonction décrivant la tâche à effectuer à chaque clic. Pour cet exemple, la fonction doit changer la couleur du tracé en fonction des options affichées dans le widget. Pour cela, la méthode .set_color() est appliqué à la variable « p », qui rend compte du tracé; cette méthode prend en entrée le nom de la couleur (une chaîne) qui doit être appliquée au tracé. La variable d'entrée de la fonction est « étiquettes » et contient l'étiquette du bouton cliqué; on passe donc cette variable à .set_color() aussi bien. Pour compléter la définition de la fonction, nous redessinons la figure et spécifions quand elle doit être exécutée, c'est-à-dire à chaque fois que le bouton "color_button" est cliqué. Les lignes de code suivantes décrivent ces procédures.

#function for changing the color of the plot
def color(labels):
    p.set_color(labels)
    fig.canvas.draw ()
#calling the function "color" when the radio button gets clicked
color_button.on_clicked(color) 

Le résultat de cette deuxième partie est affiché dans la Figure 2, avec le widget "Bouton", spécifié dans la première partie.

Illustration 2 : Les RadioButtons widget a été implémenté sur le côté gauche de la fenêtre de tracé. Il comporte quatre boutons différents, correspondant à différentes couleurs pouvant être appliquées au tracé affiché ; dans la figure, l'option "verte" est l'option active et est indiquée par le remplissage rouge.

Widget CheckButtons

Boutons de contrôle
Syntaxe : Boutons de vérification
Paramètres : hache (variable) Axes définissant l'espace dans lequel seront situés les boutons de contrôle
libellés (liste) Étiquettes de chaque bouton
actifs (liste) liste de booléens décrivant l'état de chaque bouton
Valeur de retour Aucun

Tableau 3 : La fonction CheckButtons et les paramètres définis dans ce script.

Le troisième widget qui sera implémenté dans l'intrigue est ce qu'on appelle les CheckButtons. Ce widget est similaire au précédent mais il présente quelques différences importantes. Outre l'aspect visuel, nous avons ici que les boutons sont rectangulaires et qu'ils se croisent lorsqu'ils sont activés; la différence la plus substantielle concerne le principe de fonctionnement :avec RadioButtons, il était possible de sélectionner une seule option à la fois, l'activation d'une option désactivait automatiquement celle actuellement active; avec CheckButtons à la place, il est possible d'activer plusieurs boutons à la fois. Cette fonctionnalité peut être utile chaque fois que nous voulons contrôler deux propriétés ou plus de notre parcelle qui pourraient être actives en même temps. Dans l'exemple suivant, les CheckButtons widget sera utilisé pour permettre la visualisation d'un deuxième graphique dans notre graphique. Cette tâche n'a pas pu être accomplie par RadioButtons , puisqu'il ne permet d'activer qu'une seule de ses options à la fois. Avant de définir le widget, le second graphe doit être défini (la fonction s'appelle y1); il sera affecté à la variable "p1". Comme vous pouvez le voir dans les lignes de code suivantes, nous spécifions également la visibilité initiale du tracé, en le définissant sur False, afin de ne pas l'afficher automatiquement. On définit alors trois listes, « plots », « enabled » et « labels », qui contiennent respectivement les deux plots, leur statut de visibilité et leurs labels.

#-----CHECK BUTTON------
#defining a second plot
y1 = -1*np.sin(x**2)*np.exp(x)
p1, = ax.plot(x,y1, color = 'b', label = 'Plot 2', visible = False)
plots = [p, p1]
activated = [True, False]
labels = ['Plot 1', 'Plot 2']

Après cela, nous définissons l'emplacement, la taille et les propriétés des boutons radio. Ceci est très similaire à ce qui a déjà été montré dans les deux parties précédentes. Les propriétés du widget sont définies via la fonction appropriée CheckButtons() qui prend en entrée les axes (espace dans lequel le bouton sera créé), la liste contenant les libellés des différents boutons et une liste rendant compte de leur état d'activation, liée (dans cet exemple) à la visibilité des tracés; toutes ces fonctionnalités sont résumées dans le tableau 3.

#Properties of the Check buttons
ax_check = plt.axes([0.7, 0.05, 0.08,0.1]) #xposition, yposition, width and height
plot_button = CheckButtons(ax_check, labels , activated)

À ce stade, nous devons définir la fonction qui effectuera la tâche souhaitée, c'est-à-dire activer/désactiver les graphiques. La fonction est définie par le nom select_plot() et prend en entrée l'étiquette qui correspond à l'option cliquée. Une fois obtenu le label du bouton sélectionné, il faut déterminer l'index de l'élément, au sein de la liste « labels », auquel il correspond. Pour cela, on applique la méthode .index() à la liste « labels », et on stocke cette valeur dans la variable index. Maintenant que nous savons lequel des deux tracés nous voulons activer/désactiver, nous modifions sa visibilité en tapant la commande suivante :plots[index].set_visible(not plots[index].get_visible()); où nous nous référons d'abord au tracé souhaité via plots[index] puis nous appliquons la méthode .set_visible() pour accéder à la propriété « visible » (plus de documentation ici :https://www.geeksforgeeks.org/matplotlib-axes-axes-set_visible-in-python/); pour changer sa valeur, on récupère d'abord son état actuel, en utilisant la méthode .get_visible() puis prendre son contraire (documentation complémentaire ici :https://www.geeksforgeeks.org/matplotlib-axes-axes-get_visible-in-python/ ). Toutes les procédures sont décrites dans les lignes de code suivantes.

#function for displaying the plots
def select_plot(label):
    #get the index that corresponds to the word "label" within the list labels
    index = labels.index(label)
    #set the selected plot to visible
    plots[index].set_visible(not plots[index].get_visible()) 
    fig.canvas.draw()   

Nous concluons en spécifiant l'événement déclencheur pour cette fonction, c'est-à-dire à chaque fois que les boutons de contrôle dans les widgets sont cliqués.

plot_button.on_clicked(select_plot)
plt.show() 

La figure 3 décrit la sortie finale de ce script, incluant également les deux widgets précédents.

Figure 3 : La dernière fenêtre matplotlib, avec les trois widgets. Les deux tracés sont définis comme visibles, comme on peut le voir dans les CheckButtons widget, ainsi que la grille. La couleur du premier tracé est définie sur le vert via les RadioButtons widget.

Conclusion

Dans cet article, nous avons vu comment implémenter trois types de widgets différents dans une fenêtre matplotlib. Tous les widgets ont des propriétés distinctes, ce qui les rend plus appropriés pour des tâches spécifiques. Ils représentent une solution pratique pour changer certaines des propriétés d'un tracé, sans avoir à fermer sa fenêtre, changer le script et compiler à nouveau. Bien sûr, de nombreuses tâches différentes peuvent être attribuées à chacun de ces boutons, cela dépend simplement de vos besoins. si vous voulez en savoir plus sur le matplotlib.widget package, vous pouvez trouver des informations supplémentaires sur ce lien :https://matplotlib.org/3.3.3/api/widgets_api.html .