Drawing an animated distorted grid

Here is a solution using LuaLaTeX for two reasons:

  • there are many complex formula in this graph, so it's easier with a real programming language
  • there are a lot of trigonometric calculations, and for this Lua is faster than TeX

The LaTeX file:

\documentclass{minimal}

\usepackage[a4paper,top=20mm,bottom=20mm,left=15mm,right=15mm]{geometry}
\usepackage{tikz}
\usepackage{animate}

\begin{document}

\directlua{require("anim.lua");}
\begin{center}
    \begin{animateinline}[poster=first,controls,loop]{20}
        \multiframe{20}{rt=0+0.05}{
            \begin{tikzpicture}
                \useasboundingbox (-8.5,-5.4) rectangle (8.5,3.1);
                \directlua{plot_grid(8,4,0.3,\rt);}
            \end{tikzpicture}
        }
    \end{animateinline}
\end{center}


\end{document}

File anim.lua (in same directory):

ak,bk,omegak={0.6,0.8},{10,20},{2*math.pi,4*math.pi} -- list of coefs
zmax=2
function wave(r,theta,t)
    sum=0
    for k=1,#ak do
        sum=sum+math.exp(-ak[k]*r)*math.cos(bk[k]*r-omegak[k]*t)*r^k
    end
    return sum*math.sin(theta)
end
function color(z) -- color of facets
    if z>0 then if z<zmax then col="red!"..(100*z/zmax); else col="red"; end -- red color for positive wave values
    else if z>-zmax then col="blue!"..(-100*z/zmax); else col="blue"; end -- blue color for positive wave values
    end
    return col
end
function plot_grid(width,height,shrink,t)
    local gridx,gridy={},{}
    local Nr,Nt=20,10
    local zscale=1
    for i=0,Nr do
        local r=i/Nr
        gridx[i]={}
        gridy[i]={}
        for j=-Nt,Nt do
            local theta=math.pi*j/Nt
            local z=wave(r,theta,t)
            local factor=1-shrink*math.cos(theta)
            local x=r*width*factor*math.sin(theta)
            local y=r*height*factor*math.cos(theta)+z*zscale*factor
            gridx[i][j]=x
            gridy[i][j]=y
        end
    end

    -- grid faces, from top to bottom
    for j=0,Nt-1 do
        local theta=math.pi*j/Nt
        local start,stop,step=0,Nr-1,1
        if theta<math.pi/2 then start,stop,step=Nr-1,0,-1; end
        for i=start,stop,step do
            local r=i/Nr
            -- print facet at (r,theta)
            tex.print("\\filldraw[fill="..color(wave(r,theta,t)).."] ("..gridx[i][j]..","..gridy[i][j]..") -- ("..gridx[i+1][j]..","..gridy[i+1][j]..") -- ("..gridx[i+1][j+1]..","..gridy[i+1][j+1]..") -- ("..gridx[i][j+1]..","..gridy[i][j+1]..") -- cycle;")
            -- print facet at (r,-theta)
            tex.print("\\filldraw[fill="..color(wave(r,-theta,t)).."] ("..gridx[i][-j]..","..gridy[i][-j]..") -- ("..gridx[i+1][-j]..","..gridy[i+1][-j]..") -- ("..gridx[i+1][-j-1]..","..gridy[i+1][-j-1]..") -- ("..gridx[i][-j-1]..","..gridy[i][-j-1]..") -- cycle;")

        end
    end
end

You can compile it twice with lualatex and then open it with Acrobat Reader (the only reader that shows animations). The result is: enter image description here


Explanations:

First of all, a little word about LuaLaTeX. It's like another LaTeX engine, but you can add Lua code inside. Lua is a simple scripting language, with functions, loops and conditional statements like others. Lua chunks are included for example in directlua{...} statements. When LuaLaTeX compiles the files, the directlua{...} are executed and replaced by their output; which is LaTeX code; for example, here the line \directlua{plot_grid(8,4,0.3,\rt);} is replaced by

\filldraw[fill=blue!-0] (0,2.66) -- (0,2.8) -- (-1.7667936522486,2.8044534789179) -- (-1.6784539696362,2.6194714601329) -- cycle;
\filldraw[fill=blue!0] (0,2.52) -- (0,2.66) -- (1.6784539696362,2.5462786901229) -- (1.5901142870238,2.3797166001964) -- cycle;
\filldraw[fill=blue!-0] (0,2.52) -- (0,2.66) -- (-1.6784539696362,2.6194714601329) -- (-1.5901142870238,2.5141519632038) -- cycle;
....

that is, Tikz commands. Then a pure LaTeX document is generated and compiled as another LaTeX document.

As a summary: LuaLaTeX documents are normal LaTeX ones, but with some Lua chunks that generates many LaTeX code in place of you.

Then as to the files, commencing with the LaTeX one: it's very simple; \animateinline defines an animation with 20 frames and looping, and \multiframe iterates time (real variable \rt) from 0 with step 0.05, and do this 20 times, so that \rt will have values: 0,0.05,0.10,...,0.95. Then we define a tikzpicture with a bounding box (thanks to AlexG) and call Lua plot_grid function which will generate all the graph.

The anim.lua file begins with global variables definitions: 3 arrays of coefficients corresponding to the sum you've proposed for the wave. You can add more coefs, but the 3 arrays must have same length. Then zmax is for coloring, we will see that further.

Function wave is used to compute the wave value at r,θ coordinates and t time. It computes a sum using the coefficients (this part I think is difficult in pure LaTeX) and returns the result.

Function color is for coloring the facets, we will use it later. If z>zmax the color is red; if 0 < z < zmax the color is partially red; and the same with blue for negative values.

Function plot_grid has two part. First, it calculates the cordinates of each node of the grid. It creates two empty arrays, and defines the numbers Nr and Nt of points. In the loops, you can see that r will go from 0 to 1 with Nr intervals, and theta from -π to +π with 2 Nt intervals. Then for each (r,θ) pairs it proceeds as follow:

  • compute the perspective factor. Normally the grid would show from -width to +width and -height to +height. But in your question you wanted some perspective, that is the grid on the top is smaller than on the bottom. Here I introduce parameter shrink which has this meaning: on the top, the grid size is multiplied by 1-shrink and on the bottom it is multiplied by 1+shrink.
  • compute the x and y position. The factor is used to multiply the width and height of the grid, and in y we add the amplitude of the wave (z) multipliez by a scaling factor which you can modify.
  • store the results in the arrays

When this is done, we can draw the facets, from top to bottom beacause of perspective. That's the second loop. We begin with θ close to 0, which are the farther facets. The start,stop,step lines are for perspective also: if -π/2<θ<π/2 then we should draw the big radius first and go to the center, in other cases we should go from center to border. Then comes the heart of that: tex.print allows to print output which will be replaced in the LaTeX document. Here it is a simple \filldraw Tikz command; string concatenation is .. in Lua. You can remark also that we draw simultaneously (r,θ) and (r,-θ) facets.

Concluding remark: The first time I tried LuaLaTeX I was afraid, but since then I've become found of it. When you do scientific graphs or simulations, it's really useful. With Lua in my LaTeX documents, I can draw complex plots, draw implicit plots, solve ODE, integrate functions, and then do entire simulations in my LaTeX document. It's necessary to learn a new (simple) programming language, but the power of Lua+LaTeX is awesome!