繁体   English   中英

如何在Python中运行脚本时操纵数字?

[英]How to manipulate figures while a script is running in Python?

介绍

当我来自 ,我习惯于一个交互式界面,脚本可以在运行时更新数字。 在处理期间,每个图形可以重新调整大小或甚至关闭。 这可能意味着每个数字都在自己的线程中运行,这显然不是的情况。

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

正如汤姆所说,应该避免使用%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) draw(); pause(0.0001)不是我所期待的。

摘要

使用%pylab ,一切都很棒,但我不能在IPython之外使用它

使用from pylab import *后跟一个plot ,我得到了一个阻塞行为,并且浪费了IPython的所有功能。

from pylab import *后跟ion提供了一个很好的替代前一个,但我必须使用奇怪的pause(0.0001)命令导致一个我无法手动关闭的窗口(我知道一些后端不需要pause我正在使用WxAgg ,这是唯一一款适用于Cygwin x64

这个问题建议使用matplotlib.interactive(True) 不幸的是,它不起作用,并提供与ion()相同的行为。

do_some_work函数更改为以下内容,它应该可以正常工作。

def do_some_work(): 
    plt.pause(3)

对于交互式后端, plt.pause(3)启动事件循环3秒,以便它可以处理调整大小事件。 请注意, 文档说它是一个实验函数,对于复杂的动画,您应该使用动画模块

%pylab%matplotlib魔术命令也启动了一个事件循环,这就是用户与绘图交互的原因。 或者,您可以使用%gui wx启动事件循环,并使用%gui将其关闭。 您可以使用IPython.lib.guisupport.is_event_loop_running_wx()函数来测试它是否正在运行。

使用ion()ioff()的原因在“什么是交互模式”页面中得到了很好的解释。 原则上,没有IPython就可以进行用户交互。 但是,我无法从该页面获得交互式示例以使用Qt4Agg后端,只能使用MacOSX后端(在我的Mac上)。 我没有尝试使用WX后端。

编辑

通过使用PyQt4而不是PySide,我设法让交互式示例与Qt4Agg后端一起工作(所以在我的~/.config/matplotlibrc文件中设置backend.qt4 : PyQt4 )。 我认为该示例不适用于所有后端。 在这里提交了一个问题。

编辑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 (甚至更好的动画模块)来更新数字。

我的建议是继续使用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了解详情。 您可以在示例部分找到更多示例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM