关于python:使用Matplotlib以非阻塞方式绘制

您所在的位置:网站首页 python画图matplotlib代码 关于python:使用Matplotlib以非阻塞方式绘制

关于python:使用Matplotlib以非阻塞方式绘制

2023-12-09 16:29| 来源: 网络整理| 查看: 265

在过去的几天里,我一直在与Numpy和matplotlib一起玩。 我在尝试使matplotlib绘制函数而不阻止执行时遇到问题。 我知道这里已经有很多线程在问类似的问题,并且我已经在Google上搜索了很多,但是还没有成功完成这项工作。

我曾尝试按照某些人的建议使用show(block = False),但是我得到的只是一个冻结的窗口。 如果我简单地调用show(),结果将正确绘制,但执行将被阻塞,直到关闭窗口。 从我读过的其他线程中,我怀疑show(block = False)是否起作用取决于后端。 这个对吗? 我的后端是Qt4Agg。 您能否看一下我的代码,并告诉我是否看到错误? 这是我的代码。 谢谢你的帮助。

12345678910111213141516171819202122from 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。 我忘了说,我想在每次绘制图形时都更新现有窗口,而不是创建一个新窗口。

相关讨论 您是否尝试过在plt.show()之前使用plt.ion()进行matplotlib交互模式?然后,在将每个图生成到子线程中时,它应该是非阻塞的。 @Anzel我刚刚尝试过,但似乎没有什么区别。 您如何运行脚本?如果我从终端/命令提示符处运行示例代码,它似乎可以正常工作,但我认为过去在尝试从IPython QtConsole或IDE执行此类操作时遇到了麻烦。 @Marius Aha !!你是对的。实际上,我是从IDE(PyCharm)的控制台运行它的。从cmd提示符下运行时,plt.show(block = False)运行正常!如果我问你是否有任何想法/解决方案,我会问得太多吗?非常感谢! 我真的不知道抱歉。我不太了解matplotlib如何与控制台交互的详细信息,因此如果需要使用matplotlib进行此操作,通常我只是从命令提示符切换到运行。 没关系,我将在cmd提示符下运行,再次感谢您的帮助。

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

看起来,为了获得您(和我)想要的东西,您需要组合plt.ion(),plt.show()(不推荐使用blocking=False),最重要的是,plt.pause(.001)(或任何时间)你要)。需要暂停是因为GUI事件在主要代码(包括绘图)处于休眠状态时发生。这很可能是通过从休眠线程中获取时间来实现的,所以IDE可能会为此烦恼-我不知道。

这是对我适用于python 3.5的实现:

123456789101112131415161718import 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() 相关讨论 您的回答对解决我遇到的类似问题很有帮助。以前,我先plt.draw后跟plt.show(block = False),但随后它停止工作:图形没有响应,关闭它使iPython崩溃。我的解决方案是删除plt.draw()的每个实例并将其替换为plt.pause(0.001)。而不是像之前的plt.draw一样在其后跟随plt.show(block = False),而在它之前是plt.ion()和plt.show()。我现在有一个MatplotlibDeprecationWarning,但它可以让我绘制图形,因此我对此解决方案感到满意。 请注意,在python 2.7中,您需要使用raw_input而不是input。看这里 当无法使用反应性"动画"方法时,这是非常有用的解决方法!有人知道如何摆脱弃用警告吗? 请有人告诉我为什么在plt.show之前尝试添加plt.ion时为什么得到冻结的命令提示符吗? @GabrielAugusto我不确定会导致什么,而且我不确定您的意思。我刚刚在Python 3.6中测试了此示例,但该示例仍然有效。如果您使用相同的模式并且冻结,则可能是您的安装有问题。您应该先检查法线绘图是否起作用。如果您尝试了其他不同的方法,则注释中没有太多要做。无论哪种情况,您都可以考虑问一个单独的问题。 @ krs013我应该如何编辑此代码,以使图形在结尾处不关闭,并且在matplotlib图形窗口仍处于打开状态的同时执行其余代码? @Adriaan行input("Press [enter] to continue.")将在继续之前暂停程序;您可以将其放在程序末尾以在关闭之前将其停止。程序退出时,该窗口将关闭。如果您想做的事情比所允许的更为复杂,您可能要考虑提出一个新问题。

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

在show内使用block = False参数:plt.show(block = False) 在.py脚本末尾使用另一个plt.show()。

例:

1234567891011import 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()是脚本的最后一行。

相关讨论 这会产生一个空白窗口(对我而言,在Linux,Anaconda,Python 2.7,默认后端上),直到执行完毕(直到最后填满)为止,该空白窗口一直保持空白。这对于在执行过程中更新绘图无用。 :-( @ sh37211不确定您的目标是什么。在某些情况下,您尝试绘制某些内容,但是在plot命令之后还有其他命令,这很有用,因为它允许您绘制并执行其他命令。有关更多信息,请参见此帖子:stackoverflow.com/questions/458209/。如果要更新图,则应采用另一种方法。

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

1234567891011121314151617181920212223242526272829import 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()

结果:

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

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

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

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

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

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

要么

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

如果您使用的是实际数字。 我用@ krs013和@Default Picture的答案来解决这个问题 希望这可以使某人不必在单独的线程上启动每个人物,也不必从阅读这些小说中找出答案。

Iggy的答案对我来说是最容易遵循的,但是在执行后续的subplot命令时却出现了以下错误,而我只是在执行show时不存在该命令:

MatplotlibDeprecationWarning: Adding an axes using the same arguments as a previous axes currently reuses the earlier instance. In a future version, a new instance will always be created and returned. Meanwhile, this warning can be suppressed, and the future behavior ensured, by passing a unique label to each axes instance.

为了避免此错误,它有助于在用户点击Enter后关闭(或清除)绘图。

这是对我有用的代码:

1234567def 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() 实时绘图 12345678910import 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

如果数据量太多,您可以通过一个简单的计数器降低更新率

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

程序退出后的保持图

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

如果您考虑一下,在脚本完成后,程序将终止,并且没有逻辑方式以这种方式保存绘图,因此有两种选择

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

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

SaveToFile和在外部查看器中查看

为此,保存和查看均应快速进行,查看器不应锁定文件,而应自动更新内容

选择保存格式

基于矢量的格式既小又快速

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

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

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

在Windows上,我使用SumatraPDF,它免费,快速,轻便(我的机箱仅使用1.8MB RAM)

在Linux上,有几种选择,例如Evince(GNOME)和Ocular(KDE)

示例代码和结果

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

1234567import 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的屏幕截图,该过程也足够快以获得半实时更新率(我的设置可以在间隔内使用time.sleep()达到10Hz)

Python包drawow允许以非阻塞方式实时更新绘图。 它还可以与网络摄像头和OpenCV配合使用,例如绘制每个帧的度量。 请参阅原始帖子。



【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3