advertencia sobre demasiadas figuras abiertas

En un script donde creo muchas figuras con fix, ax = plt.subplots(...) , aparece la advertencia RuntimeWarning: se han abierto más de 20 figuras. Las figuras creadas a través de la interfaz de pyplot ( matplotlib.pyplot.figure ) se conservan hasta que se cierren de manera explícita y pueden consumir demasiada memoria.

Sin embargo, no entiendo por qué recibo esta advertencia, porque después de guardar la figura con fig.savefig(...) , la fig.clear(); del fig con fig.clear(); del fig fig.clear(); del fig . En ningún punto de mi código, tengo más de una figura abierta a la vez. Aún así, recibo la advertencia sobre demasiadas figuras abiertas. ¿Qué significa eso / cómo puedo evitar recibir la advertencia?

Usa .clf o .cla en tu figura de objeto en lugar de crear una nueva figura. De @DavidZwicker

Suponiendo que ha importado pyplot como

 import matplotlib.pyplot as plt 

plt.cla() borra un eje , es decir, el eje actualmente activo en la figura actual. Deja los otros ejes sin tocar.

plt.clf() borra toda la figura actual con todos sus ejes, pero deja la ventana abierta, de modo que puede reutilizarse para otros gráficos.

plt.close() cierra una ventana , que será la ventana actual, si no se especifica lo contrario. plt.close('all') cerrará todas las figuras abiertas.

La razón por la que del fig no funciona es que la pyplot estado pyplot guarda una referencia a la figura (como debe ser si va a saber cuál es la ‘figura actual’). Esto significa que incluso si elimina su referencia a la figura, hay al menos una referencia en vivo, por lo tanto, nunca será basura.

Dado que estoy encuestando sobre la sabiduría colectiva aquí para esta respuesta, @JoeKington menciona en los comentarios que plt.close(fig) eliminará una instancia de figura específica de la máquina de estado pylab ( plt._pylab_helpers.Gcf ) y permitirá que sea basura recolectada.

Aquí hay un poco más de detalle para ampliar la respuesta de Hooked . Cuando leí por primera vez esa respuesta, clf() las instrucciones para llamar a clf() lugar de crear una nueva figura . clf() por sí solo no ayuda si luego vas y creas otra figura.

Aquí hay un ejemplo trivial que causa la advertencia:

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

Para evitar la advertencia, tengo que llamar a las subplots() fuera del ciclo. Para seguir viendo los rectangularjs, necesito cambiar clf() a cla() . Eso borra el eje sin quitar el eje mismo.

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

Si está generando plots en lotes, es posible que tenga que usar tanto cla() como close() . Me encontré con un problema en el que un lote podía tener más de 20 plots sin quejarse, pero se quejaba después de 20 lotes. Lo arreglé usando cla() después de cada gráfico, y close() después de cada lote.

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

Medí el rendimiento para ver si valía la pena reutilizar la figura dentro de un lote, y este pequeño progtwig de muestra disminuyó de 41 a 49 (20% más lento) cuando acabo de llamar a close() después de cada plot.

Si tiene intenciones de mantener muchas plots a sabiendas en la memoria, pero no quiere que se lo advierta, puede actualizar sus opciones antes de generar cifras.

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

Esto evitará que se emita la advertencia sin cambiar nada sobre la forma en que se gestiona la memoria.