En un script donde creo muchas figuras fix, ax = plt.subplots(...)
, recibo la advertencia RuntimeWarning: se han abierto más de 20 figuras. Las figuras creadas a través de la interfaz pyplot ( matplotlib.pyplot.figure
) se conservan hasta que se cierren explícitamente 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 elimino con 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?
python
python-3.x
matplotlib
andreas-h
fuente
fuente
plt
completo. Por ejemplo stackoverflow.com/a/16337909/325565 (No para conectar una de mis propias respuestas, pero es la que pude encontrar más rápido ...)Respuestas:
Use
.clf
o.cla
en su objeto de figura en lugar de crear una nueva figura. De @DavidZwickerSuponiendo que haya importado
pyplot
comoplt.cla()
borra un eje , es decir, el eje actualmente activo en la figura actual. Deja los otros ejes intactos.plt.clf()
borra toda la figura actual con todos sus ejes, pero deja la ventana abierta, de modo que puede reutilizarse para otros trazados.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 lapyplot
máquina de estado mantiene 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 se recolectará basura.Dado que estoy investigando la sabiduría colectiva aquí para esta respuesta, @JoeKington menciona en los comentarios que
plt.close(fig)
eliminarán una instancia de figura específica de la máquina de estado pylab ( plt._pylab_helpers.Gcf ) y permitirá que se recolecte basura.fuente
clf
para lafigure
clase, pero noclose
. ¿Por qué endel fig
realidad no cierra y elimina la figura?close
no funcionará en el objeto de la figura, llámelo comoplt.close()
, en lugar defig.clf()
.del fig
no funciona es que darle un__del__
método (que básicamente llamaríaplt.close(fig)
) terminaría causando referencias circulares en este caso particular, yfig
tener un__del__
método hará que otras cosas no se recojan basura . (O ese es mi vago recuerdo, de todos modos.) En cualquier caso, sin duda es un poco molesto, pero debería llamar enplt.close(fig)
lugar dedel fig
. En una nota al margen, matplotlib realmente podría usar un administrador de contexto para esto ...plt.close(fig)
eliminará una instancia de figura específica de la máquina de estado de pylab (plt._pylab_helpers.Gcf
) y permitirá que se recolecte basura.plt
es un poco desordenado y hay pensamientos sobre cómo volver a hacer un montón de cosas. El administrador de contexto es intrigante ... Ver github.com/matplotlib/matplotlib/pull/2736 , github.com/matplotlib/matplotlib/pull/2624Aquí hay un poco más de detalle para ampliar la respuesta de Hooked . Cuando leí esa respuesta por primera vez, me perdí las instrucciones para llamar en
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:
Para evitar la advertencia, tengo que tirar de la llamada
subplots()
fuera del bucle. Para seguir viendo los rectángulos, necesito cambiarclf()
acla()
. Eso despeja el eje sin quitar el eje mismo.Si está generando gráficos en lotes, es posible que tenga que usar ambos
cla()
yclose()
. Me encontré con un problema en el que un lote podía tener más de 20 parcelas sin quejarse, pero se quejaría después de 20 lotes. Lo arreglé usandocla()
después de cada parcela yclose()
después de cada lote.Medí el rendimiento para ver si valía la pena reutilizar la cifra dentro de un lote, y este pequeño programa de muestra disminuyó de 41 a 49 (20% más lento) cuando llamé
close()
después de cada trama.fuente
Si tiene la intención de mantener a sabiendas muchas parcelas en la memoria, pero no desea que se le advierta al respecto, puede actualizar sus opciones antes de generar cifras.
Esto evitará que se emita la advertencia sin cambiar nada sobre la forma en que se gestiona la memoria.
fuente
El siguiente fragmento resolvió el problema para mí:
Cuando
_wrapped_figure
sale del alcance, el tiempo de ejecución llama a nuestro__del__()
método conplt.close()
inside. Sucede incluso si la excepción se dispara después del_wrapped_figure
constructor.fuente
Esto también es útil si solo desea suprimir temporalmente la advertencia:
fuente