在我使用fix, ax = plt.subplots(…)创建许多图形的脚本中,我得到警告RuntimeWarning:超过20个图形已被打开。通过pyplot接口(matplotlib.pyplot.figure)创建的图形将被保留,直到显式关闭,并且可能会消耗太多内存。

然而,我不明白为什么我会得到这个警告,因为在用fig.savefig(…)保存图形后,我用fig.clear()删除它;在我的代码中,我没有一次打开一个以上的数字。尽管如此,我还是得到了关于太多未公开数字的警告。这是什么意思/我怎样才能避免得到警告?


当前回答

如果你只是想暂时抑制警告,这也很有用:

import matplotlib.pyplot as plt
       
with plt.rc_context(rc={'figure.max_open_warning': 0}):
    lots_of_plots()

其他回答

如果您有意在内存中保留许多图,但不想收到警告,则可以在生成图形之前更新选项。

import matplotlib.pyplot as plt
plt.rcParams.update({'figure.max_open_warning': 0})

这将防止在不改变内存管理方式的情况下发出警告。

下面的代码片段为我解决了这个问题:


class FigureWrapper(object):
    '''Frees underlying figure when it goes out of scope. 
    '''

    def __init__(self, figure):
        self._figure = figure

    def __del__(self):
        plt.close(self._figure)
        print("Figure removed")


# .....
    f, ax = plt.subplots(1, figsize=(20, 20))
    _wrapped_figure = FigureWrapper(f)

    ax.plot(...
    plt.savefig(...
# .....

当_wrapped_figure超出作用域时,运行时调用我们的__del__()方法,其中包含plt.close()。即使在_wrapped_figure构造函数之后触发异常,也会发生这种情况。

如果你只是想暂时抑制警告,这也很有用:

import matplotlib.pyplot as plt
       
with plt.rc_context(rc={'figure.max_open_warning': 0}):
    lots_of_plots()

这里有更多的细节来扩展hook的答案。当我第一次阅读这个答案时,我错过了调用clf()而不是创建一个新图形的指令。Clf()本身并不能帮助您创建另一个图形。

下面是一个引起警告的小例子:

from matplotlib import pyplot as plt, patches
import os


def main():
    path = 'figures'
    for i in range(21):
        _fig, ax = plt.subplots()
        x = range(3*i)
        y = [n*n for n in x]
        ax.add_patch(patches.Rectangle(xy=(i, 1), width=i, height=10))
        plt.step(x, y, linewidth=2, where='mid')
        figname = 'fig_{}.png'.format(i)
        dest = os.path.join(path, figname)
        plt.savefig(dest)  # write image to file
        plt.clf()
    print('Done.')

main()

为了避免出现警告,我必须将对subplots()的调用拉到循环之外。为了继续看到矩形,我需要将clf()切换到cla()。这在不移除轴本身的情况下清除了轴。

from matplotlib import pyplot as plt, patches
import os


def main():
    path = 'figures'
    _fig, ax = plt.subplots()
    for i in range(21):
        x = range(3*i)
        y = [n*n for n in x]
        ax.add_patch(patches.Rectangle(xy=(i, 1), width=i, height=10))
        plt.step(x, y, linewidth=2, where='mid')
        figname = 'fig_{}.png'.format(i)
        dest = os.path.join(path, figname)
        plt.savefig(dest)  # write image to file
        plt.cla()
    print('Done.')

main()

如果要批量生成图,可能必须同时使用cla()和close()。我遇到了一个问题,一个批次可以有超过20个地块而没有抱怨,但它会在20个批次后抱怨。我在每个绘图后使用cla(),在每个批处理后使用close()来解决这个问题。

from matplotlib import pyplot as plt, patches
import os


def main():
    for i in range(21):
        print('Batch {}'.format(i))
        make_plots('figures')
    print('Done.')


def make_plots(path):
    fig, ax = plt.subplots()
    for i in range(21):
        x = range(3 * i)
        y = [n * n for n in x]
        ax.add_patch(patches.Rectangle(xy=(i, 1), width=i, height=10))
        plt.step(x, y, linewidth=2, where='mid')
        figname = 'fig_{}.png'.format(i)
        dest = os.path.join(path, figname)
        plt.savefig(dest)  # write image to file
        plt.cla()
    plt.close(fig)


main()

我测量了性能,看看是否值得在批处理中重用图形,当我在每个plot之后调用close()时,这个小示例程序的速度从41秒减慢到49秒(慢了20%)。

matplotlib by default keeps a reference of all the figures created through pyplot. If a single variable used for storing matplotlib figure (e.g "fig") is modified and rewritten without clearing the figure, all the plots are retained in RAM memory. Its important to use plt.cla() and plt.clf() instead of modifying and reusing the fig variable. If you are plotting thousands of different plots and saving them without clearing the figure, then eventually your RAM will get exhausted and program will get terminated. Clearing the axes and figures have a significant impact on memory usage if you are plotting many figures. You can monitor your RAM consumption in task manager (Windows) or in system monitor (Linux). First your RAM will get exhausted, then the OS starts consuming SWAP memory. Once both are exhausted, the program will get automatically terminated. Its better to clear figures, axes and close them if they are not required.