PyCharm中如何实现matplotlib交互式图形而不阻塞执行。

3
我阅读了很多有关这个主题的Stack Overflow问题,但经过许多实验后,我无法解决我的问题。我在Windows 7上使用PyCharm 2016.3.2(但在OSX上我也遇到了同样的问题),我的解释器是Anaconda的最新版本,带有Python 3.6和matplotlib 2.0.0。
以下是我要实现的内容(也许我没有使用正确的方法,因为我正在尝试重新创建我在Octave / Matlab中习惯的行为):
  1. 在弹出窗口中绘制一个图形
  2. 暂停我的脚本(input("press a key to continue"))
  3. 观察图形,然后按键继续脚本
  4. 计算其他内容
  5. 在同一图形上绘制新数据
  6. 暂停我的脚本(input("press a key to continue"))
  7. 观察图形,然后按键继续脚本
以下是我的测试代码:
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt

print('Plotting Data...')

plt.ion()
plt.figure(1)
plt.plot([1, 5, 10, 20], [1, 5, 10, 20])
plt.xlabel('x label')
plt.ylabel('y label')
plt.show()
plt.pause(0.0001)

input('Plotting Data done..., Press a key to continue')

plt.figure(1)
plt.plot([1, 5, 10, 20], [2, 10, 20, 40])
plt.show()
plt.pause(0.0001)

input('Program paused. Press enter to end.\n')

这是我想要的最接近版本,图表正确但当我将鼠标移到它们上面时不会有反应(plt.pause(0.0001)会生成警告但代码可以运行)。
我试着调整参数(plt.ion(); plt.pause(); plt.show(block=False)),但大部分时间都导致空白图窗口或需要关闭窗口才能继续执行。
感谢您的帮助!

你不能同时在两个不同的事件循环中工作。为什么不可以按照正常方式绘制所有内容,并使用窗口的关闭作为程序继续执行的触发器? - ImportanceOfBeingErnest
1
通常的方法是? 如果我使用窗口关闭作为继续的触发器,即使我回调 figure(1),我也找不到在第一个数据集之上绘制第二个元素的方法(除非重新使用plt.plot)。但有时候我只想多次绘图并让它们一直保留打开状态,直到执行结束。谢谢! - Capy
@ImportanceOfBeingErnest 这篇文章关注的是同一个问题类似的问题,并且基本上使用了相同的解决方法(通过暂停实现正确绘制图形但无响应)。 - Capy
链接问题的答案是否对您有用?在我的情况下,它与此处的情况相同:输入阻止了窗口事件循环,从而变得无响应。 - ImportanceOfBeingErnest
@ImportanceOfBeingErnest 你是对的,我的行为没问题,图形也正确,只是窗口无响应。我认为试图模仿Matlab的做法并不是正确的方法。所以我可以在非交互模式下等待所有数据,然后在一个图中绘制所有图形(然后关闭它),或者在执行结束时将图形保存到文件中以便查看。非常感谢您的帮助! - Capy
这真的取决于应用程序。但无论如何,如果您有一个不需要长时间运行的计算,您可以在最后简单地绘制所有相关图形;如果您有一个需要很长时间才能完成的计算,您也不希望它被中断。 - ImportanceOfBeingErnest
1个回答

0

一旦调用plt.show(),主循环就会被窗口接管。因此,一旦调用input,主循环就会变得无响应。

您可以尝试留在GUI循环中并在那里处理按键。

import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt

print('Plotting Data...')

fig, ax = plt.subplots()
ax.set_xlabel('x label')
ax.set_ylabel('y label')
i=[0]

def f1():
    ax.plot([1, 5, 10, 20], [1, 5, 10, 20])

def f2():
    ax.plot([1, 5, 10, 20], [2, 10, 20, 40])

def f3():
    ax.plot([1, 5, 10, 20], [5, 9, 17, 28])


def update(event=None):
    if i[0]==0: f1()
    if i[0]==1: f2()
    if i[0]==2: f3()
    fig.canvas.draw_idle()
    i[0]+=1
    print('Step {} done..., Press a key to continue'.format(i[0]))

fig.canvas.mpl_connect("key_press_event", update)    

update()
plt.show()

谢谢您的回答。我正在熟悉pyplot OO语法,并需要更好地理解darw_idle。<br/> 另一种方法是再次调用已关闭的图(要么将其显示为初始状态,要么添加数据以显示新数据以及初始数据),但我还不知道如何做到这一点。 - Capy

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