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
Unlike other plotting operations, if you create an animation and do not store it in a persistent variable, it will fail.
So, for example,
importmatplotlib.pyplotaspltfrommatplotlibimportanimationfig=plt.figure()
defanimate(i):
# ... do something hereanim=animation.FuncAnimation(fig, animate)
plt.show()
will work, but changing the final lines to
animation.FuncAnimation(fig, animate)
plt.show()
(i.e. not creating a variable to store the animation) leads to a quiet failure.
I think the problem is because the figure does not store a reference to the animation object, python's garbage collection removes it if it is not explicitly stored.
Probably the best way to address this would be to add an animation attribute to the Figure class, such that any animation will store a pointer to itself in its associated figure.
I think this is a pretty easy fix, but I'm just wondering if there are any other details to be aware of when adding something like this.
This is known and @dopplershift and I have discussed this particular issue offline many times before. We have thought of your idea before, but I forget why we dismissed it. There are peculiarities/features of animation objects that doesn't quite lend itself to this approach. Do you remember the reasons, Ryan?
If memory serves correctly (and I'm older now, so that's no guarantee), my aim was to avoid any modification of the rest of matplotlib to support this. A secondary "issue" is that a figure can have more than one animation, so the figure would likely need a list of animations. If @jakevdp's extensive use of the module is any indication, this module seems to be getting good uptake and the overall approach seems like it was the right one--I'm more inclined now to make modifications to the broader matplotlib code base if they make it even easier to make animations.
Mostly however, my objection was and still (somewhat) is code purity. I personally feel it's a little silly to do this just to avoid the (correct) code of having to save a reference to the object manually. For instance, if you create a Line2D instance by hand, it's not automatically added to an axes, and if you don't save a reference, POOF! Also, it seems odd for the figure to assume ownership of the animation when it doesn't touch it otherwise at all. However, I do recognize that this seems to be somewhat of a pain point, or at least a common gotcha, and should be addressed.
So I'm not really sure what I'm arguing here. There are no technical hurdles with adding an animations attribute to Figure instances that holds the list of current animations or with having the animation add itself to this list. There's a part of me that feels like symmetry with the rest of matplotlib dictates that we use a separate (simplfied?) API call to create the animation and add it (ala plot() or add_subplot()), instead of a self-registering class instance. However, it's not clear to me what that API would look like other than a thin, dumb wrapper around the animation constructor, which, IMO, is worse code than just having the class instance do it.
Interesting thoughts. From my perspective, it would seem much more natural to do something like
fig.add_animation(anim_func)
rather than the current
anim=animation(fig, anim_func)
The class method version would probably not be more than just a wrapper around the current function, but it would be more apparent that it's actually meant to add something to the figure class.
It would bring up some questions, though: for example, if you call savefig on a figure containing an animation, should it try to use a MovieWriter class automatically? Should it raise a warning? What if there are multiple animations? I'm not sure how that should most naturally be handled.
I agree the former fits better with matplotlib's typical, minimal OOP API. However, we have two different animation classes (FuncAnimation and ArtistAnimation), so the API would end up as either:
I'm not particularly keen on either of those. I also agree about savefig(), but I'm disinclined to add to the list of options--at least as long as animations live on as integrated, but not really integrated.
I agree that all those options are a bit kludgy. Regarding the last option: because the FuncAnimation constructor needs to know about the figure it's attached to, you'd probably have to call it with something awkward like
fig.add_animation(FuncAnimation(fig, *args))
Maybe the simplest thing to do would be to keep the syntax of animations the same as what it is now, but simply add a line to the animation constructor which does something like
fig.animations.append(self)
That would maintain full backward compatibility, would be very clean, and would sufficiently address the problem of object persistence. As a bonus, you'd be able to introspect each figure and see any animations that are attached to it.
Just a note on the "code purity" thing. Creating an "isolated" Line2D is different because you don't specify the axes or figures when doing so. In the code animation.FuncAnimation(fig, animate), you are already specifying an association between the animation and a figure, so I don't see how it's impure for the figure to know about that relationship.
Looking at it with really fresh eyes (2 years later), I think @jakevdp 's last suggestion, of just adding to a fig.animations list within the constructor (should just be able to go in the Animation base class) is probably the way to go to eliminate a common gotcha for animations.
My only minor concern here is that we're taking a one-way coupling (Animation knows about Figure), and turning it into a two-way coupling (now also Figure knows about Animation). It's only one small list--but statements like that are how we ended up with the highly coupled, somewhat cohesive, ungodly mess that is much of matplotlib's (highly functional) codebase.
(For the record, I still don't consider this a problem, since FuncAnimation and co. are classes; nowhere in Python do we create an instance of a class and expect it to go on living if we don't assign a name to it.)
I'm not volunteering to do it, but adding the animations list to the Figure constructor and calling append in the Animation constructor seems straightforward enough to be beginner ready.
So, I noticed an interesting use case for this in writing tests.
Currently, when doing image comparison tests. A test function is written to make a plot, and a decorator grabs that figure and saves it as an image before comparing it. This figures are grabbed by these lines. If the figure had knowledge of the animation, then it would be easy to grab the animation and save it for comparison. Alternatively, the test function could return the animation so that the decorator could pick it up. #11839
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!
I think we've had this conversation a few times in favour of asking people to keep their animations persistent. Yes, people are still sometimes confused about this, but the docs have a lot of pointers that explain the right way to do this, so I think it's OK to close this.
Activity
WeatherGod commentedon Jan 14, 2013
This is known and @dopplershift and I have discussed this particular issue offline many times before. We have thought of your idea before, but I forget why we dismissed it. There are peculiarities/features of animation objects that doesn't quite lend itself to this approach. Do you remember the reasons, Ryan?
dopplershift commentedon Jan 14, 2013
If memory serves correctly (and I'm older now, so that's no guarantee), my aim was to avoid any modification of the rest of matplotlib to support this. A secondary "issue" is that a figure can have more than one animation, so the figure would likely need a list of animations. If @jakevdp's extensive use of the module is any indication, this module seems to be getting good uptake and the overall approach seems like it was the right one--I'm more inclined now to make modifications to the broader matplotlib code base if they make it even easier to make animations.
Mostly however, my objection was and still (somewhat) is code purity. I personally feel it's a little silly to do this just to avoid the (correct) code of having to save a reference to the object manually. For instance, if you create a Line2D instance by hand, it's not automatically added to an axes, and if you don't save a reference, POOF! Also, it seems odd for the figure to assume ownership of the animation when it doesn't touch it otherwise at all. However, I do recognize that this seems to be somewhat of a pain point, or at least a common gotcha, and should be addressed.
So I'm not really sure what I'm arguing here. There are no technical hurdles with adding an
animationsattribute to Figure instances that holds the list of current animations or with having the animation add itself to this list. There's a part of me that feels like symmetry with the rest of matplotlib dictates that we use a separate (simplfied?) API call to create the animation and add it (ala plot() or add_subplot()), instead of a self-registering class instance. However, it's not clear to me what that API would look like other than a thin, dumb wrapper around the animation constructor, which, IMO, is worse code than just having the class instance do it.jakevdp commentedon Jan 14, 2013
Interesting thoughts. From my perspective, it would seem much more natural to do something like
rather than the current
The class method version would probably not be more than just a wrapper around the current function, but it would be more apparent that it's actually meant to add something to the figure class.
It would bring up some questions, though: for example, if you call
savefigon a figure containing an animation, should it try to use aMovieWriterclass automatically? Should it raise a warning? What if there are multiple animations? I'm not sure how that should most naturally be handled.dopplershift commentedon Jan 16, 2013
I agree the former fits better with matplotlib's typical, minimal OOP API. However, we have two different animation classes (
FuncAnimationandArtistAnimation), so the API would end up as either:or
I'm not particularly keen on either of those. I also agree about
savefig(), but I'm disinclined to add to the list of options--at least as long as animations live on as integrated, but not really integrated.What about:
?
jakevdp commentedon Jan 16, 2013
I agree that all those options are a bit kludgy. Regarding the last option: because the
FuncAnimationconstructor needs to know about the figure it's attached to, you'd probably have to call it with something awkward likeMaybe the simplest thing to do would be to keep the syntax of animations the same as what it is now, but simply add a line to the animation constructor which does something like
That would maintain full backward compatibility, would be very clean, and would sufficiently address the problem of object persistence. As a bonus, you'd be able to introspect each figure and see any animations that are attached to it.
BrenBarn commentedon Aug 27, 2014
Just a note on the "code purity" thing. Creating an "isolated" Line2D is different because you don't specify the axes or figures when doing so. In the code
animation.FuncAnimation(fig, animate), you are already specifying an association between the animation and a figure, so I don't see how it's impure for the figure to know about that relationship.petehuang commentedon Jan 7, 2017
What's the latest on this?
dopplershift commentedon Jan 7, 2017
Looking at it with really fresh eyes (2 years later), I think @jakevdp 's last suggestion, of just adding to a
fig.animationslist within the constructor (should just be able to go in theAnimationbase class) is probably the way to go to eliminate a common gotcha for animations.My only minor concern here is that we're taking a one-way coupling (
Animationknows aboutFigure), and turning it into a two-way coupling (now alsoFigureknows aboutAnimation). It's only one small list--but statements like that are how we ended up with the highly coupled, somewhat cohesive, ungodly mess that is much of matplotlib's (highly functional) codebase.(For the record, I still don't consider this a problem, since
FuncAnimationand co. are classes; nowhere in Python do we create an instance of a class and expect it to go on living if we don't assign a name to it.)I'm not volunteering to do it, but adding the
animationslist to theFigureconstructor and callingappendin theAnimationconstructor seems straightforward enough to be beginner ready.3 remaining items
t-makaro commentedon Aug 10, 2018
So, I noticed an interesting use case for this in writing tests.
Currently, when doing image comparison tests. A test function is written to make a plot, and a decorator grabs that figure and saves it as an image before comparing it. This figures are grabbed by these lines. If the figure had knowledge of the animation, then it would be easy to grab the animation and save it for comparison. Alternatively, the test function could return the animation so that the decorator could pick it up. #11839
anntzer commentedon Aug 13, 2019
Untagged "good first issue", given that it's really a design problem now (and we already rejected two PRs implementing the "obvious" solution).
github-actions commentedon Feb 28, 2023
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!
jklymak commentedon Feb 28, 2023
I think we've had this conversation a few times in favour of asking people to keep their animations persistent. Yes, people are still sometimes confused about this, but the docs have a lot of pointers that explain the right way to do this, so I think it's OK to close this.