2010-09-02 16 views
25

Estoy usando matplotlib para generar muchas representaciones de los resultados de una simulación numérica. Las parcelas se utilizan como fotogramas de un vídeo, y por lo que estoy generando muchos de ellos llamando repetidamente a una función similar a éste:Matplotlib Python: la memoria no se libera al especificar el tamaño de la figura

from pylab import * 

def plot_density(filename,i,t,psi_Na): 
    figure(figsize=(8,6)) 
    imshow(abs(psi_Na)**2,origin = 'lower') 
    savefig(filename + '_%04d.png'%i) 
    clf() 

El problema es que el uso de memoria del proceso de pitón crece por una un par de megabytes con cada llamada a esta función. Por ejemplo, si lo llamo con este bucle:

if __name__ == "__main__": 
    x = linspace(-6e-6,6e-6,128,endpoint=False) 
    y = linspace(-6e-6,6e-6,128,endpoint=False) 
    X,Y = meshgrid(x,y) 
    k = 1000000 
    omega = 200 
    times = linspace(0,100e-3,100,endpoint=False) 
    for i,t in enumerate(times): 
     psi_Na = sin(k*X-omega*t) 
     plot_density('wavefunction',i,t,psi_Na) 
     print i 

, entonces el uso de la ram aumenta con el tiempo a 600MB. Sin embargo, si comento la línea figure(figsize=(8,6)) en la definición de la función, entonces el uso del ram se mantiene estable en 52MB. (8,6) es el tamaño de figura predeterminado, por lo que se producen imágenes idénticas en ambos casos. Me gustaría hacer trazados de diferentes tamaños a partir de mis datos numéricos sin quedarme sin RAM. ¿Cómo podría forzar a Python a liberar este recuerdo?

He intentado gc.collect() cada bucle para forzar la recolección de basura, y he intentado f = gcf() para obtener la cifra actual y luego del f para eliminarlo, pero fue en vano.

Estoy ejecutando CPython 2.6.5 en Ubuntu 10.04 de 64 bits.

Respuesta

35

Desde la cadena de documentación para pylab.figure:

In [313]: pylab.figure? 

Si va a crear muchas figuras, que Seguro que llama explícitamente a "cerrar" en las figuras que no esté utilizando, porque esto permitirá pylab para correctamente limpiar la memoria.

Así que tal intento:

pylab.close()  # closes the current figure 
+0

que lo hace! Muchas gracias. –

+2

Sí, 'clf' no elimina la figura ni libera sus recursos, solo la borra. Y 'f = gcf(); del f' solo borra la referencia que acaba de crear, no elimina el objeto figura en sí. Eso es lo que necesitas 'cerrar' para. (+1) –

9

El cierre de una figura es definitivamente una opción, sin embargo, que se repite muchas veces, esto es mucho tiempo. Lo que sugiero es tener un único objeto de figura persistente (a través de static function variable, o como argumento de función adicional). Si ese objeto es fig, la función llamará a fig.clf()antes de en cada ciclo de trazado.

from matplotlib import pylab as pl 
import numpy as np 

TIMES = 10 
x = np.linspace(-10, 10, 100) 
y = np.sin(x) 
def withClose(): 
    def plotStuff(i): 
     fig = pl.figure() 
     pl.plot(x, y + x * i, '-k') 
     pl.savefig('withClose_%03d.png'%i) 
     pl.close(fig) 
    for i in range(TIMES): 
     plotStuff(i) 


def withCLF(): 
    def plotStuff(i): 
     if plotStuff.fig is None: 
      plotStuff.fig = pl.figure() 
     pl.clf() 
     pl.plot(x, y + x * i, '-') 
     pl.savefig('withCLF_%03d.png'%i) 
    plotStuff.fig = None 

    for i in range(TIMES): 
     plotStuff(i) 

Aquí es valora el tiempo

In [7]: %timeit withClose() 
1 loops, best of 3: 3.05 s per loop 

In [8]: %timeit withCLF() 
1 loops, best of 3: 2.24 s per loop 
+1

Agradable. Ahora me queda claro que con cada llamada a 'figure()' en mi ejemplo original estaba creando una nueva figura y no cerraba la anterior. Además de aferrarse a una referencia, también se podría proporcionar el argumento numérico: 'figure (0, figsize = whatever)' para garantizar que se utilizara la misma figura cada vez. –

Cuestiones relacionadas