Skip to content

Cannot stop/garbage collect an animation #16853

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
nbud opened this issue Mar 20, 2020 · 7 comments
Open

Cannot stop/garbage collect an animation #16853

nbud opened this issue Mar 20, 2020 · 7 comments

Comments

@nbud
Copy link

nbud commented Mar 20, 2020

Bug report

Bug summary

The animation documentation states that the reference to the Animation object must be held to prevent the animation from stopping due to garbage collection. I cannot reproduce this. Also, I do not find any way to stop the animation. I presume the Animation object is held somewhere, and this is undocumented.

The bigger picture for me: I pass as the frames argument of FuncAnimation a generator which streams data from a device via a socket. When the generator is garbage collected, the socket is deleted and the device is free to take new connections. Because I cannot garbage collect the Animation object, I cannot garbe collec the socket instrument either and the device hangs.

Related #16221

Code for reproduction

Adapted from https://matplotlib.org/3.1.3/api/animation_api.html :

import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import gc

fig, ax = plt.subplots()
xdata, ydata = [], []
ln, = plt.plot([], [], 'ro')

def init():
    ax.set_xlim(0, 2*np.pi)
    ax.set_ylim(-1, 1)
    return ln,

def update(frame):
    xdata.append(frame)
    ydata.append(np.sin(frame))
    ln.set_data(xdata, ydata)
    return ln,

FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
                    init_func=init, blit=True)
gc.collect() # force garbage collection
plt.show()

Actual outcome

The animation works.

Expected outcome

The animation should not work, as described in the doc.

Matplotlib version

  • Operating system: Windows 10
  • Matplotlib version: 3.1.3
  • Matplotlib backend (print(matplotlib.get_backend())): issue affects at least Qt5Agg and Tk5Agg
  • Python version: 3.7.6
  • Jupyter version (if applicable):
  • Other libraries: Anaconda 2020.02

Issue was reproducted in a Python console and in Spyder 4

@ImportanceOfBeingErnest
Copy link
Member

Without having looked at this too much in detail, it seems to come from blitting being used. Would blit=False show the expected behaviour?

@nbud
Copy link
Author

nbud commented Mar 20, 2020

@ImportanceOfBeingErnest Nice catch, blit=False shows the expected behaviour.

@nbud
Copy link
Author

nbud commented Mar 20, 2020

After more thought on it, I found a way to stop the animation which does not rely on the garbage collection of the Animation object (see code below for the record).

The behaviour described in the first message of this issue is not anymore an issue for me. Up to you to leave the issue open.

import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

fig, ax = plt.subplots()
xdata, ydata = [], []
(ln,) = plt.plot([], [], "ro")


def init():
    ax.set_xlim(0, 2 * np.pi)
    ax.set_ylim(-1, 1)
    return (ln,)


def update(frame):
    xdata.append(frame)
    ydata.append(np.sin(frame))
    ln.set_data(xdata, ydata)
    return (ln,)


def generate_data():
    stop_flag = False
    x = 0
    while not stop_flag:
        x += 2 * np.pi / 128
        stop_flag = yield x
    print("stopped")

data_generator = generate_data()

def stop():
    data_generator.send("STOP")

def onClose(event):
    stop()
    
def onPress(event):
    if event.key == " ":
        stop()
    
fig.canvas.mpl_connect("close_event", onClose)
fig.canvas.mpl_connect("key_press_event", onPress)
ani = FuncAnimation(fig, update, frames=data_generator, init_func=init, blit=False)
plt.show()

@ImportanceOfBeingErnest
Copy link
Member

The culprit is indeed this line in _setup_blit:

self._resize_id = self._fig.canvas.mpl_connect('resize_event',
self._on_resize)

@github-actions
Copy link

This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!

@github-actions github-actions bot added the status: inactive Marked by the “Stale” Github Action label Jul 14, 2023
@tacaswell
Copy link
Member

mpl_connect should only be holding a weakref. This warrants more investigation.

@tacaswell tacaswell added topic: animation and removed status: inactive Marked by the “Stale” Github Action labels Jul 14, 2023
@anntzer
Copy link
Contributor

anntzer commented Sep 14, 2023

This seems to be fixed as of master for me; @tacaswell can you confirm or infirm this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants