Dies ist eine sehr lange Erklärung, die ich für einen meiner Kollegen geschrieben habe. Ich denke, das wäre auch hier hilfreich. Sei aber geduldig. Ich komme zu dem eigentlichen Problem, das Sie gegen Ende haben. Nur als Teaser geht es darum, zusätzliche Verweise auf Ihre zu habenLine2D
Objekte zu haben.
WARNUNG: Noch ein Hinweis, bevor wir eintauchen. Wenn Sie IPython zum Testen verwenden, behält IPython eigene Referenzen bei und nicht alle sind Schwachstellen. Das Testen der Garbage Collection in IPython funktioniert also nicht. Es verwirrt nur die Dinge.
Okay, los geht's. Jedes matplotlib
Objekt ( Figure
, Axes
usw.) bietet Zugang zu seinem Kind Künstler über verschiedene Attribute. Das folgende Beispiel wird ziemlich lang, sollte aber leuchten.
Wir beginnen mit der Erstellung eines Figure
Objekts und fügen Axes
dieser Figur dann ein Objekt hinzu. Beachten Sie, dass ax
und fig.axes[0]
dasselbe Objekt sind (dasselbe id()
).
>>>
>>> fig = plt.figure()
>>> fig.axes
[]
>>>
>>> ax = fig.add_subplot(1,1,1)
>>>
>>>
>>> print ax
Axes(0.125,0.1;0.775x0.8)
>>> print fig.axes[0]
Axes(0.125,0.1;0.775x0.8)
>>> id(ax), id(fig.axes[0])
(212603664, 212603664)
Dies erstreckt sich auch auf Linien in einem Achsenobjekt:
>>>
>>> lines = ax.plot(np.arange(1000))
>>>
>>> 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)
>>>
>>> id(lines[0]), id(ax.lines[0])
(216550352, 216550352)
Wenn Sie mit den oben beschriebenen Schritten anrufen plt.show()
würden, würden Sie eine Abbildung sehen, die einen Satz Achsen und eine einzelne Zeile enthält:
Obwohl wir gesehen haben, dass der Inhalt von lines
und ax.lines
derselbe ist, ist es sehr wichtig zu beachten, dass das Objekt, auf das die lines
Variable verweist, nicht dasselbe ist wie das Objekt , auf das verwiesen wird ax.lines
, wie aus dem Folgenden ersichtlich ist:
>>> id(lines), id(ax.lines)
(212754584, 211335288)
Infolgedessen hat das Entfernen eines Elements aus lines
nichts mit dem aktuellen Plot zu tun, aber das Entfernen eines Elements aus ax.lines
entfernt diese Linie aus dem aktuellen Plot. Damit:
>>>
>>> lines.pop(0)
>>>
>>> ax.lines.pop(0)
Wenn Sie also die zweite Codezeile ausführen würden, würden Sie das darin Line2D
enthaltene Objekt ax.lines[0]
aus dem aktuellen Plot entfernen und es wäre verschwunden. Beachten Sie, dass dies auch über die ax.lines.remove()
Bedeutung erfolgen kann, dass Sie eine Line2D
Instanz in einer Variablen speichern und dann an übergeben können ax.lines.remove()
, um diese Zeile wie folgt zu löschen:
>>>
>>> lines.append(ax.plot(np.arange(1000)/2.0))
>>> ax.lines
[<matplotlib.lines.Line2D object at 0xce84bd0>, <matplotlib.lines.Line2D object at 0xce84dx3>]
>>>
>>> ax.lines.remove(lines[0])
>>> ax.lines
[<matplotlib.lines.Line2D object at 0xce84dx3>]
Alle oben genannten Funktionen funktionieren fig.axes
genauso gut wie fürax.lines
Nun das eigentliche Problem hier. Wenn wir die darin enthaltene Referenz ax.lines[0]
in einem weakref.ref
Objekt speichern und dann versuchen, sie zu löschen, werden wir feststellen, dass kein Müll gesammelt wird:
>>>
>>> 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>
>>>
>>> ax.lines.remove(wr())
>>> ax.lines
[]
>>>
>>> print wr
<weakref at 0xb758af8; to 'Line2D' at 0xb757fd0>
>>> print wr()
<matplotlib.lines.Line2D at 0xb757fd0>
Die Referenz ist noch live! Warum? Dies liegt daran, dass es noch einen weiteren Verweis auf das Line2D
Objekt gibt, auf den der Verweis in wr
verweist. Erinnern Sie sich, wie Sie lines
nicht dieselbe ID hatten, ax.lines
aber dieselben Elemente enthielten? Nun, das ist das Problem.
>>>
>>> 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.
>>>
>>> lines = []
>>> print lines
[]
>>> print wr
<weakref at 0xb758af8; dead>
Die Moral der Geschichte lautet also: Räumen Sie nach sich selbst auf. Wenn Sie erwarten, dass etwas Müll gesammelt wird, dies aber nicht ist, lassen Sie wahrscheinlich irgendwo eine Referenz hängen.