39

編集: matplotlib のバックエンドを「Qt4Agg」から「Agg」に明示的に変更すると、エラーなしでコードを実行できます。これはバックエンドのバグだと思いますか?

かなり大量のデータを自動的に処理するためのコードを書いています。コードはまず、データ ファイルを解析し、関連するビットをすべて格納します。次に、必要な各グラフを作成するためのさまざまな関数があります (全部で約 25 あります)。ただし、何らかのメモリエラーが発生し続けています。これは、Matplotlib / PyPlot がメモリを正しく解放していないためだと思います。

各プロット関数は pyplot.close(fig) コマンドで終了します。グラフを保存してすぐに見たくないので、pyplot.show() は含まれていません。

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

誰もこのような問題に遭遇しましたか? ループでプロットするときに Matplotlib がメモリ不足になることに関連しているようですが、 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: パスにメモリを割り当てられませんでした」というメッセージが表示されます。

4

2 に答える 2

1

これを行っている理由は、さまざまなグラフをすべて通過するときに、おそらく適切に解放されていないため、メモリが不足しているためだと思います。

1 つのプログラムですべてのグラフを処理するのではなく、それぞれがいくつかのグラフを処理する 3 つほどのプログラムを作成してみてはいかがでしょうか。

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

プログラム 2: グラフ 9 ~ 16

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

これが@FakeDIYに役立つことを願っています:)

于 2016-02-22T18:07:28.497 に答える
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)

出力:

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

何度か定義fし直したので、これは直観に反します。axすべてのブロックで、新しい図を作成しました。これは、 経由で参照できますplt。別の Figure を作成すると、 によってアクセス可能な最上位の参照が変更されpltます。plt.show()ただし、すべての図を表示できる内部参照が必要です。これらの参照は永続的であるように見えるため、数値は gc によって収集されません。

私が解決した回避策は、プロットのデータを変更することでした。後知恵では、とにかくより良いアプローチでした:

plt.ion()
f, ax = plt.subplots(1)
line = ax.plot(np.arange(10), np.random.random(10))[0]
plt.title('first')
plt.show()

for i, s in [(2, 'second'), (3, 'third')]:
    x = np.arange(10)
    y = np.random.random(10)+i
    line.set_data(x, y)
    ax.set_xlim(np.min(x), np.max(x))
    ax.set_ylim(np.min(y), np.max(y))
    plt.title(s)
    plt.draw()
    raw_input(s)

唯一の欠点は、図を開いたままウィンドウを保持する必要があることです。そしてraw_input、プログラムがなければ、ただ実行されます

于 2016-04-24T00:35:37.790 に答える