Может быть проще всего создать собственное событие на button_press_event
событие.Чтобы продвинуть идею "set_pick_stack", выраженную в вопросе, это может выглядеть следующим образом.Идея состоит в том, чтобы сохранить набор исполнителей и при помощи button_press_event проверить, содержится ли это событие в исполнителе.Затем выполните обратный вызов для пользовательской функции onpick
.
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()
Идея состоит в том, чтобы предоставить список исполнителей в порядке, необходимом для событий выбора.Конечно, можно также использовать zorder
для определения порядка.Это может выглядеть как
self.stack = list(stack).sort(key=lambda x: x.get_zorder(), reverse=True)
в функции __init__
.
Поскольку в комментариях возникает вопрос, давайте посмотрим, почему matplotlib не выполняет эту фильтрацию автоматически.Ну, во-первых, я бы предположил, что это нежелательно, по крайней мере, в 50% случаев, когда вам нужно событие для каждого выбранного художника.Кроме того, для matplotlib гораздо проще просто создать событие для каждого артиста, который попал в событие мыши, чем отфильтровать его.Для первого вы просто сравниваете координаты (очень похоже на «грязное решение» из вопроса).Принимая во внимание, что трудно получить только самого высокого художника;конечно, в случае, если два художника имеют разные zorder, это было бы возможно, но если они имеют одинаковый zorder, то только порядок их появления в списках дочерних осей определяет, что находится впереди.«Pick_upmost_event» должен будет проверить весь набор дочерних осей, чтобы выяснить, какой из них выбрать.Это, как говорится, не является невозможным, но до сих пор, вероятно, никто не был уверен, что оно того стоитКонечно, люди могут открыть вопрос или представить реализацию в виде PR в matplotlib для такого «pick_upmost_event».