# beamer - Mark several pseudocode block and insert comments near it

I try to use the answer proposed to this question: Mark a pseudocode block and insert comments near it

But when I try to use it with several block, it does not work as perfectly as with only one highlighted block:

\documentclass{beamer}
\usepackage{algorithm,algpseudocode}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{xcolor}
\makeatletter

% to change colors
\newcommand{\fillcol}{green!20}
\newcommand{\bordercol}{black}

% code from Andrew Stacey (with small adjustment to the border color)
% https://tex.stackexchange.com/questions/51582/background-coloring-with-overlay-specification-in-algorithm2e-beamer-package
\newcounter{jumping}
\resetcounteronoverlays{jumping}

\def\jump@setbb#1#2#3{%
\@ifundefined{jump@#1@maxbb}{%
\expandafter\gdef\csname jump@#1@maxbb\endcsname{#3}%
}{%
\csname jump@#1@maxbb\endcsname
\pgf@xa=\pgf@x
\pgf@ya=\pgf@y
#3
\pgfmathsetlength\pgf@x{max(\pgf@x,\pgf@xa)}%
\pgfmathsetlength\pgf@y{max(\pgf@y,\pgf@ya)}%
\expandafter\xdef\csname jump@#1@maxbb\endcsname{\noexpand\pgfpoint{\the\pgf@x}{\the\pgf@y}}%
}
\@ifundefined{jump@#1@minbb}{%
\expandafter\gdef\csname jump@#1@minbb\endcsname{#2}%
}{%
\csname jump@#1@minbb\endcsname
\pgf@xa=\pgf@x
\pgf@ya=\pgf@y
#2
\pgfmathsetlength\pgf@x{min(\pgf@x,\pgf@xa)}%
\pgfmathsetlength\pgf@y{min(\pgf@y,\pgf@ya)}%
\expandafter\xdef\csname jump@#1@minbb\endcsname{\noexpand\pgfpoint{\the\pgf@x}{\the\pgf@y}}%
}
}

\tikzset{%
remember picture with id/.style={%
remember picture,
overlay,
draw=\bordercol,
save picture id=#1,
},
save picture id/.code={%
\edef\pgf@temp{#1}%
\immediate\write\pgfutil@auxout{%
\noexpand\savepointas{\pgf@temp}{\pgfpictureid}}%
},
if picture id/.code args={#1#2#3}{%
\@ifundefined{save@pt@#1}{%
\pgfkeysalso{#3}%
}{
\pgfkeysalso{#2}%
}
},
onslide/.code args={<#1>#2}{%
\only<#1>{\pgfkeysalso{#2}}%
},
alt/.code args={<#1>#2#3}{%
\alt<#1>{\pgfkeysalso{#2}}{\pgfkeysalso{#3}}%
},
stop jumping/.style={
execute at end picture={%
\stepcounter{jumping}%
\immediate\write\pgfutil@auxout{%
\noexpand\jump@setbb{\the\value{jumping}}{\noexpand\pgfpoint{\the\pgf@picminx}{\the\pgf@picminy}}{\noexpand\pgfpoint{\the\pgf@picmaxx}{\the\pgf@picmaxy}}
},
\csname jump@\the\value{jumping}@maxbb\endcsname
\path (\the\pgf@x,\the\pgf@y);
\csname jump@\the\value{jumping}@minbb\endcsname
\path (\the\pgf@x,\the\pgf@y);
},
}
}

\def\savepointas#1#2{%
\expandafter\gdef\csname save@pt@#1\endcsname{#2}%
}

\def\tmk@labeldef#1,#2\@nil{%
\def\tmk@label{#1}%
\def\tmk@def{#2}%
}

\tikzdeclarecoordinatesystem{pic}{%
\pgfutil@in@,{#1}%
\ifpgfutil@in@%
\tmk@labeldef#1\@nil
\else
\tmk@labeldef#1,\pgfpointorigin\@nil
\fi
\@ifundefined{save@pt@\tmk@label}{%
\tikz@scan@one@point\pgfutil@firstofone\tmk@def
}{%
\pgfsys@getposition{\csname save@pt@\tmk@label\endcsname}\save@orig@pic%
\pgfsys@getposition{\pgfpictureid}\save@this@pic%
\pgf@process{\pgfpointorigin\save@this@pic}%
\pgf@xa=\pgf@x
\pgf@ya=\pgf@y
\pgf@process{\pgfpointorigin\save@orig@pic}%
}%
}
\newcommand\tikzmark[2][]{%
\tikz[remember picture with id=#2] #1;}
\makeatother

\resetcounteronoverlays{algocf}

\newcommand<>{\boxto}[1]{%
\only#2{\tikz[remember picture with id=#1]
\draw[line width=1pt,fill=\fillcol,rectangle,rounded corners]
(pic cs:#1) ++(5.2,-.1) rectangle (-0.4,0)
;\tikz\node [anchor=base] (#1){};}% <= insertion to store the anchor to be used as based for the annotation
}

\begin{document}
\begin{frame}
\begin{algorithm}[H]
\begin{algorithmic}
\Function{tarjan}{Node* node}
\State $node.visited \gets$ \textbf{true}
\State $node.index \gets indexCounter$
\State $s.push(node)$
\boxto<1->{b}\ForAll{$successor$ in $node.successors$}
\If{$!node.visited$}
\Call{tarjan}{successor}
\EndIf
\State $node.lowlink \gets$ \Call{min}{$node.lowlink, successor.lowlink$}
\EndFor\tikzmark{b}

\boxto<1->{a}\If{$node.lowlink == node.index$}
\Repeat
\State $successor \gets stack.pop()$
\Until{$successor == node$}
\EndIf\tikzmark{a}
\EndFunction
\end{algorithmic}
\label{alg:seq2}
\end{algorithm}

% To insert the annotation
\begin{tikzpicture}[remember picture,overlay]
\coordinate (aa) at ($(a)+(8.5,3)$); % <= adjust this parameter to move the position of the annotation
\node[rectangle,draw, gray,text width=3cm,align=left,right] at (aa) {The root node was found and the whole SCC gets poped from stack};
\end{tikzpicture}
\end{frame}

\end{document}


Here is a complete working example of the answer proposed by Symbol 1: \documentclass{beamer} \usepackage{algorithm,algpseudocode} \usepackage{tikz} \usetikzlibrary{calc,fit,tikzmark} \makeatletter

\def\tikzbackgroundpath#1;{
\tikz[remember picture,overlay]\path#1;
}
}

\begin{document}

\begin{frame}
frame before
\end{frame}

\begin{frame}
\begin{algorithm}[H]
\begin{algorithmic}
\Function{tarjan}{Node* node}
\State $node.visited \gets$ \textbf{true}
\State $node.index \gets indexCounter$
\State \tikzmark{a}$s.push(node)$
\ForAll{$successor$ in $node.successors$}
\If{$!node.visited$}
\Call{tarjan}{successor}
\EndIf
\State $node.lowlink \gets$ \Call{min}{$node.lowlink, successor.lowlink$}\tikzmark{b}
\EndFor\tikzmark{c}
\State \tikzmark{d}
\If{$node.lowlink == node.index$}\tikzmark{e}
\Repeat
\State $successor \gets stack.pop()$
\Until{$successor == node$}
\EndIf\tikzmark{f}
\EndFunction
\end{algorithmic}
\label{alg:seq2}
\end{algorithm}

\tikzbackgroundpath node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a)(pic cs:b)(pic cs:c)}]{}
node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:d)(pic cs:e)(pic cs:f)}](G){}
(G.east)node[right=10,gray,draw,fill=white,text width=100,align=left]{The root node was found and the whole SCC gets popped from stack};

\end{frame}

\begin{frame}
frame after
\end{frame}

\end{document}

• Welcome to TeX.SX! – Heiko Oberdiek Sep 4 '15 at 7:27
• In Beamer, things got a little bit different. Once you insert the main tikzpicture into the header, it automatically appears under the text. Therefore one can restart the progress from \tikzmark. – Symbol 1 Sep 4 '15 at 16:37
• By the way if you have ever noticed the magic numbers 5.2, -.1, -0.4 you will realize that it would never work. – Symbol 1 Sep 4 '15 at 16:58
• @Symbol1: Unfortunately, that is not the main problem. Magic numbers are certainly one of the problems, the other is that placing the marker right before \ForAll statement does not let the rectangle be anchored right there. For numbers, sometimes magic numbers can be used proficiently, please see my answer to \boxed{}, TikZ and colored equation background. – Claudio Fiandrino Sep 4 '15 at 17:53
• @ClaudioFiandrino Yes, I knew people devoted to highlight-box so much. But since \tikzmark's examples suggest one to draw those ornaments later (which is philosophically sound), I would like to draw them later. And as you can see in my answer, once you open a new tikzpicture, all bizarre questions become TikZ exercises. – Symbol 1 Sep 4 '15 at 18:15

Perhaps my code is easier to understand.

This line

\addtobeamertemplate{headline}{}{\tikzmarkhookinbeamerheadline}


adds a hook to the headline. Where to put the hook is not important as long as the hook is expanded before the text is typeset.

And then it is your algorithm. Place some \tikzmarks nicely.

Thirdly \gdef the hook so that it draws boxes. You can see that

node[fit={([yshift=-5]pic cs:a)(pic cs:b)(pic cs:c)}]{}


draws a node that fits the first three marks, except that mark a is prior shifted.

Finally

(G.east)node[right=10,gray,draw,fill=white,text width=100,align=left]{The root node was found and the whole SCC gets popped from stack};


gives you the comment.

\documentclass{beamer}
\usepackage{algorithm,algpseudocode}
\usepackage{tikz}
\usetikzlibrary{calc,fit,tikzmark}
\makeatletter

\begin{document}

\begin{frame}
\begin{algorithm}[H]
\begin{algorithmic}
\Function{tarjan}{Node* node}
\State $node.visited \gets$ \textbf{true}
\State $node.index \gets indexCounter$
\State \tikzmark{a}$s.push(node)$
\ForAll{$successor$ in $node.successors$}
\If{$!node.visited$}
\Call{tarjan}{successor}
\EndIf
\State $node.lowlink \gets$ \Call{min}{$node.lowlink, successor.lowlink$}\tikzmark{b}
\EndFor\tikzmark{c}
\State \tikzmark{d}
\If{$node.lowlink == node.index$}\tikzmark{e}
\Repeat
\State $successor \gets stack.pop()$
\Until{$successor == node$}
\EndIf\tikzmark{f}
\EndFunction
\end{algorithmic}
\label{alg:seq2}
\end{algorithm}

\tikz[remember picture,overlay]\path
node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a)(pic cs:b)(pic cs:c)}]{}
node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:d)(pic cs:e)(pic cs:f)}](G){}
(G.east)node[right=10,gray,draw,fill=white,text width=100,align=left]{The root node was found and the whole SCC gets popped from stack};
}

\end{frame}

\end{document}


# Edit

(I am sorry I forgot this part)

Since I just defined the hook and the hook would stays in the headline, Beamer will then print the same green boxes in all subsequent frames. To come over this, Image that in the next frame you want to draw a NO-box, so you write

\gdef\tikzmarkhookinbeamerheadline{}


Then Beamer will draw no box.

One can also include a self-destruction in the original definition

\gdef\tikzmarkhookinbeamerheadline{
\tikz[remember picture,overlay]\path ...
}


Or, more conveniently, define a macro that defines hook with self-destruction

\def\gdefdisposabletikzmarkhookinbeamerheadline#1{
#1
}
}


So that you can write this instead

\gdefdisposabletikzmarkhookinbeamerheadline{
\tikz[remember picture,overlay]\path ...
}


Even more convenient: (notice the semicolon, it makes the syntax more "TikZy")

\def\tikzbackgroundpath#1;{
\tikz[remember picture,overlay]\path#1;
}
}


So that you can write this instead

\tikzbackgroundpath node[rounded corners,...]{};


# Is it compatible with overlay specification?

Not really. It depends on the usage.

For example one can put \only<> outside the \tikzbackgroundpath. Like this

\only<2>{
\tikzbackgroundpath
node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a)(pic cs:b)(pic cs:c)}]{};
}
\only<3>{
\tikzbackgroundpath
node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a)(pic cs:b)(pic cs:c)}]{}
node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:d)(pic cs:e)(pic cs:f)}](G){};
}
\only<4>{
\tikzbackgroundpath
node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a)(pic cs:b)(pic cs:c)}]{}
node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:d)(pic cs:e)(pic cs:f)}](G){}(G.east)
node[right=10,gray,draw,fill=white,text width=100,align=left]{The root node was found and the whole SCC gets popped from stack};
}


Then everything works like it should. Since Beamer is the master here, it makes sense to put overlay specification outside.

## No, I want to use pgfkeys to specify overlays

It is possible as well, see the following

\tikzset{
only/.code args={<#1>}{
\alt<#1>{\pgfkeysalso{opacity=1}}{\pgfkeysalso{opacity=0}}
}
}

.......

\tikzbackgroundpath
node[only=<3->,rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a)(pic cs:b)(pic cs:c)}]{}
node[only=<4->,rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:d)(pic cs:e)(pic cs:f)}](G){}(G.east)
node[only=<5->,right=10,gray,draw,fill=white,text width=100,align=left]{The root node was found and the whole SCC gets popped from stack};


## No you cheat, what the hell is only=<5-> while there are only four slides?

Let me explain: since these TikZ pictures are not expanded at where there are, there is a strange slide shift so that only=<5-> actually means \only<4->. Besides, I have to write \begin{frame}<-4> to inform Beamer that there are four slides for this frame.

This can be fixed if you insert the hook in frametitle. Unfortunately, frametitle is not typeset at all if there is no frame title.

## How about... do not use hook?

This is indeed a great idea. Putting this at the beginning of the frame solves the problem.

\tikz[remember picture,overlay]\path
node[only=<2->,rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a2)(pic cs:b2)(pic cs:c2)}]{}
node[only=<3->,rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:d2)(pic cs:e2)(pic cs:f2)}](G){}(G.east)
node[only=<4->,right=10,gray,draw,fill=white,text width=100,align=left]{The root node was found and the whole SCC gets popped from stack};


However I do not feel comfortable that I can refer to a future node. In some case, I name different nodes by the same name to achieve some special goal. Such trick would definitely conflict with this trick.

# How about \againframe? second screen? No fill if handout?

Generally speaking: I do not know. I can only show you the logic. I am not able to handle all possibilities. Also it is unnecessary if you (and all potential viewers) are light users.

Nevertheless, if you do have some specific requirement, feel free to leave a comment. I can show you how to custom the code to fit specific goal.

# Overall code

\documentclass{beamer}
\usepackage{algorithm,algpseudocode}
\usepackage{tikz}
\usetikzlibrary{calc,fit,tikzmark}
\makeatletter

\begin{document}

\def\tikzmarkhookinbeamerbackground{}
\def\tikzbackgroundpath#1;{
\gdef\tikzmarkhookinbeamerbackground{
\gdef\tikzmarkhookinbeamerbackground{}
\tikz[remember picture,overlay]\path#1;
}
}

\frame{This is an innocent that should contain no boxes.}

\frame{This is an innocent that should contain no boxes.}

\begin{frame}
\begin{algorithm}[H]
\begin{algorithmic}
\Function{tarjan}{Node* node}
\State $node.visited \gets$ \textbf{true}
\State $node.index \gets indexCounter$
\State \tikzmark{a}$s.push(node)$
\ForAll{$successor$ in $node.successors$}
\If{$!node.visited$}
\Call{tarjan}{successor}
\EndIf
\State $node.lowlink \gets$ \Call{min}{$node.lowlink, successor.lowlink$}\tikzmark{b}
\EndFor\tikzmark{c}
\State \tikzmark{d}
\If{$node.lowlink == node.index$}\tikzmark{e}
\Repeat
\State $successor \gets stack.pop()$
\Until{$successor == node$}
\EndIf\tikzmark{f}
\EndFunction
\end{algorithmic}
\label{alg:seq2}
\end{algorithm}

\only<2>{
\tikzbackgroundpath
node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a)(pic cs:b)(pic cs:c)}]{};
}
\only<3>{
\tikzbackgroundpath
node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a)(pic cs:b)(pic cs:c)}]{}
node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:d)(pic cs:e)(pic cs:f)}](G){};
}
\only<4>{
\tikzbackgroundpath
node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a)(pic cs:b)(pic cs:c)}]{}
node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:d)(pic cs:e)(pic cs:f)}](G){}(G.east)
node[right=10,gray,draw,fill=white,text width=100,align=left]{The root node was found and the whole SCC gets popped from stack};
}
\end{frame}

\frame{This is an innocent that should contain no boxes.}

\frame{This is an innocent that should contain no boxes.}

\tikzset{
only/.code args={<#1>}{
\alt<#1>{\pgfkeysalso{opacity=1}}{\pgfkeysalso{opacity=0}}
}
}

\begin{frame}<-4>
\begin{algorithm}[H]
\begin{algorithmic}
\Function{tarjan}{Node* node}
\State $node.visited \gets$ \textbf{true}
\State $node.index \gets indexCounter$
\State \tikzmark{a}$s.push(node)$
\ForAll{$successor$ in $node.successors$}
\If{$!node.visited$}
\Call{tarjan}{successor}
\EndIf
\State $node.lowlink \gets$ \Call{min}{$node.lowlink, successor.lowlink$}\tikzmark{b}
\EndFor\tikzmark{c}
\State \tikzmark{d}
\If{$node.lowlink == node.index$}\tikzmark{e}
\Repeat
\State $successor \gets stack.pop()$
\Until{$successor == node$}
\EndIf\tikzmark{f}
\EndFunction
\end{algorithmic}
\label{alg:seq2}
\end{algorithm}

\tikzbackgroundpath
node[only=<3->,rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a)(pic cs:b)(pic cs:c)}]{}
node[only=<4->,rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:d)(pic cs:e)(pic cs:f)}](G){}(G.east)
node[only=<5->,right=10,gray,draw,fill=white,text width=100,align=left]{The root node was found and the whole SCC gets popped from stack};

\end{frame}

\frame{This is an innocent that should contain no boxes.}

\frame{This is an innocent that should contain no boxes.}

\begin{frame}
\tikz[remember picture,overlay]\path
node[only=<2->,rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a2)(pic cs:b2)(pic cs:c2)}]{}
node[only=<3->,rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:d2)(pic cs:e2)(pic cs:f2)}](G){}(G.east)
node[only=<4->,right=10,gray,draw,fill=white,text width=100,align=left]{The root node was found and the whole SCC gets popped from stack};
\begin{algorithm}[H]
\begin{algorithmic}
\Function{tarjan}{Node* node}
\State $node.visited \gets$ \textbf{true}
\State $node.index \gets indexCounter$
\State \tikzmark{a2}$s.push(node)$
\ForAll{$successor$ in $node.successors$}
\If{$!node.visited$}
\Call{tarjan}{successor}
\EndIf
\State $node.lowlink \gets$ \Call{min}{$node.lowlink, successor.lowlink$}\tikzmark{b2}
\EndFor\tikzmark{c2}
\State \tikzmark{d2}
\If{$node.lowlink == node.index$}\tikzmark{e2}
\Repeat
\State $successor \gets stack.pop()$
\Until{$successor == node$}
\EndIf\tikzmark{f2}
\EndFunction
\end{algorithmic}
\label{alg:seq2}
\end{algorithm}
\end{frame}

\frame{This is an innocent that should contain no boxes.}

\frame{This is an innocent that should contain no boxes.}

\tikzset{
alt/.code args={<#1>#2#3}{
\alt<#1>{\pgfkeysalso{#2}}{\pgfkeysalso{#3}}
}
}

\begin{frame}

\tikzbackgroundpath[alt=<3>{red}{blue}]
node[rounded corners,line width=1,draw,fill=green!20,fit={([yshift=-5]pic cs:a)(pic cs:b)(pic cs:c)}]{};

\tikz[alt=<3>{red}{blue}]\draw[line width=1](0,0)--(10,0);

\only<1>{1}
\only<2>{2}
\only<3>{3}
\only<4>{4}

\end{frame}

\setbeamertemplate{background}{
\tikz[remember picture,overlay]\fill[alt=<3>{yellow}{green}](current page.west)+(0,-1)rectangle+(2,1);
}

\begin{frame}{title}
\only<1-5>{only?}
\end{frame}

\end{document}

• Thanks for your answer, but if I add other frames, then the green rounded rectangle are on this other frames too... How can I avoid this ? – Benjamin Sep 7 '15 at 12:21
• @Benjamin Oh my god... I am very sorry... See my edit. – Symbol 1 Sep 7 '15 at 13:14
• It works for the green rounded rectangle, if I add \gdef\tikzmarkhookinbeamerheadline{} juste after the \begin{document} for the frames before the one with the code. But the comments are not displayed. Any idea ? – Benjamin Sep 7 '15 at 13:33
• In addition, I try to use visible on properties, using this configuration: \tikzset{ invisible/.style={opacity=0}, visible on/.style={alt={#1{}{invisible}}}, alt/.code args={<#1>#2#3}{% \alt<#1>{\pgfkeysalso{#2}}{\pgfkeysalso{#3}} % \pgfkeysalso doesn't change the path }, } And it does not work. – Benjamin Sep 7 '15 at 13:37
• @Benjamin it seems like you want the comment comes before the green box? This will not work (comment will be at top left corner) because the position of comment (see G.east?) depends on the green box. You need to move to an independent position or create phantom box. For your second question give me some time. – Symbol 1 Sep 7 '15 at 13:42