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.

The beamer command \alt<*overlay specification*>{foo}{bar} will insert foo if the current slide is within the given overlay specification, and bar otherwise. It's equivalent to

\only<*overlay specification*>{foo}\only<*complementary overlay specification*>{bar}

Here is a sample document using it:

\documentclass{beamer}
\begin{document}
\begin{frame}
\begin{align*}
y &= \frac{(x^2+1)\sqrt{x+3}}{x-1} \\
\ln y &= \ln (x^2+1) + \frac{1}{2} \ln(x+3) - \ln(x-1) \\
\frac{1}{y} \frac{dy}{dx}
      &= \frac{2x}{x^2+1} + \frac{1}{2(x+3)} - \frac{1}{x-1}
\end{align*}
So
\[
\begin{split}
\frac{dy}{dx} &= \left(\frac{2x}{x^2+1} + \frac{1}{2(x+3)} - \frac{1}{x-1}
\right)
\alt<2>{\frac{(x^2+1)\sqrt{x+3}}{x-1}}{y}
\end{split}
\]
\end{frame}
\end{document}

This is very useful and saves typing. But if one of the alternatives is larger than the other, it leads to jiggling slides.

What I would like is a overlay-specification-aware command \altvisible that would take the same amount of space on each slide. So it would have to insert a box as big as the bigger of the two, and then set the correct material. So the above document with \altvisible instead of \alt would not jiggle.

Any takers?

share|improve this question
    
Take a look at Uncover a multiline equation with beamer. Do the answers to this question help you? –  Hendrik Vogt Mar 18 '11 at 12:07
    
Such things are normally done using overprint, but I only used it for whole lines/paragraphs, never for short material. See my answer at the question liked by Hendrik. –  Martin Scharrer Mar 18 '11 at 13:02
2  
@Hendrik, @Martin: Thanks for the pointers. overprint is relevant, but because my particular use case is within a math expression it's not flexible enough. overlayarea might work. –  Matthew Leingang Mar 18 '11 at 13:27
add comment

5 Answers

up vote 11 down vote accepted

Following up the discussion of diabonas answer, here my suggestion. The idea to use phantom boxes seems the way to go. Here the two alternatives are boxed so that they can be measured. The code could be improved to detect the mode (text, math, display math, etc.) by itself and avoid the re-boxing which happens in the phantom commands.

\documentclass{beamer}
\newcommand<>\Alt[2]{{%
    \sbox0{$\displaystyle #1$}%
    \sbox1{$\displaystyle #2$}%
    \alt#3%
        {\rlap{\usebox0}\vphantom{\usebox1}\hphantom{\ifnum\wd0>\wd1 \usebox0\else\usebox1\fi}}%
        {\rlap{\usebox1}\vphantom{\usebox0}\hphantom{\ifnum\wd0>\wd1 \usebox0\else\usebox1\fi}}%
}}

\begin{document}
\begin{frame}
\begin{align*}
y &= \frac{(x^2+1)\sqrt{x+3}}{x-1} \\
\ln y &= \ln (x^2+1) + \frac{1}{2} \ln(x+3) - \ln(x-1) \\
\frac{1}{y} \frac{dy}{dx}
      &= \frac{2x}{x^2+1} + \frac{1}{2(x+3)} - \frac{1}{x-1}
\end{align*}
So
\[
\begin{split}
\frac{dy}{dx} &= \left(\frac{2x}{x^2+1} + \frac{1}{2(x+3)} - \frac{1}{x-1}
\right)
\Alt<2>{\frac{(x^2+1)\sqrt{x+3}}{x-1}}{y}
\end{split}
\]
\end{frame}
\end{document}

Here the version which checks the mode and math-style automatically. It works in all math and text modes:

\documentclass{beamer}

\makeatletter
% Detect mode. mathpalette is used to detect the used math style
\newcommand<>\Alt[2]{%
    \begingroup
    \ifmmode
        \expandafter\mathpalette
        \expandafter\math@Alt
    \else
        \expandafter\make@Alt
    \fi
    {{#1}{#2}{#3}}%
    \endgroup
}

% Un-brace the second argument (required because \mathpalette reads the three arguments as one
\newcommand\math@Alt[2]{\math@@Alt{#1}#2}

% Set the two arguments in boxes. The math style is given by #1. \m@th sets \mathsurround to 0.
\newcommand\math@@Alt[3]{%
    \setbox\z@ \hbox{$\m@th #1{#2}$}%
    \setbox\@ne\hbox{$\m@th #1{#3}$}%
    \@Alt
}

% Un-brace the argument
\newcommand\make@Alt[1]{\make@@Alt#1}

% Set the two arguments into normal boxes
\newcommand\make@@Alt[2]{%
    \sbox\z@ {#1}%
    \sbox\@ne{#2}%
    \@Alt
}

% Place one of the two boxes using \rlap and place a \phantom box with the maximum of the two boxes
\newcommand\@Alt[1]{%
    \alt#1%
        {\rlap{\usebox0}}%
        {\rlap{\usebox1}}%
    \setbox\tw@\null
    \ht\tw@\ifnum\ht\z@>\ht\@ne\ht\z@\else\ht\@ne\fi
    \dp\tw@\ifnum\dp\z@>\dp\@ne\dp\z@\else\dp\@ne\fi
    \wd\tw@\ifnum\wd\z@>\wd\@ne\wd\z@\else\wd\@ne\fi
    \box\tw@
}

\makeatother

\begin{document}

% Test the different modes and math styles
\begin{frame}
Display:
\[
\begin{split}
\frac{dy}{dx} &= \left(\frac{2x}{x^2+1} + \frac{1}{2(x+3)} - \frac{1}{x-1}
\right)
\Alt<2>{\frac{(x^2+1)\sqrt{x+3}}{x-1}}{y}.
\end{split}
\]

In-Text:
\(
\frac{dy}{dx} = \left(\frac{2x}{x^2+1} + \frac{1}{2(x+3)} - \frac{1}{x-1}
\right)
\Alt<2>{\frac{(x^2+1)\sqrt{x+3}}{x-1}}{y}.
\)

Subscript:
\(
\frac{dy}{dx} = \left(\frac{2x}{x^2+1} + \frac{1}{2(x+3)} - \frac{1}{x-1}
\right) X_{\Alt<2>{\frac{(x^2+1)\sqrt{x+3}}{x-1}}{y}}.
\)
\[
\frac{dy}{dx} = \left(\frac{2x}{x^2+1} + \frac{1}{2(x+3)} - \frac{1}{x-1}
\right) X_{\Alt<2>{\frac{(x^2+1)\sqrt{x+3}}{x-1}}{y}}.
\]

Sub-Subscript:
\(
\frac{dy}{dx} = \left(\frac{2x}{x^2+1} + \frac{1}{2(x+3)} - \frac{1}{x-1}
\right) X_{X_{\Alt<2>{\frac{(x^2+1)\sqrt{x+3}}{x-1}}{y}}}.
\)
\[
\frac{dy}{dx} = \left(\frac{2x}{x^2+1} + \frac{1}{2(x+3)} - \frac{1}{x-1}
\right) X_{X_{\Alt<2>{\frac{(x^2+1)\sqrt{x+3}}{x-1}}{y}}}.
\]

Text-mode:
XXXX  \Alt<2>{aaaaa}{Ag}.


\end{frame}
\end{document}

The dots at the end are to visualize the constant width only.

Result

share|improve this answer
1  
This looks excellent. I will test it on Monday. –  Matthew Leingang Mar 19 '11 at 12:33
    
@Matthew: Did this work out for you? –  Martin Scharrer May 10 '11 at 13:36
2  
I find myself using this again and thinking that it deserves more than a paltry three votes ... –  Andrew Stacey Dec 2 '11 at 11:30
2  
@AndrewStacey: I have to make a real package out of it and announce it here. Maybe then I get some more votes. –  Martin Scharrer Dec 2 '11 at 11:43
4  
Do that! I've already put it in a .sty file in my own texmf tree for easy use in various documents. I called it extalt, most likely for extended alt (I chose the name back in May so the actual reasons are - thankfully - lost in the mists (and midsts) of time). –  Andrew Stacey Dec 2 '11 at 11:50
show 5 more comments

As a further revision to Martin Scharrer's and bcat's nifty answers, here is a version that allows one to specify the position (l, c, or r) of the smaller text within the larger box:

\usepackage{etoolbox}
\usepackage{mathtools}

\makeatletter
% Detect mode. mathpalette is used to detect the used math style
\newcommand<>\Alt[3][l]{%
  \begingroup
    \providetoggle{Alt@before}%
    \alt#4{\toggletrue{Alt@before}}{\togglefalse{Alt@before}}%
    \ifbool{mmode}{%
      \expandafter\mathpalette
      \expandafter\math@Alt
    }{%
      \expandafter\make@Alt
    }%
    {{#1}{#2}{#3}}%
  \endgroup
}

% Un-brace the second argument (required because \mathpalette reads the three arguments as one
\newcommand\math@Alt[2]{\math@@Alt{#1}#2}

% Set the two arguments in boxes. The math style is given by #1. \m@th sets \mathsurround to 0.
\newcommand\math@@Alt[4]{%
  \setbox\z@ \hbox{$\m@th #1{#3}$}%
  \setbox\@ne\hbox{$\m@th #1{#4}$}%
  \@Alt{#2}%
}

% Un-brace the argument
\newcommand\make@Alt[1]{\make@@Alt#1}

% Set the two arguments into normal boxes
\newcommand\make@@Alt[3]{%
  \sbox\z@ {#2}%
  \sbox\@ne{#3}%
  \@Alt{#1}%
}

% Place one of the two boxes using \rlap and place a \phantom box with the maximum of the two boxes
\newcommand\@Alt[1]{%
  \setbox\tw@\null
  \ht\tw@\ifnum\ht\z@>\ht\@ne\ht\z@\else\ht\@ne\fi
  \dp\tw@\ifnum\dp\z@>\dp\@ne\dp\z@\else\dp\@ne\fi
  \wd\tw@\ifnum\wd\z@>\wd\@ne\dimexpr\wd\z@/2\relax\else\dimexpr\wd\@ne/2\relax\fi
  %
  \ifstrequal{#1}{l}{%
    \rlap{\iftoggle{Alt@before}{\usebox\z@}{\usebox\@ne}}%
    \copy\tw@
    \box\tw@
  }{%
    \ifstrequal{#1}{c}{%
      \copy\tw@
      \clap{\iftoggle{Alt@before}{\usebox\z@}{\usebox\@ne}}%
      \box\tw@
    }{%
      \ifstrequal{#1}{r}{%
        \copy\tw@
        \box\tw@
        \llap{\iftoggle{Alt@before}{\usebox\z@}{\usebox\@ne}}%
      }{%
      }%
    }%
  }%
}
\makeatother

Unlike bcat's macro, I use \mathpalette and avoid the bug in Martin's answer by toggling a flag inside \alt; the flag says whether the first or second argument of \Alt should be set.

This was my first attempt at writing a nontrivial macro involving plain TeX, so please let me know if there are better style practices I should use.

share|improve this answer
    
Scratch registers with an odd index (\box1, for instance) should be used only for global assignments. This is a recommended practice, not following it might lead to memory problems. –  egreg Jul 16 '12 at 22:28
    
@egreg So I should not be using \box\@ne in this case? Should I prefer the LaTeX style of \newsavebox etc. here, or is there a reason to stick to the plain TeX primitives for this macro? Thanks in advance for your help! –  Henry DeYoung Jul 17 '12 at 17:06
    
You can use \box\tw@ or \box4, \box6, \box8; in this case the scratch boxes seem to be correctly used. When in doubt allocate new ones. –  egreg Jul 17 '12 at 18:27
add comment

The second \Alt command in Martin Scharrer's answer is excellent; however, it can cause problems when used with Beamer's incremental overlay specifications (e.g., <+>). This is because Martin's implementation invokes the underlying \alt command using \mathpalette. \mathpalette internally uses \mathchoice, which actually typesets the contents given for each of the four math styles before deciding which to use in the final output.

Example of the issue

\documentclass{beamer}

% [Paste Martin's second set of `\Alt` macros here.]

\begin{document}

\begin{frame}
  \begin{itemize}
    \item Some stuff\dots

      \pause

    \item An equation I'll reveal in pieces:
      \[
        \frac{-4}{2} + \frac{9}{3} =
        \Alt<+>{
          \vcenter{\hbox{ ?\thinspace?}}
        }{
          \frac{-4 + 9}{2 + 3} = 1.
        }
      \]

      \pause

    \item Some more stuff\dots
  \end{itemize}
\end{frame}

\end{document}

Compiling this code yields a document with seven slides rather than the desired four, as TeX is executing the Beamer \alt macro---and thus incrementing the beamerpauses counter---four times rather than one.

Solving the problem

Move the \alt invocation outside of \mathpalette/\mathchoice. Unfortunately, this means that the new \Alt command's arguments will be typeset eight times (four for each of the \alt macro's two arguments) rather than four times as in Martin's code, but the added overhead seems necessary to make \Alt behave the same as \alt with respect to incremental overlays.

Also, it's a minor thing, but adding a \leavevmode before typesetting the \Alt content box seems to make the command behave a bit less surprisingly in some cases, e.g., at the start of a list item.

Revised code (supports incremental overlays)

\usepackage{etoolbox} % For `\ifbool`, `\ifnumcomp`.

\makeatletter
\newcommand*\Alt{\alt{\Alt@branch0}{\Alt@branch1}}

\newcommand\Alt@branch[3]{%
  \begingroup
  \ifbool{mmode}{%
    \mathchoice{%
      \Alt@math#1{\displaystyle}{#2}{#3}%
    }{%
      \Alt@math#1{\textstyle}{#2}{#3}%
    }{%
      \Alt@math#1{\scriptstyle}{#2}{#3}%
    }{%
      \Alt@math#1{\scriptscriptstyle}{#2}{#3}%
    }%
  }{%
    \sbox0{#2}%
    \sbox1{#3}%
    \Alt@typeset#1%
  }%
  \endgroup
}

\newcommand\Alt@math[4]{%
  \sbox0{$#2{#3}\m@th$}%
  \sbox1{$#2{#4}\m@th$}%
  \Alt@typeset#1%
}

\newcommand\Alt@typeset[1]{%
  \ifnumcomp{\wd0}{>}{\wd1}{%
    \def\setwider   ##1##2{##2##1##2 0}%
    \def\setnarrower##1##2{##2##1##2 1}%
  }{%
    \def\setwider   ##1##2{##2##1##2 1}%
    \def\setnarrower##1##2{##2##1##2 0}%
  }%
  \sbox2{}%
  \sbox3{}%
  \setwider2{\wd}%
  \setwider2{\ht}%
  \setwider2{\dp}%
  \setnarrower3{\ht}%
  \setnarrower3{\dp}%
  \leavevmode
  \rlap{\usebox#1}%
  \usebox2%
  \usebox3%
}
\makeatother
share|improve this answer
2  
+1 for improving an already good answer a year later and the excellent explanations! –  Daniel Mar 31 '12 at 22:05
add comment

Maybe \vphantom could help? The following code defines a macro \altvphantom which uses the normal \alt command and additionally inserts \vphantom{<first argument>} and \vphantom{<second argument>} to ensure a consistent vertical spacing and to prevent the jiggling:

\newcommand<>{\altvphantom}[2]{\alt#3{#1}{#2}\vphantom{#1}\vphantom{#2}}

Just add this line to your document and replace \alt<2>{...}{...} with \altvphantom{...}{...}, and the preceding lines will stop moving around.

UPDATE: If you do not want the last line to move left and right either, you can say \usepackage{mathtools} in the preamble and change the "\alt-line" to

\altvphantom<2>{\mathrlap{\frac{(x^2+1)\sqrt{x+3}}{x-1}}}{\mathrlap{y}}

Another possibilty would be to use the fleqn option: If you use \documentclass[fleqn]{beamer}, all the equations will flush left, which solves the problem with the moving line, too.

share|improve this answer
    
This doesn't appear to work. Did you test it? –  Seamus Mar 18 '11 at 14:49
    
@Seamus Yes, I tested it and it worked fine for me. I uploaded the resulting PDF for you. –  diabonas Mar 18 '11 at 14:53
    
@Seamus @diabonas thanks. The vertical jiggling is gone (because the \vphantom{#1}{#2} stretches the line to have a height equal to the maximum of the two) but it still moves horizontally. –  Matthew Leingang Mar 18 '11 at 15:13
    
@Matthew @Seamus I've updated my solution to prevent this movement, too. –  diabonas Mar 18 '11 at 15:24
1  
@Matthew: You could place the shorter one in a \rlap macro and use \phantom{<longer one>} to fill the correct amount of space. –  Martin Scharrer Mar 18 '11 at 15:26
show 3 more comments

Here is the definition of alt in beamerbaseoverlay.sty:

\def\alt{\@ifnextchar<{\beamer@alt}{\beamer@alttwo}}
\long\def\beamer@alttwo#1#2{\beamer@ifnextcharospec{\beamer@altget{#1}{#2}}{#1}}
\long\def\beamer@altget#1#2<#3>{%
  \def\beamer@doifnotinframe{#2}\def\beamer@doifinframe{#1}%
  {\beamer@masterdecode{#3}}\beamer@donow}
\long\def\beamer@alt<#1>#2#3{%
  \def\beamer@doifnotinframe{#3}\def\beamer@doifinframe{#2}%
  {\beamer@masterdecode{#1}}\beamer@donow}

Weirdly, \uncover is defined in terms of \alt:

\newcommand{\uncover}{\alt{\beamer@fakeinvisible}{\beamer@makecovered}}

So I suspect that putting \beamer@fakeinvisible and \beamer@makeuncovered at some point in a definition like that of \alt should work? But I couldn't work out where exactly to fit it in.

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.