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


介绍

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

IPython可以使用magic命令模仿Matlab行为 %pylab 要么 %matplotlib 做了一些我还不了解的事情,这是我的问题的重点。

我的目标是让独立的Python脚本像Matlab一样工作(或者像IPython一样工作) %matplotlib 一样)。换句话说,我希望从命令行执行此脚本。我期待每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()

有什么替代品 %matplotlib 当脚本在Python(而不是IPython)中运行时,我可以用来操纵数字?

我已经调查了哪些解决方案?

我目前找到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) 不是我所期待的。

概要

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

from pylab import * 接下来是 plot,我得到了阻止行为,并且浪费了IPython的所有功能。

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

这个  建议使用 matplotlib.interactive(True)。不幸的是,它不起作用,并给出了相同的行为 ion() 确实。


10301
2017-11-13 16:00


起源

作为旁注:不建议使用 pylab完全没了;我们应该进口 matplotlib.pyplot 和 numpy 而是分别防止命名空间被污染。看这里: matplotlib.org/faq/... - tom


答案:


改变你的 do_some_work 功能如下,它应该工作。

def do_some_work(): 
    plt.pause(3)

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

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

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

编辑

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

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


7
2017-11-17 09:52



嗯,这正是我想去的地方。内在的魔力显而易见 %gui wx。不幸 IPython.lib.guisupport.get_app_wx 在我的IPython中不可用。我该如何手动访问? - nowox
好的,现在我对你的实际目标感到困惑。我认为你想要用户交互而不依赖于IPython。该 get_app_wx 功能和 %gui  魔术命令 都是IPython功能。我只包括他们来解释为什么 %pylab 选项有效,对不起,如果不清楚。实际的解决方案是更换 time.sleep 同 plt.pause 在里面 do_some_work 功能。这对你有用吗?而且 互动的例子, 那样有用吗? - titusjan
我的意思是我们仍然没有解决方案,但至少你解释了一些魔力。我可能还会这样做 import IPython 从我的独立脚本启用 IPython.lib.guisupport.get_app_wx。不幸的是,这还不行。该 ion() 在我的问题上解释不起作用。 - nowox
你用的是什么版本的IPython? get_app_wx 自2010年以来一直在那里,所以它应该是可用的,除非你使用古代版本。你也可以解释为什么你认为使用 get_app_wx 是可行的解决方案吗?在这种情况下,你仍然依赖于IPython。恕我直言,真正的解决方案是使用 plt.pause 在里面 do_some_work 功能,但你还没有给出任何反馈。 - titusjan
运用 plt.pause 和 do_some_work 因为在所有处理期间都不起作用 do_some_work,这个数字没有刷新。用户不能 操纵这个数字 do_some_work 在跑。似乎满足我需求的唯一解决方案是 %matplotlib。我发现这个神奇的功能实际上隐藏了一个调用 get_app_wx。如果我可以通过使用它在我的脚本中使用它,我会很高兴。主要的问题是,即使我这样做,也无法在独立脚本中使用魔术功能 import IPython - nowox


我的建议是继续使用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 详情。你会在中找到更多的例子 例子部分


3
2017-11-22 15:48



用你的例子,你告诉我了 matplotlib.animation 不会解决我的问题。与此同时,我问道 另一个问题 我想在哪里使用线程绘制几个数字。不幸的是线程与IPython或交互式matplotlib不兼容。 - nowox
是的线程和GUI循环不能很好地协同工作。如果您想要真正的并发,请将每个matplotlib窗口放入一个自己的进程 - IPython.parallel(ipython.org/ipython-doc/dev/parallel)可以用于它,它在多核机器上运行良好(它可以在没有IPython解释器的情况下使用)。不幸的是,我从来没有真正使用过这样的IPython.parallel - 所以我不能给你一个例子。 - Dietrich