代码之家  ›  专栏  ›  技术社区  ›  lucatastrophe

可拖动线在Matplotlib中相互选择

  •  4
  • lucatastrophe  · 技术社区  · 7 年前

    我正在尝试使用matplotlib处理和拾取创建一类可拖动的线。目的是在图上设置不同的阈值和间隔。代码如下:

    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)
    

    当只使用一行时,该行为是我所期望的(即使在我释放该行时它也会通知选择)。

    当我使用多行时,它会同时选择所有行!

    我认为我误解了事件管理器的功能,但我无法理解为什么不同的对象可以很好地区分(正如我在 print("line selected ", event.artist) )应该选择自己和他人!

    1 回复  |  直到 7 年前
        1
  •  8
  •   Anurag Dhadse    4 年前

    有人可能会提出不同的问题:如果单击其中任何一行,matplotlib如何知道要拖动哪一行?答:不会,因为它有三个回调,每行一个,并将全部执行。

    因此,解决方案是首先检查单击的线是否实际上是要在 'pick_event' 回调:

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

    canvas.draw() 经常如此,但是 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()
    

    enter image description here