防止 matplotlib ginput 注册点击小部件按钮

prevent matplotlib ginput registering click on widget button

我编写了一个代码来使用 ginput 注册在绘图 window 中单击的 x 值,它工作正常并且仅在您在 window 中单击时注册。

然后我想使用我所做的 matplotlib 小部件添加一些控制按钮,它们也可以很好地使用这些方法,到目前为止一切都很好...

但是,我的问题是,当我点击按钮时,按钮的坐标也被 ginput 注册了,这是我不想要的。有什么办法可以防止这种情况发生吗?使按钮区域对 ginput 无效或以某种方式检测到并拒绝这些点击?

我也很高兴使用 ginput 的替代方法,我并不是真的拘泥于任何特定的方法(我对 python 中的 GUI 非常陌生,只想设置一个简单的示例).

这是我的可重现示例,单击测试按钮也会向列表中添加行:-(

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Button

class Index:
    def test(self, event):
        print ("test")

# fake data
x=np.arange(30)
y=x**2
times=[]

fig,ax=plt.subplots()

ax.plot(x,y)
callback = Index()
buttonname=['test']
colors=['white']
idx=[0.2]
bax,buttons={},{}

# set up list of buttons.
for i,col,button in zip(idx,colors,buttonname):
  bax[button] = plt.axes([0.92, i, 0.07, 0.07])
  buttons[button] = Button(bax[button],button,color=col,hovercolor='green')
  buttons[button].on_clicked(getattr(callback,button))

# register click on plot
while True:
     pts=plt.ginput(1)
     print ("pts is",pts)
     timebegin=pts[0][0]
     times.append(timebegin)
     ax.axvline(x=timebegin)
     print ("adding",timebegin)
     print ("all ",times)
     plt.pause(0.05)

示例截图:

编辑:我暂时想到了一个软糖,在按钮方法中我添加了一个弹出窗口以从时间列表中删除条目并取消绘制线条(我还将时间和线条声明为全局), 可以用,但是很笨重而且不太优雅,因为程序画错了线然后又删除了,呃。

# in the main code I now append the ax.axvline to a list "lines"
def test(self,event):
    times.pop()
        times.pop()
        lines.pop().remove()

避免该问题的一种方法是不使用按钮来终止输入,而是使用 ginput 函数(描述为 here)的 mouse_stop 参数使用鼠标按钮或回车键。 然后可以在绘图中添加文本以向用户显式显示此方法...交互性不如按钮,但它有效。

您可以在回调中执行 times.append(nan),因此如果 times[-1]nan,则 pop() 它并忽略点击。注册按钮事件有一些延迟,所以 pause() 在检查 times[-1].

之前短暂
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Button

times = []

# on click event, append nan
class Index:
    def test(self, event):
        global times
        times.append(np.nan)
        print('test')

fig, ax = plt.subplots()
x = np.arange(30)
y = x**2
ax.plot(x, y)

callback = Index()
bax = fig.add_axes([0.92, 0.2, 0.07, 0.07])
button = Button(bax, 'Test', color='white', hovercolor='green')
button.on_clicked(callback.test)

while True:
    pts = plt.ginput(1)

    # allow callback to finish (duration may need to be adjusted)
    plt.pause(0.15)

    # ignore if newest element is nan
    if times and np.isnan(times[-1]):
        print(f'ignoring {times[-1]}')
        times.pop()
    else: # otherwise store and plot
        timebegin = pts[0][0]
        print(f'adding {timebegin}')
        times.append(timebegin)
        ax.axvline(x=timebegin)

    print(f'times = {times}')
    plt.pause(0.05)