Matplotlib drag overlapping points interactively

前端 未结 2 1604
时光取名叫无心
时光取名叫无心 2020-12-06 07:29

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

2条回答
  •  孤城傲影
    2020-12-06 08:19

    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()
    

提交回复
热议问题