Thomas Fischer's Weblog

Life, Linux, LaTeX

Archive for August 2010

Some new LaTeX Beamer Tricks

with 7 comments

The Swedish summer fades into a rainy autumn, which means it is time again to prepare lectures for the coming months. As a long-time LaTeX user, I use the LaTeX Beamer package for all my slides. During the last few months, I have developed some new helper commands and environments for LaTeX slides, which I want to present here.

The multiframe environment

The Beamer package’s frame environment has the option allowframebreaks to automatically split a frame once it becomes full or split frames manually using the \framebreak command. Although this solution works, it has two drawbacks:

  1. No animation steps can be included using e.g. \only or \pause.
  2. The first frame is such a sequence of “split” frames sets its content with a slightly different vertical offset. This is very annoying, because flipping between slides makes the content jump up and down.

Therefore I designed my own solution. Although it is not perfect, it does not show above flaws. The idea is to define a new environment called multiframe via newenvironment and accept one optional parameter. This new environment acts as a replacement for the known frame environment. An important difference is the optional parameter: Whereas Beamer’s original frame parameter accepts a list of options such as allowframebreaks or fragile, multiframe‘s parameter is the frame’s title. Thus, the frame title is no longer set via \frametitle but with this parameter.

Now, the trick to get a sequence of frames is to omit the optional parameter with subsequent frames. In this case, the multiframe environment assumes that this new frame is part of sequence, reuses the previous frame title, but increases the sequence counter as shown in the title.

% new counter to now which frame it is within the sequence
\newcounter{multiframecounter}
% initialize buffer for previously used frame title
\gdef\lastframetitle{\textit{undefined}}
% new environment for a multi-frame
\newenvironment{multiframe}[1][]{%
\ifthenelse{\isempty{#1}}{%
% if no frame title was set via optional parameter,
% only increase sequence counter by 1
\addtocounter{multiframecounter}{1}%
}{%
% new frame title has been provided, thus
% reset sequence counter to 1 and buffer frame title for later use
\setcounter{multiframecounter}{1}%
\gdef\lastframetitle{#1}%
}%
% start conventional frame environment and
% automatically set frame title followed by sequence counter
\begin{frame}%
\frametitle{\lastframetitle~{\normalfont(\arabic{multiframecounter})}}%
}{%
\end{frame}%
}

Drawback with this solution is that it creates a completely new frame, whereas \framebreak can be used (nearly) everywhere in the frame. For example, you can use \framebreak inside an itemize list and split this list. In my solution, you have to close all environments up to the current multiframe and open again all environments as desired.

Example

Without my new environment, you would set plain, single frames using the frame environment. Nothing changes here:

\begin{frame}
\frametitle{The Frame's Title}
Some content \ldots
\end{frame}

Things get different for sequences of frames. With plain LaTeX Beamer, you would do something like this:

\begin{frame}[allowframebreaks]
\frametitle{The Frame's Title}
Some content \ldots
\framebreak
More content on next page
\end{frame}

With my new environment, the corresponding solution would look like this:

\begin{multiframe}[The Frame's Title]
Some content \ldots
\only<2>{Only seen in animation step}
\end{multiframe}
% this is like a frame break
\begin{multiframe}% no optional parameter here!
More content on next page
\end{multiframe}

The copyrightbox Command

When you include photos, images, or drawing on your slides, you should always give credit to the original creator and show license and origin. Some licenses require you to state where you got the image from and which rights have been granted. For someone who wants to reuse your slides or parts of it, it clarifies under which conditions the materials are accessible. From a legal aspect, it suffices in most cases to show all relevant information next to the included image, or collected at the end of your document in a single list.

In the next-to-the-image case, it is common to set the information text in fine print along the bottom or right border of the image. But how to do it in LaTeX? For the solution I am presenting here, I am using a tikzpicture environment to set both the image and the accompanying text in two nodes next to each other. The new command \copyrightbox takes two mandatory parameters and one optional parameter. The first mandatory parameter is supposed to contain the command showing the image or drawing, e.g. an \includegraphics command. The second parameter takes the copyright statement and is usually plain text. The optional parameter is a single character describing the position of the text in relation to the image. Possible values include b (below), l (left), and r (right), where “right” is default if nothing else is specified.

Now, the tricky part is that the image should determine the copyrightbox‘s size and the text should follow this format. In particular, if the text is below the image, the text (more specific, the node containing the text) should be node wider than the image (more specific, the node containing the image); instead it should wrap around consuming several lines if necessary. The same applies to the height in case of left or right alignment. To get the width and height of a node in TikZ, I had to search for a proper solution on the Internet resulting in a quite long statement for commands ydiff and xdiff.

\makeatletter
\newdimen\tu@tmpa%
\newdimen\ydiffl%
\newdimen\xdiffl%
\newcommand\ydiff[2]{%
    \coordinate (tmpnamea) at (#1);%
    \coordinate (tmpnameb) at (#2);%
    \pgfextracty{\tu@tmpa}{\pgfpointanchor{tmpnamea}{center}}%
    \pgfextracty{\ydiffl}{\pgfpointanchor{tmpnameb}{center}}%
    \advance\ydiffl by -\tu@tmpa%
}
\newcommand\xdiff[2]{%
    \coordinate (tmpnamea) at (#1);%
    \coordinate (tmpnameb) at (#2);%
    \pgfextractx{\tu@tmpa}{\pgfpointanchor{tmpnamea}{center}}%
    \pgfextractx{\xdiffl}{\pgfpointanchor{tmpnameb}{center}}%
    \advance\xdiffl by -\tu@tmpa%
}
\makeatother
\newcommand{\copyrightbox}[3][r]{%
\begin{tikzpicture}%
\node[inner sep=0pt,minimum size=2em](ciimage){#2};
\usefont{OT1}{phv}{n}{n}\fontsize{4}{4}\selectfont
\ydiff{ciimage.south}{ciimage.north}
\xdiff{ciimage.west}{ciimage.east}
\ifthenelse{\equal{#1}{r}}{%
\node[inner sep=0pt,right=1ex of ciimage.south east,anchor=north west,rotate=90]%
{\raggedleft\color{black!33}\parbox{\the\ydiffl}{\raggedright{}#3}};%
}{%
\ifthenelse{\equal{#1}{l}}{%
\node[inner sep=0pt,right=1ex of ciimage.south west,anchor=south west,rotate=90]%
{\raggedleft\color{black!33}\parbox{\the\ydiffl}{\raggedright{}#3}};%
}{%
\node[inner sep=0pt,below=1ex of ciimage.south west,anchor=north west]%
{\raggedleft\color{black!33}\parbox{\the\xdiffl}{\raggedright{}#3}};%
}
}
\end{tikzpicture}
}

Example

To use this new command, you simply set the mandatory parameters with some useful values:

\copyrightbox{\includegraphics[width=0.5\linewidth]{images/osmphoto}}{CC-BY-SA, Thomas Fischer}
\copyrightbox[b]{\includegraphics[width=0.5\linewidth]{images/osmphoto}}{CC-BY-SA, Thomas Fischer}

The first example above creates a copyrightbox containing an image as loaded from images/osmphoto.jpg (pdflatex searches for known extensions if you do not specify one), scaled to 50% of the line width, and the copyright statement “CC-BY-SA, Thomas Fischer”. The text will be written on the image’s right side, starting in the lower right corner going upwards. In the second line, the text’s alignment is changed to b: Here the text starts in the lower left corner and goes to the right as usual.

Be aware that the copyrightbox‘s total size is a combination of both the image and text. It will thus be larger than the image alone (as specified with width or height).

Advertisements

Written by Thomas Fischer

August 17, 2010 at 18:52

Posted in LaTeX