让matplotlib按钮断开自己的回调



我想要一个只能使用一次的matplotlib按钮。理想情况下,我可以通过断开回调来实现这一点。然而,回调断开连接本身存在时间问题。

import matplotlib.pyplot as plt
from matplotlib.widgets import Button
fig, ax = plt.subplots()
donebutton = Button(ax, "Disconnect the button")
def donecallback(event):
donebutton.disconnect(donecid)
print("Disconnected")
donecid = donebutton.on_clicked(donecallback)
plt.show()

要断开回调,我需要它的回调IDdonecid,这是我连接回调时获得的。要连接回调,我首先必须定义它donecallback。要定义回调,我必须已经知道CID。因此,我陷入了鸡和蛋的问题。

有一些变通方法,比如定义一个类,这样我就可以通过self将数据传递到回调中,有一个全局标志来跟踪按钮是否被按下,或者创建一个新的、相同的、没有连接回调的按钮。然而,如果有一个更简单的方法,那就太好了。有吗?

编辑:当我使用我给出的任何一个代码时,都会出现以下错误。或dnalow提供的代码。

func(*args, **kwargs)
File "C:UsersMyNameAppDataLocalPackagesPythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0LocalCachelocal-packagesPython38site-packagesmatplotlibwidgets.py", line 210, in _release
for cid, func in self.observers.items():
RuntimeError: dictionary changed size during iteration```

您可以围绕它包装一个类:


class MyButton(Button):
def on_clicked(self, func):
self.cb_id = super(MyButton, self).on_clicked(func)
return self.cb_id
def disconnect(self):
return super(MyButton, self).disconnect(self.cb_id)

donebutton = MyButton(ax, "Disconnect the button")
def donecallback(event):
donebutton.disconnect()
print("Disconnected")
donebutton.on_clicked(donecallback)

然而,可能需要更好地处理定义了多个事件的情况。此外,您还可以定义一个Button类,在第一个事件发生后自动断开连接?!

编辑:

上述方法不起作用。相反,您可以使用active属性来停用整个按钮。它不会与某个回调函数断开连接,所以它并不是您真正想要的。

以您为例:

import matplotlib.pyplot as plt
from matplotlib.widgets import Button
fig, ax = plt.subplots()
donebutton = Button(ax, "Disconnect the button")
def donecallback(event):
donebutton.active = False
print("Disconnected")
donecid = donebutton.on_clicked(donecallback)
plt.show()

编辑2:

通过覆盖按钮的_release方法的另一种方法:

class SingleUseButton(Button):
def _release(self, event):
if self.ignore(event):
return
if event.canvas.mouse_grabber != self.ax:
return
event.canvas.release_mouse(self.ax)
if not self.eventson:
return
if event.inaxes != self.ax:
return
for cid in list(self.observers):
func = self.observers.pop(cid)
func(event)

最新更新