Это очень длинное объяснение, которое я напечатал для своего коллеги. Думаю, здесь тоже было бы полезно. Но будьте терпеливы. Я подхожу к реальной проблеме, с которой вы столкнулись ближе к концу. Как тизер, это проблема наличия дополнительных ссылок на ваши Line2Dобъекты.
ПРЕДУПРЕЖДЕНИЕ. Еще одно замечание, прежде чем мы углубимся. Если вы используете IPython для проверки этого, IPython сохраняет собственные ссылки, и не все из них являются слабыми ссылками. Итак, тестирование сборки мусора в IPython не работает. Это просто сбивает с толку.
Хорошо, поехали. Каждый matplotlibобъект ( Figure, Axesи т. Д.) Предоставляет доступ к своим дочерним художникам через различные атрибуты. Следующий пример становится довольно длинным, но должен проливать свет.
Мы начинаем с создания Figureобъекта, а затем добавляем Axesобъект к этой фигуре. Обратите внимание, что axи fig.axes[0]являются одним и тем же объектом (одинаковым 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)
Это также распространяется на строки в объекте оси:
>>>
>>> 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)
Если бы вы вызывали, plt.show()используя то, что было сделано выше, вы бы увидели фигуру, содержащую набор осей и одну строку:

Теперь, хотя мы увидели, что содержимое linesи ax.linesявляется одинаковым, очень важно отметить, что объект, на который ссылается linesпеременная, не совпадает с объектом, на который обращается внимание, ax.linesчто можно увидеть из следующего:
>>> id(lines), id(ax.lines)
(212754584, 211335288)
Как следствие, удаление элемента из linesтекущего графика ничего не делает, но удаление элемента из ax.linesудаляет эту строку из текущего графика. Так:
>>>
>>> lines.pop(0)
>>>
>>> ax.lines.pop(0)
Итак, если вы запустите вторую строку кода, вы удалите Line2Dобъект, содержащийся в ax.lines[0]текущем графике, и он исчезнет. Обратите внимание, что это также можно сделать, ax.lines.remove()имея в виду, что вы можете сохранить Line2Dэкземпляр в переменной, а затем передать его, ax.lines.remove()чтобы удалить эту строку, например:
>>>
>>> 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>]

Все вышеперечисленное работает fig.axesтак же хорошо, как и дляax.lines
Итак, настоящая проблема здесь. Если мы сохраняем ссылку , содержащуюся в ax.lines[0]в weakref.refобъект, а затем попытаться удалить его, мы заметим , что он не получает мусора:
>>>
>>> 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>
Ссылка все еще жива! Почему? Это потому, что есть еще одна ссылка на Line2Dобъект, на который wrуказывает ссылка . Помните, как linesне было такого же идентификатора, как, ax.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.
>>>
>>> lines = []
>>> print lines
[]
>>> print wr
<weakref at 0xb758af8; dead>
Итак, мораль этой истории такова: убирайте за собой. Если вы ожидаете, что что-то будет собрано сборщиком мусора, но это не так, вы, скорее всего, оставите где-то висеть ссылку.