Gif Animation of Family of Algebraic Curves using Tikz and Gnuplot

Tags: Tikz , LaTeX , Curves

(Español: Animación gif de una familia de curvas algebraicas usando Tikz y Gnuplot)

The animation above is a gif file that was created with LaTeX and TikZ. I had been trying to do something like this with TikZ unsuccessfully for a long time and I finally figured out how to do it. In this blog post I describe all the steps.

There were two “complicated pieces” to sort out:

  1. LaTeX and TikZ do not natively support graphing algebraic curves (implicit plots of the form $f(x,y)=g(x,y)$ with polynomial $f$ and $g$) because it requires precise numerical calculation which LaTeX is not very good at (being a typesetting system, after all).
  2. Latex and TikZ are also not very good at animations, and do not produce gifs. There seems to be some svg animation functionality, and there seems to have been some pdf animation functionality, but neither browsers or pdf viewers have provided good support for these. On the other hand, the web-friendly gif format is the de-facto standard for providing low-res animations on the web (think of rotating 3D logos from the 1990s web).

Given these complications, one may very well wonder why I kept trying to do it. My answer to that is that TikZ is fantastic in several ways:

  • Highly supported, and will probably be for a very long time. LaTeX runs basically on all computers.
  • TikZ gives full graphic control, while still allowing one to have high quality mathematical notation using LaTeX.
  • Images are “programmed” so they can be re-tooled/re-used very easily. Just change some lines in the code and re-compile to get a new pdf!
  • Output is easy to share (pdf, or can be converted to png or svg for the web).
  • Open source.

Thinking in the opposite direction, alternate ways to do these “animations” have downsides:

  • Animation software: difficulty with LaTeX equations, and curve plotting.
  • Geogebra: Not so easy to share – either .ggb files, or hosting it geogebratube and embedding it here, which relies on geogebratube still existing!
  • Desmos: Fantastic for interactivity, but there is no “file” that I can store. I can only create a link, which depends on desmos.com existing in the future.

This is why I kept trying to do it with TikZ! Here are the details which I figured out after plenty of web surfing and testing.

Producing One Frame of the Animation - Graphing an Algebraic Curve

As I mentioned above, LaTeX and TikZ do not natively support graphing algebraic curves because this requires very precise numerical calculations which LaTeX was not built for. It is already marvelous that the graphical programing language TikZ can live inside LateX, given that LaTeX is a typesetting system!

Nonetheless, there is a way to “outsource” the numerical calculations while still feeling one is just running TikZ code. This involves using Gnuplot which TikZ knows how to use internally.

There don’t seem to be many sources on the internet on how to accomplish this. I constructed the following workflow from things I learned from the following links:

Requirements: Gnuplot

See the Gnuplot website for installation instructions. In MacOS this is very easy to do using homebrew.

  • Install Homebrew if you don’t have it already (from the terminal.app). Instructions at their website.
  • To install Gnuplot, just run:
    brew install gnuplot
    

Implicit plots in TikZ using Gnuplot

To plot $f(x,y)=g(x,y)$ in Gnuplot, one plots the slice $z=0$ of the surface $$z=f(x,y)-g(x,y).$$ The code to do this in TikZ is pretty clean.

Here is a sample:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Enrique Acosta, 2022
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% To make pdf:
% ----------------------------------------
% *  Have gnuplot installed (brew install gnuplot)
% 
% *  Compile this with shellscape: 
%    pdflatex -shell-escape ChaslesCubic.tex
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\documentclass[border=2pt, tikz]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\begin{document}

\def\a{-3.3}
\def\b{5.4}
\def\c{1.5}
\def\d{4}

\begin{tikzpicture}
\begin{axis}[xmin=-1, xmax=1, ymin=-1, ymax=1]

    \addplot[blue,
        no markers,
        raw gnuplot,
        thick,
        empty line = jump %this is the default behaviour of PGFPlots
     ] gnuplot {
        f(x,y)=y-(\a*x^3+\b*x^2*y+\c*x*y^2+\d*y^3);
        set xrange [-1:1];
        set yrange [-1:1];
        set cntrparam levels incremental 0.001, 0.001, 0.001;
        set cont base;
        set view 0,0;
        unset surface;
        set isosamples 100,100;
        splot f(x,y);
    };

    % Equation of the curve
    \node[blue, fill=white] at (0,0.7) {$y=\a x^{3}+\b x^{2}y+\c xy^{2}+\d y^{3}$};
\end{axis}
\end{tikzpicture}
\end{document}

And here is the beautiful output:

The curve is a Chasles Cubic of the form $$ y=a x^{3}+b x^{2}y+c xy^{2}+d y^{3}.$$

You can play with the parameters $a,b,c,d$ yourself in the following desmos interactive I built. Desmos, is very good at interactivity!

Follow this link if the interactive does not load.

Back to the TikZ code, here are some details:

  • Gnuplot is run inside the TikZ code in the following piece:

    \addplot[blue,
            no markers,
            raw gnuplot,
            thick,
            empty line = jump %this is the default behaviour of PGFPlots
         ] gnuplot {
            F(x,y)=y-(\a*x^3+\b*x^2*y+\c*x*y^2+\d*y^3);
            set xrange [-1:1];
            set yrange [-1:1];
            set cntrparam levels incremental 0.001, 0.001, 0.001;
            set cont base;
            set view 0,0;
            unset surface;
            set isosamples 100,100;
            splot F(x,y);
        };
    

    This produces, using Gnuplot, the surface plot for $F(x,y)=0$, so for $$ y-\left(\backslash a * x^3+ \backslash b * x^2 * y+ \backslash c * x * y^2+ \backslash d * y^3\right)=0, $$ which one can rewrite as $$ y= \backslash a * x^3+ \backslash b * x^2 * y+ \backslash c * x * y^2+ \backslash d * y^3. $$

  • The \a, \b, \c and \d are the parameters, which one can change by changing their definitions in this piece of the code:

    \def\a{-3.3}
    \def\b{5.4}
    \def\c{1.5}
    \def\d{4}
    
  • So, the TikZ code is really a “ChaslesCubic pdf generator”, giving the graph of the cubic $$ y=a x^{3}+b x^{2}y+c xy^{2}+d y^{3}$$ for the specified values of \a, \b, \c and \d.

  • To run the code one needs to run LaTeX in a special mode that allows it to execute Gnuplot. Specifically, one needs to run pdflatex with the shell-escape flag, as follows:

    pdflatex -shell-escape ChaslesCubic.tex
    

That is it! Looks like TikZ code, is compiled just like TikZ code, but uses Gnuplot to handle the delicate numerical calculations.

Making the gif Animation

Making the gif animation is surprisingly simple after on frame is set up. It relies on the following facts:

  • Adding another \begin{tikzpicture}...\end{tikzpicture} to the LaTeX file creates a new page in the output pdf, and includes the figured specified by this second set of instructions in this new page.
  • One can create a loop in TikZ that creates many of these new pages \begin{tikzpicture}...\end{tikzpicture} using varying parameter. Think of this as being able to create the animation frames automatically using a loop!
  • It is very easy to grab these multi-page pdfs and make a gif out of them using ImageMagick.

Here are the details:

Prerequisites: Install ImageMagick

I had mentioned ImageMagick in another post in which it played a crucial role in getting good quality pngs for the web out of vector graphic pdfs. Here it plays an equally important role.

How to get ImageMagick for MacOS:

  • Install Homebrew if you don’t have it already (from the terminal.app). Instructions at their website.
  • Install ImageMagick from the terminal using Homebrew by executing the command:
    brew install imagemagick
    

Making multiple TikZ figures with a varying parameter

This is surprisingly simple. The code just looks like this:

\foreach \a in {0,0.5,1.0,...,10}{
   \begin{tikzpicture}
      ... 
         figure specifications for the picture with value \a
      ...
   \end{tikzpicture}
}

This will create one new pdf page with a new figure using the value of $a$. Page 1 will correspond to $a=0$, page 2 will be $a=0.5$, page 3 will be $a=1.0$, and so on up to $a=10$.

In the case of the animation at the beginning of this post, the code is the following:

\foreach \a in {-4, -3.8, ..., 4}{
    \begin{tikzpicture}
    \begin{axis}[xmin=-3, xmax=3, ymin=-8, ymax=8]
    \addplot[blue,
        no markers,
        raw gnuplot,
        thick,
        empty line = jump % this is the default behaviour
     ] gnuplot {
        f(x,y)=x*(x^2+y^2)-(\a*y+5.8*x);
        set xrange [-3:3];
        set yrange [-8:8];
        set cntrparam levels incremental 0.001, 0.001, 0.001;
        set cont base;
        set view 0,0;
        unset surface;
        set isosamples 100,100;
        splot f(x,y);
    };

    % Equation with white around it
    \node[right, blue, fill=white] at (-2,6) {$x(x^2+y^2)=(ay+5.8x)$};

    % Print the value of a
    \pgfkeys{/pgf/number format/.cd,fixed};
    \node[right] at (-2.7,-6) {$a=\pgfmathprintnumber{\a}$};

    \end{axis}
    \end{tikzpicture}
}

(code must be warpped around the usual TikZ commands – full code can be downloaded here.)

This plots the algebraic curve $$x(x^2+y^2)=a y+5.8 x$$ for varying values of $a$, one value per page. The parameter $a$ is varying as $a=-4,-3.8,-3.6, …,0.0,0.2,…,4.0$, so this code creates a 41 page pdf, one page and plot for each value of $a$! If interested, you can download the pdf here. It is pretty small, at 188kb.

The last lines in the code add the nice looking LaTeX equation with a white background on top of the curve, and the value of $a$ in the display a=___ on the bottom left.

This is the frame corresponding to $a=1.2$:

And this is the interesting frame corresponding to $a=0$:

This last frame shows actually shows the union of two lower degree curves since when $a=0$, the curve $$x(x^2+y^2)=a y+5.8 x,$$ becomes $$x(x^2+y^2)=5.8 x,$$ which factors as: $$x(x^2+y^2-5.8)=0.$$ The last equation shows that the cubic curve for $a=0$ is the union of the vertical line $x=0$ and the degree two circle $x^2+y^2=5.8$.

Creating the gif out of the multi-page pdf

This is a breeze with imageMagick once one has the pdf with one frame per page. Just run in the terminal:

convert -density 300 -delay 5 -loop 0 -alpha remove gnuplotTest.pdf gnuplotTest.gif

The density parameter determines the size and quality of each frame (300 is pretty high), the delay determines the speed of the animation.

Here is the gif once more:

More Samples

Just now started playing with this, but it seems pretty useful! This next one is less elaborate since it does not require the use of Gnuplot (no implicit curve plotting is needed):

The code for this last animation is here.

One final note on use of Gnuplot

The method I described to do the implicit plot using Gnuplot uses raw Gnuplot. There seems to be an even more straightforward method in newer versions of pgfplots that use [contour gnuplot={levels={0}] in a regular 3d plot. I played around with this a bit, and it seemed to be both slower and not deal with singularities as well as the method I outlined above. Here is how the code to plot $x(x^2+y^2)=(ay+5.8 x)$ would look like:

\documentclass[border=2pt, tikz]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.17}

\begin{document}
    \def\a{1.2}

    \begin{tikzpicture}
    \begin{axis}[view={0}{90}, xmin=-3, xmax=3]
    
    \addplot3 [
        domain=-3:3,
        domain y=-8:8,
        samples=150,
        thick,
        contour gnuplot={levels={0}, labels=false},
    ]{x*(x^2+y^2)-(\a*y+\b*x)};

    % Equation with white around it
    \node[right, blue, fill=white] at (-2,6) {$x(x^2+y^2)=(ay+5.8 x)$};

    % Print the value of a
    \pgfkeys{/pgf/number format/.cd,fixed};
    \node[right] at (-2.7,-6) {$a=\pgfmathprintnumber{\a}$};

    \end{axis}
    \end{tikzpicture}

\end{document}

There also seems to be a way to do these implicit plots in TikZ without depending on Gnuplot, but relying on compiling the .tex file with LuaLaTeX instead of pdfLaTeX. But this is the subject of a possible future blog entry…

Subscribe

Want to get an email when a new post is added? If so, subscribe here.