在matplotlib中,有一种简单的方法可以在不中断脚本控制流的情况下绘制图形吗?
为了清晰起见使用伪代码,这是我想要实现的:
fig1 = figure()
fig1.plot_a_figure(datasets)
for dataset in datasets:
results = analyze(dataset) # this takes several minutes
update(fig1)
pop_up_another_figure(results) # would like to have a look at this one
# while the next dataset is being processed
当然,我可以保存这些中间数字,但我只需要快速浏览它们,最好让它们实时弹出屏幕。
编辑:一个可运行的例子:
#!/usr/bin/python
import pylab as plb
import matplotlib.pyplot as plt
fig1=plt.figure(1)
ax = fig1.add_subplot(1,1,1)
ax.plot([1,2,3],[4,5,6],'ro-')
#fig1.show() # this does not show a figure if uncommented
plt.show() # until the plot window is closed, the next line is not executed
print "doing something else now"
我错过了非常基本的东西吗?
首先,不要忘记一个简单的替代方案就是制作新的数字窗口 plt.figure(2)
, plt.figure(3)
如果你真的想要更新现有的图形窗口,你最好保持你的线对象的句柄
h = ax.plot([1,2,3],[4,5,6],'ro-')
然后你会做以下事情:
h[0].set_data(some_new_results)
ax.figure.canvas.draw()
至于问题的真正含义,如果你还在努力解读这个问题......
如果需要,您需要启用交互模式 plt.show()
是非阻塞的。要修改您的可运行示例,以便 “现在做点什么” 会立即打印,而不是等待数字窗口关闭,以下情况会:
#!/usr/bin/python
import pylab as plb
import matplotlib.pyplot as plt
fig1=plt.figure(1)
ax = fig1.add_subplot(1,1,1)
ax.plot([1,2,3],[4,5,6],'ro-')
#fig1.show() # this does not show a figure if uncommented
plt.ion() # turns on interactive mode
plt.show() # now this should be non-blocking
print "doing something else now"
raw_input('Press Enter to continue...')
然而,这只是表面上的事情 - 一旦你开始想要在与地块交互时做背景工作,就会出现许多复杂情况。这是使用基本上是状态机的绘画的自然结果,它在面向对象的环境中与线程和编程不能很好地协作。
- 昂贵的计算必须进入工作线程(或者进入子进程)以避免冻结GUI。
Queue
应该用于传递输入数据并以线程安全的方式从worker函数中获取结果。
- 根据我的经验,打电话是不安全的
draw()
在工作线程中,您还需要设置一种计划重绘的方法。
- 不同的后端可能会开始做奇怪的事情
TkAgg
似乎是唯一一个100%工作的人(见 这里)。
最简单和最好的解决方案是不使用vanilla python解释器,而是使用 ipython -pylab
(正如ianalis正确建议的那样),因为他们已经找到了让互动内容顺利运作所需的大部分技巧。它可以不用 ipython
/pylab
但这是一项大量的额外工作。
注意: 我仍然经常喜欢在使用ipython和pyplot GUI窗口时修剪工作线程,并且为了使线程顺利工作,我还需要使用另一个命令行参数 ipython -pylab -wthread
。我上线了 python 2.7.1+
同 matplotlib v1.1.0
, 你的旅费可能会改变。希望这可以帮助!
Ubuntu用户请注意:存储库现在仍然在v0.99上已经很长一段时间了,这是值得的 升级 你的 matplotlib
因为有 许多改进 来到v1.0版本,包括一个 修正马拉松,以及行为的重大变化 show()
。
可能最简单的解决方案是使用IPython作为你的python shell。使用-pylab选项运行它。
ipython -pylab