Matplotlib,savefig()的替代品,以便在保存到CString对象时提高性能?

时间:2011-03-22 12:15:23

标签: python performance matplotlib plot cstring

我正在努力加快将图表保存到图像的过程。现在我正在创建一个cString对象,我使用savefig保存图表;但我真的非常感谢任何帮助改进这种保存图像的方法。我必须做几十次这个操作,而savefig命令非常慢;必须有更好的方法。我读了一些关于将其保存为未压缩的原始图像的内容,但我不知道如何做到这一点。如果我可以切换到另一个更快的后端,我真的不关心agg。

即:

RAM = cStringIO.StringIO()

CHART = plt.figure(.... 
**code for creating my chart**

CHART.savefig(RAM, format='png')

我一直在使用带有FigureCanvasAgg后端的matplotlib。

谢谢!

2 个答案:

答案 0 :(得分:33)

如果您只想要原始缓冲区,请尝试fig.canvas.print_rgbfig.canvas.print_raw等(两者之间的差异是raw是rgba,而rgb是rgb。还有print_pngprint_ps等)

这将使用fig.dpi而不是savefig(100 dpi)的默认dpi值。尽管如此,即使比较fig.canvas.print_raw(f)fig.savefig(f, format='raw', dpi=fig.dpi)print_canvas版本稍微快一点也要快得多,因为它不会重新设置轴补丁的颜色等等。 ,savefig默认执行。

尽管如此,大部分时间花在以原始格式保存数字上的只是绘制数字,这是无法绕过的。

无论如何,作为一个毫无意义但又有趣的例子,请考虑以下因素:

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

plt.ion()
fig = plt.figure()
ax = fig.add_subplot(111)
num = 50
max_dim = 10
x = max_dim / 2 * np.ones(num)
s, c = 100 * np.random.random(num), np.random.random(num)
scat = ax.scatter(x,x,s,c)
ax.axis([0,max_dim,0,max_dim])
ax.set_autoscale_on(False)

for i in xrange(1000):
    xy = np.random.random(2*num).reshape(num,2) - 0.5
    offsets = scat.get_offsets() + 0.3 * xy
    offsets.clip(0, max_dim, offsets)
    scat.set_offsets(offsets)
    scat._sizes += 30 * (np.random.random(num) - 0.5)
    scat._sizes.clip(1, 300, scat._sizes)
    fig.canvas.draw()

Brownian walk animation

如果我们查看原始抽奖时间:

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

fig = plt.figure()
ax = fig.add_subplot(111)
num = 50
max_dim = 10
x = max_dim / 2 * np.ones(num)
s, c = 100 * np.random.random(num), np.random.random(num)
scat = ax.scatter(x,x,s,c)
ax.axis([0,max_dim,0,max_dim])
ax.set_autoscale_on(False)

for i in xrange(1000):
    xy = np.random.random(2*num).reshape(num,2) - 0.5
    offsets = scat.get_offsets() + 0.3 * xy
    offsets.clip(0, max_dim, offsets)
    scat.set_offsets(offsets)
    scat._sizes += 30 * (np.random.random(num) - 0.5)
    scat._sizes.clip(1, 300, scat._sizes)
    fig.canvas.draw()

我的机器需要大约25秒。

如果我们将原始RGBA缓冲区转储到cStringIO缓冲区,它实际上在~22秒时稍微快一点(这只是因为我使用的是交互式后端!否则它将是等效的。):

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

fig = plt.figure()
ax = fig.add_subplot(111)
num = 50
max_dim = 10
x = max_dim / 2 * np.ones(num)
s, c = 100 * np.random.random(num), np.random.random(num)
scat = ax.scatter(x,x,s,c)
ax.axis([0,max_dim,0,max_dim])
ax.set_autoscale_on(False)

for i in xrange(1000):
    xy = np.random.random(2*num).reshape(num,2) - 0.5
    offsets = scat.get_offsets() + 0.3 * xy
    offsets.clip(0, max_dim, offsets)
    scat.set_offsets(offsets)
    scat._sizes += 30 * (np.random.random(num) - 0.5)
    scat._sizes.clip(1, 300, scat._sizes)
    ram = cStringIO.StringIO()
    fig.canvas.print_raw(ram)
    ram.close()

如果我们将此与使用savefig进行比较,并使用相对设置的dpi:

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

fig = plt.figure()
ax = fig.add_subplot(111)
num = 50
max_dim = 10
x = max_dim / 2 * np.ones(num)
s, c = 100 * np.random.random(num), np.random.random(num)
scat = ax.scatter(x,x,s,c)
ax.axis([0,max_dim,0,max_dim])
ax.set_autoscale_on(False)

for i in xrange(1000):
    xy = np.random.random(2*num).reshape(num,2) - 0.5
    offsets = scat.get_offsets() + 0.3 * xy
    offsets.clip(0, max_dim, offsets)
    scat.set_offsets(offsets)
    scat._sizes += 30 * (np.random.random(num) - 0.5)
    scat._sizes.clip(1, 300, scat._sizes)
    ram = cStringIO.StringIO()
    fig.savefig(ram, format='raw', dpi=fig.dpi)
    ram.close()

这需要大约23.5秒。基本上,savefig只设置一些默认参数并调用print_raw,在这种情况下,所以差别很小。

现在,如果我们将原始图像格式与压缩图像格式(png)进行比较,我们会发现更显着的差异:

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

fig = plt.figure()
ax = fig.add_subplot(111)
num = 50
max_dim = 10
x = max_dim / 2 * np.ones(num)
s, c = 100 * np.random.random(num), np.random.random(num)
scat = ax.scatter(x,x,s,c)
ax.axis([0,max_dim,0,max_dim])
ax.set_autoscale_on(False)

for i in xrange(1000):
    xy = np.random.random(2*num).reshape(num,2) - 0.5
    offsets = scat.get_offsets() + 0.3 * xy
    offsets.clip(0, max_dim, offsets)
    scat.set_offsets(offsets)
    scat._sizes += 30 * (np.random.random(num) - 0.5)
    scat._sizes.clip(1, 300, scat._sizes)
    ram = cStringIO.StringIO()
    fig.canvas.print_png(ram)
    ram.close()

这需要~52秒!显然,压缩图像会产生很多开销。

无论如何,这可能是一个不必要的复杂例子......我想我只是想避免实际的工作......

答案 1 :(得分:2)

我还需要快速生成大量的情节。我发现多处理可以提高绘图速度和可用内核数量。例如,如果在一个进程中100个绘图需要10秒,那么当任务分成4个核心时需要大约3秒。