在Matplotlib图形中等待用户特定按键的输入

3
我希望用户能够输入并通过特定的按键来停止循环。
from __future__ import print_function
import sys
import numpy as np
import matplotlib.pyplot as plt


def press(event):
    print('press', event.key)
    sys.stdout.flush()
    if event.key == 'x':
       visible = xl.get_visible()
       xl.set_visible(not visible)
       fig.canvas.draw()
    if event.key == 'enter':
       cnt.append(1)

cnt=[]
List=[]
fig, ax = plt.subplots()

fig.canvas.mpl_connect('key_press_event', press)

ax.plot(np.random.rand(12), np.random.rand(12), 'go')
xl = ax.set_xlabel('easy come, easy go')
ax.set_title('Press a key')
plt.show()
plt.waitforbuttonpress() #non specific key press!!!

result=cnt[0]+cnt[1]

我希望停止循环,等待用户按下Enter键后,再使用cnt继续代码。但如果我不加入plt.waitforbuttonpress(),代码将运行并完成,但如果我加入plt.waitforbuttonpress(),任何键盘或鼠标按键都将运行并结束整个代码。


你想停止哪个循环?是指运行以允许用户输入的事件循环,还是上面未显示的外部循环?你的示例对我来说可以运行,使用x打开和关闭轴。按下回车键不会发生任何事情,因为应该是小写的“enter”(“interval”也未定义)。 - Ed Smith
我想使用用户输入并在输入后执行一些代码:result=cnt[0]+cnt[1] - user5960525
代码对我来说运行得如预期。您创建了一个应该在 plt.show 命令处停止的图形。由于 mpl_connect('key_press_event') 已启动事件处理程序,因此我不需要 plt.waitforbuttonpress()。这可能与您的 matplotlib 或后端有关。使用 plt.show(block=True) 是否有帮助?还要添加 plt.ioff()(关闭交互模式)。 - Ed Smith
1个回答

3
代码对我来说运行正常(matplotlib版本为2.0.0和TkAgg后端)。您创建了一个图形,它应该在plt.show命令处阻塞。
如果没有,请尝试使用matplotlib.use("TkAgg")更改后端(请参见此处的顺序
然后您有几个选项,
1)将要运行的代码包含在事件处理循环中,可以在事件后或者特定按键下执行。
import numpy as np
import matplotlib.pyplot as plt

def press(event):
    print('press', event.key)
    if event.key == 'enter':
        cnt.append(1)
    if event.key == 'a':
        result = sum(cnt)
        print(result, cnt)

cnt=[]
fig, ax = plt.subplots()
fig.canvas.mpl_connect('key_press_event', press)
ax.plot(np.random.rand(12), np.random.rand(12), 'go')
plt.show()

当你按下a键时,假设已经按下了8次enter键。

2)添加一个退出命令以优雅地退出图形(您可能需要找出最佳的退出方式)。

import numpy as np
import matplotlib.pyplot as plt

def press(event):
    print('press', event.key)
    if event.key == 'enter':
        cnt.append(1)
    if event.key == "escape":
        plt.close()

cnt=[]
fig, ax = plt.subplots()
fig.canvas.mpl_connect('key_press_event', press)
ax.plot(np.random.rand(12), np.random.rand(12), 'go')
plt.show()
result = sum(cnt)
print(result, cnt)

plt.show()命令后,应该运行下一个命令。

3) 为事件循环设置超时时间,您的代码将在此时间之后运行。

import numpy as np
import matplotlib.pyplot as plt

def press(event):
    print('press', event.key)
    if event.key == 'enter':
        cnt.append(1)

cnt=[]
fig, ax = plt.subplots()
fig.canvas.mpl_connect('key_press_event', press)
ax.plot(np.random.rand(12), np.random.rand(12), 'go')
plt.show(block=False)
plt.waitforbuttonpress()
plt.pause(5.)
result = sum(cnt)
print(result, cnt)

看起来plt.waitforbuttonpress(time = 5.)应该做类似的事情,但我无法让它工作。


由于某些原因,“key_press_event”似乎不允许我在处理程序中使用“ax.imshow”,即使我已经在处理程序内部有了“ax”。图形没有任何变化。 - CMCDragonkai
嗨@CMCDragonkai,也许值得提一个新问题,包括matplotlib的版本等信息。 - Ed Smith
谢谢你的代码,@Ed Smith。你的代码对我来说很好用,但是当我把cnt从列表改成整数时,它就失败了。(我把cnt=[]改成了cnt=0,把cnt.append(1)改成了cnt+=1)。你有任何想法吗?当我按回车键时,会出现“UnboundLocalError: local variable 'cnt' referenced before assignment”的错误提示。 - Blitzer
我认为你需要确保在注册事件“fig.canvas.mpl_connect”之前定义了cnt,因为该事件可能会使用它,但是如果没有看到代码就很难知道。 - Ed Smith

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接