Animación gif de una familia de curvas algebraicas usando Tikz y Gnuplot

Etiquetas: Tikz , LaTeX , Curvas

(English: Gif Animation of Family of Algebraic Curves using Tikz and Gnuplot)

Esta animación es un archivo gif que se creó con LaTeX y TikZ (un lenguaje de programación para producir imágenes dentro de LaTeX). Había intentado sin éxito, lograr hacer algo de este estilo con TikZ durante mucho tiempo, y finalmente descubrí cómo hacerlo. En esta entrada de blog describo todos los pasos.

Había dos aspectos “complicados” que había que resolver:

  1. LaTeX y TikZ to tienen funcionalidad para graficar curvas algebraicas (gráficas de ecuaciones implícitas de la forma $ f (x, y) = g (x, y) $ con polinomios $ f $ y $ g $) ya que esto requiere cálculos numéricos con alta precisión en los que LaTeX no es muy bueno (al ser, después de todo, un sistema de composición de textos).

  2. LaTeX y TikZ tampoco se pensaron para hacer animaciones, y no producen archivos gif. Parece haber cierta funcionalidad de animación con el formato SVG, y parece haber habido alguna funcionalidad de animación en PDF, pero ni los navegadores modernos ni los visores de PDF parecen comportarse bien con estas animaciones. Además, el formato gif es el estándar de facto de las animaciones de baja resolución en la web (piense en los íconos 3D que rotaban de la web de los años noventa – esos eran gifs).

Con estas complicaciones, no sobra preguntar por qué seguí intentándolo. Mi respuesta es que TikZ es fantástico de varias maneras:

  • Es compatible con la mayoría de los computadores modernos, y probablemente lo será por mucho tiempo. LaTeX ha sido parte del ecosistema de la computación desde hace aproximadamente 40 años.
  • TikZ permite tener mucho control sobre los elementos gráficos y al mismo tiempo permite que uno tenga notación matemática de alta calidad con LaTeX.
  • Las imágenes están “programadas”, por lo que se pueden modificar y usar para otras imágenes con mucha facilidad. Simplemente se cambian algunas líneas en el código, se vuelve a compilar con LaTeX, ¡y se obtiene una imagen!
  • Los formatos que produce TikZ son fáciles de compartir (PDF, o puede convertirse en PNG o SVG para la web).
  • Licencia de código abierto. Software “de la humanidad para la humanidad”.

Pensando en la dirección opuesta, le veo desventajas a formas alternativas de hacer estas animaciones:

  • Software de animación “estándar”: Dificultad con símbolos de matemáticas y graficando expresiones algebraicas.
  • Geogebra: No es tan fácil de compartir – las opciones son (1) compartir un archivo .ggb con el que muchas personas no saben qué hacer, o (2) alojarlo en geogebra.org e insertarlo en esta página web, que depende de que la página de geogebra siga manteniendo esa funcionalidad.
  • Desmos: Es fantástico para la interactividad y graficando curvas implícitas, pero no hay archivo que pueda almacenar. Solo puedo crear un enlace, que depende de que desmos.com exista en el futuro.

¡Por eso seguí tratando de hacerlo con TikZ! A continuación describo los detalles de cómo lograr hacer una animación de este estilo.

Producir una imagen de la animación: la gráfica de una curva algebraica

Como mencioné anteriormente, en LaTeX y TikZ no se pueden hacer gráficas de ecuaciones implícitas porque esto requiere cálculos numéricos muy precisos que van más allá del alcance de LaTeX. De por sí, es maravilloso que el lenguaje de programación gráfico TikZ pueda vivir dentro de LaTeX, ¡dado que el LaTeX es un sistema de composición de textos!

No obstante, hay una manera bastante simple de “encargar” los cálculos numéricos a Gnuplot que TikZ sabe cómo usar internamente.

Parece no haber muchas fuentes en Internet sobre cómo lograr esto. Construí el siguiente proceso a partir de cosas que aprendí de los siguientes enlaces:

Requisito: Gnuplot

Consulte el sitio web de Gnuplot para obtener instrucciones de instalación. En MacOS, esto es muy fácil de hacer con HomeBrew.

  • Instale el Homebrew (instrucciones en su sitio web).

  • Para instalar Gnuplot usando Homebrew tan solo hay que ejecutar el siguiente comando en la terminal:

    brew install gnuplot
    

Gráficos implícitos en TikZ con Gnuplot

Para graficar $ f (x, y) = g (x, y) $ con Gnuplot, uno produce la gráfica de la tajada $ z = 0 $ de la superficie $$ z = f (x, y) -g (x, y). $$ El código para hacer esto dentro de TikZ es bastante simple.

Este es un ejemplo:

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 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}

Y esta es la curva que produce:

La curva es una Cúbica de Chasles, es decir, de la forma $$ y=a x^{3}+b x^{2}y+c xy^{2}+d y^{3}.$$

Puede ver el efecto de los parámetros $a, b, c, d$ en la forma de la curva con el siguiente applet de Desmos que construí.

Visite esta página si la gráfica interactiva no carga.

De regreso al código de TikZ de la imagen, estos son unos aspectos clave:

  • El llamado a Gnuplot desde TikZ se hace en esta parte del código:

    \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);
        };
    

    El código produce, con Gnuplot, la gráfica de $F(x,y)=0$. Es decir, la gráfica de $$ y-\left(\backslash a * x^3+ \backslash b * x^2 * y+ \backslash c * x * y^2+ \backslash d * y^3\right)=0, $$ que se puede reescribir como $$ y= \backslash a * x^3+ \backslash b * x^2 * y+ \backslash c * x * y^2+ \backslash d * y^3. $$

  • Los \a, \b, \c y \d son los parámetros de la Cúbica, que se pueden cambiar con en esta parte del código:

    \def\a{-3.3}
    \def\b{5.4}
    \def\c{1.5}
    \def\d{4}
    
  • Así, el código de TikZ es en realidad un “Graficador de Cúbicas de Chasles”, pues da la gráfica de la cúbica $$ y=a x^{3}+b x^{2}y+c xy^{2}+d y^{3}$$ para los valores que se dan de \a, \b, \c y \d.

  • Para compilar este código de TikZ se debe usar PdfLaTeX en un modo especial que le permita ejecutar Gnuplot. Específicamente, se debe ejecutar pdflatex con la opción shell-escape, de la siguiente forma:

    pdflatex -shell-escape ChaslesCubic.tex
    

¡Eso es todo! El código para graficar curvas implícitas se compila igual que el código TikZ normal, pero utiliza Gnuplot para hacer los cálculos numéricos de alta precisión.

Creación de la animación en formato gif

Hacer la animación en formato gif es sorprendentemente simple después de que se descifró cómo hacer una sola imagen de la animación. Se basa en los siguientes hechos:

  • Agregar otro \begin{tikzpicture}...\end{tikzpicture} en el archivo de LaTeX crea una nueva página en el PDF, con una nueva imagen.
  • Uno puede crear un ciclo (en el sentido de programación) en TikZ el que crea muchas de estas nuevas páginas \begin{tikzpicture}...\end{tikzpicture} con un parámetro variable. Con esto, ¡se pueden crear las imágenes estáticas de la animación automáticamente con un ciclo! (este fenómeno – que lograr hacer una buena figura simplifica enormemente futuros usos – parece ser una constante al usar TikZ).
  • Es fácil tomar estos PDF de varias páginas y hacer un GIF con ellos usando ImageMagick.

Estos son los detalles:

Requisitos: ImageMagick

Mencioné ImageMagick en otra entrada de blog en donde jugó un papel crucial para obtener un PNG de buena calidad para la web a partir de un PDF con un gráfico vectorial. Aquí juega un papel igualmente importante.

Para instalar ImageMagick en MacOS:

  • Instale el Homebrew (instrucciones en su sitio web).

  • Instale ImageMagick desde la terminal usando Homebrew ejecutando el comando:

    brew install imagemagick
    

Creación de varias figuras con TikZ con un parámetro variable

El código se ve así:

\foreach \a in {0,0.5,1.0,...,10}{
   \begin{tikzpicture}
      ... 
         especificaciones de figura para la imagen con valor \a
      ...
   \end{tikzpicture}
}

Esto crea una página en el PDF para cada valor de $a$. En el caso que se muestra arriba con \a in {0,0.5,1.0,...,10}, la página 1 corresponde a $a= 0$, la página 2 corresponde a $ a = 0.5 $, la página 3 corresponde a $ a = 1.0 $ etc., hasta $ a = 10 $.

Ejemplo

Para obtener la animación al comienzo de esta entrada de blog, el código es el siguiente:

\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}
}

(hay que rodearlo con los comandos de TikZ usuales – puede descargar el código completo acá).

Esto traza la curva algebraica $$ x (x^2+y^2) = a y+5.8 x, $$ para distintos valores de $ a $. Un valor por página. El parámetro $a$ varía así: $$ a = -4, -3.8, -3.6, …, 0.0,0.2, …, 4.0, $$ ¡por lo que este código crea un pdf de 41 páginas! Si está interesado, puede descargar el PDF acá. Es muy pequeño (188 kb).

Las últimas líneas en el código agregan la ecuación de LaTeX bonita con el fondo blanco que se muestra en la parte superior de la imagen y el valor de $ a $ en la parte inferior izquierda ( a = ___ ).

Esta es la imagen que corresponde a $a = 1.2$:

Y esta es la imagen que corresponde al valor interesante $a = 0$:

Esta última imagen en realidad muestra la unión de dos curvas de grado menor, ya que cuando $a=0$ la curva $$x(x^2+y^2)=a y+5.8 x,$$ es en realidad $$x(x^2+y^2)=5.8 x,$$ que se puede factorizar como: $$x(x^2+y^2-5.8)=0.$$ La última ecuación muestra que la curva cúbica del valor $ a = 0 $ es la unión de la línea vertical $ x = 0 $ y el círculo $ x^2+y^2 = 5.8 $.

Creación del GIF a partir del PDF con varias páginas

¡Esto lo hace ImageMagick con mucha facilidad! Una vez uno tiene el PDF con una imagen por página, simplemente hay que ejecutar en la terminal:

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

El parámetro de densidad determina el tamaño y la calidad de cada imagen (300 es bastante alto), el delay determina la velocidad de la animación.

Este es, una vez más, el GIF que produce:

Más ejemplos

Hasta ahora empecé a explorar las posibilidades de esto, ¡pero parece bastante útil! El siguiente ejemplo es menos elaborado, ya que no requiere el uso de Gnuplot (no requiere gráficas de curva implícitas):

El código para esta última animación es este.

Nota final sobre el uso de Gnuplot en TikZ

El método que describí para hacer la gráfica implícita usando Gnuplot usa lo que se llama raw Gnuplot. Al parecer, en las nuevas versiones de pgfplots (la parte de TikZ que hace estas gráficas) parece haber un método aún más sencillo que usa el comando [contour gnuplot={levels={0}] en la especificación de una gráfica 3D regular. Jugué un poco con esto, y me pareció más lento y menos robusto en el manejo de singularidades en las curvas (como el caso $a=0$ que mostré arriba). En todo caso, vale la pena tenerlo presente. Así es como se ve el código para graficar $x(x^2+y^2) = (ay+5.8 x)$ con este método que no usa raw Gnuplot (el código es más corto):

\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}

También parece haber una forma de no depender de Gnuplot y usar luaLaTeX. Pero eso es tema para otra entrada de blog en el futuro.

Suscríbase

¿Quiere recibir un email cuando haya una nueva entrada de blog? Suscríbase acá.