提问者:小点点

警告打开的数字太多


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

然而,我不明白为什么会收到这个警告,因为在用fig.savefig(…)保存图形后,我用figclear()删除了它;del fig。在我的代码中,我一次打开的数字不超过一个。尽管如此,我还是得到了关于太多公开数字的警告。这意味着什么/我如何避免收到警告?


共3个答案

匿名用户

在您的图形对象上使用. clf.cla,而不是创建新图形。来自@DavidZwicker

假设您已经将< code>pyplot导入为

import matplotlib.pyplot as plt

plt.cla() 清除一个轴,即当前图中当前活动的轴。它使其他轴保持不变。

plt.clf()清除整个当前图形及其所有轴,但使窗口保持打开状态,这样可以将其重新用于其他绘图。

plt.close()关闭一个窗口,如果未另行指定,该窗口将是当前窗口。plt.close('all')将关闭所有打开的图形。

del fig 不起作用的原因是 pyplot 状态机保留了对图形的引用(如果它要知道“当前图形”是什么,它必须这样做)。这意味着即使您删除了对该图的引用,也至少有一个实时引用,因此它永远不会被垃圾回收。

由于我在这里对这个答案的集体智慧进行投票,@JoeKington在评论中提到,plt.close(fig)将从pylab状态机(plt._pylab_helpers.Gcf)中删除一个特定的图形实例,并允许它被垃圾收集。

匿名用户

这里有更多细节来扩展Hooked的答案。当我第一次阅读该答案时,我错过了调用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()off()。我遇到了一个问题,一个批次可以有20多个绘图而不抱怨,但它会在20个批次后抱怨。我通过在每个绘图后使用cla()和在每个批次后使用off()来解决这个问题。

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

我测量了性能,看看是否值得在批次中重用该图,当我在每个绘图后调用 close() 时,这个小示例程序从 41s 减慢到 49s(慢 20%)。

匿名用户

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

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

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