2012-01-21 479 views
65

我目前正在评估不同的python绘图库。现在我正在尝试matplotlib,并且对性能感到非常失望。下面的例子是从SciPy examples修改过来的,每秒只给我8帧!为什么绘制Matplotlib这么慢?

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

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) 
+0

以下可能是相关的:http://stackoverflow.com/questions/5003094/how-can-i-speed-up-an-animation – NPE

+2

@aix - Glumpy只在这个例子中有所帮助,因为他正在处理快速显示图像数据。这在这种情况下不起作用。 –

+1

尝试更改后端。看到我的答案:http://stackoverflow.com/a/30655528/2066079。或关于后端的这个FAQ:http://matplotlib.org/faq/usage_faq.html#what-is-a-backend – dberm22

回答

85

首先,(虽然这将不会改变的性能)考虑清理你的代码,与此类似:

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,您必须使用后端特定的代码。在实践中,如果你真的担心流畅的动画,你通常会将matplotlib图块嵌入到某种GUI工具箱中,无论如何,这并不是什么问题。

然而,如果不了解更多关于你在做什么,我无法帮到你。

尽管如此,还是有一个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中有一个animations模块。

举个例子:

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() 
+0

你的代码确实非常快,但是我最终得到了每轴2000行!以某种方式“line.set_ydata”创建一个新行,而不是更新它 - 或者是背景只是没有被清除?另外,为什么你的版本更快?只是因为你放弃了“draw()”并将其替换为“ax.draw_artist”? – memyself

+0

在哪个例子中? (我测试了它们,但是可能将错误的版本复制到答案中。)另外,您使用的是哪个版本的matplotlib? –

+0

我的意思是第二个例子。我使用matplotlib版本1.0.1。 – memyself

4

对于由Joe Kington(.copy_from_bbox & .draw_artist & canvas.blit)提出的第一溶液,我不得不捕捉背景之后 fig.canvas.draw()行,否则背景没有效果,我得到了和你所提到的相同的结果。如果你把它放在fig.show()之后,它仍然不能像迈克尔布朗提出的那样工作。

所以只要把背景线的canvas.draw():

[...] 
fig.show() 

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

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

你应该编辑他的答案,而不是作为一个单独发布 – endolith

9

要开始,Joe Kington's answer使用GUI中立的方法提供了非常好的建议,你一定要带他建议(特别是关于Blitting)并将其付诸实践。有关此方法的更多信息,请参阅Matplotlib Cookbook

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

把这两行从matplotlib导入之前别的:

import matplotlib 
matplotlib.use('GTKAgg') 

当然,也有使用,而不是GTKAgg各种选项,但根据前面提到的食谱,这是最快的。查看关于后端的链接以获取更多选项。

+0

这只适用于Windows,你知道一种方法,使其在Mac上工作。它是Windows特定的原因是pygtk是特定于Windows的 – user308827

+1

pygtk不是Windows特定的。事实上,让它在Windows下工作是一个巨大的痛苦(如果它甚至有可能,我已经放弃了。) –

1

这可能不适用于你们许多人,但我通常在Linux下操作我的电脑,所以默认情况下我将我的matplotlib图保存为PNG和SVG。这在Linux下运行良好,但是在我的Windows 7安装[MiKTeX在Python(x,y)或Anaconda下]很慢,所以我已经开始添加此代码,并且在那里再次正常工作:

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')