Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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.

share|improve this question
add comment

4 Answers 4

up vote 12 down vote accepted

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}
share|improve this answer
    
Fantastic solution, @Jake! That's what I originally had in mind, thanks! –  Paulo Cereda Jul 20 '11 at 14:19
add comment

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

share|improve this answer
    
Very interesting! I'll take a deeper look in the code, seems promising. Thanks! –  Paulo Cereda Jul 20 '11 at 14:12
add comment

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.

share|improve this answer
    
Thanks a lot @fabikw, your solution is excellent, I found it very clear and easy to understand! –  Paulo Cereda Jul 20 '11 at 14:10
add comment

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

share|improve this answer
    
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 Jul 20 '11 at 1:42
    
Apology for the poor formatting above; how do you get code blocks in comments?? –  Ben Lerner Jul 20 '11 at 1:43
1  
@Martin: How to produce GIF from a series of Beamer frames? –  xport Jul 20 '11 at 2:45
    
@Ben: You don't get code blocks in comments. Use back-ticks to get the correct font still works. –  Martin Scharrer Jul 20 '11 at 11:00
    
Impressive code, @Martin! It's surely a great solution! And thanks for the gif bonus! =P –  Paulo Cereda Jul 20 '11 at 14:14
show 3 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.