Python 在评论中,让我们看看matplotlib为什么不自动进行过滤。首先,我想这至少在50%的情况下是不受欢迎的,在这种情况下,你会希望为每一位挑选的艺术家举办一次活动。而且,matplotlib只为每个被MouseeEvent击中的艺术家发出一个事件要比过滤它
Python 在评论中,让我们看看matplotlib为什么不自动进行过滤。首先,我想这至少在50%的情况下是不受欢迎的,在这种情况下,你会希望为每一位挑选的艺术家举办一次活动。而且,matplotlib只为每个被MouseeEvent击中的艺术家发出一个事件要比过滤它,python,matplotlib,event-handling,Python,Matplotlib,Event Handling,在评论中,让我们看看matplotlib为什么不自动进行过滤。首先,我想这至少在50%的情况下是不受欢迎的,在这种情况下,你会希望为每一位挑选的艺术家举办一次活动。而且,matplotlib只为每个被MouseeEvent击中的艺术家发出一个事件要比过滤它们容易得多。对于前者,您只需比较坐标(很像问题中的“混乱解决方案”)。然而,很难只找到最顶尖的艺术家;当然,如果两个艺术家有不同的zorder,这是可能的,但是如果他们有相同的zorder,那么只是他们在子轴列表中出现的顺序决定了哪个在前面。“
在评论中,让我们看看matplotlib为什么不自动进行过滤。首先,我想这至少在50%的情况下是不受欢迎的,在这种情况下,你会希望为每一位挑选的艺术家举办一次活动。而且,matplotlib只为每个被MouseeEvent击中的艺术家发出一个事件要比过滤它们容易得多。对于前者,您只需比较坐标(很像问题中的“混乱解决方案”)。然而,很难只找到最顶尖的艺术家;当然,如果两个艺术家有不同的zorder,这是可能的,但是如果他们有相同的zorder,那么只是他们在子轴列表中出现的顺序决定了哪个在前面。“pick_upmost_事件”需要检查轴子级的完整堆栈,以确定要拾取哪一个。话虽如此,这并非不可能,但到目前为止,可能没有人相信这是值得的。当然,人们可以为此类“pick_upmost_事件”打开一个问题或将一个实现作为PR提交给matplotlib。使用
event.artist.get_zorder()
?因为我想要一个pick事件,它的艺术家在指定的鼠标点在所有艺术家中拥有最大的zorder值。zorder确实可以在上面的“button\u press\u事件”解决方案中使用,但是这个“button\u press\u事件”只是一个黑客行为,而不是一个pick事件。我已经重写了我的答案,包括一个使用pick事件提示的示例。我无法在Python 3中运行它(错误:“AttributeError:'NoneType'对象没有属性'格式'),但我明白了这个想法。但是,我认为这不会起作用,因为它不会执行特定于点的zorder检查。也就是说,行
应该是点
艺术家未涵盖的所有点的最高艺术家。在这段代码中,点
艺术家总是最上面的。对不起,我把括号放错了,“你点击了…”
打印语句,我在上面修复了它。如果我理解正确,您希望总是让单击()上的仅作用于绘图中最上面的项目;这意味着您需要,我可能会选择前者,即为收集的事件提示和比较zorder。这是可行的,但使用计时器比上面的按钮\u press\u event
解决方案更麻烦。我发现@ImportanceOfBeingErnest的解决方案更简洁、更具普遍性。谢谢你的建议!谢谢你。这很有效。我本来希望Matplotlib有一个更简单的内置解决方案。不知道这个期望从何而来,但现在它已经写下来了,你可以在任何地方复制这个类并按原样使用它,这是最简单的了,对吧?我希望如此,因为其他GUI环境(如Qt和wxPython)根据用户的最高控件解析选择。我知道,在大多数GUI中,单次鼠标单击(不拖动)是不可能选择多个对象的。所以我不明白一次点击按钮就发出多个拾取事件的目的。我明白了。我在回答中添加了一些prosa,关于为什么我认为还没有人实施这样的统一事件。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backend_bases import PickEvent
class PickStack():
def __init__(self, stack, on_pick):
self.stack = stack
self.ax = [artist.axes for artist in self.stack][0]
self.on_pick = on_pick
self.cid = self.ax.figure.canvas.mpl_connect('button_press_event',
self.fire_pick_event)
def fire_pick_event(self, event):
if not event.inaxes:
return
cont = [a for a in self.stack if a.contains(event)[0]]
if not cont:
return
pick_event = PickEvent("pick_Event", self.ax.figure.canvas,
event, cont[0],
guiEvent=event.guiEvent,
**cont[0].contains(event)[1])
self.on_pick(pick_event)
fig, ax = plt.subplots()
# add line:
x = np.arange(10)
y = np.random.randn(10)
line, = ax.plot(x, y, 'b-', label="Line", picker=5)
# add points overlapping the line:
xpoints = [2, 4, 7]
points, = ax.plot(x[xpoints], y[xpoints], 'ro', label="Points", picker=5)
def onpick(event):
txt = f"You picked {event.artist} at xy: " + \
f"{event.mouseevent.xdata:.2f},{event.mouseevent.xdata:.2f}" + \
f" index: {event.ind}"
print(txt)
p = PickStack([points, line], onpick)
plt.show()
self.stack = list(stack).sort(key=lambda x: x.get_zorder(), reverse=True)