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

问题描述

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

然后我想使用我所做的 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)

示例截图:

enter image description here

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

# 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()

解决方法

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

,

您可以在回调中执行 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)