Comments (7)
Hi @stas-sl!
I'm using "blitting the technique" not "blitting the functionality built into FuncAnimation
". 😄
The easiest way to animate a plot is to do as I mentioned in the post and just redraw everything, like I did here: https://github.com/agude/agude.github.io/blob/master/files/names/Most%20Popular%20Names%20Blit%20Same%20Time.ipynb (Cell 14). This takes a long time because you have the overhead of redrawing everything every frame.
What I do in the Blitting example is manually update just the artists that need to change. That's the 20x improvement. I believe I took this technique from the Matplotlib tutorial here: https://matplotlib.org/stable/tutorials/advanced/blitting.html Although their method goes an extra step and implements it's own handler. I think they used to have a tutorial that was not very clear and used the method I do in my post. In essence I was trying to make a clear version of their tutorial.
All that said, it looks like you can now let FuncAnimation
handle more of the blitting process for you by setting blitting=True
, as you say. But you need to modify what your functions do if you use that. You'll notice my update function updates the artists it needs to and returns None
where as if you want FuncAnimation
to handle blitting you have to return the changed artists.
from agude.github.io.
Thanks for quick response! But I'm still quite confused 🤔
I checked your another notebook that you mentioned, but TBH I don't see much difference. In both notebooks on each iteration you are updating data (set_data(...)
) for existing artists. You are not creating the whole plot/artists from scratch. The only difference is that in "Names" notebook you have many lines/artists, whereas in "Supernova" there is only a single line.
I also don't see in your "Supernova" example where is exactly the "blit technique" used? I do see it in Matplotlib tutorial you referenced. They explicitly save background before starting animation: bg = fig.canvas.copy_from_bbox(fig.bbox)
and restore it on each animation iteration: fig.canvas.restore_region(bg)
and they do not use FuncAnimation
or any other Animation
subclass. Probably, I also should go that way, but I just was hoping that FuncAnimation
could do all bit bliting for me, instead of manually implementing it. But I've tried and seems like setting blit=True
didn't have any effect for me, at least when saving to file. I spent some time debugging/digging through their source code, and it seems that the methods actually responsible for bliting just not being called. I believe, it depend on matplotlib backend, and as I said probably it could work in interactive backend, but not when saving to file, that looks strange to me, but that's what I understood.
Moreover, they do not save animation anywhere, so you need to implement it as well to produce a video, probably by copying parts of their code. But if feels already more complicated than it should be.
I'm not sure when your post was written, but looks like blit
parameter was there already 12 years ago 🙂:
from agude.github.io.
Basically here is comment at the top of animation.py from 12 years ago (last line):
It confirms that bliting is not used for movies, but probably could be.
from agude.github.io.
BTW, the blog looks really cool! I mean not just content, but overall look - typography (larger font), spacing, alignment, illustrations - it feels just "right" 👍
from agude.github.io.
I checked your another notebook that you mentioned, but TBH I don't see much difference.
You're right, because I actually use blitting there too. I never checked in the slow version (but thought I had). Oops!
I also don't see in your "Supernova" example where is exactly the "blit technique" used?
Here it is:
# Apply the three plotting functions written above
init = partial(init_fig, fig=fig, ax=ax, artists=artists)
step = partial(step_through_frames, -15, 25)
update = partial(update_artists, artists=artists, lambdas=df["lambda"].unique())
# Generate the animation
anim = animation.FuncAnimation(
fig=fig,
func=update,
frames=step,
init_func=init,
save_count=150, #len(list(step())),
repeat_delay=5000,
)
My init()
function is passed in with init_func=init
, which is (from the docs):
A function used to draw a clear frame. If not given, the results of drawing from the first item in the frames sequence will be used. This function will be called once before the first frame.
So that draws the unchanging portion.
Then the update()
function is called each frame and updates the artists that change. FuncAnimation
then saves that frame and moves on.
But if you look closely I have to use some global variables to track the artists:
# Set the artists
artists = Artists(
plt.plot([], [], animated=True, label="Flux")[0],
ax.text(0.987, 0.955, "", fontsize=20, transform=ax.transAxes, horizontalalignment='right', verticalalignment='center'),
)
This tuple of the two artists (the line and the text) is passed in to the functions via partial
which means that it's passed in each call with its current values. It's a really bad way to hack around the fact that I need to track state.
So that's the blitting.
But turns out that FuncAnimation
has a blit=
option where instead of doing the weird, global values with partial application, will just return the artists from the function and use those. I didn't know about it when trying to figure this out 5 years ago so I wrote some worse code. I really should update the post. 😖
But I've tried and seems like setting
blit=True
didn't have any effect for me, at least when saving to file.
I've never tried using that unfortunately. Maybe I'll get to it next month and try to rewrite this post with better code. But if you're correct maybe it never worked for the movie backend... 🤔 So my version (horrible as it is) seems to work for movies.
But just to check, you're changing your init_func
and func
to return artists right? My version doesn't because I'm not setting blit=True
. If you don't make that change, I suspect nothing happens...
BTW, the blog looks really cool! I mean not just content, but overall look - typography (larger font), spacing, alignment, illustrations - it feels just "right" 👍
Thanks! I'm no designer, but I've tried to make it look nice.
from agude.github.io.
Ok, seems like I understood where is the source of my confusion. Probably we have a bit different understanding of what is “blitting”.
Just for clarity, in your non-optimized version which was 20x slower, you were recreating the whole figure/artists including legends, bands and calling plt.plot()
for each frame, not just setting new data on existing artists? I understand that this is an optimization, definitely, but I probably wouldn’t call it “blitting”.
As I understand, what happens under the hood, when matplotlib renders each frame, it can’t “undraw” only changed artists, as they could overlap with others, so it has to clear whole canvas and redraw all artists one by one - those that changed as well as those that are considered “background”, that didn’t change. Yes, in your optimized case no additional objects/artists created, but still everything is redrawn on each frame.
So what could be optimized further is what I would call “blitting”. Instead of redrawing all artists when rendering each frame, some of them that are static, and don’t change from frame to frame could be drawn just once and saved into a buffer as rasterized bitmap, and then on each frame instead of clearing whole canvas and redrawing all of them, this bitmap just quickly gets copied from memory buffer, and then only changed artists being redrawn on top. This is what happens in the matplotlib example you linked and also if you set blit=True
(but sadly not for movies, as I found out).
The reason why I’m particularly interested in this optimization is because in my case I have pretty heavy background layer that renders a map (which is essentially plt.imshow(), just quite high resolution) - and it takes about 300 ms on each frame to redraw it, although I’m adding it to the figure only once in init
and update data only for some artists on top of it on each iteration.
I’m actually not sure if the latter optimization would give much gain in your case, as you don’t have heavy background layers, that’s probably why you are not noticing if it is turned on or off.
from agude.github.io.
The reason why I’m particularly interested in this optimization is because in my case I have pretty heavy background layer that renders a map (which is essentially plt.imshow(), just quite high resolution) - and it takes about 300 ms on each frame to redraw it, although I’m adding it to the figure only once in init and update data only for some artists on top of it on each iteration.
Sounds like it isn't caching that for whatever reason then. Unfortunate.
I think we're past the stage where I can help. You'll need to ask for help from either the mapping people, or the Matplotlib people. Best off luck!
from agude.github.io.
Related Issues (20)
- Make nicer tables
- Consider accessible alternatives to tables for layout
- Tweak spacing of elements
- Automatically format updated date
- Break out the update line to a template HOT 1
- Check <head> tag
- CSS issues: misaligned footnotes and social sharing buttons
- Check font sizes
- The Terribly Clever(ly Terrible) Code is a post
- Back-link to the negotiating post.
- Remove NLTK from practice notebook
- Make sure there are no spaces in links
- Consider <detail> for the Data Manipulation Post
- random sub sample HOT 3
- Consider `font-display: optional` HOT 1
- Add a CSP
- Add hover anchor links HOT 1
- On the `/books/by-series/` books without series don't show up.
- Make series_link.html better
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from agude.github.io.