Python Matplotlib,savefig()的替代方案,用于在保存到CString对象时提高性能?

Python Matplotlib,savefig()的替代方案,用于在保存到CString对象时提高性能?,python,performance,matplotlib,plot,cstring,Python,Performance,Matplotlib,Plot,Cstring,我正在尝试加快将图表保存到图像的过程。现在,我正在创建一个cString对象,使用savefig将图表保存到其中;但是我真的非常感谢任何帮助来改进这种保存图像的方法。这个操作我要做几十次,savefig命令非常慢;一定有更好的办法。我读了一些关于将其保存为未压缩的原始图像的内容,但我不知道如何做。如果我能切换到另一个更快的后端,我真的不在乎agg 即: 我一直在使用matplotlib和FigureCanvasAgg后端 谢谢如果您只是想要一个原始缓冲区,请尝试fig.canvas.print\

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

即:

我一直在使用matplotlib和FigureCanvasAgg后端


谢谢

如果您只是想要一个原始缓冲区,请尝试
fig.canvas.print\u rgb
fig.canvas.print\u raw
等(两者之间的区别是
raw
是rgba,而
rgb
是rgb。还有
print\u png
print\u 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()

如果我们查看原始绘制时间:

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秒时稍微快一点(这是因为我使用的是交互式后端!否则它将是等效的。):

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

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\u 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秒!显然,压缩图像会有很多开销


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

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

我对此不太了解。但您可以查看以下帮助:
format='raw'
format='rgba'
。看起来它们产生了相同的输出。您是否尝试过分析代码,以便查看savefig在哪里花费了大部分时间?您是否尝试过降低分辨率(dpi参数)或其他图像类型(jpeg、gif、tif,如果支持)?这是一个很好的例子,Joe,即使这可能有些过分。我想知道您是否将每次迭代绘制的帧保存在磁盘上,然后将其脱机编译成动画gif,或者是否有某种方法将“流中”绘制的帧编译成动画gif?我不是说使用$animation$模块,因为我想保存由交互式(鼠标事件驱动)绘图生成的动画。嗯,进行了一些搜索,我想您的建议可能如下所示:,对吗?实际上,这个特定的gif是通过保存每个迭代并脱机编译而生成的(使用imagemagick的
convert
)(我认为这个例子比带有
动画
模块的matplotlib版本更早发布。)无论如何,应该可以使用
ffmpeg
创建动画gif,但如果我回忆正确,使用
animation
模块保存为gif并不能完全正确工作。(我可能记错了,不管怎样,它现在可能已经被修复了。我已经尝试了一段时间。)意识到这是一个旧线程,但想知道是否有办法避免cStringIO。有纯Matplotlib解决方案吗?
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()
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()