Skip to content
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

Animation stops working after upgrade to matplotlib 3.3.2 #18837

Closed
npapnet opened this issue Oct 29, 2020 · 7 comments
Closed

Animation stops working after upgrade to matplotlib 3.3.2 #18837

npapnet opened this issue Oct 29, 2020 · 7 comments

Comments

@npapnet
Copy link

npapnet commented Oct 29, 2020

Bug report

Bug summary

The following code for an animated visualization stopped working after an upgrade from matplotlib 3.2.2 to 3.3.2.

Code for reproduction

Below is a minimum code for reproducible problem.

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

def create_animated_plot(xs, niter, xlim =(-1.5, 1.5), ylim = [-3, 3]):

    line_coords = np.vstack((  np.array([-1,1]), np.array([0,0]) ))
    
    boxData = [np.array([np.zeros(niter), xs])]

    fig, ax1 = plt.subplots(1,1)
    line, = ax1.plot([], [], lw=2)
    ax1.set_ylabel('position')
    ax1.set_ylim(ylim)
    ax1.set_xlim(xlim)

    lines = [ax1.plot([],[],lw=2,color="black")[0]]

    def init():
        lines[0].set_data([],[])
        return lines

    def animate(i):
        xs = [boxData[0][0, i]]
        ys = [boxData[0][1, i]]

        lines[0].set_data(line_coords[0,:]+xs[0], line_coords[1,:]+ys[0]) 
        return lines

    anim = animation.FuncAnimation(fig, animate, init_func=init,
                                frames=niter, interval=10, blit=True)
    #writer = animation.PillowWriter(fps=25) 
    #anim.save('animation.gif', writer=writer)

niter = 1001
t = np.linspace(0,10,niter)

create_animated_plot(xs =np.sin(t), niter=niter)
plt.show()

Actual outcome

The actual outcome of the code is the following figure. I.e. an empty plot with all xlabels but there is no plot of the line.

image

Additionally, something that might help with the debugging, is that if the last two lines in the create_animated_plot() are uncommented,

    #writer = animation.PillowWriter(fps=25) 
    #anim.save('animation.gif', writer=writer)

the resulting gif works as expected (see below).

Expected outcome

The code at the end of the post moves a line up and down in the y direction. It does that successfully with matplotlib 3.2.2, but not with 3.3.2. This is reproducible in different settings.

animation

This code was tested on the following setups (C1, C2, C3 are different computers) with the same results:

  • C1: A desktop with Asrock Z370 P4, Nvidia 1050 Ti, i5-8600K.
    Tested with:
    • Python: 3.8.3, matplotlib: 3.2.2 OK
    • Python: 3.8.3, matplotlib: 3.3.2 (problematic)
  • C2: An Acer Spin 5 SP513-52N laptop.
    Tested with:
    • Python: 3.8.3, matplotlib: 3.2.2 OK
    • Python: 3.8.3, matplotlib: 3.3.2 (problematic)
  • C3
    Tested with:
    • Win 10, Python: 3.8.3, matplotlib: 3.3.2 (problematic)
    • Ubuntu 20.04, Python: 3.8.3, matplotlib: 3.1.2 OK
    • Ubuntu 20.04, Python: 3.8.3, updated to matplotlib: 3.3.2 (problematic)

In all cases, when I upgraded the problem appeared, and when I downgraded the problem disappeared.

Matplotlib version

  • Operating system: Win10, Ubuntu 20.04
  • Matplotlib version: 3.3.2
  • Matplotlib backend (print(matplotlib.get_backend())): Qt5Agg
  • Python version: 3.8.3 (also tested in 3.7.6)
  • Jupyter version (if applicable):
  • Other libraries:

In machine C1, and C2 I installed through conda.

@jklymak
Copy link
Member

jklymak commented Oct 29, 2020

On master, this gives a warning:

/Users/jklymak/matplotlib/lib/matplotlib/animation.py:934: UserWarning: Animation was 
deleted without rendering anything. This is most likely unintended. To prevent deletion, 
assign the Animation to a variable that exists for as long as you need the Animation.

So this looks to be a duplicate of #18438 where the culprit is garbage collection destroying your animation before it is used.

OTOH I won't close because I find the warning not very helpful in trying to fix the problem in your code. What is the user supposed to do here to get the animation to run when plt.show() is used? @QuLogic @anntzer @dopplershift ?

@npapnet
Copy link
Author

npapnet commented Oct 29, 2020

Apparently the user can return the anim object and assign to a variable. The following was tested and it works.

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

def create_animated_plot(xs, niter, xlim =(-1.5, 1.5), ylim = [-3, 3]):

    line_coords = np.vstack((  np.array([-1,1]), np.array([0,0]) ))
    
    boxData = [np.array([np.zeros(niter), xs])]

    fig, ax1 = plt.subplots(1,1)
    line, = ax1.plot([], [], lw=2)
    ax1.set_ylabel('position')
    ax1.set_ylim(ylim)
    ax1.set_xlim(xlim)

    lines = [ax1.plot([],[],lw=2,color="black")[0]]

    def init():
        lines[0].set_data([],[])
        return lines

    def animate(i):
        xs = [boxData[0][0, i]]
        ys = [boxData[0][1, i]]

        lines[0].set_data(line_coords[0,:]+xs[0], line_coords[1,:]+ys[0]) 
        return lines

    anim = animation.FuncAnimation(fig, animate, init_func=init,
                                frames=niter, interval=10, blit=True)
    return anim

niter = 1001
t = np.linspace(0,10,niter)

anim = create_animated_plot(xs =np.sin(t), niter=niter)
plt.show()

@jklymak
Copy link
Member

jklymak commented Oct 29, 2020

Oh, duh. Thanks! Is it ok to close this then?

@npapnet npapnet closed this as completed Oct 29, 2020
@tacaswell
Copy link
Member

Would it help to pull the paragraph under this table in this section into a warning box? https://matplotlib.org/api/animation_api.html?highlight=animation#animation

As a side note, in 3.4 via #17826 we added the ability to pause/resume the animation.


I am more surprised that this ever worked....

@npapnet
Copy link
Author

npapnet commented Oct 29, 2020

I guess it might make a difference. The problem was that the same note was already present in 3.2.2 version, but then the animation worked. I know because I compared 3.2.2 and 3.3.2 and the only changes that were flaged were some errata and the HTMLwriter.
I guess the key is emphasising that the gc is collecting the animation references more aggresively after 3.3.2.

@tacaswell
Copy link
Member

This change bisects to 0539da4 . The key change is 0539da4#diff-8cc60f6e5a45e5dfd502623cdb3c033d7b2bbb63a0f55d0a49485f6390bcba26L1241-L1245 which was unintentionally smuggling a a hard-reference to the animation object into the callbacks through a closure on a lambda.

If you set blit=False than the OP code does not work on v3.2.2.

@npapnet I'm sorry we caught you with this edge case, but I think that the "bug" here was that we were accidentally keeping anim alive when we did not intend to...

@anntzer
Copy link
Contributor

anntzer commented Oct 29, 2020

I'm very sad for being responsible for accidentally getting rid of such a ref-via-closure :)

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