使用Matplotlib以非阻塞方式绘图

ope*_*och 106 python plot matplotlib

在过去的几天里,我一直在玩Numpy和matplotlib.我在尝试使matplotlib绘制函数而不阻塞执行时遇到问题.我知道在这里已经有很多线索提出了类似的问题,而且我已经搜索了很多但是没有设法让这项工作成功.

我曾经尝试过使用show(block = False),但我得到的只是一个冻结的窗口.如果我只是调用show(),则会正确绘制结果,但会阻止执行直到窗口关闭.从我读过的其他主题,我怀疑show(block = False)是否有效取决于后端.它是否正确?我的后端是Qt4Agg.你能看看我的代码并告诉我你是否看错了吗?这是我的代码.谢谢你的帮助.

from math import *
from matplotlib import pyplot as plt
print plt.get_backend()



def main():
    x = range(-50, 51, 1)
    for pow in range(1,5):   # plot x^1, x^2, ..., x^4

        y = [Xi**pow for Xi in x]
        print y

        plt.plot(x, y)
        plt.draw()
        #plt.show()             #this plots correctly, but blocks execution.
        plt.show(block=False)   #this creates an empty frozen window.
        _ = raw_input("Press [enter] to continue.")


if __name__ == '__main__':
    main()
Run Code Online (Sandbox Code Playgroud)

PS.我忘了说我想在每次绘制内容时更新现有窗口,而不是创建一个新窗口.

krs*_*013 142

我花了很长时间寻找解决方案,并找到了答案.

看起来,为了得到你(和我)想要的东西,你需要组合plt.ion(),plt.show()(不是blocking=False,已经弃用),最重要的是plt.pause(.001)(或者你想要的任何时间).该暂停是必须的,因为GUI事件,而主代码正在睡觉,包括绘图发生.这可能是通过从睡眠线程中获取时间来实现的,所以也许IDE会搞乱 - 我不知道.

这是一个适用于python 3.5的实现:

import numpy as np
from matplotlib import pyplot as plt

def main():
    plt.axis([-50,50,0,10000])
    plt.ion()
    plt.show()

    x = np.arange(-50, 51)
    for pow in range(1,5):   # plot x^1, x^2, ..., x^4
        y = [Xi**pow for Xi in x]
        plt.plot(x, y)
        plt.draw()
        plt.pause(0.001)
        input("Press [enter] to continue.")

if __name__ == '__main__':
    main()
Run Code Online (Sandbox Code Playgroud)

  • 您的回答帮助我解决了我遇到的类似问题。以前,我有 `plt.draw` 后跟 `plt.show(block = False)`,但后来它停止工作:图没有响应,关闭它使 iPython 崩溃。我的解决方案是删除 `plt.draw()` 的每个实例并将其替换为 `plt.pause(0.001)`。它没有像之前的 `plt.draw` 那样跟在 `plt.show(block = False)` 之后,而是在它前面是 `plt.ion()` 和 `plt.show()`。我现在有一个`MatplotlibDeprecationWarning`,但它让我可以绘制我的图形,所以我对这个解决方案很满意。 (5认同)
  • 请注意,在python 2.7中,您需要使用`raw_input`而不是`input`.见[here](http://stackoverflow.com/questions/21122540/python-input-error-nameerror-name-is-not-defined) (3认同)
  • 我必须将暂停时间增加到 0.1 秒才能生效 (3认同)
  • @krs013:我记得这在过去对我有用。但是,现在无需使用“plt.ion()”或“plt.draw()”即可实现。我不知道 matplotlib 版本是否发生了变化(我使用的是最新版本“3.1.2”) (2认同)

mak*_*kis 19


一个对我有用的简单技巧如下:

  1. 在show:plt.show中使用block = False参数(block = False)
  2. 在.py脚本的末尾使用另一个plt.show() .

示例:

import matplotlib.pyplot as plt

plt.imshow(add_something)
plt.xlabel("x")
plt.ylabel("y")

plt.show(block=False)

#more code here (e.g. do calculations and use print to see them on the screen

plt.show()
Run Code Online (Sandbox Code Playgroud)

注意:plt.show()是我脚本的最后一行.

  • 这会产生(对我来说,在Linux上,Anaconda,Python 2.7,默认后端)一个**空白**窗口,在执行结束之前一直保持空白,当它最终被填入时.对于更新中间的绘图没有用执行.:-( (4认同)

Def*_*ure 14

您可以通过将绘图写入数组,然后在不同的线程中显示数组来避免阻止执行.以下是使用pyformulas 0.2.8中的 pf.screen同时生成和显示绘图的示例:

import pyformulas as pf
import matplotlib.pyplot as plt
import numpy as np
import time

fig = plt.figure()

canvas = np.zeros((480,640))
screen = pf.screen(canvas, 'Sinusoid')

start = time.time()
while True:
    now = time.time() - start

    x = np.linspace(now-2, now, 100)
    y = np.sin(2*np.pi*x) + np.sin(3*np.pi*x)
    plt.xlim(now-2,now+1)
    plt.ylim(-3,3)
    plt.plot(x, y, c='black')

    # If we haven't already shown or saved the plot, then we need to draw the figure first...
    fig.canvas.draw()

    image = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='')
    image = image.reshape(fig.canvas.get_width_height()[::-1] + (3,))

    screen.update(image)

#screen.close()
Run Code Online (Sandbox Code Playgroud)

结果:

正弦动画

免责声明:我是pyformulas的维护者.

参考:Matplotlib:将绘图保存到numpy数组


Ali*_*i80 9

实时绘图

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 2 * np.pi, 100)
# plt.axis([x[0], x[-1], -1, 1])      # disable autoscaling
for point in x:
    plt.plot(point, np.sin(2 * point), '.', color='b')
    plt.draw()
    plt.pause(0.01)
# plt.clf()                           # clear the current figure
Run Code Online (Sandbox Code Playgroud)

如果数据量太多,您可以使用简单的计数器降低更新率

cnt += 1
if (cnt == 10):       # update plot each 10 points
    plt.draw()
    plt.pause(0.01)
    cnt = 0
Run Code Online (Sandbox Code Playgroud)

程序退出后保持绘图

这是我无法找到满意答案的实际问题,我想要在脚本完成后没有关闭的绘图(如 MATLAB),

想想看,脚本写完后,程序就终止了,没有逻辑的方式来保持情节,所以有两种选择

  1. 阻止脚本退出(这是 plt.show() 而不是我想要的)
  2. 在单独的线程上运行绘图(太复杂了)

这对我来说并不令人满意,所以我在盒子外找到了另一个解决方案

SaveToFile 和在外部查看器中查看

为此,保存和查看应该都很快,并且查看器不应锁定文件而应自动更新内容

选择保存格式

基于矢量的格式既小又快

  • SVG很好,但除了默认需要手动刷新的 Web 浏览器之外,找不到合适的查看器
  • PDF可以支持矢量格式,并且有支持实时更新的轻量级查看器

带实时更新的快速轻量级查看器

对于PDF,有几个不错的选择

  • 在 Windows 上,我使用免费、快速且轻便的SumatraPDF(我的情况仅使用 1.8MB RAM)

  • 在 Linux 上有几个选项,例如Evince (GNOME) 和Ocular (KDE)

示例代码和结果

将绘图输出到文件的示例代码

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 2 * np.pi, 100)
y = np.sin(2 * x)
plt.plot(x, y)
plt.savefig("fig.pdf")
Run Code Online (Sandbox Code Playgroud)

第一次运行后,在上面提到的一个查看器中打开输出文件并享受。

这是 VSCode 与 SumatraPDF 的屏幕截图,该过程也足够快以获得半实时更新率(我的设置可以接近 10Hz,只需time.sleep()在间隔之间使用) pyPlot,非阻塞


Jim*_*Jim 9

我发现命令plt.pause(0.001)是唯一需要的东西,没有别的东西。

plt.show() 和 plt.draw() 是不必要的和/或以一种或另一种方式阻塞。因此,这里有一段代码,用于绘制和更新图形并继续进行。本质上 plt.pause(0.001) 似乎是与 matlab 的drawow 最接近的等价物。

不幸的是,除非您插入 input() 命令,否则这些图不会是交互式的(它们会冻结),但随后代码将停止。

plt.pause(interval)命令的文档指出:

如果有活动图形,它将在暂停之前更新并显示……这可以用于粗制动画。

这正是我们想要的。试试这个代码:

import numpy as np
from matplotlib import pyplot as plt

x = np.arange(0, 51)               # x coordinates  
         
for z in range(10, 50):

    y = np.power(x, z/10)          # y coordinates of plot for animation

    plt.cla()                      # delete previous plot
    plt.axis([-50, 50, 0, 10000])  # set axis limits, to avoid rescaling
    plt.plot(x, y)                 # generate new plot
    plt.pause(0.1)                 # pause 0.1 sec, to force a plot redraw

Run Code Online (Sandbox Code Playgroud)


igg*_*345 5

这些答案很多都是夸张的,据我所知,答案并不难理解。

您可以plt.ion()根据需要使用,但我发现使用plt.draw()同样有效

对于我的特定项目,我正在绘制图像,但是您可以使用plot()scatter()或其他任何一种来代替figimage(),这没关系。

plt.figimage(image_to_show)
plt.draw()
plt.pause(0.001)
Run Code Online (Sandbox Code Playgroud)

要么

fig = plt.figure()
...
fig.figimage(image_to_show)
fig.canvas.draw()
plt.pause(0.001)
Run Code Online (Sandbox Code Playgroud)

如果您使用的是实际数字。
我使用了@ krs013和@Default Picture的答案来解决这个问题,
希望这可以使某人不必在一个单独的线程上启动每个单独的角色,或者不必阅读这些小说就可以解决这个问题。

  • 这是因为不清除图像会导致内存泄漏,并且会导致 matplotlib 尝试绘制所有现有的迭代,这会减慢执行速度 (2认同)

归档时间:

查看次数:

98889 次

最近记录:

6 年,11 月 前