2011-03-22 105 views
14

我想加快將圖表保存爲圖像的過程。現在我正在創建一個cString對象,通過savefig將圖表保存到其中;但我真的很感激任何幫助來改進這種保存圖像的方法。我必須做這個操作幾十次,並且savefig命令非常慢;必須有更好的方式來做到這一點。我讀了一些關於將它保存爲未壓縮的原始圖像的內容,但我不知道如何去做。如果我可以切換到另一個更快的後端,我真的不關心agg。Matplotlib,savefig()的替代方法在保存到CString對象時提高性能?

即:

RAM = cStringIO.StringIO() 

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

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

我一直在使用matplotlib與FigureCanvasAgg後端。

謝謝!

+0

我對這件事並不十分了解。但是你可以看看下面的幫助:'format ='raw''或'format ='rgba''。它看起來像他們產生相同的輸出。 – 2011-03-22 13:24:06

+0

您是否嘗試過分析代碼以查看savefig大部分時間花在哪裏?您是否嘗試過降低分辨率(dpi參數)或其他圖像類型(如果支持,則爲jpeg,gif,tif)? – Bernhard 2011-03-22 15:14:25

+0

@Bernhard:我該怎麼做? – relima 2011-03-22 16:08:09

回答

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)RAW圖像格式,我們看到了一個更加顯著差異:

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秒!顯然,壓縮圖像有很多開銷。

在任何情況下,這可能是一個不必要的複雜例子......我想我只是想避免實際工作...

+0

不錯的例子喬,即使它可能是矯枉過正。我想知道是否將每次迭代繪製的幀保存在磁盤上,然後將它們脫機編譯成動畫gif,或者有人將繪製的幀「in-stream」編譯爲動畫gif嗎?我不是說使用$ animation $模塊,因爲我想保存由交互式(鼠標事件驅動)圖產生的動畫。 – achennu 2013-04-16 07:32:45

+1

那麼,做了一些搜索,我想你的建議可能是這裏顯示:http://stackoverflow.com/a/14986894/467522,對不對? – achennu 2013-04-16 07:37:46

+0

實際上,這個特殊的gif是通過保存每個迭代並離線編譯它們(使用imagemagick的'convert')來完成的。 (我認爲這個例子早於用'animation'模塊釋放matplotlib版本。)無論如何,應該可以使用'ffmpeg'來創建一個動畫gif,但是如果我記得正確的話,使用gif保存'animation'模塊不能正常工作。 (我可能會誤解,現在可能已經修復,無論如何,已經過了一段時間,因爲我已經嘗試過了。) – 2013-04-17 03:14:01

2

我需要快速生成大量的地塊爲好。我發現多處理能夠提高繪圖速度和可用內核的數量。例如,如果100個繪圖在一個進程中花費了10秒,則在任務分成4個內核時花費約3秒。

+7

你能分享你的代碼嗎? – bigbug 2013-02-16 14:57:45

相關問題