5

I am writing a simple animation in beamer using tikz. The code is as follows

\documentclass{beamer}
\usepackage{tikz}
\usetikzlibrary{positioning}

\begin{document}

\begin{frame}[fragile]\relax
\foreach \i in {0,...,3}{
\only<+>{
    \begin{tikzpicture}[node distance=.3]
        \node[circle,draw](x0){$x_0$};
        \foreach\x [remember=\x as \px (initially 0)] in {1,...,\i}{
            \node[draw, right=of x\px](P\x){$P[x_{\px}, x_{\x}]$};
            \node[circle,draw, right=of P\x](x\x){$x_{\x}$};
            \draw (P\x) edge (x\px) edge (x\x);
        }
        \node[draw, right=of x\i] (L) {$L[x_{\i}]$};
        \draw (L) edge (x\i) ;
    \end{tikzpicture}
}}
\end{frame}

\end{document}

As you can see, the outer foreach starts from \i=0; the inner one loops over a list {1,...,\i} which in the first iteration of the outer for rewrites to {1,...,0}. Now the intended semantics of the inner for's list in the first iteration is the empty list but PGF interprets it as {1,0}, which generates the wrong picture in my example. A bit surprisingly {1,2,...,0} is treated as {1,2}.

I solved the issue by extracting the first iteration outside the outer loop but I was wondering: is there a more elegant solution?

2

You can make use of the package xifthen. It provides a function called \ifthenelse{<if-clause>}{then-code}{else-code}. In the above before calling the \foreach-loop there's a test if your \i-counter is bigger than 0. If it is 0 no code will be run (empty else-code). If it is bigger your \foreach-loop is executed.

Hope this helps

\documentclass{beamer}
\usepackage{tikz}
\usetikzlibrary{positioning}

% Use package xifthen
\usepackage{xifthen}

\begin{document}
\begin{frame}[fragile]\relax
\foreach \i in {0,...,3}{
\only<+>{
 \begin{tikzpicture}[node distance=.3]
  \node[circle,draw](x0){$x_0$};
   \ifthenelse{\i > 0}{ % Check if \i bigger than 0, if true then run
    \foreach\x [remember=\x as \px (initially 0)] in {1,...,\i}{
     \node[draw, right=of x\px](P\x){$P[x_{\px}, x_{\x}]$};
     \node[circle,draw, right=of P\x](x\x){$x_{\x}$};
     \draw (P\x) edge (x\px) edge (x\x);
    }
   }{}; % Else run nothing
  \node[draw, right=of x\i] (L) {$L[x_{\i}]$};
  \draw (L) edge (x\i) ;
 \end{tikzpicture}
 }}
\end{frame}
\end{document}

Edit: As percusse stated in his comment, the check for \i > 0 can also be done by the internals without using extra libraries (like xifthen). For example with \ifnum

\documentclass{beamer}
\usepackage{tikz}
\usetikzlibrary{positioning}

\begin{document}
\begin{frame}[fragile]\relax
\foreach \i in {0,...,3}{
\only<+>{
 \begin{tikzpicture}[node distance=.3]
  \node[circle,draw](x0){$x_0$};
   \ifnum\i>0 % Check if \i bigger than 0 and if true run the \foreach
    \foreach\x [remember=\x as \px (initially 0)] in {1,...,\i}{
     \node[draw, right=of x\px](P\x){$P[x_{\px}, x_{\x}]$};
     \node[circle,draw, right=of P\x](x\x){$x_{\x}$};
     \draw (P\x) edge (x\px) edge (x\x);
    }
    \fi % End if-clause
  \node[draw, right=of x\i] (L) {$L[x_{\i}]$};
  \draw (L) edge (x\i) ;
 \end{tikzpicture}
 }}
\end{frame}
\end{document}
  • Pgf also has if then functionality. – percusse Aug 27 '14 at 6:58
  • The \ifnum solution is my preferred one. However I was hoping there was a way to tell PGF to generate the empty list for the inner loop on the first iteration. At least this avoids code duplication. – Bordaigorl Aug 27 '14 at 21:32

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.