1

Matplotlib 中是否有函数或方法可以告诉您已连接哪些事件,以及该侦听器正在调用哪些代码?我都看了一遍,一点都不开心。我正在寻找一种通用的解决方案,而不是特定于后端的解决方案,但我会尽我所能。

4

1 回答 1

1

在这些情况下,不要害怕 matplotlib 代码库——它在大多数情况下都相当 Python 且清晰易读(可能到处都有一两个骨架)。

我将通过我将要采取的步骤与您交谈,以了解正在发生的事情以及您可以访问的内容。

首先,从 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中找到文本。https://github.com/matplotlib/matplotlib/blob/v3.0.2/lib/matplotlib/backend_bases.py#L1621self.callbacks =

    # 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

我没有尝试阅读所有这些内容,而是寻找公共数据结构(那些不以 a 开头的数据结构_)以查看是否有任何我可以查询的内容。它开始看起来像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>
于 2018-12-15T20:30:01.597 回答