Making Quality Animations in IDL

Here is a brief post that outlines how I easily create high quality animations using IDL. I realize IDL is not the most popular language in the astrophysics community these days, but this processes works for any language that can render plots to a file. While there are other ways to do this in Python, I think this processes works well since it allows you to experiment with each stage independently. I'll also embed a few animations I have created, hopefully to give you an idea of what is possible.

The workflow is relatively simple:
render many still frames > convert to images > encode them as a video

Note, this is the same workflow to create animated gifs, just swap the last step.

Note also, this guide assumes you are using OS X or LINUX.





1. Make (Good) Still Frames

So you have a fantastic plot, or maybe a really complex dataset, but you need to animate it. I'll assume you're already using a good color scheme, and making smart choices about contrast.

The initial, very basic stage is to figure out what variable you need to step over during the course of the animation. This could be actual time, or data subset, or you could simply move the position of the visualization (e.g. making data or a sphere spin). Then you want to write the most hated of all IDL code: a FOR loop!

With each step of the FOR loop you generate a single frame of the animation. Here's some generic sample code:

Nframes = 1000
FOR i=0L,Nframes-1 DO BEGIN
    device, filename = 'frame' + string(i, f='(I05)') + $
        '.eps', /encap,/inch,/color, $
        xsize=10,ysize=10
    plot, xdata, ydata, /xstyle, xrange=[0,1]+i
    device, /close
ENDFOR


This will create a series of still frames where the data moves along the x-axis. A couple key points:
  1. This will create 1000 files with names "frame00001.eps", "frame00002.eps".... etc. Padding numbers with zeroes is a very helpful trick.
  2. Save these files as (encapsulated) postscripts in IDL. I will go against the advice of the Coyote and say use the highest quality output that IDL offers: the postscript. You'll be glad you did later. So what if these files are huge, harddrive be damned.

You see LOTS of examples in the wild where people don't generate .eps or .ps files for their animations with IDL, and instead essentially screengrab from the IDL X Window device (many of the direct-to-jpeg outputs do this). We all know that IDL's native X Window graphing is really... rough. OK, It's down right horrid. So use the postscript output and get nice, high quality frames!

The example code is virtually the same for Python, wrapping a plt.savefig() call in a for loop. Note for Python, however, you can plot directly to a JPEG file, thus skipping step 2 below.



2. Convert Still Frames to Images

Now you've got a directory full of 1000 postscript files. This is helpful, but to create the movie you'll want to convert them to JPEG (or similar).

To do this conversion, I use ImageMagick's convert command. This does exactly as you expect, you tell it what to convert images to and it just works. I like to do this on the fly while the evil FOR loop is running since convert can't (as far as I know) do batches. The example code would then be:

FOR i=0L,Nframes-1 DO BEGIN
    device, filename = 'frame' + string(i, f='(I05)') + $
        '.eps', /encap,/inch,/color, $
        xsize=10,ysize=10
    plot, xdata, ydata, /xstyle, xrange=[0,1]+i
    device, /close

    spawn, 'convert -density 150x150 -flatten ' + $
        'frame' + string(i, f='(I05)') + '.eps ' + $
        'frame' + string(i, f='(I05)') + '.jpeg'

    spawn, 'rm frame' + string(i, f='(I05)') + '.eps' 
ENDFOR

I'm being a bit verbose here, but you get the idea. IDL generates the .eps file, ImageMagick converts it to a .jpeg, and then a shell call deletes the redundant .eps file. You can play around with the jpeg resolution of course. The end result is 1000 JPEG files, ready for encoding into a single movie!



3. Encode the Video

The next step is thankfully the easiest! Some people will drag/drop files in to iMovie, adjust still frame duration, hope all the frames land in order... This is a great idea if you're comfortable with something like iMovie. (note: it also makes adding credits, effects, transitions, and audio way easier)

Instead, for my normal workflow I use FFmpeg (installed via MacPorts). The beauty of this is I can just add one more line to my IDL code (after the FOR loop), and out pops the movie!

spawn, 'ffmpeg -r 20 -i frame%05d.jpeg ' + $
    ' -qscale 1 my_movie.mp4'

done! You can adjust the frame rate (-r 20 means 20 frames per second) and output quality (qscale). FFmpeg has approximately a trillion options, including cropping and rescaling existing animations to fit different screen sizes, and handling audio tracks.

Bonus: Animated GIFs

All the videos I have featured here were created using this process. As I mentioned in the introduction, the same processes applies for creating animated gifs: just swap the JPEG for still GIF frames in step 2, and then I use the old-school Gifsicle tool to create the animated version. The one extra trick for Gifsicle is that I haven't been able to use the % wild card trick I showed above, and instead you need to hand it all the file names. I just create a giant string of all the still frames I'm rendering, and pass that to Gifscile. The example code then becomes:

Nframes = 10
Flist = ''
FOR i=0L,Nframes-1 DO BEGIN
    device, filename = 'frame' + string(i, f='(I05)') + $
        '.eps', /encap,/inch,/color, $
        xsize=10,ysize=10
    plot, xdata, ydata, /xstyle, xrange=[0,1]+i
    device, /close

    spawn, 'convert -density 150x150 -flatten ' + $
        'frame' + string(i, f='(I05)') + '.eps ' + $
        'frame' + string(i, f='(I05)') + '.gif'

    spawn, 'rm frame' + string(i, f='(I05)') + '.eps' 

    Flist = Flist+' frame'+string(i,f='(I05)')+'.gif'
ENDFOR
spawn, 'gifsicle -d 5 --loop O2' + Flist + $
    ' > my_anim.gif'

Ta-Da!

No comments:

Post a Comment

Inappropriate comments, advertisements, or spam will be removed.
Posts older than 2 weeks have moderated comments.
(Anonymous commenting disabled due to increasing spam)