72

I have a diagram of 4 nodes in my beamer slide.

  \begin{figure}[h]
  \begin{centering}
  \begin{tikzpicture}[system/.style={draw,rectangle,rounded corners=3,minimum width=2cm,text width=1.8cm,text centered}]
    \node [system] (fe) {Feature Extraction};
    \node [system] (am) [right=of fe] {Acoustic Model};
    \node [system] (lm) [right=of am] {Language Model};
    \node [system] (d) [below=of lm] {Decoder};

    \draw[->] (fe) |- (am);
    \draw[->] (am) |- (d);
    \draw[->] (lm) -- (d.north);

  \end{tikzpicture}
  \end{centering}
  \end{figure}

How can I in a second slide "highlight" one of the nodes, like I can do with <alert@n> for a item in a list?

With highlighting I mean for example giving a color and thickening the lines.

2 Answers 2

93

I used to do this according to Andrew's solution until I read his note #2, and it reminded me that PGF's keys can do pretty much anything. The key (excuse the pun) is to create a key that processes other keys conditional on the slide number:

\tikzset{onslide/.code args={<#1>#2}{%
  \only<#1>{\pgfkeysalso{#2}} 
}}

Using \pgfkeysalso doesn't reset the current key path, whereas \pgfkeys or \tikzset would. The .code args key handler means that

onslide=<overlay specification>{keys}

causes the the following code to be expanded:

\only<overlay specification>{\pgfkeysalso{keys}}

Then you can use the key onslide=<overlay specification>{keys} to set keys only on specific slides. The slightly inelegant twist is that if your overlay specification contains commas the entire pair of overlay spec and keys has to be embraced.

Here is a complete example:

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

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

\tikzstyle{highlight}=[red,ultra thick]


\begin{document}
\begin{frame}
 \begin{figure}[h]
  \begin{centering}
  \begin{tikzpicture}[
    system/.style={draw,rectangle,rounded corners=3,minimum width=2cm,text width=1.8cm,text centered},
    node distance=2cm
  ]
    \node [system,onslide=<3->{highlight},anchor=center] (fe) {Feature Extraction};
    \node [system,onslide={<2,4>{green}}] (am) [right=of fe.center] {Acoustic Model};
    \node [system,temporal=<3>{blue}{highlight}{green}] (lm) [right=of am.center] {Language Model};
    \node [system] (d) [below=of lm.center] {Decoder};

    \draw[->] (fe) |- (am);
    \draw[->] (am) |- (d);
    \draw[->] (lm) -- (d.north);

  \end{tikzpicture}
  \end{centering}
  \end{figure}
\end{frame}
\end{document}

You will be disappointed about the jiggling of your picture when the line thickness keys are applied. You might have to avoid relative positioning to make that go away.

For more on key handlers like .code args, see the pgfkeys section of the TikZ-PGF manual.

14
  • 1
    Fantastic! I'm going to use this in future. I clearly need to delve into the depths of pgfkeys to learn the Deeper Magic. To avoid the jiggling, but still use relative positioning, one could use the centres of the nodes for positioning rather than their edges. Nov 29, 2010 at 13:24
  • 1
    @Andrew: Thanks for the idea, and good point about the positioning fix. True confessions: I have the PGF manual loaded in iBooks so I can (and have) read it on my iPad on the train. Nov 29, 2010 at 13:30
  • 1
    Given my comment on this question: tex.stackexchange.com/questions/3/compiling-documents-online, I don't think that I would get much sympathy calling you a "PGF-Nerd" on that one! If I had an iPad, and used a mode of transport where it was safe to read such (not walking given our current weather), I'd probably do the same. Nov 29, 2010 at 14:07
  • I tried to modify this solution to work with the beamer command \temporal but failed. Of course one can use 3 onslide options to achieve the behavoir of \temporal. But still, can you add an example that uses \temporal directly? Thanks. Jan 4, 2013 at 19:46
  • 1
    I've noticed that this only seems to work if you put the \tikzset before \begin{document}. That is, I tried to place it just before my tikzpicture and got some errors...
    – Seamus
    Jan 31, 2017 at 14:24
17

There are a few ways to do this, exactly which is best will depend on what you want the highlighting effect to be. One way is to have separate nodes with the two styles and then show one on one slide and one on the other. Another way is to define a style that is wrapped in an \only. Actually, using beamer's reimplementation of \newcommand, one can make \tikzset overlay-aware. Here's a couple of possibilities:

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

\newcommand<>{\btikzset}[2]{\alt#3{\tikzset{#1}}{\tikzset{#2}}}

\tikzset{highlight/.style={red,fill=green,text=blue}}

\begin{document}
\begin{frame}
\begin{figure}[h]
  \begin{centering}
  \begin{tikzpicture}[system/.style={draw,rectangle,rounded corners=3,minimum width=2cm,text width=1.8cm,text centered}]
    \node [system] (fe) {Feature Extraction};
    \node<1> [system] (am) [right=of fe] {Acoustic Model};
    \node<2> [system,highlight] (am) [right=of fe] {Acoustic Model};
    \node [system] (lm) [right=of am] {Language Model};
    \node [system] (d) [below=of lm] {Decoder};

    \draw[->] (fe) |- (am);
    \draw[->] (am) |- (d);
    \draw[->] (lm) -- (d.north);

  \end{tikzpicture}
  \end{centering}
  \end{figure}
\end{frame}
\begin{frame}
\begin{figure}[h]
  \begin{centering}
  \begin{tikzpicture}[system/.style={draw,rectangle,rounded corners=3,minimum width=2cm,text width=1.8cm,text centered}]
  \btikzset<2>{highlighton2/.style={highlight}}{highlighton2/.style={}}

    \node [system] (fe) {Feature Extraction};
    \node [system,highlighton2] (am) [right=of fe] {Acoustic Model};
    \node [system] (lm) [right=of am] {Language Model};
    \node [system] (d) [below=of lm] {Decoder};

    \draw[->] (fe) |- (am);
    \draw[->] (am) |- (d);
    \draw[->] (lm) -- (d.north);

  \end{tikzpicture}
  \end{centering}
  \end{figure}
\end{frame}
\end{document}

Notes:

  1. I found that \renewcommand<> didn't work, possibly because I was making \tikzset take two arguments - thus having it work like \alt rather than \only. This was to avoid complaints of unknown keys. An alternative would be to define an empty style, say highlightOn at the start and then have \tikzset map highlightOn to highlight on frame 2 and do nothing on other frames. This would work with \renewcommand<>:

    \renewcommand<>{\tikzset}[1]{\only#2{\beameroriginal{\tikzset}{#1}}}
    
    
    \tikzset{highlight/.style={red,fill=green,text=blue}}
    \tikzset{highlighton2/.style={}}
    

    Then in the frame:

    \tikzset<2>{highlighton2/.style={highlight}}
    
  2. Perhaps the truly elegant way would be to define a new key, "highlight on=", using the code handler. But I've only just learnt of the existence of that so I'll leave that solution to someone else.

You must log in to answer this question.

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