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