在一个使用fix,ax=plt.subplots(…)
创建许多图形的脚本中,我得到警告RuntimeWarning:已打开20多个图形。通过pyplot接口创建的图形(matplotlib.pypplot.figure
)将被保留,直到显式关闭,并且可能会消耗太多内存。
然而,我不明白为什么会收到这个警告,因为在用fig.savefig(…)
保存图形后,我用figclear()删除了它;del fig
。在我的代码中,我一次打开的数字不超过一个。尽管如此,我还是得到了关于太多公开数字的警告。这意味着什么/我如何避免收到警告?
在您的图形对象上使用. 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})
这将防止在不更改内存管理方式的情况下发出警告。