Python 为什么使用Matplotlib绘图如此缓慢?

Python 为什么使用Matplotlib绘图如此缓慢?,python,matplotlib,Python,Matplotlib,我目前正在评估不同的python绘图库。现在我正在尝试matplotlib,我对它的性能非常失望。下面的示例是从中修改的,每秒仅提供~8帧 有没有加快速度的方法,或者我应该选择一个不同的绘图库 from pylab import * import time ion() fig = figure() ax1 = fig.add_subplot(611) ax2 = fig.add_subplot(612) ax3 = fig.add_subplot(613) ax4 = fig.add_subp

我目前正在评估不同的python绘图库。现在我正在尝试matplotlib,我对它的性能非常失望。下面的示例是从中修改的,每秒仅提供~8帧

有没有加快速度的方法,或者我应该选择一个不同的绘图库

from pylab import *
import time

ion()
fig = figure()
ax1 = fig.add_subplot(611)
ax2 = fig.add_subplot(612)
ax3 = fig.add_subplot(613)
ax4 = fig.add_subplot(614)
ax5 = fig.add_subplot(615)
ax6 = fig.add_subplot(616)

x = arange(0,2*pi,0.01)
y = sin(x)
line1, = ax1.plot(x, y, 'r-')
line2, = ax2.plot(x, y, 'g-')
line3, = ax3.plot(x, y, 'y-')
line4, = ax4.plot(x, y, 'm-')
line5, = ax5.plot(x, y, 'k-')
line6, = ax6.plot(x, y, 'p-')

# turn off interactive plotting - speeds things up by 1 Frame / second
plt.ioff()


tstart = time.time()               # for profiling
for i in arange(1, 200):
    line1.set_ydata(sin(x+i/10.0))  # update the data
    line2.set_ydata(sin(2*x+i/10.0))
    line3.set_ydata(sin(3*x+i/10.0))
    line4.set_ydata(sin(4*x+i/10.0))
    line5.set_ydata(sin(5*x+i/10.0))
    line6.set_ydata(sin(6*x+i/10.0))
    draw()                         # redraw the canvas

print 'FPS:' , 200/(time.time()-tstart)

首先,(尽管这不会改变性能)考虑清理代码,类似于:

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

x = np.arange(0, 2*np.pi, 0.01)
y = np.sin(x)

fig, axes = plt.subplots(nrows=6)
styles = ['r-', 'g-', 'y-', 'm-', 'k-', 'c-']
lines = [ax.plot(x, y, style)[0] for ax, style in zip(axes, styles)]

fig.show()

tstart = time.time()
for i in xrange(1, 20):
    for j, line in enumerate(lines, start=1):
        line.set_ydata(np.sin(j*x + i/10.0))
    fig.canvas.draw()

print 'FPS:' , 20/(time.time()-tstart)
在上面的例子中,我得到大约10fps

请注意,根据具体的用例,matplotlib可能不是一个很好的选择。它面向出版物质量数据,而不是实时显示

但是,您可以做很多事情来加速这个示例

有两个主要的原因,为什么这是缓慢的,因为它是

1) 调用
fig.canvas.draw()。这是你的瓶颈。在您的情况下,不需要重新绘制轴边界、记号标签等

2) 在你的例子中,有很多子地块,有很多勾号标签。这些画要花很长时间

这两个问题都可以通过使用blitting来解决

为了有效地执行blitting,您必须使用特定于后端的代码。在实践中,如果您真的担心平滑的动画,您通常会在某种gui工具包中嵌入matplotlib绘图,所以这不是什么大问题

但是,如果我不知道你在做什么,我就帮不了你

尽管如此,仍然有一种与gui无关的方法可以相当快地完成

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

x = np.arange(0, 2*np.pi, 0.1)
y = np.sin(x)

fig, axes = plt.subplots(nrows=6)

fig.show()

# We need to draw the canvas before we start animating...
fig.canvas.draw()

styles = ['r-', 'g-', 'y-', 'm-', 'k-', 'c-']
def plot(ax, style):
    return ax.plot(x, y, style, animated=True)[0]
lines = [plot(ax, style) for ax, style in zip(axes, styles)]

# Let's capture the background of the figure
backgrounds = [fig.canvas.copy_from_bbox(ax.bbox) for ax in axes]

tstart = time.time()
for i in xrange(1, 2000):
    items = enumerate(zip(lines, axes, backgrounds), start=1)
    for j, (line, ax, background) in items:
        fig.canvas.restore_region(background)
        line.set_ydata(np.sin(j*x + i/10.0))
        ax.draw_artist(line)
        fig.canvas.blit(ax.bbox)

print 'FPS:' , 2000/(time.time()-tstart)
这给了我大约200fps

为了方便起见,matplotlib的最新版本中有一个
动画
模块

例如:

import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np

x = np.arange(0, 2*np.pi, 0.1)
y = np.sin(x)

fig, axes = plt.subplots(nrows=6)

styles = ['r-', 'g-', 'y-', 'm-', 'k-', 'c-']
def plot(ax, style):
    return ax.plot(x, y, style, animated=True)[0]
lines = [plot(ax, style) for ax, style in zip(axes, styles)]

def animate(i):
    for j, line in enumerate(lines, start=1):
        line.set_ydata(np.sin(j*x + i/10.0))
    return lines

# We'd normally specify a reasonable "interval" here...
ani = animation.FuncAnimation(fig, animate, xrange(1, 200), 
                              interval=0, blit=True)
plt.show()

Matplotlib可以生成高质量的图形,但在速度方面没有得到很好的优化。 有各种各样的python绘图软件包,它们的设计都考虑了速度:


  • [编辑:不再维护pyqwt;先前的维护者正在推荐pyqtgraph]

对于(.copy_from_bbox&.draw_artist&canvas.blit)提出的第一个解决方案,我必须在fig.canvas.draw()行之后捕获背景,否则背景没有效果,我得到的结果与您提到的相同。如果你把它放在fig.show()后面,它仍然不能像迈克尔·布朗所建议的那样工作

因此,只需将背景线放在画布的后面即可。draw()

首先,使用gui中立的方法提供了非常好的建议,您一定要采纳他的建议(特别是关于Blitting的建议)并将其付诸实践。有关此方法的更多信息,请阅读

然而,非GUI中立(GUI偏向?)方法是加速绘图的关键。换句话说,速度对绘图速度非常重要

在从matplotlib导入任何其他内容之前,请先放置以下两行:

import matplotlib
matplotlib.use('GTKAgg') 

当然,可以使用各种选项来代替
GTKAgg
,但根据前面提到的食谱,这是最快的。有关更多选项,请参阅关于后端的链接。

这可能不适用于许多人,但我通常在Linux下操作计算机,因此默认情况下,我将matplotlib绘图保存为PNG和SVG。这在Linux下运行良好,但在我的Windows 7安装上速度慢得令人无法忍受[Python(x,y)或Anaconda下的MiKTeX],因此我开始添加这段代码,并且在那里运行良好:

import platform     # Don't save as SVG if running under Windows.
#
# Plot code goes here.
#
fig.savefig('figure_name.png', dpi = 200)
if platform.system() != 'Windows':
    # In my installations of Windows 7, it takes an inordinate amount of time to save
    # graphs as .svg files, so on that platform I've disabled the call that does so.
    # The first run of a script is still a little slow while everything is loaded in,
    # but execution times of subsequent runs are improved immensely.
    fig.savefig('figure_name.svg')

以下内容可能与此相关:@aix-Glumpy仅在该示例中有所帮助,因为他正在处理快速显示的图像数据。在这种情况下没有帮助。请尝试更改后端。请参阅我的答案:。或者这个关于后端的常见问题解答:使用
fig.canvas.draw\u idle()
而不是
fig.canvas.draw()
对我来说很有效。你的代码确实非常快,但是我最终每个轴有2000行!不知何故,“line.set_ydata”创建了一个新行,而不是更新它——或者背景没有被清除?另外,为什么你的版本要快得多?就因为你删除了“draw()”并用“ax.draw\u artist”替换了它?在哪个例子中?(我测试了它们,但有可能复制粘贴了错误的版本到答案中。)此外,您使用的是哪个版本的matplotlib?这里有一个指向生成图像的链接。这可能是我的图形卡造成的瑕疵吗?我在I.imgur.com/aBRFz.png中看到的东西与memyself在I.imgur.com/aBRFz.png中看到的一样,直到我将背景捕获移到fig.show()下面。很好,但是
animation
似乎会在
interval
一段时间内更新绘图,如果我只想在新数据准备好时更新它呢?你应该编辑他的答案,而不是作为单独的答案发布。这只适用于windows,你知道一种方法让它在Mac上工作吗。它是windows专用的原因是pygtk是windows专用的pygtk不是windows专用的。事实上,让它在Windows下工作是一件非常痛苦的事情(如果可能的话,我已经放弃了)。我非常喜欢实时流数据。干得好,卢克
import platform     # Don't save as SVG if running under Windows.
#
# Plot code goes here.
#
fig.savefig('figure_name.png', dpi = 200)
if platform.system() != 'Windows':
    # In my installations of Windows 7, it takes an inordinate amount of time to save
    # graphs as .svg files, so on that platform I've disabled the call that does so.
    # The first run of a script is still a little slow while everything is loaded in,
    # but execution times of subsequent runs are improved immensely.
    fig.savefig('figure_name.svg')