使用 Matplotlib 以非阻塞方式绘图

2025-01-08 08:49:00
admin
原创
117
摘要:问题描述:我在尝试使 matplotlib 绘制函数而不阻止执行时遇到问题。我尝试过使用show(block=False)某些人建议的方法,但我得到的只是一个冻结的窗口。如果我简单地调用show(),结果会正确绘制,但执行会被阻止,直到窗口关闭。从我读过的其他线程来看,我怀疑是否show(block=Fals...

问题描述:

我在尝试使 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()

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


解决方案 1:

我花了很长时间寻找解决方案,最终找到了这个答案。

看起来,为了得到你(和我)想要的东西,你需要结合plt.ion()plt.show()(而不是block=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()

解决方案 2:


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

  1. 在 show 中使用block = False参数: plt.show(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()

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

解决方案 3:

您可以通过将绘图写入数组,然后在另一个线程中显示该数组来避免阻塞执行。以下是使用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()

结果:

正弦动画

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

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

解决方案 4:

实时绘图

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

如果数据量太大,你可以用一个简单的计数器降低更新率

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

程序退出后保留图

这是我的实际问题,找不到令人满意的答案,我想要脚本完成后不关闭的绘图(如 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")

首次运行后,在上面提到的查看器之一中打开输出文件并欣赏。

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

解决方案 5:

很多这样的答案都被夸大了,但从我所找到的内容来看,答案并不难理解。

你可以使用plt.ion(),但我发现使用plt.draw()同样有效

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

plt.figimage(image_to_show)
plt.draw()
plt.pause(0.001)

或者

fig = plt.figure()
...
fig.figimage(image_to_show)
fig.canvas.draw()
plt.pause(0.001)

如果您使用的是实际人物。

我使用了@krs013 和@Default Picture 的答案来解决这个问题,

希望这可以节省人们在单独的线程上启动每个人物的时间,或者不必阅读这些小说才能解决这个问题

解决方案 6:

我发现plt.pause(0.001)只需要命令,不需要其他任何东西。

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

不幸的是,这些图表不具有交互性(它们会冻结),除非你插入一个 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

解决方案 7:

Iggy 的回答对我来说是最容易理解的,但是当我执行后续命令时出现了以下错误,subplot而当我刚才执行时却没有出现该命令show

MatplotlibDeprecationWarning:使用与先前轴相同的参数添加轴当前会重用先前的实例。在未来版本中,将始终创建并返回新实例。同时,可以通过向每个轴实例传递唯一标签来抑制此警告并确保未来的行为。

为了避免这个错误,在用户按下回车键后关闭(或清除)情节会有所帮助。

这是对我有用的代码:

def plt_show():
    '''Text-blocking version of plt.show()
    Use this instead of plt.show()'''
    plt.draw()
    plt.pause(0.001)
    input("Press enter to continue...")
    plt.close()

解决方案 8:

Python 包drawnow允许以非阻塞方式实时更新绘图。

它还可以与网络摄像头和OpenCV配合使用,例如绘制每帧的测量值。

请参阅原始帖子。

解决方案 9:

替换 matplotlib 的后端可以解决我的问题。

在之前写入下面的命令import matplotlib.pyplot as plt

替换后端命令应先运行。

导入 matplotlib

matplotlib.use('TkAgg')

我的答案来自Pycharm does not show plot

解决方案 10:

对于subplots,我修改了@krs013 的示例,如下所示。每个循环中都必须有clear面板,然后draw

from matplotlib import pyplot as plt

plt.ion()

def plot():
    x = plt.np.arange(-50, 51)
    fig, [ax1, ax2] = plt.subplots(ncols=2)
    fig.canvas.toolbar.zoom()
    for pow in range(1, 5):   # plot x^1, x^2, ..., x^4
        ax1.clear()
        ax1.plot(x, x**pow)
        plt.draw()
        input("Press [enter] to continue.")

plot()

不需要pause
在此处输入图片描述

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用