You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Doc]: Surprising behavior of FuncAnimation example in the first frames #29856
When looking carefully at the first few frames of the animation from the FuncAnimation example by setting interval=2_000 for instance, there are some surprises:
First, a single point is plotted, corresponding to the initial scatter plot
Then this point disappears, corresponding to the first frame which is empty because frame=0 and we take slices (x = t[:frame], y = z[:frame])
Then the point reappears, and in the following frames the trajectory is plotted as expected
I think the expected behavior is that the first point appears, and then the trajectory starts, which can be obtained by replacing frames=40 with frames=range(2, 40).
Side point
That does raise another related point which I encountered and which is what led me to look at that example, which is that saving the animation to a file and showing it in an interactive window behave differently with respect to the first frame. The initial state of the plot is shown in interactive mode but does not show up in the saved GIF. In the FuncAnimation example, when saving the animation to a GIF, the first frame doesn't have any point, then the point appears and the trajectory then proceeds normally (so it's like I described above but without the first frame).
My understanding is this comes from the fact that the animation does not have access to the initial figure setup, but I might be wrong. This "inconsistency" is a little sad for me because in order to have the first frame show up in the GIF I have to accept the fact that it's shown twice in interactive mode.
the current behavior becomes more clear when adding a title
title = ax.set_title("initial")
...
def update(frame):
...
title.set_text(f"frame {frame}")
The initial plot is drawn and stays it for one full interval. Only then frame 0 is drawn. Note also that the initial state does not come back in following cycles of the animation.
The initial plot is not part of the animation as you have realized when saving the file, the same happens when you do this in a jupyter notebook.
from IPython.display import HTML
...
ani = animation.FuncAnimation(fig=fig, func=update, frames=40, interval=1000)
HTML(ani.to_jshtml())
So we currently have:
if the animation is saved, it contains only the frames
if the animation is displayed, the animation is started by the draw_event
This leaves the initial state standing at the beginning
I therefore think the startup behavior for an animation that is shown is incorrect. Maybe we should try to render the first frame as part of _start(). Not sure how well this works because of the warning in DrawEvent. Probably the cleaner but also more complicated apporach is to not trigger the Animation through a draw event, but built in explicit logic in show() to directly transfer the drawing control to the animation when a figure with an animation is shown. But that requires more rearchitecting since figures currently do not know that they have an animation (see #16221 (comment)).
Activity
timhoffm commentedon Apr 3, 2025
the current behavior becomes more clear when adding a title
The initial plot is drawn and stays it for one full interval. Only then frame 0 is drawn. Note also that the initial state does not come back in following cycles of the animation.
The initial plot is not part of the animation as you have realized when saving the file, the same happens when you do this in a jupyter notebook.
So we currently have:
matplotlib/lib/matplotlib/animation.py
Line 898 in a364dc5
It then starts the timer but the first frame is only drawn when the timer expires
matplotlib/lib/matplotlib/animation.py
Lines 917 to 930 in a364dc5
This leaves the initial state standing at the beginning
I therefore think the startup behavior for an animation that is shown is incorrect. Maybe we should try to render the first frame as part of
_start(). Not sure how well this works because of the warning in DrawEvent. Probably the cleaner but also more complicated apporach is to not trigger the Animation through a draw event, but built in explicit logic inshow()to directly transfer the drawing control to the animation when a figure with an animation is shown. But that requires more rearchitecting since figures currently do not know that they have an animation (see #16221 (comment)).bluthej commentedon Apr 4, 2025
I do agree!