我目前正在评估不同的python绘图库。现在我正在尝试使用matplotlib,我对性能非常失望。以下示例是从SciPy examples修改而来的,每秒只有~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)
答案 0 :(得分:102)
首先,(虽然这根本不会改变性能)考虑清理代码,类似于:
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图,所以这不是一个很大的问题。
但是,如果不了解您正在做什么,我无法帮助您。
尽管如此,仍然有一种非常中立的方式,但速度相当快。
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()
答案 1 :(得分:19)
Matplotlib可以提供出色的出版品质图形,但速度并不是很好。 有各种各样的python绘图包,其设计考虑了速度:
答案 2 :(得分:10)
首先,Joe Kington's answer使用gui-neutral方法提供非常好的建议,你一定要接受他的建议(特别是关于Blitting)并将其付诸实践。有关此方法的更多信息,请阅读Matplotlib Cookbook
然而,非GUI中立(GUI偏向?)方法是加速绘图的关键。换句话说,backend对于绘制速度非常重要。
在从matplotlib导入其他任何内容之前,请先输入这两行:
import matplotlib
matplotlib.use('GTKAgg')
当然,有多种选择可以代替GTKAgg
使用,但根据前面提到的食谱,这是最快的。有关更多选项,请参阅有关后端的链接。
答案 3 :(得分:5)
对于Joe Kington(.copy_from_bbox& .draw_artist& canvas.blit)提出的第一个解决方案,我必须在 fig.canvas.draw()之后捕获背景线,否则背景没有效果,我得到了与你提到的相同的结果。如果你把它放在fig.show()之后,它仍然不能像Michael Browne所建议的那样工作。
所以只需将 放在 后面的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]
答案 4 :(得分:1)
这可能不适用于你们中的许多人,但我通常在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')