Matplotlib和Pyplot.close()不释放内存? -后端相关的Qt4Agg [英] Matplotlib and Pyplot.close() not releasing memory? - backend related Qt4Agg

查看:204
本文介绍了Matplotlib和Pyplot.close()不释放内存? -后端相关的Qt4Agg的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我明确将matplotlib的后端从'Qt4Agg'更改为'Agg',那么我可以无错误地运行我的代码.我认为这是后端中的错误?

If I explicity change the backend for matplotlib from 'Qt4Agg' to just 'Agg' then I am able to run my code with no errors. I assume this is a bug in the backend?

我正在编写一些用于自动处理大量数据的代码.该代码首先解析我的数据文件并存储所有相关位.然后,我将使用不同的函数来生成所需的每张图(总共约25张).但是,我一直遇到某种内存错误,我认为这是因为Matplotlib/PyPlot无法正确释放内存.

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). However, I keep running into some kind of memory error and I think it is because Matplotlib / PyPlot are not releasing the memory correctly.

每个绘图功能都以pyplot.close(fig)命令结尾,由于我只想保存图形而不是立即查看它们,因此它们 not 都没有pyplot.show().

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().

如果我在解释器中单独运行绘图功能,那么我不会遇到任何问题.但是,如果我做一个单独的函数又依次调用每个绘图函数,则会遇到"MemoryError:无法为路径分配内存"的问题.

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".

有人遇到过这样的问题吗?它似乎与 Matplotlib耗尽有关循环绘制时内存不足,但是pyplot.close()不能解决我的问题.

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.

这是典型的绘图函数在我的代码中的样子:

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

然后它遍历大约一半的图形,然后出现"MemoryError:无法为路径分配内存".

Then it runs through about half of the graphs and then I get "MemoryError: Could not allocate memory for path".

推荐答案

我曾经遇到一个非常相似的问题.我假设matplotlib在内部保留每个图的引用.给定以下代码,创建三个单独的图形:

I run into a very similar problem once. I assume matplotlib keeps references for each plots internally. 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)

输出:

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


这是反直观的,因为我们多次重新定义了fax. 对于每个块,我们都创建了一个新图形,可以通过plt进行引用.创建另一个图形会更改plt可访问的最上面的引用.但是必须有一些内部参考,这允许plt.show()显示所有数字.这些引用似乎是永久性的,因此gc不会收集这些数字.


This is counter intuitive, because we redefined f and ax several times. With every block, we created a new figure, which can be referenced via plt. Creating another figure changes the topmost references accessible by plt. But there must be some internal reference, which allows plt.show() to show all figures. Those references seem to be persistent and thus the figures won't be collected by the 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)

唯一的缺点是您必须保持窗口处于打开状态.如果没有raw_input,程序将直接运行

Only drawback is you have to keep the Window with the figure open. And without the raw_input the program will just run through

这篇关于Matplotlib和Pyplot.close()不释放内存? -后端相关的Qt4Agg的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆