简体   繁体   English

Matplotlib和Pyplot.close()没有释放内存? - 后端相关的Qt4Agg

[英]Matplotlib and Pyplot.close() not releasing memory? - backend related Qt4Agg

EDIT: If I explicity change the backend for matplotlib from 'Qt4Agg' to just 'Agg' then I am able to run my code with no errors. 编辑:如果我明确地将matplotlib的后端从'Qt4Agg'更改为'Agg',那么我能够运行我的代码而没有错误。 I assume this is a bug in the backend? 我认为这是后端的一个错误?

I am writing some code for processing a fairly large amount of data automatically. 我正在编写一些代码来自动处理相当大量的数据。 The code first of all parses my data files and stores all of the relevant bits. 代码首先解析我的数据文件并存储所有相关的位。 I then have different functions for producing each of the graphs I need (there are about 25 in all). 然后,我有不同的功能来生成我需要的每个图形(总共大约有25个)。 However, I keep running into some kind of memory error and I think it is because Matplotlib / PyPlot are not releasing the memory correctly. 但是,我一直遇到某种内存错误,我认为这是因为Matplotlib / PyPlot没有正确释放内存。

Each plotting function ends with a pyplot.close(fig) command and since I just want to save the graphs and not look at them immediately they do not include a pyplot.show(). 每个绘图函数都以pyplot.close(fig)命令结束,因为我只想保存图形而不立即查看它们,所以它们包含pyplot.show()。

If I run the plotting functions individually in an interpreter then I don't get any problems. 如果我在翻译中单独运行绘图功能,那么我不会遇到任何问题。 However, if I make a separate function which calls each plotting function in turn then I run into a "MemoryError: Could not allocate memory for path". 但是,如果我创建一个单独调用每个绘图函数的函数,那么我会遇到“MemoryError:无法为路径分配内存”。

Has anyone came across a problem like this? 有人遇到过这样的问题吗? It would seem to be related to Matplotlib runs out of memory when plotting in a loop but pyplot.close() doesn't fix my problem. 在绘制循环时,似乎与Matplotlib内存不足有关,但pyplot.close()无法解决我的问题。

This is what a typical plot function looks like in my code: 这是我的代码中典型的绘图函数:

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)

If I now run in a terminal 如果我现在在终端跑

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

Then I don't get any errors. 然后我没有得到任何错误。 The same is true for all of my plot functions. 我的所有绘图功能都是如此。

If I make a new function which does this: 如果我创建一个新函数来执行此操作:

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

Then it runs through about half of the graphs and then I get "MemoryError: Could not allocate memory for path". 然后它运行大约一半的图形,然后我得到“MemoryError:无法为路径分配内存”。

I think the reason it is doing this is because as it goes through all of the different graphs it then runs out of memory probably because it isn't releasing it properly. 我认为这样做的原因是因为它经历了所有不同的图形,然后耗尽内存可能是因为它没有正确地释放它。

Why don't you try creating about 3 or so programs each of which do a few graphs instead of one program doing all the graphs: 为什么不尝试创建大约3个左右的程序,每个程序执行一些图形而不是一个程序执行所有图形:

Program 1: Graphs 1-8 计划1:图1-8

Program 2: Graphs 9-16 计划2:图9-16

Program 3: Graphs 17-25 计划3:图17-25

Hope this helps @FakeDIY : ) 希望这有助于@FakeDIY :)

I run into a very similar problem once. 我遇到过一次非常类似的问题。 I assume matplotlib keeps references for each plots internally. 我假设matplotlib在内部保留每个图的参考。 Given the following code, creating three separate figures: 给出以下代码,创建三个单独的数字:

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)

Output: 输出:

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

This is counter intuitive, because we redefined f and ax several times. 这是违反直觉的,因为我们多次重新定义了fax With every block, we created a new figure, which can be referenced via plt . 对于每个块,我们创建了一个新的图形,可以通过plt引用。 Creating another figure changes the topmost references accessible by plt . 创建另一个数字会更改plt可访问的最顶层引用。 But there must be some internal reference, which allows plt.show() to show all figures. 但必须有一些内部引用,它允许plt.show()显示所有数字。 Those references seem to be persistent and thus the figures won't be collected by the gc. 这些引用似乎是持久性的,因此gc不会收集这些数字。

The workaround I settled with, was changing the data of the plot. 我解决的解决方法是改变情节的数据。 In hindsight it was a better approach anyway: 事后看来,无论如何,这是一个更好的方法:

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)

Only drawback is you have to keep the Window with the figure open. 唯一的缺点是你必须保持窗口打开图形。 And without the raw_input the program will just run through 没有raw_input ,程序就会完成

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM