Ésta es una explicación muy larga que he escrito para un compañero de trabajo mío. Creo que sería útil aquí también. Sé paciente, sin embargo. Llego al verdadero problema que tienes hacia el final. Solo como un adelanto, es una cuestión de tener referencias adicionales a sus objetos Line2D
dando vueltas.
ADVERTENCIA: Otra nota antes de sumergirnos. Si está usando IPython para probar esto, IPython conserva sus propias referencias y no todas son referencias débiles. Por lo tanto, probar la recolección de basura en IPython no funciona. Simplemente confunde las cosas.
Bien, aquí vamos. Cada objeto matplotlib
(Figure
, Axes
, etc.) proporciona acceso a sus artistas secundarios a través de diversos atributos. El siguiente ejemplo es bastante largo, pero debe ser esclarecedor.
Comenzamos creando un objeto Figure
, luego agregamos un objeto Axes
a esa figura. Tenga en cuenta que ax
y fig.axes[0]
son el mismo objeto (el mismo id()
).
>>> #Create a figure
>>> fig = plt.figure()
>>> fig.axes
[]
>>> #Add an axes object
>>> ax = fig.add_subplot(1,1,1)
>>> #The object in ax is the same as the object in fig.axes[0], which is
>>> # a list of axes objects attached to fig
>>> print ax
Axes(0.125,0.1;0.775x0.8)
>>> print fig.axes[0]
Axes(0.125,0.1;0.775x0.8) #Same as "print ax"
>>> id(ax), id(fig.axes[0])
(212603664, 212603664) #Same ids => same objects
Esto también se extiende a las líneas en un ejes del objeto:
>>> #Add a line to ax
>>> lines = ax.plot(np.arange(1000))
>>> #Lines and ax.lines contain the same line2D instances
>>> print lines
[<matplotlib.lines.Line2D object at 0xce84bd0>]
>>> print ax.lines
[<matplotlib.lines.Line2D object at 0xce84bd0>]
>>> print lines[0]
Line2D(_line0)
>>> print ax.lines[0]
Line2D(_line0)
>>> #Same ID => same object
>>> id(lines[0]), id(ax.lines[0])
(216550352, 216550352)
Si se va a llamar plt.show()
usando lo que se hizo anteriormente, que se vería una figura que contiene un conjunto de ejes y una sola línea :
Ahora, si bien hemos visto que el contenido de lines
y es ax.lines
el mismo, es muy importante tener en cuenta que el objeto referenciado por la variable de lines
no es el mismo que el objeto reverenciado por ax.lines
como puede verse por el siguiente:
>>> id(lines), id(ax.lines)
(212754584, 211335288)
Como consecuencia, la eliminación de un elemento de lines
no hace nada con el trazado actual, pero al eliminar un elemento del ax.lines
se elimina esa línea del trazado actual. Por lo tanto:
>>> #THIS DOES NOTHING:
>>> lines.pop(0)
>>> #THIS REMOVES THE FIRST LINE:
>>> ax.lines.pop(0)
lo tanto, si se va a ejecutar la segunda línea de código, se eliminaría el objeto Line2D
contenida en ax.lines[0]
de la trama actual y que se había quedado. Tenga en cuenta que esto también se puede hacer a través de ax.lines.remove()
significado que puede guardar una instancia Line2D
en una variable, luego pasarlo a ax.lines.remove()
eliminar esa línea, así:
>>> #Create a new line
>>> lines.append(ax.plot(np.arange(1000)/2.0))
>>> ax.lines
[<matplotlib.lines.Line2D object at 0xce84bd0>, <matplotlib.lines.Line2D object at 0xce84dx3>]
>>> #Remove that new line
>>> ax.lines.remove(lines[0])
>>> ax.lines
[<matplotlib.lines.Line2D object at 0xce84dx3>]
Todo lo anterior funciona para fig.axes
tan bien como funciona para ax.lines
Ahora, el problema real aquí. Si almacenamos la referencia contenida en ax.lines[0]
en un objeto weakref.ref
, a continuación, intentar eliminarlo, notaremos que no consigue basura recogida:
>>> #Create weak reference to Line2D object
>>> from weakref import ref
>>> wr = ref(ax.lines[0])
>>> print wr
<weakref at 0xb758af8; to 'Line2D' at 0xb757fd0>
>>> print wr()
<matplotlib.lines.Line2D at 0xb757fd0>
>>> #Delete the line from the axes
>>> ax.lines.remove(wr())
>>> ax.lines
[]
>>> #Test weakref again
>>> print wr
<weakref at 0xb758af8; to 'Line2D' at 0xb757fd0>
>>> print wr()
<matplotlib.lines.Line2D at 0xb757fd0>
La referencia sigue vivo! ¿Por qué? Esto se debe a que todavía hay otra referencia al objeto Line2D
al que apunta la referencia en wr
. ¿Recuerda que lines
no tenía la misma ID que ax.lines
pero contenía los mismos elementos? Bueno, ese es el problema.
>>> #Print out lines
>>> print lines
[<matplotlib.lines.Line2D object at 0xce84bd0>, <matplotlib.lines.Line2D object at 0xce84dx3>]
To fix this problem, we simply need to delete `lines`, empty it, or let it go out of scope.
>>> #Reinitialize lines to empty list
>>> lines = []
>>> print lines
[]
>>> print wr
<weakref at 0xb758af8; dead>
Por lo tanto, la moraleja de la historia es, limpiar después de ti mismo. Si espera que algo sea basura, pero no lo es, es probable que deje una referencia en alguna parte.
Ejecuté su código y obtuve: [8:37 pm] @flattop: ~/Escritorio/sandbox> python delete_lines.py Estoy usando matplotlib versión 0.99.1.1 en ubuntu 10.04 –
@David Morton Acabo de degradar a 0.99.1 y ahora reproduzco su problema. Creo que solo puedo recomendar actualizar a 1.0.1.Hubo un * lote * de correcciones de errores desde 0.99.x – Paul
¡Gracias! Agradezco mucho tu ayuda. –