25

I gave a very fetching presentation written with beamer today. It included a pgfplot animated with the animate package, and the result was fantastic. The problem? One of my colleagues wants to borrow the plot for a presentation written in something non-LaTeX. In addition, it would be nice to know how to externalise animated pgfplots frame by frame for animation using using convert or mencoder to produce a standalone file for inclusion in websites etc.

Naturally, I turned to externalize to do the job for me. It seems that animate and externalize don't agree... How can I convince them to kiss and make up?

Below is a massively simplified example for the wizards to work with

\documentclass{standalone}
\usepackage{pgfplots}
\usepackage{animate}
% Comment out the following line to see what the plot looks like.
\usepgfplotslibrary{external}\tikzexternalize 

\begin{document}
%
\begin{animateinline}[controls]{10}
  \multiframe{30}{ind=0+1}{
    \begin{tikzpicture}
      \begin{axis}[ymin=-1, ymax=1, xmin=0, xmax=3.14]
        \addplot {sin(deg(x+\ind*pi/16))};
      \end{axis}
    \end{tikzpicture}
  }
\end{animateinline}
%
\end{document}
5
  • the idea when doing animate and externalize is to loop (with \foreach or equivalent) externalizing the plots (preferably in a separate document). Then you can animate the pdf's after they have been externalized. I did this also by using the overlay feature which can drastically reduce the size of the ouput pdf. If i have time in the following days i will supply what i did in my bachelor thesis.
    – nickpapior
    Dec 21, 2011 at 9:56
  • @zeroth: I already know how to do that, and it's a lot of effort for something that should be simple (in principle). I'd rather be able to do it this way to keep things neat and easily repeatable.
    – qubyte
    Dec 21, 2011 at 10:00
  • 1
    i see. I have always done it the other way. I am not sure if what you want is possible, we will see if an answer arrives! :)
    – nickpapior
    Dec 21, 2011 at 10:08
  • As a bi-product this would improve the time to compile after the first time as TikZ would grab the externalised images for animate.
    – qubyte
    Dec 21, 2011 at 10:09
  • Can we see the NOT simplified version of the animation? I am interested. Oct 19, 2012 at 17:03

3 Answers 3

18

Does the animate package do things with the shipout routine of TeX? The external lib replaces it -- probably in an incompatible way.

Nevertheless, the following approach also works:

\documentclass{article}
\usepackage{pgfplots}
\usepackage{animate}
% Comment out the following line to see what the plot looks like.
\usepgfplotslibrary{external}

\tikzexternalize


\begin{document}
%
\begin{animateinline}[controls]{10}
  \multiframe{30}{ind=0+1}{
    \tikzifexternalizing{%
        Work-around to make animate happy
    }{}%
    \begin{tikzpicture}
      \begin{axis}[ymin=-1, ymax=1, xmin=0, xmax=3.14]
        \addplot {sin(deg(x+\ind*pi/16))};
      \end{axis}
    \end{tikzpicture}
  }
\end{animateinline}
%
\end{document}

the statement \tikzifexternalizing is only true if one of the frames is being converted. In this case, only the picture of interest makes its way into the output pdf - and we can safely generate non-empty content (and the animate package is happy).

8
  • Very neat! Could be winner.
    – qubyte
    Dec 21, 2011 at 16:11
  • I think shipout is probably affected, but I can handle that with a little bash magic. The important thing is just getting the frames out.
    – qubyte
    Dec 21, 2011 at 16:29
  • Thanks for your elegant solution @Christian. Animate doesn't tinker with the output routines, it just typesets graphics or inline material into saveboxes and produces Form XObjects (special pdf objects) from them.
    – AlexG
    Dec 22, 2011 at 8:50
  • @Alexander thanks for the technical background. In case you know the precise reason for the failure: let me know. Perhaps I can fix the external lib. If it is unrelated to \shipout hackery, there may be a general fix. Dec 22, 2011 at 11:44
  • 2
    @Mark thanks for the praise :) I'm glad they prove to be useful. Dec 22, 2011 at 13:57
11

All in one approach

Read the comments whether or not you need ImageMagick and/or FFMPEG installed on your machine.

\documentclass{article}

\usepackage{filecontents}

% create a parameterized template
\begin{filecontents*}{template.tex}
\documentclass[tikz,border=12pt]{standalone}
\usepackage{pgfplots}
\begin{document}
  \foreach \ind in {1,2,...,30}
    {
    \begin{tikzpicture}
      \begin{axis}[ymin=-1, ymax=1, xmin=0, xmax=3.14]
        \addplot[color=\clr]  {sin(deg(x+\ind*pi/16))};
      \end{axis}
    \end{tikzpicture}
  }
\end{document}
\end{filecontents*}


\usepackage{animate}

% creater a PDF file containing frames
%\def\param{red}
%\immediate\write18{pdflatex -jobname=frames "\def\noexpand\clr{\param} \noexpand\input{template}"}

% just another way with \unexpanded to save more keystrokes!
\def\param#1{%
\immediate\write18{\unexpanded{pdflatex -jobname=frames "\def\clr{#1} \input{template}"}}}
\param{blue}

% create a GIF animation (needs ImageMagick installed)
\immediate\write18{convert -delay 5 -loop 0 -density 100 -alpha remove frames.pdf frames.gif}

% create a list of PNG images, one for each frame (needs ImageMagick installed)
\makeatletter
\immediate\write18{convert -density 100 -alpha remove frames.pdf frames-\@percentchar02d.png}
\makeatother

% create a MP4 video (needs both ImageMagick and FFMPEG installed)
\makeatletter
\immediate\write18{convert -density 100 -alpha remove frames.pdf frames-\@percentchar02d.png}
\immediate\write18{ffmpeg -r 5 -i frames-\@percentchar02d.png -vcodec libx264 frames.mp4}
\makeatother

\begin{document}
% create a PDF animation
\begin{center}
    \animategraphics[controls,autoplay,loop,scale=1]{10}{frames}{}{}
\end{center}
\end{document}

GIF output

enter image description here

PNG output

I will not show all as they will waste your bandwidth.

enter image description here

enter image description here

...

enter image description here

3
  • Don't forget to use pdflatex -shell-escape inputfilename.tex to compile the given code above. Oct 25, 2013 at 14:19
  • I know it's "against the rules", but I just had to thank you for this – awesome answer!
    – sudosensei
    May 13, 2014 at 13:35
  • @kissmyarmpit I'll kiss your armpit for this great answer :p
    – JeT
    Feb 14, 2021 at 18:02
10

\usepgfplotslibrary{external} and package animate don't work well together.

\tikzexternalize moves the tikzpicture environment into an external file to be processed separately (therefore, --shell-escape must be activated) and replaces the tikzpicture environment with \includegraphics.

On the first pass when no external pdf graphics are available, the boxes into which the animateinline environment stores the code it encloses have zero size. animate measures the box dimensions of the first frame and scales the animation widget accordingly. There is a built-in stop condition in animate when it finds that the box is empty.

To work-around this, consider the following code:

\documentclass{article}
\usepackage{pgfplots}
\usepackage{animate}
% Comment out the following line to see what the plot looks like.
\usepgfplotslibrary{external}

\newlength\mywidth
\newlength\myheight
\newsavebox\mybox
\begin{lrbox}{\mybox}
  \def\ind{0}%
  \begin{tikzpicture}
    \begin{axis}[ymin=-1, ymax=1, xmin=0, xmax=3.14]
      \addplot {sin(deg(x+\ind*pi/16))};
    \end{axis}
  \end{tikzpicture}
\end{lrbox}
\settowidth\mywidth{\usebox\mybox}
\settoheight\myheight{\usebox\mybox}

\tikzexternalize
\begin{document}
%
\begin{animateinline}[controls]{10}
  \multiframe{30}{ind=0+1}{
    \makebox[\mywidth][l]{\rule{0pt}{\myheight}%
      \begin{tikzpicture}
        \begin{axis}[ymin=-1, ymax=1, xmin=0, xmax=3.14]
          \addplot {sin(deg(x+\ind*pi/16))};
        \end{axis}
      \end{tikzpicture}%
    }
  }
\end{animateinline}
%
\end{document}

An easy way to produce a standalone, correctly sized multipage PDF of all animation frames is:

\documentclass{article}
\usepackage{pgfplots}
\usepackage{ifthen}
\usepackage[tightpage,active]{preview}
\PreviewEnvironment{tikzpicture}

\begin{document}
%
\newcounter{ind}%
\whiledo{\theind<30}{%
  \begin{tikzpicture}
    \begin{axis}[ymin=-1, ymax=1, xmin=0, xmax=3.14]
      \addplot {sin(deg(x+\theind*pi/16))};
    \end{axis}
  \end{tikzpicture}%
  \stepcounter{ind}%
  \newpage%
}
%
\end{document}

This multipage PDF can be further converted to other formats, such as SWF:

pdf2swf frames.pdf
swfcombine -r10 --output frames10fps.swf --dummy frames.swf
7
  • 1
    I actually debated whether or not to use article or standalone with myself (my code didn't work with either) and should have stuck with the former as being in article is fine as far as the code is concerned. Note however that the original diagram is in beamer which I ruled out immediately. I like your answer, but as noted in the comments I already know of a way to do it independently of animate. I'd rather use animate and external together if it can be achieved.
    – qubyte
    Dec 21, 2011 at 10:17
  • @Mark: See my edit which makes animate and external work more or less smoothly together.
    – AlexG
    Dec 21, 2011 at 11:56
  • Thanks, but your first block of code gives me some errors...
    – qubyte
    Dec 21, 2011 at 13:26
  • @Mark. Everything ok on my side (copied back the code into a new file and ran pdflatex --shell-escape on it.)
    – AlexG
    Dec 21, 2011 at 13:41
  • Oh strange. It works perfectly now! It even works in standalone. ;) This is exactly what I was looking for. Thanks!
    – qubyte
    Dec 21, 2011 at 14:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.