关于太多开放数字的警告

新手上路,请多包涵

在我使用 fix, ax = plt.subplots(...) 创建许多图形的脚本中,我收到警告 RuntimeWarning: More more than 20 figures have been opened。通过 pyplot 接口 ( matplotlib.pyplot.figure ) 创建的图形将保留到明确关闭,并且可能会消耗太多内存。

但是,我不明白 为什么 会收到此警告,因为在使用 fig.savefig(...) 保存图形后,我使用 fig.clear(); del fig 将其删除。在我的代码中,我一次打开不止一个图形。尽管如此,我还是收到了太多开放数字的警告。这是什么意思/我怎样才能避免收到警告?

原文由 andreas-h 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.6k
2 个回答

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

假设您已导入 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 发布,翻译遵循 CC BY-SA 3.0 许可协议

这里有更多细节来扩展 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()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()

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

原文由 Don Kirkby 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题