... | ... | @@ -76,27 +76,35 @@ plt.show() |
|
|
Cette fois, on va calculer la distance du point à chacun des points de la courbe, et on va retenir l'indice de la distance minimale, qui nous servira à aller chercher les bonnes coordonnées dans x et y. Attention, il s'agit ici de la distance "en unités de la courbe", on verra dans l'exemple du picker qu'il vaut mieux travailler en distances "écran", en pixels, pour que le point sélectionné corresponde à l'impression visuelle. Il restera à déplacer la courbe "selection",réduite à un point matérialisé par une grande étoile rouge, aux coordonnées de ce point.
|
|
|
|
|
|
```python
|
|
|
def onclick_proche(event):
|
|
|
def onclick_plus_proche(event):
|
|
|
x_souris, y_souris = event.xdata, event.ydata
|
|
|
# deux syntaxes équivalentes, une avec get_data() l'autre avec get_xdata() et get_ydata()
|
|
|
# line2D.get_xdata() et get_ydata() permettent de récupérer les vecteurs des x et y respectivement d'un objet line2D
|
|
|
# zip permet de boucler sur deux listes en même temps pour former un tuple (x,y)
|
|
|
distances = [((x-x_souris)**2 + (y-y_souris)**2)**(1/2) for (x,y) in zip(donnees.get_xdata(), donnees.get_ydata())]
|
|
|
distances = [((x - x_souris) ** 2 + (y - y_souris) ** 2) ** (1 / 2) for (x, y) in
|
|
|
zip(donnees.get_xdata(), donnees.get_ydata())]
|
|
|
|
|
|
distance_min = min(distances)
|
|
|
idx_min = np.argmin(distances)
|
|
|
# on va affecter à la courbe nommée selection les coordonnées du point le plus proche
|
|
|
selection.set_data([donnees.get_xdata()[idx_min]], [donnees.get_ydata()[idx_min]])
|
|
|
fig.canvas.draw_idle()
|
|
|
|
|
|
fig,ax = plt.subplots()
|
|
|
|
|
|
# Corps du programme
|
|
|
|
|
|
fig, ax = plt.subplots()
|
|
|
ax.set_title("détermination du point de la courbe le plus proche")
|
|
|
donnees, = ax.plot(range(10), marker='o')
|
|
|
selection, = ax.plot([0],[0], marker='*', c='red', markersize=20)
|
|
|
|
|
|
fig.canvas.mpl_connect('button_press_event', onclick_proche)
|
|
|
# la méthode plot renvoie une liste d'objets line2D ;
|
|
|
# on récupère le premier pour le nommer avec la syntaxe d'unpacking des tuples : premier_terme, = tuple
|
|
|
donnees, = ax.plot(range(10), marker='o') # y= les entiers de 0 à 9 ; en l'absence de x , le rang sera utilisé
|
|
|
selection, = ax.plot([0], [0], marker='*', c='red', markersize=20) # un seul point, placé en (0,0)
|
|
|
|
|
|
fig.canvas.mpl_connect('button_press_event', onclick_plus_proche)
|
|
|
plt.show()
|
|
|
|
|
|
```
|
|
|
|
|
|
Le code "fait le travail", vous pouvez tester et essayer avec d'autres jeux de données. Vous pourrez trouver des données pour lesquelles le calcul des distances proposé ici n'est pas satisfaisant car il n'identifie pas le point le plus proche "visuellement" : il est donc préférable de raisonner en unités "écran", ce qu'on fera dans la suite.
|
|
|
Le code "fait le travail", vous pouvez aussi essayer avec d'autres jeux de données. Avec des graphiques non orthonormés, le point sélectionné ne sera pas forcément le point le plus proche "visuellement" : selon l'objectif du code, il faudra choisir de raisonner en unités "des données" ou "écran", ce qu'on fera dans la suite.
|
|
|
|
|
|
| code ci-dessus | code ci-dessous, avec plusieurs courbes |
|
|
|
|----------------|-----------------------------------------|
|
... | ... | @@ -120,7 +128,8 @@ import matplotlib.pyplot as plt |
|
|
import numpy as np
|
|
|
|
|
|
fig = None
|
|
|
adnotacja_ecran = None
|
|
|
# "Annotation" étant un nom de classe de mpl, on utilise ici par précaution un nom de variable différent ; ici la précaution est inutile car on a précisé _ecran
|
|
|
adnotacja_ecran = None
|
|
|
adnotacja_ecran_2 = None
|
|
|
une_croix = None
|
|
|
carre_jaune=None
|
... | ... | @@ -136,13 +145,13 @@ def onclick_proche_2courbes(event): |
|
|
"""
|
|
|
|
|
|
if ratio_w_sur_h is None:
|
|
|
# on raisonne en "distances en unité des données"
|
|
|
# on raisonne en "distances en unité des données" (et donc on ne devrait pas appeler la variable "distances_ecran"...)
|
|
|
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)
|
|
|
# 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)
|
... | ... | |