This is a very long explanation that I typed for my colleague. I think that would be helpful here. Be patient. I get to the real question that you have towards the end. Like a teaser, this is a question about additional links to your Line2D objects hanging around.
WARNING: One more note before we dive. If you use IPython to verify this, IPython saves the links yourself, and not all of them are weak. Thus, checking garbage collection in IPython does not work. It just confuses the questions.
Ok, here we go. Each matplotlib object ( Figure , Axes , etc.) Provides access to its child artists through various attributes. The following example is quite long, but should be highlighted.
We start by creating a Figure object, and then add an Axes object to this figure. Note that ax and fig.axes[0] are the same object (same id() ).
>>>
This also applies to lines in the axis object:
>>>
If you were to call plt.show() using what was done above, you will see a figure containing a set of axes and one line:

Now that we have seen that the contents of lines and ax.lines the same, it is very important to note that the object referenced by the lines variable does not match the object respected by ax.lines , as can be seen from the following:
>>> id(lines), id(ax.lines) (212754584, 211335288)
As a result, deleting an element from lines does nothing for the current graph, but deleting an element from ax.lines removes this row from the current graph. So:
>>> #THIS DOES NOTHING: >>> lines.pop(0) >>> #THIS REMOVES THE FIRST LINE: >>> ax.lines.pop(0)
So, if you would execute the second line of code, you would remove the Line2D object contained in ax.lines[0] from the current chart, and it will disappear. Note that this can also be done with ax.lines.remove() , which means that you can save an instance of Line2D in a variable and then pass it to ax.lines.remove() to remove this line, for example:
>>>

>>> #Remove that new line >>> ax.lines.remove(lines[0]) >>> ax.lines [<matplotlib.lines.Line2D object at 0xce84dx3>]

All of the above works for fig.axes as well as ax.lines
Now, the real problem is here. If we save the link contained in ax.lines[0] to the weakref.ref object and then try to delete it, we will notice that it does not receive 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>
The link is still alive! What for? This is due to the fact that there is another reference to the Line2D object pointed to by the link in wr . Remember how lines did not have the same identifier as ax.lines , but contained the same elements? Well, that problem.
>>> #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>
So the moral of this story, cleanse yourself. If you expect something to collect garbage, but it isnβt, you will probably leave a link somewhere.