Las líneas arrastrables se seleccionan entre sí en Matplotlib

Estoy tratando de crear una clase de líneas arrastrables usando el manejo y selección de matplotlib. El objective es establecer diferentes umbrales e intervalos en un gráfico. Aquí está el código:

import matplotlib.pyplot as plt import matplotlib.lines as lines import numpy as np class draggable_lines: def __init__(self, ax, kind, XorY): self.ax = ax self.c = ax.get_figure().canvas self.o = kind self.XorY = XorY if kind == "h": x = [-1, 1] y = [XorY, XorY] elif kind == "v": x = [XorY, XorY] y = [-1, 1] else: print("choose h or v line") self.line = lines.Line2D(x, y, picker=5) self.ax.add_line(self.line) self.c.draw() sid = self.c.mpl_connect('pick_event', self.clickonline) # pick line when I select it def clickonline(self, event): self.active_line = event.artist print("line selected ", event.artist) self.follower = self.c.mpl_connect("motion_notify_event", self.followmouse) self.releaser = self.c.mpl_connect("button_press_event", self.releaseonclick) # The selected line must follow the mouse def followmouse(self, event): if self.o == "h": self.line.set_ydata([event.ydata, event.ydata]) else: self.line.set_xdata([event.xdata, event.xdata]) self.c.draw() # release line on click def releaseonclick(self, event): if self.o == "h": self.XorY = self.line.get_ydata()[0] else: self.XorY = self.line.get_xdata()[0] print (self.XorY) self.c.mpl_disconnect(self.releaser) self.c.mpl_disconnect(self.follower) plt.ion() fig = plt.figure() ax = fig.add_subplot(111) Vline = draggable_lines(ax, "h", 0.5) Tline = draggable_lines(ax, "v", 0.5) Tline2 = draggable_lines(ax, "v", 0.1) 

El comportamiento es el que esperaba cuando usaba solo 1 línea (incluso si notifica a la selección también cuando libero la línea).

¡Cuando estoy usando más de una línea, las selecciona todas al mismo tiempo!

Creo que estoy entendiendo mal la funcionalidad del administrador de eventos, pero no puedo entender por qué diferentes objetos, bien distinguidos (como puedo ver en la print("line selected ", event.artist) ) deben seleccionarse a sí mismos y a otro.

    Uno podría preguntar de otra manera: ¿cómo matplotlib sabría qué línea arrastrar si hace clic en cualquiera de ellos? Respuesta: no, porque tiene tres devoluciones de llamada, una para cada línea y las ejecutará todas.

    Por lo tanto, la solución es primero verificar si la línea que se hizo clic es en realidad la línea que se 'pick_event' dentro de la devolución 'pick_event' llamada 'pick_event' :

     if event.artist == self.line: # register other callbacks 

    (En una nota diferente: se beneficiaría de no llamar a canvas.draw() tanta frecuencia, sino de canvas.draw_idle() )

     import matplotlib.pyplot as plt import matplotlib.lines as lines class draggable_lines: def __init__(self, ax, kind, XorY): self.ax = ax self.c = ax.get_figure().canvas self.o = kind self.XorY = XorY if kind == "h": x = [-1, 1] y = [XorY, XorY] elif kind == "v": x = [XorY, XorY] y = [-1, 1] self.line = lines.Line2D(x, y, picker=5) self.ax.add_line(self.line) self.c.draw_idle() self.sid = self.c.mpl_connect('pick_event', self.clickonline) def clickonline(self, event): if event.artist == self.line: print("line selected ", event.artist) self.follower = self.c.mpl_connect("motion_notify_event", self.followmouse) self.releaser = self.c.mpl_connect("button_press_event", self.releaseonclick) def followmouse(self, event): if self.o == "h": self.line.set_ydata([event.ydata, event.ydata]) else: self.line.set_xdata([event.xdata, event.xdata]) self.c.draw_idle() def releaseonclick(self, event): if self.o == "h": self.XorY = self.line.get_ydata()[0] else: self.XorY = self.line.get_xdata()[0] print (self.XorY) self.c.mpl_disconnect(self.releaser) self.c.mpl_disconnect(self.follower) fig = plt.figure() ax = fig.add_subplot(111) Vline = draggable_lines(ax, "h", 0.5) Tline = draggable_lines(ax, "v", 0.5) Tline2 = draggable_lines(ax, "v", 0.1) plt.show()