如何确定在Matplotlib中连接了哪些事件?

时间:2018-11-07 20:33:01

标签: python-3.x matplotlib events listener matplotlib-widget

Matplotlib中是否有一个函数或方法可以告诉您 哪些事件已连接,或者该侦听器正在调用什么代码?我四处张望,没有喜悦。我正在寻找一种通用的解决方案,而不是特定于后端的解决方案,但是我会尽力而为。

1 个答案:

答案 0 :(得分:0)

在这种情况下,请不要担心matplotlib代码库-大部分情况下它是相当合理的pythonic且清晰易读(可能到处都是一两个骨架)。

我将通过步骤我将要通过的与您进行交流,以了解发生了什么以及可以访问哪些内容。

首先,从GitHub上带标签的matplotlib版本开始-它会使所有链接保持一致(并且不会随代码移动而腐烂)。 https://github.com/matplotlib/matplotlib/tree/v3.0.2

我们的切入点是我们通过mpl_connect方法附加事件。在matplotlib代码库中对此内容进行快速搜索(使用"def mpl_connect",包括引号)会弹出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>