В этих ситуациях не бойтесь кодовой базы matplotlib - она достаточно разумна и по большей части разборчива и разборчива (возможно, с одним или двумя скелетами здесь и там).
Я собираюсь рассказать вам о шагах Я собираюсь взять , чтобы понять, что происходит и к чему вы можете получить доступ.
Прежде всего, начните с теговой версии matplotlib на GitHub - она сделает все ссылки согласованными (и не сгниющими при перемещении кода). https://github.com/matplotlib/matplotlib/tree/v3.0.2
Наша точка входа заключается в том, что мы прикрепляем события с помощью метода mpl_connect
. Быстрый поиск этого (с использованием "def mpl_connect"
, включая кавычки) в кодовой базе matplotlib обнаруживает https://github.com/matplotlib/matplotlib/blob/v3.0.2/lib/matplotlib/backend_bases.py#L2134-L2180.
self.callbacks.connect(s, func)
Итак, теперь нам нужно выяснить, что на самом деле есть self.callbacks
на этом объекте. Я сделал ctrl+f
, чтобы найти текст self.callbacks =
в этом файле.
https://github.com/matplotlib/matplotlib/blob/v3.0.2/lib/matplotlib/backend_bases.py#L1621
# a dictionary from event name to a dictionary that maps cid->func
self.callbacks = cbook.CallbackRegistry()
Мы делаем успехи и становимся все глубже каждый раз :)
После логического импорта нам нужно выяснить, как выглядит matplotlib.cbook.CallbackRegistry
. https://github.com/matplotlib/matplotlib/blob/v3.0.2/lib/matplotlib/cbook/init.py#L88.
В частности, мы вызывали метод CallbackRegistry.connect
: https://github.com/matplotlib/matplotlib/blob/v3.0.2/lib/matplotlib/cbook/init.py#L162-L177. Реализация на момент написания:
def connect(self, s, func):
"""Register *func* to be called when signal *s* is generated.
"""
self._func_cid_map.setdefault(s, {})
try:
proxy = WeakMethod(func, self._remove_proxy)
except TypeError:
proxy = _StrongRef(func)
if proxy in self._func_cid_map[s]:
return self._func_cid_map[s][proxy]
cid = next(self._cid_gen)
self._func_cid_map[s][proxy] = cid
self.callbacks.setdefault(s, {})
self.callbacks[s][cid] = proxy
return cid
Вместо того, чтобы пытаться прочитать все это, я ищу общедоступные структуры данных (те, которые не начинаются с _
), чтобы посмотреть, могу ли я что-нибудь запросить. Он начинает выглядеть так: CallbackRegistry.callbacks
- это словарь, который отображает имена событий в некоторую форму набора, содержащего эти функции событий.
Действительно, это подтверждается попытками:
In [6]: fig.canvas.callbacks.callbacks
Out[6]:
{'button_press_event': {0: <weakref at 0x117bcff98; to 'FigureCanvasTkAgg' at 0x117c0f860>,
4: <matplotlib.cbook._StrongRef at 0x117c0f550>,
5: <matplotlib.cbook._StrongRef at 0x119686dd8>},
'scroll_event': {1: <weakref at 0x117be4048; to 'FigureCanvasTkAgg' at 0x117c0f860>},
'key_press_event': {2: <weakref at 0x117be43c8; to 'FigureManagerTk' at 0x117c0fe10>},
'motion_notify_event': {3: <weakref at 0x117be4438; to 'NavigationToolbar2Tk' at 0x117c0fe48>}}
Что интересно, в данном конкретном случае я лично добавил только один обработчик событий (button_press_event
), но у меня явно больше событий, чем это. То, что мы видели здесь, - это на самом деле все события, которые происходят и в вашем бэкэнде. Когда-нибудь задумывались, как отключить некоторые из них (например, сочетания клавиш)? Это просто словарь событий, и ничто не мешает просто уничтожить их:
# Delete / remove the keyboard press event handlers.
fig.canvas.callbacks.callbacks.pop('key_press_event')
Если вы хотите получить ссылку на нижележащую функцию, немного самоанализа предлагает вам сделать что-то вроде:
In [37]: for cid, func_ref in fig.canvas.callbacks.callbacks['button_press_event'].items():
...: func = func_ref()
...: print(cid, func)
Out[37]: 5 <function onclick at 0x114d7e620>