Questo è un tempo molto lungo spiegazione che ho scritto per un collega di miniera. Penso che sarebbe utile anche qui. Sii paziente, però. Arrivo al vero problema che stai avendo verso la fine. Proprio come un teaser, è un problema di avere riferimenti extra ai tuoi oggetti Line2D
in giro.
ATTENZIONE: Un'altra nota prima di immergerci. Se si sta utilizzando IPython per verificarlo, IPython mantiene i propri riferimenti e non tutti sono weakrefs. Quindi, testare la garbage collection in IPython non funziona. Semplicemente confonde le cose.
Ok, ci siamo. Ogni oggetto matplotlib
(Figure
, Axes
, ecc.) Fornisce l'accesso ai suoi artisti figlio tramite vari attributi. L'esempio seguente sta diventando piuttosto lungo, ma dovrebbe essere illuminante.
Iniziamo creando un oggetto Figure
, quindi aggiungere un oggetto Axes
a tale figura. Notare che ax
e fig.axes[0]
sono lo stesso oggetto (stesso 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
Questo si estende anche alle linee in un asse oggetto:
>>> #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)
Se si dovesse chiamare plt.show()
con quanto fatto in precedenza, si vede una figura contenente una serie di assi e una singola linea :

Ora, mentre abbiamo visto che i contenuti di lines
e ax.lines
è lo stesso, è molto importante notare che l'oggetto si riferisce la variabile lines
non è la stessa come l'oggetto riverito da ax.lines
come si può vedere dalla seguente:
>>> id(lines), id(ax.lines)
(212754584, 211335288)
Di conseguenza, la rimozione di un elemento da lines
non esegue nulla per il grafico corrente, ma la rimozione di un elemento da ax.lines
rimuove quella linea dal grafico corrente. Quindi:
>>> #THIS DOES NOTHING:
>>> lines.pop(0)
>>> #THIS REMOVES THE FIRST LINE:
>>> ax.lines.pop(0)
Quindi, se si dovesse eseguire la seconda riga di codice, è necessario rimuovere l'oggetto Line2D
contenuta nel ax.lines[0]
dalla trama attuale e sarebbe andato. Si noti che questo può essere fatto anche tramite ax.lines.remove()
senso che è possibile salvare un'istanza Line2D
in una variabile, poi passarlo a ax.lines.remove()
cancellare quella linea, in questo modo:
>>> #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>]

Tutti i suddetti articoli per fig.axes
funzionano altrettanto bene per ax.lines
Ora, il vero problema qui. Se conserviamo il riferimento contenuto in ax.lines[0]
in un oggetto weakref.ref
, quindi tentare di eliminarlo, noteremo che non ottiene garbage collection:
>>> #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>
Il riferimento è ancora vivo! Perché? Questo perché esiste ancora un altro riferimento all'oggetto Line2D
a cui punta il riferimento in wr
. Ricorda come lo lines
non aveva lo stesso ID di ax.lines
ma conteneva gli stessi elementi? Bene, questo è il 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>
Quindi, la morale della storia è, ripulisci te stesso. Se ti aspetti che qualcosa sia raccolto dalla spazzatura ma non lo è, probabilmente lascerai un riferimento da qualche parte.
Ho eseguito il codice e ho ricevuto: [8:37 pm] @flattop: ~/Desktop/sandbox> python delete_lines.py Sto usando la versione di matplotlib 0.99.1.1 in ubuntu 10.04 –
@David Morton Ho appena effettuato il downgrade a 0.99.1 e ora riproduco il problema. Credo di poter solo raccomandare l'aggiornamento a 1.0.1.C'era un * lotto * di bugfix dal 0.99.x – Paul
Grazie! Apprezzo molto il tuo aiuto. –