Skip to content
GitLab
Projects Groups Topics Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Register
  • Sign in
  • PYTHON - Atelier MatPlotLib PYTHON - Atelier MatPlotLib
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributor statistics
    • Graph
    • Compare revisions
  • Issues 0
    • Issues 0
    • List
    • Boards
    • Service Desk
    • Milestones
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Packages and registries
    • Packages and registries
    • Package Registry
    • Terraform modules
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar

La forge institutionnelle d'INRAE étant en production depuis le 10 juin 2025, nous vous recommandons d'y créer tous vos nouveaux projets.

  • Poulard Christine
  • PYTHON - Atelier MatPlotLibPYTHON - Atelier MatPlotLib
  • Wiki
  • Atelier_clics

Atelier_clics · Changes

Page history
Update Atelier_clics authored Sep 15, 2021 by Poulard Christine's avatar Poulard Christine
Hide whitespace changes
Inline Side-by-side
Atelier_clics.md
View page @ 168377ba
...@@ -21,11 +21,11 @@ Exemple [d'événements ](https://matplotlib.org/stable/users/event_handling.htm ...@@ -21,11 +21,11 @@ Exemple [d'événements ](https://matplotlib.org/stable/users/event_handling.htm
| 'pick_event' | PickEvent | artist in the canvas is selected | | 'pick_event' | PickEvent | artist in the canvas is selected |
| 'resize_event' | ResizeEvent | figure canvas is resized | | 'resize_event' | ResizeEvent | figure canvas is resized |
## Avec un "MouseEvent" ## Comprendre et manipuler un "MouseEvent"
On travaille d'abord avec une figure ne comportant qu'une seule courbe. ### Avec une figure ne comportant qu'une seule courbe.
### pour commencer, le "clic" écrit juste les coordonnées dans la console #### pour commencer, le "clic" écrit juste les coordonnées dans la console
```python ```python
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
...@@ -96,16 +96,137 @@ selection, = ax.plot([0],[0], marker='*', c='red', markersize=20) ...@@ -96,16 +96,137 @@ selection, = ax.plot([0],[0], marker='*', c='red', markersize=20)
fig.canvas.mpl_connect('button_press_event', onclick_proche) fig.canvas.mpl_connect('button_press_event', onclick_proche)
plt.show() plt.show()
### Le tableau ci-dessous montre le résultat de l'identification du point le plus proche à partir des coordonnées de la souris ou de Picker, pour ce deuxième cas en montrant la différence de calculs distance "unités courbes" et distances "écran"
``` ```
| code ci-dessus, basé sur mouseclick | code avec 2 calculs de distance et annotations, utilisant Picker (voir ci-dessous)|
Le code "fait le travail", vous pouvez tester et essayer avec d'autres jeux de données. Vous pourrez trouvez des données pour lesquels le calcul des distances proposé ici n'est pas satisfaisant car il n'identifie pas le point le plus proche "visuellement".
### Le tableau ci-dessous montre le résultat de l'identification du point le plus proche à partir des coordonnées de la souris ou de Picker, pour ce deuxième cas en montrant la différence de calculs distance "unités courbes" et distances "écran"
```plaintext
| code ci-dessus, basé sur MouseEvent | code basé sur Picker (voir ci-dessous)|
|-----------------|------------------------------| |-----------------|------------------------------|
| ![Figure initiale, 10points alignés](uploads/467300d845b9a2e75b1b8ecca19328d8/selection_point_mouseclick.png) | ![selection_picker2](uploads/36f24ebb707baac8a9af0c29c562d76c/selection_picker2.png) | | ![Figure initiale, 10points alignés](uploads/467300d845b9a2e75b1b8ecca19328d8/selection_point_mouseclick.png) | ![selection_picker2](uploads/36f24ebb707baac8a9af0c29c562d76c/selection_picker2.png) |
|<i> une étoile rouge matérialise le point identifié comme le plus proche du clic de souris </i>|résultats en distance "unités courbes" et distances "écran"| |<i> une étoile rouge matérialise le point identifié comme le plus proche du clic de souris </i>|<i>résultats en distance "unités courbes" et distances "écran", avec affichage dans des annotations</i>|
### Avec une figure comportant 2 courbes ou plus.
Dans ce nouveau code, on va introduire deux difficultés (toutes relatives !):
- calculer la **distance aux points en "coordonnées écran"**, en normant les composantes de la distance par la largeur et la hauteur respectivement en coordonnées données, puis en dénormant par les largeur et la hauteur respectivement en "unité écran" (pixels ou unités proportionnelles). On donne la possibilité de passer d'une distance à l'autre en passant à l'argument ratio_w_sur_h soit le ratio w/h de la vignette ce qui conduira à un calcul en distances "écran", soit rien, ce qui conduira à un calcul en distances "données"
- répéter l'opération pour 2 courbes (ou plus) : le minimum de chacune est repérée par un carré et une annotation ; le plus proche des deux est repéré par une étoile inratable.
On a "factorisé" le code en définissant dans la fonction onclick_proche_2courbes une sous-fonction qui fera l'opération sur une courbe, son annotation associée et son "carré" fluo associé.
``` python
import matplotlib.pyplot as plt
import numpy as np
fig = None
adnotacja_ecran = None
adnotacja_ecran_2 = None
une_croix = None
carre_jaune=None
carre_orange=None
curseur = None
def onclick_proche_2courbes(event):
def operations_sur_une_courbe(courbe, annotation, carre, ratio_w_sur_h = None):
"""
# si on ne passe pas comme argument ratio_w_sur_h, sa valeur par défaut sera None : on raisonne en "distance données"
# pour ça il faut aussi REASSIGNER LOCALEMENT DANS CETTE SOUS-FONCTION 1 à ratio_w_sur_h, delta_x et delta_y
# sinon, on passe le ratio largeur/hauteur de la vignette et on raisonne bien en "distance écran"
"""
if ratio_w_sur_h is None:
# on raisonne en "distances en unité des données"
distances_ecran = [((x - x_souris) ** 2 + (y - y_souris)**2) ** (1 / 2) for (x, y) in zip(courbe.get_xdata(), courbe.get_ydata())]
else:
# on raisonne en "unités écran", donc on norme par w/h unité données et on dénorme par le ratio w/h de la vignette
distances_ecran = [((ratio_w_sur_h *(x - x_souris) / delta_x ) ** 2 +
((y - y_souris) / delta_y)**2) ** (1 / 2) for (x, y) in zip(courbe.get_xdata(), courbe.get_ydata())]
# print("liste des distances écran", distances_ecran)
idx_ecran = np.argmin(distances_ecran)
xpt, ypt = courbe.get_xdata()[idx_ecran], courbe.get_ydata()[idx_ecran] # tuple
distance_min = min(distances_ecran)
carre.set_data(xpt,ypt)
annotation.xy = (xpt, ypt)
annotation.set_visible(True)
return xpt, ypt, distance_min
x_souris, y_souris = event.xdata, event.ydata
curseur.set_data(x_souris, y_souris)
ax.set_title(f"détermination du point de la courbe le plus proche de {x_souris:.2f}, {y_souris:.2f}")
# unités écran
xdroite, xgauche = ax.get_xlim()
ybas, yhaut = ax.get_ylim()
delta_x = abs(xdroite - xgauche)
delta_y = abs(ybas - yhaut)
bbox = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
ratio_w_sur_h = bbox.width / bbox.height # le graphique est "ratio_w_sur_h fois plus large que haut"
print("delta_x, delta_y, ratio_w_sur_h)", delta_x, delta_y, ratio_w_sur_h)
#print("type :", type(line_pk6700.get_data()), " => ", line_pk6700.get_data())
# première courbe
x1, y1, distance_min1 = operations_sur_une_courbe(line_pk6700, adnotacja_ecran, carre_jaune, ratio_w_sur_h)
adnotacja_ecran.set_text ( f"courbe Pk6700 : {x1:.2f}, {y1:.2f}")
adnotacja_ecran.set_position( (x1+100, y1+2.5))
adnotacja_ecran.set_color("blue")
# deuxième courbe
x2, y2, distance_min2 = operations_sur_une_courbe(line_decalee, adnotacja_ecran_2, carre_orange, ratio_w_sur_h)
adnotacja_ecran_2.set_text ( f"courbe Pk6700 : {x1:.2f}, {y1:.2f}")
adnotacja_ecran_2.set_position( (x1-250, y1+1.5))
adnotacja_ecran_2.set_color("green")
if distance_min2 < distance_min1 :
selection.set_data([x2], [y2])
selection.set_color("blue")
else:
selection.set_data([x1], [y1])
selection.set_color("green")
fig.canvas.draw_idle()
# CORPS DU PROGRAMME
fig,ax = plt.subplots()
ax.set_title("détermination du point de la courbe le plus proche")
x_sc = [-240.838,-80.39,-78.15,-34,-20.91,-17.27,0,4.51,6.76,8.76,14.76,42.76,46.76,57.76,74.76,78.62,83.32,86.85,104,136.22,143.85,262.877]
z_sc=[142.75,139,140,139.17,139.17,138.47,137.8,136.73,135.21,135.01,134.71,134.51,134.61,134.29,134.71,135.83,138.48,137.77,139.53,140.68,141.5,141.91]
carre_jaune, = ax.plot(x_sc[0], z_sc[0], 's', c='yellow',alpha=0.5, markersize =20)
line_pk6700, = ax.plot(x_sc, z_sc, '*', c='red', label="pk6700", ls='-')
x_2 = [x+25 for x in x_sc]
z_2 = [z+1 for z in z_sc]
minimum_des_x = min(min(x_sc), min(x_2))
minimum_des_y = min(min(z_sc), min(z_2))
curseur, = ax.plot(x_2[0], z_2[0], '+', c='blue', markersize =20)
carre_orange, = ax.plot(x_2[0], z_2[0], 's', c='orange',alpha=0.5, markersize =20)
line_decalee, = ax.plot(x_2, z_2, '^', c='sienna', label="pk6700 décalé", ls=":")
selection, = ax.plot(x_2[0], z_2[0], marker='*', c='red', markersize=20)
adnotacja_ecran = ax.annotate("X", xytext=(minimum_des_x,minimum_des_y), xy=(minimum_des_x, minimum_des_y), bbox = dict(boxstyle='round,pad=0.5', fc='yellow', alpha=0.75), arrowprops = dict(arrowstyle='->', connectionstyle='arc3,rad=0', color='grey'))
adnotacja_ecran.set_visible(False)
adnotacja_ecran_2 = ax.annotate("X", xytext=(minimum_des_x,minimum_des_y), xy=(minimum_des_x, minimum_des_y), bbox = dict(boxstyle='round,pad=0.5', fc='lightblue', alpha=0.75), arrowprops = dict(arrowstyle='->', connectionstyle='arc3,rad=0', color='grey'))
adnotacja_ecran_2.set_visible(False)
fig.canvas.mpl_connect('button_press_event', onclick_proche_2courbes)
plt.show()
```
## Avec un "PickEvent" : ## Avec un "PickEvent" :
...@@ -157,8 +278,6 @@ largeur_en_pixels, hauteur_en_pixels = bbox.width* fig.dpi , bbox.height * fig.d ...@@ -157,8 +278,6 @@ largeur_en_pixels, hauteur_en_pixels = bbox.width* fig.dpi , bbox.height * fig.d
Dans ce code, on commence par tracer une courbe, en la nommant, et des objets supplémentaire comme des courbes réduites à un point et des annotations, toujours en les nommant, mais sans les afficher dans un premier temps grâce à set_visible(False). On rappelle que dans une fonction, on ne pourrait pas redéfinir ces objets (courbe = plt.plot(nouveaux_x, nouveaux_y)) mais par contre on peut parfaitement appliquer des méthodes sur des objets définis dans le programme principal, ou en changer des attributs : courbe = set_data(nouveaux_x, nouveaux_y). Ainsi, dans la fonction on_pick_cp on va pouvoir modifier certains arguments de ces objets. On peut donc déplacer la croix bleue vers les coordonnées de la souris, et déplacer également les annotations en mettant à jour leur texte, et bien sûr changer leur statut avec set_visible(True). On pourrait également modifier le titre de la figure, avec ax.set_text() Dans ce code, on commence par tracer une courbe, en la nommant, et des objets supplémentaire comme des courbes réduites à un point et des annotations, toujours en les nommant, mais sans les afficher dans un premier temps grâce à set_visible(False). On rappelle que dans une fonction, on ne pourrait pas redéfinir ces objets (courbe = plt.plot(nouveaux_x, nouveaux_y)) mais par contre on peut parfaitement appliquer des méthodes sur des objets définis dans le programme principal, ou en changer des attributs : courbe = set_data(nouveaux_x, nouveaux_y). Ainsi, dans la fonction on_pick_cp on va pouvoir modifier certains arguments de ces objets. On peut donc déplacer la croix bleue vers les coordonnées de la souris, et déplacer également les annotations en mettant à jour leur texte, et bien sûr changer leur statut avec set_visible(True). On pourrait également modifier le titre de la figure, avec ax.set_text()
## Exemple 2: comprendre l'argument pickradius ## Exemple 2: comprendre l'argument pickradius
Le "Picker" sélectionne plus ou moins de points "autour" du clic de souris, en fonction d'un argument correspondant à un rayon. Le "Picker" sélectionne plus ou moins de points "autour" du clic de souris, en fonction d'un argument correspondant à un rayon.
...@@ -223,3 +342,5 @@ def submit_radius(val): ...@@ -223,3 +342,5 @@ def submit_radius(val):
nuage, = ax.plot(x, y, '*', c='blue', label="nuage", picker=init_radius, ls='None') nuage, = ax.plot(x, y, '*', c='blue', label="nuage", picker=init_radius, ls='None')
textbox_radius.on_submit(submit_radius) textbox_radius.on_submit(submit_radius)
``` ```
![selection_point_mouseclick_2courbes](uploads/5e59b3773c9d83f464047deb72e4d5ff/selection_point_mouseclick_2courbes.png)
\ No newline at end of file
Clone repository
  • AtelierB1_Graphiques_simples
  • AtelierB2_Lire_un_fichier
  • AtelierC
  • Atelier_D_carte
  • Atelier_D_carte_a_partir_de_fichiers_binaires
  • Atelier_E_longues_series
  • Atelier_G_widgets
  • Atelier_clic_afficher
  • Atelier_clics
  • Cartes focus sur le redimensionnement
  • GUI avec QT
  • La doc avec Sphinx
  • Lexique
  • Point Théorie Subplots
  • Pour les contributeurs
View All Pages