Introduction
A long time ago I started learning how to use TikZ and I created some not very well made diagrams. One of those diagrams is a state space representation of linear dynamical systems. When I discovered I could perform animations with TikZ I tried my best to animate that diagram as an explanation of one should think step by step to draw and to understand the diagram.
Recently I redesigned some old diagrams with new methods I learned and decided to create some animations, but I noticed I should also revise how to animate them, since they were different from the originals draws I made.
Question
And now comes the decision-making point. What would be the best method to animate these diagrams, creating step by step, in diagrams where I create the nodes and then the connections between them (MWE 2 below)? How to create such step by step animation after a already read TikZ diagram?
I know asking for "The Best " is a little bit subjective and opinion based, but in this case, it just lacks me information to decide how to proceed and it would take a long time to learn by trial and error which method is more suitable.
Criteria for "The Best".
- Less changes in the original TikZ drawn
- Allowing step by step of the diagram in (almost) any order
- Compiling fast (or not so long)
Background
I've seen some possibilities with uncover
, multido
, creating multiple pages pdf and using \animategraphics
, but I don't know which one would fit the best my needs.
- uncover: Animate Line / Path using Tikz and 'animate' package
- multido: how to hold previous lines in \multiframe in \tikz?
- multiple pages pdf animation How to draw a cobweb graph like this one?
\animategraphics[<options>]{<frame rate>}{<file basename>}{<first>}{<last>}
The animate Package
As fas as I've read, I guess uncover
seems to better fill my criteria.
Original diagram and animation – MWE 1
This is the first method I created the animation. It is clumsy, I used \ifthenelse
to define what is presented in ecah step, the code is long, I didn't know how to keep what have already been draw. It is a mess. (I don't even remember where I find the example I based this code).
MWE 1 follows:
\documentclass[border=5pt]{standalone}
\usepackage{amsmath,xifthen,tikz,animate}
\usetikzlibrary{calc}
\begin{document}
\begin{animateinline}[poster=last, controls]{1}
\multiframe{8}{ii=0+1}{% ii=0,1,...99 ; rj=9.9,9.8,...,0.0
\begin{tikzpicture}[very thick, every node/.style={font=\LARGE}];
\definecolor{dkg}{rgb}{0,0.5,0};
% ==========
\useasboundingbox (-6,-3) rectangle ++(20,8);
\node[blue, right] at (9.5,-0.5) {\Huge Step:\ii};
\draw (2.5,0) rectangle ++(2,2) coordinate(G) node[pos=0.5] {\Huge{$\int$}};
\node at (-1,-1.5) {
\begin{tabular}{l}
$\dot{x} = A x + B u$ \\
$y = C x + D u$
\end{tabular}
};
\ifthenelse{\ii < 1}{
\draw [-latex, teal] (G)++(0,-1) -- ++(1,0) coordinate(X) node[above]{$x$} -- ++(1,0);
}{
\ifthenelse{\ii < 2}{
\draw [-latex, teal] (G)++(0,-1) -- ++(1,0) coordinate(X) node[above]{$x$} -- ++(1,0);
\draw (1,1) coordinate(S) circle (1/2);
\draw [-latex, orange] (S)++(1/2,0) -- ++(1,0) coordinate(E) node[midway, above]{$\dot{x}$};
}{
\ifthenelse{\ii < 3}{
\draw [-latex, teal] (G)++(0,-1) -- ++(1,0) coordinate(X) node[above]{$x$} -- ++(1,0);
\draw (1,1) coordinate(S) circle (1/2);
\draw [-latex, orange] (S)++(1/2,0) -- ++(1,0) coordinate(E) node[midway, above]{$\dot{x}$};
\draw (2.5,-2.5) coordinate(A) rectangle ++(2*1,2*1) node[pos=0.5]{$A$};
\draw [-latex, teal] (X) -- ++(0,-2.5) -- ++(-1,0);
}{
\ifthenelse{\ii < 4}{
\draw [-latex, teal] (G)++(0,-1) -- ++(1,0) coordinate(X) node[above]{$x$} -- ++(1,0);
\draw (1,1) coordinate(S) circle (1/2);
\draw [-latex, orange] (S)++(1/2,0) -- ++(1,0) coordinate(E) node[midway, above]{$\dot{x}$};
\draw (2.5,-2.5) coordinate(A) rectangle ++(2*1,2*1) node[pos=0.5]{$A$};
\draw [-latex, teal] (X) -- ++(0,-2.5) -- ++(-1,0);
\draw [-latex, cyan] ($(A)+(0,1)$) -| ($(S)+(0,-0.5)$) node[below right]{$+$};
}{
\ifthenelse{\ii < 5}{
\draw [-latex, teal] (G)++(0,-1) -- ++(1,0) coordinate(X) node[above]{$x$} -- ++(1,0);
\draw (1,1) coordinate(S) circle (1/2);
\draw [-latex, orange] (S)++(1/2,0) -- ++(1,0) coordinate(E) node[midway, above]{$\dot{x}$};
\draw (2.5,-2.5) coordinate(A) rectangle ++(2*1,2*1) node[pos=0.5]{$A$};
\draw [-latex, teal] (X) -- ++(0,-2.5) -- ++(-1,0);
\draw [-latex, cyan] ($(A)+(0,1)$) -| ($(S)+(0,-0.5)$) node[below right]{$+$};
\draw (-2.5,0) rectangle ++(2*1,2*1) coordinate(B) node[pos=0.5]{$B$};
\draw [-latex, red] (B)++(0,-1) -- ++(1,0) node[above left]{$+$};
\draw [-latex, dkg] (-4,1) coordinate(u) node[above]{$u$} |- ++(1.5,0);
}{
\ifthenelse{\ii < 6}{
\draw [-latex, teal] (G)++(0,-1) -- ++(1,0) coordinate(X) node[above]{$x$} -- ++(1,0);
\draw (1,1) coordinate(S) circle (1/2);
\draw [-latex, orange] (S)++(1/2,0) -- ++(1,0) coordinate(E) node[midway, above]{$\dot{x}$};
\draw (2.5,-2.5) coordinate(A) rectangle ++(2*1,2*1) node[pos=0.5]{$A$};
\draw [-latex, teal] (X) -- ++(0,-2.5) -- ++(-1,0);
\draw [-latex, cyan] ($(A)+(0,1)$) -| ($(S)+(0,-0.5)$) node[below right]{$+$};
\draw (-2.5,0) rectangle ++(2*1,2*1) coordinate(B) node[pos=0.5]{$B$};
\draw [-latex, red] (B)++(0,-1) -- ++(1,0) node[above left]{$+$};
\draw [-latex, dkg] (-4,1) coordinate(u) node[above]{$u$} |- ++(1.5,0);
\draw (6.5,0) coordinate(C) rectangle ++(2*1,2*1) node[pos=0.5]{$C$};
\draw (10.5,1) coordinate(y) circle (1/2);
\draw [-latex, violet] (y)++(0.5,0) -- ++(1,0) node[above]{$y$};
\draw [-latex, olive] ($(C)+(2*1,1)$) -- ($(y)+(-0.5,0)$) node[above left]{$+$};
}{
\ifthenelse{\ii < 7}{
\draw [-latex, teal] (G)++(0,-1) -- ++(1,0) coordinate(X) node[above]{$x$} -- ++(1,0);
\draw (1,1) coordinate(S) circle (1/2);
\draw [-latex, orange] (S)++(1/2,0) -- ++(1,0) coordinate(E) node[midway, above]{$\dot{x}$};
\draw (2.5,-2.5) coordinate(A) rectangle ++(2*1,2*1) node[pos=0.5]{$A$};
\draw [-latex, teal] (X) -- ++(0,-2.5) -- ++(-1,0);
\draw [-latex, cyan] ($(A)+(0,1)$) -| ($(S)+(0,-0.5)$) node[below right]{$+$};
\draw (-2.5,0) rectangle ++(2*1,2*1) coordinate(B) node[pos=0.5]{$B$};
\draw [-latex, red] (B)++(0,-1) -- ++(1,0) node[above left]{$+$};
\draw [-latex, dkg] (-4,1) coordinate(u) node[above]{$u$} |- ++(1.5,0);
\draw (6.5,0) coordinate(C) rectangle ++(2*1,2*1) node[pos=0.5]{$C$};
\draw (10.5,1) coordinate(y) circle (1/2);
\draw [-latex, violet] (y)++(0.5,0) -- ++(1,0) node[above]{$y$};
\draw [-latex, olive] ($(C)+(2*1,1)$) -- ($(y)+(-0.5,0)$) node[above left]{$+$};
\draw (2.5,2.5) coordinate(D) rectangle ++(2*1,2*1) coordinate(B) node[pos=0.5]{$D$};
\draw [-latex, dkg] ($(u)+(0.5*1,0)$) |- ($(D)+(0,1)$);
\draw [-latex, cyan] ($(D)+(2*1,1)$) -| ($(y)+(0,0.5)$) node[above right]{$+$};
}{
\draw [-latex, teal] (G)++(0,-1) -- ++(1,0) coordinate(X) node[above]{$x$} -- ++(1,0);
\draw (1,1) coordinate(S) circle (1/2);
\draw [-latex, orange] (S)++(1/2,0) -- ++(1,0) coordinate(E) node[midway, above]{$\dot{x}$};
\draw (2.5,-2.5) coordinate(A) rectangle ++(2*1,2*1) node[pos=0.5]{$A$};
\draw [-latex, teal] (X) -- ++(0,-2.5) -- ++(-1,0);
\draw [-latex, cyan] ($(A)+(0,1)$) -| ($(S)+(0,-0.5)$) node[below right]{$+$};
\draw (-2.5,0) rectangle ++(2*1,2*1) coordinate(B) node[pos=0.5]{$B$};
\draw [-latex, red] (B)++(0,-1) -- ++(1,0) node[above left]{$+$};
\draw [-latex, dkg] (-4,1) coordinate(u) node[above]{$u$} |- ++(1.5,0);
\draw (6.5,0) coordinate(C) rectangle ++(2*1,2*1) node[pos=0.5]{$C$};
\draw (10.5,1) coordinate(y) circle (1/2);
\draw [-latex, violet] (y)++(0.5,0) -- ++(1,0) node[above]{$y$};
\draw [-latex, olive] ($(C)+(2*1,1)$) -- ($(y)+(-0.5,0)$) node[above left]{$+$};
\draw (2.5,2.5) coordinate(D) rectangle ++(2*1,2*1) coordinate(B) node[pos=0.5]{$D$};
\draw [-latex, dkg] ($(u)+(0.5*1,0)$) |- ($(D)+(0,1)$);
\draw [-latex, cyan] ($(D)+(2*1,1)$) -| ($(y)+(0,0.5)$) node[above right]{$+$};
\draw [very thick, red] (-3,-3) coordinate(eq) rectangle ++(12,8);
}}}}}}}
\end{tikzpicture}
}
\end{animateinline}
\end{document}
The result is as follows.
New diagram to animated – MWE 2
This new diagram uses some personal local defined /.style
s and is much better organized. Nodes are defined first and then connections are made. The code is clean, easy to change, much better than the older one. But I don't how the best way to animate it.
MWE 2 follows:
\documentclass[border=10pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\tikzset{addCross/.style n args={6}{
minimum size={#5 mm}, %minimum height=10mm,
path picture={
\draw[#6]
(path picture bounding box.south east) -- (path picture bounding box.north west)
(path picture bounding box.south west) -- (path picture bounding box.north east);
\node at ($(path picture bounding box.south)!0.4!(path picture bounding box.center)$) {#1};
\node at ($(path picture bounding box.west)!0.4!(path picture bounding box.center)$) {#2};
\node at ($(path picture bounding box.north)!0.4!(path picture bounding box.center)$) {#3};
\node at ($(path picture bounding box.east)!0.4!(path picture bounding box.center)$) {#4};
}
},
addCross/.default={}{}{}{}{10}{}
}
\tikzset{mySimpleArrow/.style n args={2}{
>={latex[#1]},
every path/.style={draw=#2}
},
mySimpleArrow/.default={black}{black}
}
\tikzset{myBlockOpacity/.style n args={4}{
every node/.style={rectangle,draw, text=black,
minimum width=#1, minimum height=#2,
fill opacity=#3, text opacity=#4}
},
myBlockOpacity/.default={1cm}{1cm}{0.4}{1}
}
\begin{document}
\begin{tikzpicture}[very thick]
\begin{scope}
\node[circle,draw,addCross={$+$}{$+$}{}{}{10}{black}] (N1) at (1,-0.5) {};
\end{scope}
\begin{scope}[shift={(3.0,-0.5)},myBlockOpacity]
\node[fill=red] (A) at (0,-1.5) {$A$};
\node[fill=green!50!black] (B) at (-4,0) {$B$};
\node[fill=yellow!75!black] (C) at (3,0) {$C$};
\node (I) at (0,0) {$\displaystyle \int$};
\end{scope}
\begin{scope}[mySimpleArrow={blue}{cyan}]
\path[->] (-2.5,-0.5) node[above]{$u$} -- (B);
\path[->] (B) -- (N1);
\path[->] (N1) -- (I) node[midway, above] {$\dot{x}$};
\path[->] (I) -- (4.5,-0.5) coordinate(x) node[above]{$x$} -- (C);
\path[->] (x) |- (A) -| (N1);
\path[->] (C) -- ++(1.5,0) node[above]{$y$};
\end{scope}
\end{tikzpicture}
\end{document}
which produces
Best Answer
An off-
beamer
class\uncover
command is defined, that specifies the frame number at which an object in atikzpicture
is to be revealed.It relies on the
\phantom{...}
command which prevents the object from being drawn, yet evaluates coordinate definitions and even TikZ's automatic bounding box calculations. This allows us to reference node coordinates of hidden objects without changing too much of the original code.