Как определить, какие события связаны в Matplotlib? - PullRequest
0 голосов
/ 07 ноября 2018

Есть ли в Matplotlib функция или метод, который сообщит вам какие события были связаны, и, возможно, какой код вызывается этим слушателем? Я посмотрел повсюду, без радости. Я предпочитаю найти общее решение, а не конкретное для бэкенда, но я возьму то, что смогу получить.

1 Ответ

0 голосов
/ 15 декабря 2018

В этих ситуациях не бойтесь кодовой базы 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>
...