当我来自matlab时,我习惯于一个交互式界面,脚本可以在运行时更新数字。在处理期间,每个图形可以重新调整大小或甚至关闭。这可能意味着每个数字都在自己的线程中运行,显然不是matplotlib的情况。
IPython可以使用魔术命令%pylab
或%matplotlib
来模仿Matlab行为,这些命令做了我还不了解的事情,这是我的问题的重点。
我的目标是允许独立的Python脚本像Matlab一样工作(或者像%matplotlib
那样的IPython)。换句话说,我希望从命令行执行此脚本。我期待每3秒弹出一个新的数字。在执行期间,我可以缩放,调整大小甚至关闭图形。
#!/usr/bin/python
import matplotlib.pyplot as plt
import time
def do_some_work():
time.sleep(3)
for i in range(10):
plt.plot([1,2,3,4])
plt.show() # this is way too boilerplate, I'd like to avoid it too.
do_some_work()
当脚本在Python(而不是IPython)中运行时,我可以使用
%matplotlib
替代操作数字吗?
我目前找到3种获得情节剧的方法。
1。 %pylab
/ %matplotlib
正如tom所述,应避免使用%pylab
以防止名称空间被污染。
>>> %pylab
>>> plot([1,2,3,4])
这个解决方案很好,情节是非阻塞的,不需要额外的show()
,之后我仍然可以添加grid()
的网格,我可以关闭,调整大小或放大我的数字没有其他问题。
不幸的是,%matplotlib
命令仅在IPython上可用。
2。 from pylab import *
或from matplotlib.pyplot import plt
>>> from pylab import *
>>> plot([1,2,3,4])
这里的情况完全不同。我需要添加命令show()
来显示阻塞的数字。我不能做任何事情,只是关闭图来执行下一个命令,例如grid()
,因为该图现在已经关闭,所以没有任何效果......
** 3. from pylab import *
或from matplotlib.pyplot import plt
+ ion()
**
一些建议建议使用ion()
命令,如下所示:
>>> from pylab import *
>>> ion()
>>> plot([1,2,3,4])
>>> draw()
>>> pause(0.0001)
不幸的是,即使情节显示,我也无法手动关闭数字。我需要在终端上执行close()
,这不是很方便。此外,需要两个额外的命令,如draw(); pause(0.0001)
,这不是我所期待的。
使用%pylab
,一切都很棒,但我不能在IPython之外使用它
from pylab import *
后跟plot
,我得到了阻止行为,并且浪费了所有IPython的力量。
from pylab import *
后跟ion
提供了一个很好的替代前一个,但我必须使用奇怪的pause(0.0001)
命令导致我无法手动关闭的窗口(我知道)某些后端不需要pause
。我使用WxAgg
,这是Cygwin x64
唯一适用的{。}}。
此question建议使用matplotlib.interactive(True)
。不幸的是,它不起作用并且提供与ion()
相同的行为。
答案 0 :(得分:7)
将您的do_some_work
功能更改为以下功能,它应该有效。
def do_some_work():
plt.pause(3)
对于交互式后端plt.pause(3)
启动事件循环3秒钟,以便它可以处理您的调整大小事件。请注意,the documentation表示它是一个实验函数,对于复杂的动画,您应该使用animation module。
%pylab
和%matplotlib
魔术命令也会启动事件循环,这就是用户与绘图进行交互的原因。或者,您可以使用%gui wx
启动事件循环,然后使用%gui
将其关闭。您可以使用IPython.lib.guisupport.is_event_loop_running_wx()函数来测试它是否正在运行。
在'What is interactive mode'页面中详细说明了使用ion()
或ioff()
的原因。原则上,没有IPython就可以进行用户交互。但是,我无法从该页面获取交互式示例以使用Qt4Agg
后端,只能使用MacOSX
后端(在我的Mac上)。我没有尝试使用WX
后端。
修改强>
我设法通过使用PyQt4而不是PySide来使交互式示例与Qt4Agg后端一起工作(因此在我的backend.qt4 : PyQt4
文件中设置~/.config/matplotlibrc
。我认为这个例子并不适用于所有后端。我提交了一个问题here。
修改2
我担心在不使用线程的情况下,在长计算运行时我无法想到操纵数字的方法。正如你所提到的:Matplotlib不会启动一个线程,也不会启动IPython。 %pylab和%matplotlib命令在处理来自read-eval-print循环的命令之间交替,并让GUI处理事件的时间很短。他们按顺序这样做。
事实上,即使使用%matplotlib或%pylab魔法,我也无法重现您的行为。 (为了清楚起见:在ipython
我首先调用%matplotlib
然后调用%run yourscript.py
)。 %matplotlib魔术将Matplotlib置于交互模式,这使得plt.show()
调用非阻塞,以便立即执行do_some_work
函数。但是,在time.sleep(3)
通话期间,该数字没有响应(如果我增加睡眠时间,则会变得更加明显)。我不明白这是如何工作的。
除非我错了,否则你必须用较小的部分分解你的计算并使用plt.pause
(甚至更好的动画模块)来更新数字。
答案 1 :(得分:3)
我的建议是继续使用IPython,因为它为你管理GUI事件循环(这是pylab / pylot的作用)。
我在普通的解释器中尝试了交互式绘图,它按照预期的方式工作,即使没有调用ion()
(Debian unstable,Python 3.4.3 +,Matplotlib 1.4.2-3.1)。如果我没记错,它在Matplotlib中是一个相当新的功能。
或者,您也可以使用Matplotlib的动画功能定期更新绘图:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import time
plt.ion()
tt = np.linspace(0, 1, 200)
freq = 1 # parameter for sine
t0 = time.time() # for measuring ellapsed time
fig, ax = plt.subplots()
def draw_func(i):
""" This function gets called repeated times """
global freq # needed because freq is changed in this function
xx = np.sin(2*np.pi*freq*tt)/freq
ax.set_title("Passed Time: %.1f s, " % (time.time()-t0) +
"Parameter i=%d" % i)
ax.plot(tt, xx, label="$f=%d$ Hz" % freq)
ax.legend()
freq += 1
# call draw_func every 3 seconds 1 + 4 times (first time is initialization):
ani = animation.FuncAnimation(fig, draw_func, np.arange(4), interval=3000,
repeat=False)
# plt.show()
结帐matplotlib.animation.FuncAnimation了解详情。您可以在examples section中找到更多示例。