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