Matplotlib 中的可拖动线 select
Draggable lines select one another in Matplotlib
我正在尝试使用 matplotlib 处理和拾取创建 class 可拖动线。目的是在图形上设置不同的阈值和间隔。这是代码:
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)
该行为是我仅使用 1 行时的预期行为(即使它在我释放该行时也会通知 selection)。
当我使用多条线路时,它 select 会同时使用所有线路!
我想我误解了事件管理器的功能,但我不明白为什么不同的对象,很好区分(正如我在 print("line selected ", event.artist)
中看到的)应该 select 自己和另一个!
有人可能会问不同的问题:如果你点击其中任何一条线,matplotlib 如何知道要拖动哪条线?答:不会,因为它有3个回调,每行一个,会全部执行。
因此,解决方案是首先检查单击的行是否实际上是要在 '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()
我正在尝试使用 matplotlib 处理和拾取创建 class 可拖动线。目的是在图形上设置不同的阈值和间隔。这是代码:
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)
该行为是我仅使用 1 行时的预期行为(即使它在我释放该行时也会通知 selection)。
当我使用多条线路时,它 select 会同时使用所有线路!
我想我误解了事件管理器的功能,但我不明白为什么不同的对象,很好区分(正如我在 print("line selected ", event.artist)
中看到的)应该 select 自己和另一个!
有人可能会问不同的问题:如果你点击其中任何一条线,matplotlib 如何知道要拖动哪条线?答:不会,因为它有3个回调,每行一个,会全部执行。
因此,解决方案是首先检查单击的行是否实际上是要在 '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()