1

I've got a lot of beamer/tikz code with multiple slides on each frame. I end up with a lot of code that looks like this (not a MWE, just an example):

\only<1-3>{
   \node (rpctrace Message) [message, anchor=north, opacity=0] {};
}
\only<4-5>{
   \node (rpctrace Message) [message, anchor=north] {};
}
\only<6>{
   \node (rpctrace Message) [message, anchor=north, fill=none, dashed] {};
}

So now, I might want to add a new slide between 5 and 6, and 6 becomes 7. So, I need to change 4-5 to read 4-6 and 6 changes to 7.

Any way to easily change the numbering on a whole bunch of \only macros?

Conversely, I sometimes need to remove slides and adjust the numbering.

Any ideas?

4

There is a robust mechanism for this already in beamer presentations... You need to use the symbols + and ..

For more information about them I will refer you to the beamer manual, section 9.6.4.

For our purposes, I will provide a small explanation.

Small explanation

  • Basically, whenever you write a + sign inside the overlay specification, like so:

    <+>
    

    A counter called beamerpauses is updated, adding one unit to it. After the counter is updated, it replaces the + sign with the value of the counter beamerpauses.

    <1>
    
  • If you write a number in parenthesis after the + sign, it shifts the value by that much.

    <+-+(2)> 
    

    will be replaced by

    <1-3>
    
  • There is an issue though, even if you have more than one + sign inside one specification, it will only updates the value of the counter once for each overlay specification. (It assumes you always want to just add "one" frame)

  • Therefore, you have to update the value manually afterwards.

    In our example, we wanted to have a pause that lasted 3 frames. Therefore, we need to add two extra pauses after our \only<> command is done:

    \only<+-+(2)>{
        %your code here
    }
    \addtocounter{beamerpauses}{2}
    
    %continue
    

Solution

With that in mind, now we can use the relative coordinates, as showcased on this example:

  1. The first frame shows how you can re-write your slide to use relative overlay specifications.

  2. The second frame of this beamer presentation showcases how now it becomes easy to add some other slide in-between, without having to rewrite the entire frame.

With that:

\documentclass{beamer}
\usepackage{tikz}

\begin{document}
\begin{frame}
\frametitle{First try}
    \begin{tikzpicture}
        \only<+-+(2)>{
           \node   {First};
        }
        \addtocounter{beamerpauses}{2}


        \only<+-+(1)>{
           \node   {Second};
        }
        \addtocounter{beamerpauses}{1}      



        \only<+>{
           \node   {Third};
        }
    \end{tikzpicture}
\end{frame}


\begin{frame}
\frametitle{Intermediate step}
    \begin{tikzpicture}
        \only<+-+(2)>{
           \node   {First};
        }
        \addtocounter{beamerpauses}{2}


        \only<+-+(1)>{
           \node   {Second};
        }
        \addtocounter{beamerpauses}{1}      

        \only<+-+(3)>{
           \node   {Between second and third};
        }
        \addtocounter{beamerpauses}{3}      



        \only<+>{
           \node   {Third};
        }
    \end{tikzpicture}
\end{frame}
\end{document}

If you have multiple elements, not just your tikz picture:

If you have multiple elements, not just the tikz picture, and you want to use relative coordinates for all of those elements that come together on the same frame. You can update the beamerpauses counter to zero before each "element" starts.

% itemize using relative overlay... with + and the like.

\setcounter{beamerpauses}{0}
\begin{tikzpicture}

    \only<+-+(2)>{
        %your code here
    }
    \addtocounter{beamerpauses}{2}

    %continue

\end{tikzpicture}

Solution

  • 2
    Very nice answer! – user36296 Jan 26 '18 at 20:49
1

I don't care for the complexity of relative slide numbering and the need to constantly reset the beamerpauses counter. Instead, I've written a GNU Emacs LISP function to adjust the numbering on \only macros that use absolute numbering.

This code creates two new interactive functions, slide-duplicate and slide-remove, that prompt for a slide number and then start an interactive search-and-replace to adjust the numbering accordingly. It only works on absolute numbered \only macros.

(defun slide-func (slide)
  "add or remove a slide number from only macros"
  (let ((mystr (match-string 0)) (start 0) value1 value2 newstr (sign (/ slide (abs slide))))
       (save-match-data (while (string-match "\\([0-9]+\\)\\(-\\([0-9]+\\)?\\)?" mystr start)
                               (setq value1 (string-to-number (match-string 1 mystr)))
                               (setq value2 (cond ((match-string 3 mystr) (string-to-number (match-string 3 mystr)))
                                                  ((match-string 2 mystr) 1000000)
                                                  (t value1)))
                               (if (> value1 (abs slide)) (setq value1 (+ value1 sign)))
                               (if (>= value2 (abs slide)) (setq value2 (+ value2 sign)))
                               (setq newstr (cond ((> value1 value2) "0")
                                                  ((eq value1 value2) (format "%d" value1))
                                                  ((>= value2 999999) (format "%d-" value1))
                                                  (t (format "%d-%d" value1 value2))))
                               (setq mystr (replace-match newstr nil nil mystr))
                               (setq start (+ (match-beginning 0) (length newstr)))))
       mystr))

(defun slide-duplicate (slide)
  "duplicate slide numbers in only macros"
  (interactive "NSlide number to duplicate: ")
  (query-replace-regexp "\\only<[0-9-,]+>" `(replace-eval-replacement replace-quote (slide-func ,slide))))

(defun slide-remove (slide)
  "remove slide numbers from only macros"
  (interactive "NSlide number to remove: ")
  (query-replace-regexp "\\only<[0-9-,]+>" `(replace-eval-replacement replace-quote (slide-func ,(- slide)))))

Copy it into emacs and run eval-region on it, or put it in your .emacs file, or any other way you'd like to run it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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