In my case, I only want to drag one point each time. However, since the two points are heavily overlapping, dragging one point would cause another point to be dragged. How c
I would synchronize which artist is currently active through a single class that works with multiple artists.
It's easiest to use the pick_event for this. It also makes it easier to generalize to other artists. As an example:
import matplotlib.pyplot as plt
import matplotlib.patches as patches
class DraggablePoints(object):
def __init__(self, artists, tolerance=5):
for artist in artists:
artist.set_picker(tolerance)
self.artists = artists
self.currently_dragging = False
self.current_artist = None
self.offset = (0, 0)
for canvas in set(artist.figure.canvas for artist in self.artists):
canvas.mpl_connect('button_press_event', self.on_press)
canvas.mpl_connect('button_release_event', self.on_release)
canvas.mpl_connect('pick_event', self.on_pick)
canvas.mpl_connect('motion_notify_event', self.on_motion)
def on_press(self, event):
self.currently_dragging = True
def on_release(self, event):
self.currently_dragging = False
self.current_artist = None
def on_pick(self, event):
if self.current_artist is None:
self.current_artist = event.artist
x0, y0 = event.artist.center
x1, y1 = event.mouseevent.xdata, event.mouseevent.ydata
self.offset = (x0 - x1), (y0 - y1)
def on_motion(self, event):
if not self.currently_dragging:
return
if self.current_artist is None:
return
dx, dy = self.offset
self.current_artist.center = event.xdata + dx, event.ydata + dy
self.current_artist.figure.canvas.draw()
if __name__ == '__main__':
fig, ax = plt.subplots()
ax.set(xlim=[-1, 2], ylim=[-1, 2])
circles = [patches.Circle((0.32, 0.3), 0.2, fc='r', alpha=0.5),
patches.Circle((0.3, 0.3), 0.2, fc='b', alpha=0.5)]
for circ in circles:
ax.add_patch(circ)
dr = DraggablePoints(circles)
plt.show()