Closed kbarnhart closed 6 months ago
I often find that using ffmpeg
gives me ugly movies (e.g., text in the plots looks bad due to compression artifacts), whereas matplotlib's animation.save()
gives movies with no compression artifacts (the text and plot lines are perfectly crisp). I imagine that it's a question of using the right options for ffmpeg
(and will also depend on the image format you're converting from, which isn't an issue for animation.save()
).
I'm not objecting to this PR, just saying that I personally would never use it as I get bad results from this approach.
@kbarnhart: I agree it's good to have something like this, but I think it might be made simpler using what's in animation_tools.py
and/or animation.save
. Also it would be good if there were another line in the PlotIndex.html
file generated with a pointer to the new animation. I can try to play around with this a bit, but might not get too it right away.
@ketch: It seems like animation.save()
has to use some MovieWriter, and I see there is e.g. FFMpegWriter and a ImageMagickWriter. Can you be more specific about what you use to get nice plots?
For higher quality animations (and much smaller file sizes) I usually use a separate script that creates the plot and then just modifies the data plotted each frame (the more proper way to use matplotlib.animation rather than re-displaying a bunch of png files as is done in plotpages.py
or animation_tools.py
. I think this is what @ketch is alluding to also. It's really the re-plotting of png images that gives crappy resolution, not the use of ffmpeg, I think.
There is one example of how to do this for GeoClaw output in the example $CLAW/geoclaw/examples/tsunami/chile2010_fgmax-fgout, see the make_fgout_animation.py script.
I've been meaning to clean up some more examples of this and post them....
Thanks for the input. All I really want/need is the ability to write something like
plotdata.make_mp4=True
and end up with some standalone .mp4 files that have a similar resolution to the .pngs. I can play around with whether there is an easy way to do that with the current animation tools and report back.
Yes, I should have been more precise. For line plots, I've found that nowadays the following gives excellent results with no compression artifacts:
anim = animation.FuncAnimation(fig, plot_function, frames=num_plots+1, repeat=False)
anim.save('movie.mp4')
I think this is also using ffmpeg under the hood, though I haven't checked. It's all a question of what image format is used, what video encoding is used, etc. I used to mess with that directly but now matplotlib seems to do it best automatically.
@ketch: The issue with what you suggest is that you have to supply a plot_function
that updates the plot from one frame to the next, and presumably you do this for line plots by simply resetting the data used to specify the line from one frame to the next. This works great for simple plots, also for pcolor plots as in the example I pointed to above, which is for a sequence of fgout frames that are each a single array with the same dimensions for every frame, making it easy to replace the data appearing in the plot from one frame to the next.
Sadly it would be much harder if not impossible to do the same thing for pcolor plots showing AMR results, in which each frame shows dozens or hundreds of individual patches and the number and dimensions change from one frame to the next. Hence for complex plots of this nature about the best we can do is animate the sequence of png's generated for each frame, I think. (If someone knows how to do this better, I'm all ears.). Nonetheless, in spite of the poor resolution, it's very useful to make these animations for quickly viewing animations after doing make plots
. For higher quality it seems necessary to do something like specifying an fgout fixed grid, which was one of the main motivations for introducing that capability.
I've resuscitated this effort and think I almost have it and this is ready for some additional feedback.
I found one issue and have a proposed solution. If the fig size and dpi are set as large, then the embedded JS movie doesn't fit in a browser window nicely. I addressed this by adding an html_movie_dpi attribute to plotdata (default of 100). As long as someone doesn't give fig sizes that are huge, I think this will work.
I consider using the existing html_movie_width attribute (which does not appear to be used). I'd prefer to just specify the width... however, if figsize was not set by the user, I don't know the figsize from within the plotclaw_driver() and thus don't know how to set the dpi to get a width. It didn't make sense to me to reproduce something like L120-L124 of animation_tools.py, so I just settled on using a lower DPI.
@kbarnhart: Thanks for continuing to work on this. I'll take a look and think about the figsize issue.
In my pre-5.0 workflows, I've found it very useful to make .mp4s with ffmpeg. (I know that this somewhat duplicates the workflow in the visclaw.make_anim routines 😬 ).
This PR adds the ffmpeg functionality, and constructs the ffmpeg command as
to mimic the ffmpeg syntax of:
https://ffmpeg.org/ffmpeg.html
I've set the input and output options to a set that (after a moderate amount of fiddling) I found worked for my applications.
Happy to improve it based on feedback.