Невозможно удалить объекты matplotlib.animation.FuncAnimation
EDIT / TL; DR: Похоже, что естьmatplotlib.backends.backend_qt4.TimerQT
объект, который содержит ссылку на мой объект FuncAnimation. Как я могу удалить его, чтобы освободить объект FuncAnimation?
1 - маленький контекст
Я пытаюсь оживить сюжет, созданный с помощью matplotlib. Я использую matplotlib.animation.FuncAnimation. Этот анимированный сюжет содержится в FigureCanvasQTAgg (matplotlib.backends.backend_qt4agg), т.е. виджет PyQt4.
class ViewerWidget(FigureCanvasQTAgg):
def __init__(self, viewer, parent):
# viewer is my FuncAnimation, encapsulated in a class
self._viewer = viewer
FigureCanvasQTAgg.__init__(self, viewer.figure)
Когда изменение конфигурации происходит в GUI, рисунок очищается (figure.clf()
) и его подзаговоры (оси и линии) заменены новыми.
2 - Исходный код из классаViewer
(инкапсулированияFuncAnimation
)
Это самая важная часть моего методаViewer.show(...)
, который воплощает FuncAnimation
2.a - Сначала я попробовал:
animation.FuncAnimation(..., blit=True)
Конечно, случай был мусором сразу
2.b - Затем я сохранил его в переменной класса:
self._anim = animation.FuncAnimation(..., blit=True)
Это сработало для первой анимации, но как только изменилась конфигурация, у меня появились артефакты от предыдущих анимаций по всем новым
2.c - так что я вручную добавилdel
:
# Delete previous FuncAnimation if any
if self._anim:
del self._anim
self._anim = animation.FuncAnimation(..., blit=True)
Ничего не изменилось
2.d - После некоторой отладки я проверил сборщик мусора:
# DEBUG: check garbage collector
def objects_by_id(id_):
for obj in gc.get_objects():
if id(obj) == id_:
return obj
self._id.remove(id_)
return "garbage collected"
# Delete previous FuncAnimation if any
if self._anim:
del self._anim
# DEBUG
print "-"*10
for i in self._id.copy():
print i, objects_by_id(i)
print "-"*10
self._anim = animation.FuncAnimation(self._figure_handler.figure,
update,
init_func=init,
interval=self._update_anim,
blit=True)
# DEBUG: store ids only, to enable object being garbage collected
self._anim_id.add(id(anim))
После 3 изменений конфигурации он показал:
----------
140488264081616 <matplotlib.animation.FuncAnimation object at 0x7fc5f91360d0>
140488264169104 <matplotlib.animation.FuncAnimation object at 0x7fc5f914b690>
140488145151824 <matplotlib.animation.FuncAnimation object at 0x7fc5f1fca750>
140488262315984 <matplotlib.animation.FuncAnimation object at 0x7fc5f8f86fd0>
----------
Итак, это подтвердило, что ни одна из FuncAnimation не была собрана мусором
2.e - Последняя попытка со слабым ответом:
# DEBUG: check garbage collector
def objects_by_id(id_):
for obj in gc.get_objects():
if id(obj) == id_:
return obj
self._id.remove(id_)
return "garbage collected"
# Delete previous FuncAnimation if any
if self._anim_ref:
anim = self._anim_ref()
del anim
# DEBUG
print "-"*10
for i in self._id.copy():
print i, objects_by_id(i)
print "-"*10
anim = animation.FuncAnimation(self._figure_handler.figure,
update,
init_func=init,
interval=self._update_anim,
blit=True)
self._anim_ref = weakref.ref(anim)
# DEBUG: store ids only, to enable object being garbage collected
self._id.add(id(anim))
На этот раз, логи, где путают, я не уверен, что происходит.
----------
140141921353872 <built-in method alignment>
----------
----------
140141921353872 <built-in method alignment>
140141920643152 Bbox('array([[ 0., 0.],\n [ 1., 1.]])')
----------
----------
140141921353872 <built-in method alignment>
140141920643152 <viewer.FftPlot object at 0x7f755565e850>
140141903645328 Bbox('array([[ 0., 0.],\n [ 1., 1.]])')
----------
(...)
Где мои<matplotlib.animation.FuncAnimation object at 0x...>
?
Предыдущих анимационных артефактов больше не было, но пока все хорошо, но ... FuncAnimation больше не может выполнять "обновление". Только часть "init". Я предполагаю, что FuncAnimation - сборщик мусора, как только методViewer.show(...)
возвращается, грешитanim
идентификаторы уже переработаны.
3 - Помощь
Я не знаю, где искать отсюда. Любое предложение?
РЕДАКТИРОВАТЬ: Я установилobjgraph чтобы визуализировать все обратные ссылки на FuncAnimation, я получил это:
import objgraph, time
objgraph.show_backrefs([self._anim],
max_depth=5,
filename="/tmp/debug/func_graph_%d.png"
% int(time.time()))
Итак, естьmatplotlib.backends.backend_qt4.TimerQT
это все еще содержит ссылку. Любой способ удалить это?