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.

I am using Beamer for creating a presentation and I am trying to highlight some lines in an algorithm. I am actually using algcompatible.

I found a solution here and created a couple of new commands to highlight some code lines in an algorithm, based on that solution:

\newcommand{\algcolor}[2]{\hspace*{-\fboxsep}\colorbox{#1}{\parbox{\linewidth}{#2}}}
\newcommand{\algemph}[1]{\algcolor{GreenYellow}{#1}}

That works pretty well, but it is failing in some cases, depending on the lines that I want to highlight. For instance, the following algorithm works fine:

\begin{algorithmic}[1]
    \FORALL{$elem$ in $collection$}
        \STATE $foo(elem)$
        \algemph{\STATE $bar(elem)$}
    \ENDFOR
\end{algorithmic}

But, if I swap the two statements in the loop:

\begin{algorithmic}[1]
    \FORALL{$elem$ in $collection$}
        \algemph{\STATE $bar(elem)$}
        \STATE $foo(elem)$
    \ENDFOR
\end{algorithmic}

I get this error when calling pdflatex:

! Missing \endcsname inserted.
<to be read again> 
                  \ALG@currentblock@2 
l.19 \end{frame}

Here you have a minimal reproducible test case:

\PassOptionsToPackage{dvipsnames}{xcolor} % prevent an option clash
\documentclass{beamer}

\usepackage[dvipsnames]{xcolor}
\usepackage{algcompatible}

\newcommand{\algcolor}[2]{\hspace*{-\fboxsep}\colorbox{#1}{\parbox{\linewidth}{#2}}}
\newcommand{\algemph}[1]{\algcolor{GreenYellow}{#1}}

\begin{document}

\begin{frame}{Test Frame}
    \begin{algorithmic}[1]
        \FORALL{$elem$ in $collection$}
            \algemph{\STATE $bar(elem)$}
            \STATE $foo(elem)$
        \ENDFOR
    \end{algorithmic}
\end{frame}

\end{document}

Is it possible to fix the current approach that I am using? Is there any other solution for coloring lines in an algorithm?

share|improve this question
add comment

2 Answers

up vote 13 down vote accepted

Here's one possible solution using (oh, surprise!) the improved version of \tikzmark provided by Andrew Stacey in his answer to tikzmark to have different behaviour if first run (and mark locations not yet available).

The idea is to define a new family of loops and declarations, totally analogous to the ones provided by algcompatible, but adding automatically the colored background; for each command of the form \X now you have the corresponding command \CX (prepending a capital C to the original name) which automatically handles the color; for example, now you have the standard \STATE command and the colored version \CSTATE; the functionality and syntax of each \CX command is exactly the same as that of its corresponding \X command.

\PassOptionsToPackage{dvipsnames}{xcolor}
\documentclass{beamer}
\usepackage[dvipsnames]{xcolor}
\usepackage{algcompatible}
\usepackage{tikz}
\usetikzlibrary{calc}

\makeatletter
% code borrowed from Andrew Stacey; See
% http://tex.stackexchange.com/a/50054/3954
\tikzset{%
  remember picture with id/.style={%
    remember picture,
    overlay,
    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}%
    }
  }
}

\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,(0pt,0pt)\@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}%
  \advance\pgf@x by -\pgf@xa
  \advance\pgf@y by -\pgf@ya
  }%
}

\makeatother
% end of Andrew's code

% main command to draw the colored background
\newcounter{mymark}
\newcommand\ColorLine{%
  \stepcounter{mymark}%
  \tikz[remember picture with id=mark-\themymark,overlay] {;}%
  \begin{tikzpicture}[remember picture,overlay]%
    \filldraw[GreenYellow]%
   let \p1=(pic cs:mark-\themymark), 
   \p2=(current page.east)  in 
   ([xshift=-0.3em,yshift=-0.7ex]0,\y1)  rectangle ++([xshift=-1.2cm]\x2,\baselineskip);
  \end{tikzpicture}%
}%

% colored loops and declarations
\makeatletter
\algnewcommand\CREQUIRE{\item[\ColorLine\algorithmicrequire]}%
\algnewcommand\CENSURE{\item[\ColorLine\algorithmicensure]}%
\algnewcommand\CSTATE{\State\ColorLine}%
\algnewcommand\CSTATEx{\Statex\ColorLine}%
\algnewcommand\CCOMMENT{\Comment\ColorLine}%

\algdef{SE}[WHILE]{CWHILE}{ENDWHILE}%
   [2][default]{\ColorLine\algorithmicwhile\ #2\ \algorithmicdo\ALG@compatcomm{#1}}%
   {\algorithmicend\ \algorithmicwhile}%
\algdef{SE}[FOR]{CFOR}{ENDFOR}%
   [2][default]{\ColorLine\algorithmicfor\ #2\ \algorithmicdo\ALG@compatcomm{#1}}%
   {\algorithmicend\ \algorithmicfor}%
\algdef{S}[FOR]{CFORALL}%
   [2][default]{\ColorLine\algorithmicforall\ #2\ \algorithmicdo\ALG@compatcomm{#1}}%
\algdef{SE}[LOOP]{CLOOP}{ENDLOOP}%
   [1][default]{\ColorLine\algorithmicloop\ALG@compatcomm{#1}}%
   {\algorithmicend\ \algorithmicloop}%
\algdef{SE}[REPEAT]{CREPEAT}{UNTIL}%
   [1][default]{\ColorLine\algorithmicrepeat\ALG@compatcomm{#1}}%
   [1]{\algorithmicuntil\ #1}%
\algdef{SE}[IF]{CIF}{ENDIF}%
   [2][default]{\ColorLine\algorithmicif\ #2\ \algorithmicthen\ALG@compatcomm{#1}}%
   {\algorithmicend\ \algorithmicif}%
\algdef{C}[IF]{IF}{CELSIF}%
   [2][default]{\ColorLine\algorithmicelse\ \algorithmicif\ #2\ \algorithmicthen\ALG@compatcomm{#1}}%
\algdef{Ce}[ELSE]{IF}{CELSE}{ENDIF}%
   [1][default]{\ColorLine\algorithmicelse\ALG@compatcomm{#1}}%
\makeatother

\begin{document}

\begin{frame}{Test Frame 1}

\begin{algorithmic}[1]
\CREQUIRE Some initial values
\ENSURE Some conditions
\CLOOP
  \STATE$bar(elem)$
  \STATE$baz(elem)$
  \CFOR{$quality\ge 9$}
    \STATE$a\gets perfect$
    \CSTATE$a\gets unusable$
  \ENDFOR
\ENDLOOP
\end{algorithmic}

\end{frame}

\begin{frame}{Test Frame 2}

\begin{algorithmic}[1]
\REQUIRE Some initial values
\CENSURE Some conditions
\FORALL{$elem$ in $collection$}
  \STATE$bar(elem)$
  \CSTATE$foo(elem)$
  \STATE$baz(elem)$
  \CIF{$quality\ge 9$}
    \STATE$a\gets perfect$
  \ELSE
    \CSTATE$a\gets unusable$
  \ENDIF
\ENDFOR
\end{algorithmic}

\end{frame}

\end{document}

The images of the obtained document:

enter image description here

enter image description here

The document has to be processed twice.

And here's a little variation in which the background colored stripes have uniform length:

\PassOptionsToPackage{dvipsnames}{xcolor}
\documentclass{beamer}
\usepackage[dvipsnames]{xcolor}
\usepackage{algcompatible}
\usepackage{tikz}
\usetikzlibrary{calc}

\makeatletter
% code borrowed from Andrew Stacey; See
% http://tex.stackexchange.com/a/50054/3954
\tikzset{%
  remember picture with id/.style={%
    remember picture,
    overlay,
    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}%
    }
  }
}

\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,(0pt,0pt)\@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}%
  \advance\pgf@x by -\pgf@xa
  \advance\pgf@y by -\pgf@ya
  }%
}

% end of Andrew's code

\newlength\AlgIndent
\setlength\AlgIndent{0pt}
% main command to draw the colored background
\newcounter{mymark}
\newcommand\ColorLine{%
  \stepcounter{mymark}%
  \tikz[remember picture with id=mark-\themymark,overlay] {;}%
  \begin{tikzpicture}[remember picture,overlay]%
    \filldraw[GreenYellow]%
   let \p1=(pic cs:mark-\themymark), 
   \p2=(current page.east)  in 
   ([xshift=-\ALG@thistlm-0.3em,yshift=-0.7ex]0,\y1)  rectangle ++(\linewidth+\AlgIndent,\baselineskip);
  \end{tikzpicture}%
}%

% colored loops and declarations
\algnewcommand\CREQUIRE{\item[\setlength\AlgIndent{1.6em}\ColorLine\algorithmicrequire]}%
\algnewcommand\CENSURE{\item[\setlength\AlgIndent{1.6em}\ColorLine\algorithmicensure]}%
\algnewcommand\CSTATE{\State\ColorLine}%
\algnewcommand\CSTATEx{\Statex\ColorLine}%
\algnewcommand\CCOMMENT{\Comment\ColorLine}%

\algdef{SE}[WHILE]{CWHILE}{ENDWHILE}%
   [2][default]{\ColorLine\algorithmicwhile\ #2\ \algorithmicdo\ALG@compatcomm{#1}}%
   {\algorithmicend\ \algorithmicwhile}%
\algdef{SE}[FOR]{CFOR}{ENDFOR}%
   [2][default]{\ColorLine\algorithmicfor\ #2\ \algorithmicdo\ALG@compatcomm{#1}}%
   {\algorithmicend\ \algorithmicfor}%
\algdef{S}[FOR]{CFORALL}%
   [2][default]{\ColorLine\algorithmicforall\ #2\ \algorithmicdo\ALG@compatcomm{#1}}%
\algdef{SE}[LOOP]{CLOOP}{ENDLOOP}%
   [1][default]{\ColorLine\algorithmicloop\ALG@compatcomm{#1}}%
   {\algorithmicend\ \algorithmicloop}%
\algdef{SE}[REPEAT]{CREPEAT}{UNTIL}%
   [1][default]{\ColorLine\algorithmicrepeat\ALG@compatcomm{#1}}%
   [1]{\algorithmicuntil\ #1}%
\algdef{SE}[IF]{CIF}{ENDIF}%
   [2][default]{\ColorLine\algorithmicif\ #2\ \algorithmicthen\ALG@compatcomm{#1}}%
   {\algorithmicend\ \algorithmicif}%
\algdef{C}[IF]{IF}{CELSIF}%
   [2][default]{\ColorLine\algorithmicelse\ \algorithmicif\ #2\ \algorithmicthen\ALG@compatcomm{#1}}%
\algdef{Ce}[ELSE]{IF}{CELSE}{ENDIF}%
   [1][default]{\ColorLine\algorithmicelse\ALG@compatcomm{#1}}%
\makeatother

\begin{document}

\begin{frame}{Test Frame 1}

\begin{algorithmic}[1]
\CREQUIRE Some initial values
\ENSURE Some conditions
\CLOOP
  \STATE$bar(elem)$
  \STATE$baz(elem)$
  \CFOR{$quality\ge 9$}
    \STATE$a\gets perfect$
    \CSTATE$a\gets unusable$
  \ENDFOR
\ENDLOOP
\end{algorithmic}

\end{frame}

\begin{frame}{Test Frame 2}

\begin{algorithmic}[1]
\REQUIRE Some initial values
\CENSURE Some conditions
\FORALL{$elem$ in $collection$}
  \STATE$bar(elem)$
  \CSTATE$foo(elem)$
  \STATE$baz(elem)$
  \CIF{$quality\ge 9$}
    \STATE$a\gets perfect$
  \ELSE
    \CSTATE$a\gets unusable$
  \ENDIF
\ENDFOR
\end{algorithmic}

\end{frame}

\end{document}

enter image description here

enter image description here

share|improve this answer
    
This is really great! It does exactly what I needed. Just one question, some colored tags (such as CENDFOR) are not defined, so it is impossible to color a whole for loop. It is not a big deal since, end for has not too much information, but it could be useful sometimes. I was thinking to add a new definition such as: \algdef{SE}[FOR]{CFOR}{CENDFOR}% [2][default]{\ColorLine\algorithmicfor\ #2\ \algorithmicdo\ALG@compatcomm{#1}}% {\ColorLine\algorithmicend\ \algorithmicfor}%. Would that be the correct way to implement coloring for end for? –  betabandido Jul 26 '12 at 9:02
    
@betabandido yes, that's the correct way. –  Gonzalo Medina Jul 26 '12 at 12:40
    
Thank you very much! :) –  betabandido Jul 26 '12 at 12:56
    
@GonzaloMedina Any idea how to make this work correctly for lines like \State$a$\gets$\max_x f(x)$, where the subscript extends below the "normal" height of the line? Other than that it works great! –  3lectrologos Mar 20 '13 at 19:29
    
@3lectrologos I did some tests using the code you proposed (fixing some typos): \CSTATE$a\gets\max_x f(x)$ and the colored stripe covers the text with no problems; if you are experiencing something different, please open a fresh new question as a follow-up questions to this one; don't forget to add a MWE to the new question, allowing us to replicate the problem. –  Gonzalo Medina Mar 20 '13 at 20:55
show 1 more comment

The following definition of \algemph works, but should be used in the following way:

\STATE \algemph{<stuff>}

enter image description here

\PassOptionsToPackage{dvipsnames}{xcolor} % prevent an option clash
\documentclass{beamer}% http://ctan.org/pkg/beamer

\usepackage[dvipsnames]{xcolor}% http://ctan.org/pkg/xcolor
\usepackage{algcompatible}% http://ctan.org/pkg/algorithmicx

\makeatletter
\newcommand{\algcolor}[2]{%
  \hskip-\ALG@thistlm\colorbox{#1}{\parbox{\dimexpr\linewidth-2\fboxsep}{\hskip\ALG@thistlm\relax #2}}%
}
\newcommand{\algemph}[1]{\algcolor{GreenYellow}{#1}}
\makeatother

\begin{document}
\begin{frame}{Test Frame}
  \begin{algorithmic}[1]
    \FORALL{$elem$ in $collection$}
      \STATE $foo(elem)$
      \STATE \algemph{$bar(elem)$}
    \ENDFOR
    \FORALL{$elem$ in $collection$}
      \STATE \algemph{$bar(elem)$}
      \STATE $foo(elem)$
    \ENDFOR
  \end{algorithmic}
\end{frame}

\end{document}

The logical approach is to set the line number first (which in the case of algorithmicx) includes the indent. \algemph subsequently skips back (horizontally), and then sets the coloured box (with the required indentation re-inserted).

share|improve this answer
add comment

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.