2012-05-17 162 views
39

EDIT:matplotlibのバックエンドを 'Qt4Agg'から 'Agg'に変更するとエラーなしでコードを実行できます。これはバックエンドのバグだと思いますか?MatplotlibとPyplot.close()はメモリを解放しませんか?バックエンドに関連するQt4Agg

かなり大量のデータを処理するためのコードを自動的に作成しています。コードはまずすべて自分のデータファイルを解析し、すべての関連ビットを格納します。私は必要なグラフをそれぞれ作成するために異なる機能を持っています(全部で約25種類あります)。しかし、何らかのメモリエラーが発生し続けています.Matplotlib/PyPlotがメモリを正しく解放していないためです。

各プロット関数はpyplot.close(fig)コマンドで終了し、グラフを保存して直ちにそれらを見ないので、は表示されません。にはpyplot.show()が含まれています。

私がインタプリタでプロット関数を個別に実行すると、問題は発生しません。しかし、順番に各プロット関数を呼び出す別の関数を作成すると、 "MemoryError:メモリをパスに割り当てることができませんでした"というエラーが発生します。

誰かがこのような問題に遭遇しましたか?それはMatplotlib runs out of memory when plotting in a loopに関連しているようですが、pyplot.close()は私の問題を解決しません。

これは典型的なプロット機能は私のコードで次のようになります。

def TypicalPlot(self, title=None, comment=False, save=False, show=True): 

    if title is None: 
     title = self.dat.title 

    fig = plt.figure() 
    host = SubplotHost(fig, 111) 
    fig.add_subplot(host) 
    par = host.twinx() 
    host.set_xlabel("Time (hrs)") 
    host.set_ylabel("Power (W)") 
    par.set_ylabel("Temperature (C)") 
    p1, = host.plot(self.dat.timebase1, self.dat.pwr, 'b,', label="Power", 
        markevery= self.skip) 
    p2, = par.plot(self.dat.timebase2, self.dat.Temp1, 'r,', 
        label="Temp 1", markevery= self.skip) 
    p3, = par.plot(self.dat.timebase2, self.dat.Temp2, 'g,', 
        label="Temp 2", markevery= self.skip) 
    p4, = par.plot(self.dat.timebase2, self.dat.Temp3, 'm,', 
        label="Temp 3", markevery= self.skip) 
    host.axis["left"].label.set_color(p1.get_color()) 
    # par.axis["right"].label.set_color(p2.get_color()) 
    #host.legend(loc='lower left') 
    plt.title(title+" Temperature") 

    leg=host.legend(loc='lower left',fancybox=True) 
    #leg.get_frame().set_alpha(0.5) 
    frame = leg.get_frame() 
    frame.set_facecolor('0.80') 

    ### make the legend text smaller 
    for t in leg.get_texts(): 
     t.set_fontsize('small') 

    ### set the legend text color to the same color as the plots for added 
    ### readability 
    leg.get_texts()[0].set_color(p1.get_color()) 
    leg.get_texts()[1].set_color(p2.get_color()) 
    leg.get_texts()[2].set_color(p3.get_color())  
    leg.get_texts()[3].set_color(p4.get_color())   

    if show is True and save is True: 
     plt.show() 
     plt.savefig('temp.png') 
    elif show is True and save is False: 
     plt.show() 
    elif show is False and save is True: 
     plt.savefig('temp.png') 
     plt.clf() 
     plt.close(fig) 

私は今、端末

MyClass.TypicalPlot(save=True, show = False) 

で実行した場合、私はすべてのエラーを得ることはありません。私のプロット関数のすべてについても同じことが当てはまります。

私はこれを行う新機能作る場合:

def saveAllPlots(self, comments = False): 

     if self.comment is None: comment = False 
     else: comment = True 
     self.TypicalPlot(save=True, show=False, comment=comment) 
     self.AnotherPlot(save=True, show=False) 
     self.AnotherPlot2(save=True, show=False) 
     self.AnotherPlot3(save=True, show=False) 
     ...etc, etc, etc 

をそれからそれはグラフの約半分を通ると、私は「MemoryErrorを:パスメモリを割り当てることができませんでした」を得ます。

+0

まで実行されます。それらを閉じる前に数字をクリアしようとしましたか? –

+1

あなたは 'plt.clf()'を試しましたか? – moooeeeep

+3

関数の最後にif/elifの後ろに「del fig」を追加してみてください。 –

答えて

1

私は、それが適切に解放されていない可能性があるため、おそらくメモリが不足している可能性があります。

あなたの代わりにすべてのグラフをやって一つのプログラムのいくつかのグラフを行い、それぞれが約3かそこらのプログラムを作成してみません理由:

プログラム1:グラフ1-8

をプログラム2:グラフ9-16

プログラム3:グラフ17-25

希望これは@FakeDIY役立ちます)私はかつて非常に同様の問題に遭遇し

1

。私はmatplotlibが内部的に各プロットの参照を保持すると仮定します。3つの別々の数字を作成する、次のコードを考える:

import matplotlib.pyplot as plt 
import numpy as np 

# block 1 
f, ax = plt.subplots(1) 
plt.plot(np.arange(10), np.random.random(10)) 
plt.title("first") 
print 'first', sys.getrefcount(f), sys.getrefcount(ax) 

# bock 2 
f, ax = plt.subplots(1) 
plt.plot(np.arange(10), np.random.random(10)+1) 
plt.title("second") 
print 'second', sys.getrefcount(f), sys.getrefcount(ax) 

# block 3 
f, ax = plt.subplots(1) 
plt.plot(np.arange(10), np.random.random(10)+2) 
plt.title("third") 
print 'third', sys.getrefcount(f), sys.getrefcount(ax) 

plt.show() 

print 'after show', sys.getrefcount(f), sys.getrefcount(ax) 

出力:我々はfax数回再定義するので

first 69 26 
second 69 26 
third 69 26 
after show 147 39 

これは、カウンター直感的です。 ブロックごとに、新しい図形を作成しました。図形はpltで参照できます。別の図を作成すると、アクセス可能な最上位の参照がpltに変更されます。しかし、plt.show()にすべての数字を表示できる内部参照が必要です。それらの参照は永続的であるように見えるので、数字はgcによって収集されません。

私が解決した回避策は、プロットのデータを変更することでした。後見では、とにかくより良いアプローチでした:図を開いたままにしておかなければならない欠点のみが欠点です。そして、raw_inputがなければ、プログラムはちょうど

関連する問題