27

Friends, sometimes during an automata keynote, I have to present a string recognition step-by-step example. Please consider the following TikZ code:

\begin{tikzpicture}[shorten >=1pt,node distance=2cm,on grid,auto,/tikz/initial text=] 
   \node[state,initial] (q_0)   {$q_0$}; 
   \node[state] (q_1) [right=of q_0] {$q_1$}; 
   \node[state,accepting] (q_2) [right=of q_1] {$q_2$}; 
    \path[->] 
    (q_0) edge node {a} (q_1)
    (q_1) edge [loop above] node {a} ()
    (q_1) edge node {b} (q_2);
\end{tikzpicture}

which outputs the following automaton:

Automaton 1

So far so good. Then, for an example, I take a string and show how the execution will happen. Let's say I want to check aab:

Image 1 Image 2

Image 3 Image 4

Image 5 Image 6

Image 7 Image 8

I achieve these slides by manually highlighting the specific parts of my automaton. The full code is as follows:

\documentclass{beamer}

\usepackage{tikz}
\usetikzlibrary{automata,positioning}

\begin{document}

\begin{frame}{String recognition}

\begin{itemize}
    \item \textbf{String:} \texttt{aab}
\end{itemize}

\begin{tikzpicture}[shorten >=1pt,node distance=2cm,on grid,auto,/tikz/initial text=] 
   \node[state,initial] (q_0)   {$q_0$}; 
   \node[state] (q_1) [right=of q_0] {$q_1$}; 
   \node[state,accepting] (q_2) [right=of q_1] {$q_2$}; 
    \path[->] 
    (q_0) edge node {a} (q_1)
    (q_1) edge [loop above] node {a} ()
    (q_1) edge node {b} (q_2);
\end{tikzpicture}

\end{frame}

\begin{frame}{String recognition}

\begin{itemize}
    \item \textbf{String:} \texttt{aab}
\end{itemize}

\begin{tikzpicture}[shorten >=1pt,node distance=2cm,on grid,auto,every initial by arrow/.style={draw=blue},/tikz/initial text=] 
   \node[state,initial,draw=blue] (q_0)   {\color{blue} $q_0$}; 
   \node[state] (q_1) [right=of q_0] {$q_1$}; 
   \node[state,accepting] (q_2) [right=of q_1] {$q_2$}; 
    \path[->] 
    (q_0) edge node {a} (q_1)
    (q_1) edge [loop above] node {a} ()
    (q_1) edge node {b} (q_2);
\end{tikzpicture}

\end{frame}

\begin{frame}{String recognition}

\begin{itemize}
    \item \textbf{String:} \texttt{aab}
\end{itemize}

\begin{tikzpicture}[shorten >=1pt,node distance=2cm,on grid,auto,/tikz/initial text=] 
   \node[state,initial] (q_0)   {$q_0$}; 
   \node[state] (q_1) [right=of q_0] {$q_1$}; 
   \node[state,accepting] (q_2) [right=of q_1] {$q_2$}; 
    \path[->] 
    (q_0) edge [draw=blue] node {\color{blue} a} (q_1)
    (q_1) edge [loop above] node {a} ()
    (q_1) edge node {b} (q_2);
\end{tikzpicture}

\end{frame}

\begin{frame}{String recognition}

\begin{itemize}
    \item \textbf{String:} \texttt{aab}
\end{itemize}

\begin{tikzpicture}[shorten >=1pt,node distance=2cm,on grid,auto,/tikz/initial text=] 
   \node[state,initial] (q_0)   {$q_0$}; 
   \node[state] (q_1) [draw=blue,right=of q_0] {\color{blue} $q_1$}; 
   \node[state,accepting] (q_2) [right=of q_1] {$q_2$}; 
    \path[->] 
    (q_0) edge node {a} (q_1)
    (q_1) edge [loop above] node {a} ()
    (q_1) edge node {b} (q_2);
\end{tikzpicture}

\end{frame}

\begin{frame}{String recognition}

\begin{itemize}
    \item \textbf{String:} \texttt{aab}
\end{itemize}

\begin{tikzpicture}[shorten >=1pt,node distance=2cm,on grid,auto,/tikz/initial text=] 
   \node[state,initial] (q_0)   {$q_0$}; 
   \node[state] (q_1) [right=of q_0] {$q_1$}; 
   \node[state,accepting] (q_2) [right=of q_1] {$q_2$}; 
    \path[->] 
    (q_0) edge node {a} (q_1)
    (q_1) edge [draw=blue,loop above] node {\color{blue} a} ()
    (q_1) edge node {b} (q_2);
\end{tikzpicture}

\end{frame}

\begin{frame}{String recognition}

\begin{itemize}
    \item \textbf{String:} \texttt{aab}
\end{itemize}

\begin{tikzpicture}[shorten >=1pt,node distance=2cm,on grid,auto,/tikz/initial text=] 
   \node[state,initial] (q_0)   {$q_0$}; 
   \node[state] (q_1) [draw=blue,right=of q_0] {\color{blue} $q_1$}; 
   \node[state,accepting] (q_2) [right=of q_1] {$q_2$}; 
    \path[->] 
    (q_0) edge node {a} (q_1)
    (q_1) edge [loop above] node {a} ()
    (q_1) edge node {b} (q_2);
\end{tikzpicture}

\end{frame}

\begin{frame}{String recognition}

\begin{itemize}
    \item \textbf{String:} \texttt{aab}
\end{itemize}

\begin{tikzpicture}[shorten >=1pt,node distance=2cm,on grid,auto,/tikz/initial text=] 
   \node[state,initial] (q_0)   {$q_0$}; 
   \node[state] (q_1) [right=of q_0] {$q_1$}; 
   \node[state,accepting] (q_2) [right=of q_1] {$q_2$}; 
    \path[->] 
    (q_0) edge node {a} (q_1)
    (q_1) edge [loop above] node {a} ()
    (q_1) edge [draw=blue] node {\color{blue} b} (q_2);
\end{tikzpicture}

\end{frame}

\begin{frame}{String recognition}

\begin{itemize}
    \item \textbf{String:} \texttt{aab}
\end{itemize}

\begin{tikzpicture}[shorten >=1pt,node distance=2cm,on grid,auto,/tikz/initial text=] 
   \node[state,initial] (q_0)   {$q_0$}; 
   \node[state] (q_1) [right=of q_0] {$q_1$}; 
   \node[state,accepting,draw=blue] (q_2) [right=of q_1] {\color{blue} $q_2$}; 
    \path[->] 
    (q_0) edge node {a} (q_1)
    (q_1) edge [loop above] node {a} ()
    (q_1) edge node {b} (q_2);
\end{tikzpicture}

\end{frame}

\end{document}  

As you can see, the drawing is basically the same for every step, apart from the highlighting. I thought of creating a new command called \myautomaton which takes an integer as parameter, representing the current step. In the drawing definition itself, I tried to use the \ifthenelse command from the xifthen package to check if, e.g., state q_0 should be highlighted. Unfortunately, I had some problems, as I tried to insert them like:

\node[state,initial\ifthenelse{#1=2}{,draw=blue}{} ] (q_0) {\ifthenelse{#1=2}{\color{blue}}{}$q_0$}; 

Anyway, I was wondering if there's any technique to highlight specific parts of a TikZ drawing without so much code repetition. Any ideas?


UPDATE: I'd like to say that all answers to this question are equally awesome! The accepted answer is the one that better suits my needs.

Usually, my automata representations tend to become more and more complex. Besides, the string complexity also follows the model tendency.

When I have several states and transitions, I find the \automaton{} approach better, as it gives me the flexibility of setting which highlight step I want based on a state number and not on the input string. That way, I can map all the possible highlights in my automaton and call them when needed.

For conventional automata representations, all answers are feasible. Thanks to all the answerers.

4 Answers 4

16

fabikw's answer is excellent if you're working with beamer. In order to get this working in a non-beamer application, I would use a /.code key to check whether the id of a part of the drawing is equal to the current step number, and set the color accordingly.

Here's one way of doing that:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{positioning,automata}

\begin{document}

\newif\ifhighlight
\tikzset{
    highlight/.is if=highlight,
    highlight=false,
    step number/.initial=0
}

\pgfkeys{
    /tikz/id/.code={
        \pgfmathparse{ifthenelse(#1==\pgfkeysvalueof{/tikz/step number},"true","false")}
        \pgfkeys{/tikz/highlight=\pgfmathresult}
        \ifhighlight
            \tikzset{
                orange!60!red,
            }
        \fi
    }
}


\newcommand{\automaton}[1]{
\begin{tikzpicture}[shorten >=1pt,node distance=2cm,on grid,auto,/tikz/initial text=,step number=#1,] 
   \begin{scope}[id=1]  % Necessary to colour the initial arrow
   \node[initial,state] (q_0)   {$q_0$};
   \end{scope}
   \node[state,id=3] (q_1) [right=of q_0] {$q_1$}; 
   \node[state,accepting,id=6] (q_2) [right=of q_1] {$q_2$}; 
    \path[->] 
    (q_0) edge [id=2] node [id=2] {a} (q_1)
    (q_1) edge [loop above,id=4] node {a} ()
    (q_1) edge [id=5] node {b} (q_2);
\end{tikzpicture}
}

\automaton{1}

\automaton{2}

\automaton{3}

\automaton{4}

\automaton{3}

\automaton{5}

\automaton{6}
\end{document}
1
  • Fantastic solution, @Jake! That's what I originally had in mind, thanks! Commented Jul 20, 2011 at 14:19
22

I prefer a (more general) onslide={<overlay spec> keys}, originally suggested by Matthew Leingang in this answer. It comes closer to the general syntax of beamer overlays, makes it easier to highlight an element on more than one slide or to get a different representation in the handout, and is pretty flexible in general:

\documentclass{beamer}

\usepackage{tikz}
\usetikzlibrary{automata,positioning}

\tikzset{onslide/.code args={<#1>#2}{%
  \only<#1>{\pgfkeysalso{#2}} % \pgfkeysalso doesn't change the path
}}

\begin{document}

\begin{frame}{String recognition}
  \begin{tikzpicture}[highlight/.style={draw=blue, text=blue},shorten >=1pt,node distance=2cm,on grid,auto,/tikz/initial text={}] 
     \node[state,initial,onslide={<2> highlight}] (q_0)   {$q_0$}; 
     \node[state] (q_1) [onslide={<4,6> highlight},right=of q_0] {$q_1$}; 
     \node[state,accepting,onslide={<8> highlight}] (q_2) [right=of q_1] {$q_2$}; 
      \path[->] 
      (q_0) edge [onslide={<3> highlight}] node {a} (q_1)
      (q_1) edge [onslide={<5> highlight}, loop above] node {a} ()
      (q_1) edge [onslide={<7> highlight}] node {b} (q_2);
  \end{tikzpicture}
\end{frame}

\end{document}  

Result animation

1
  • Very interesting! I'll take a deeper look in the code, seems promising. Thanks! Commented Jul 20, 2011 at 14:12
18

You can do everything in a single frame using overlays. Doing something like:

\documentclass{beamer}

\usepackage{tikz}
\usetikzlibrary{automata,positioning}

\begin{document}

\begin{frame}{String recognition}

\begin{tikzpicture}[shorten >=1pt,node distance=2cm,on grid,auto,/tikz/initial text=] 
   \alt<2>{\node[state,initial,blue] (q_0) {\color{blue}$q_0$};}%
      {\node[state,initial] (q_0)   {$q_0$};}
   \alt<4,6>{\node[state,blue] (q_1) [right=of q_0] {\color{blue}$q_1$};}%
      {\node[state] (q_1) [right=of q_0] {$q_1$};}
   \alt<8>{\node[state,accepting,blue] (q_2) [right=of q_1] {\color{blue}$q_2$};}%
      {\node[state,accepting] (q_2) [right=of q_1] { $q_2$};}

    \alt<3>{\path[->] (q_0) edge[blue] node {\color{blue}a} (q_1);}%
      {\path[->] (q_0) edge node {a} (q_1);}
    \alt<5>{\path[->] (q_1) edge [loop above,blue] node {\color{blue}a} ();}%
      {\path[->] (q_1) edge [loop above] node {a} ();}
    \alt<7>{\path[->] (q_1) edge [blue] node {\color{blue}b} (q_2);}%
      {\path[->] (q_1) edge  node {b} (q_2);}
\end{tikzpicture}

\end{frame}

\end{document}

will paint blue that part only on the selected slides. I had to repeat everything twice in an alt command because a \only changing only the needed commands did not work.

1
  • Thanks a lot @fabikw, your solution is excellent, I found it very clear and easy to understand! Commented Jul 20, 2011 at 14:10
14

In one of my last conference presentation I needed this as well and had issues using \alt with my complex schematic. I define an animate TikZ key for this. It takes a numeric argument to specify the overlay step and executes some TikZ options for the node or path the key is used only for this overlay step.

\makeatletter
\tikzset{animate/.code={\ifnum#1=\beamer@slideinframe \tikzset{draw=hl,text=hl}\colorlet{fc}{hlfc}\fi},animate/.value required}
\makeatother

A better name for it is actually highlight because it highlights the element at this overlay step. The code is very simple and doesn't increase the overall overlay counter, so you need to state the range manually, i.e. using the < > argument of the frame.

The following code does what you want, I think:

\documentclass{beamer}

\usepackage{tikz}
\usetikzlibrary{automata,positioning}

\makeatletter
\providecommand{\beamer@slideinframe}{0}%
\tikzset{highlight/.code={\ifnum#1=\beamer@slideinframe \tikzset{draw=blue,text=blue}\fi},highlight/.value required}
\makeatother

\begin{document}

\begin{frame}<1-8>{String recognition}

\begin{itemize}
    \item \textbf{String:} \texttt{aab}
\end{itemize}

\begin{tikzpicture}[shorten >=1pt,node distance=2cm,on grid,auto,/tikz/initial text=] 
   \node[state,initial,highlight=2] (q_0)   {$q_0$}; 
   \node[state] (q_1) [highlight=4,highlight=6,right=of q_0] {$q_1$}; 
   \node[state,accepting,highlight=8] (q_2) [right=of q_1] {$q_2$}; 
    \path[->] 
    (q_0) edge [highlight=3] node {a} (q_1)
    (q_1) edge [highlight=5,loop above] node {a} ()
    (q_1) edge [highlight=7] node {b} (q_2);
\end{tikzpicture}

\end{frame}

\end{document}  

Result

8
  • Looks like you could easily make this much more customizable (warning, untested code): \tikzset{highlight/.code 2 args={\ifnum#1=\beamer@slideinframe \ifthenelse{\equals{#2}{}}{\tikzset{highlight/.default}}{\tikzset{#2}}\fi} \tikzset{highlight/.default={draw=blue,text=blue}} Then a call like \node[highlight=3,highlight=2 blue,highlight=3 custom] would call \tikzset{highlight/.default}, \tikzset{blue}, and \tikzset{custom}, so you can customize text highlighting and node highlighting independently, perhaps... (I'm not sure if /.default works with code 2 args or not...)
    – Ben Lerner
    Commented Jul 20, 2011 at 1:42
  • Apology for the poor formatting above; how do you get code blocks in comments??
    – Ben Lerner
    Commented Jul 20, 2011 at 1:43
  • 1
    @Martin: How to produce GIF from a series of Beamer frames? Commented Jul 20, 2011 at 2:45
  • @Ben: You don't get code blocks in comments. Use back-ticks to get the correct font still works. Commented Jul 20, 2011 at 11:00
  • Impressive code, @Martin! It's surely a great solution! And thanks for the gif bonus! =P Commented Jul 20, 2011 at 14:14

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .