[Tex/LaTex] Explanatory bubbles in beamer

beamerpresentationstikz-pgf

In the MWE below I want to place an "explanatory bubble" (see picture inserted below) pointing to the word "Integer" in the 8th line (the bubble should superimpose the text, a transparency effect such that the text behind the bubble is still weakly visible would be nice but is by no means necessary if this would make things significantly more complex) .

What is the most simple and elegant solution to do this?

\documentclass[10pt,xcolor=dvipsnames]{beamer}
\usepackage{lipsum}
\begin{document}
  \frame{\frametitle{A Modern Exegesis of Lipsum}
  \lipsum[1]
  \begin{itemize}
    \item WDQGCBIOZBWIWURZBBTBRTTVVUQRWXWTVEWQVY
    \item BXWZTVWQTVCWRCQTVXTTQVRQXTRCVCVRTCVVTX
    \item AUXZWTCVWVWUTVRTVCUZTEVWTVCUTVTVERVCTV
  \end{itemize}
  }
\end{document}

The pdf output of the MWE:

MWE

The bubble should look somewhat like this:

bubble

PS: I saw Simple speech bubbles, arrows or balloon like shapes in beamer but it seems quite complicated to me — hopefully there is a simpler solution to my problem. In case the solution involves TikZ some explanations would be appreciated since I have never used TikZ yet. NB: The solution should work with standard LaTeX and preferably not require PDFLaTeX.


EDIT: There is a follow-up question TikZ callout pointing to nested nodes. The accepted answer to that question also gives an alternative solution to the above problem which may be more robust in combination with beamer than the solution suggested below.

Best Answer

Here is a possible solution:

\documentclass[10pt,xcolor=dvipsnames]{beamer}
\usepackage{lmodern}

\usepackage{tikz}
\usetikzlibrary{shapes.callouts}

\usepackage{xparse}

\tikzset{
    invisible/.style={opacity=0,text 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
    },
}

\NewDocumentCommand{\mycallout}{r<> O{opacity=0.8,text opacity=1} m m}{%
\tikz[remember picture, overlay]\node[align=center, fill=cyan!20, text width=2cm,
#2,visible on=<#1>, rounded corners,
draw,rectangle callout,anchor=pointer,callout relative pointer={(230:1cm)}]
at (#3) {#4};
}

\newcommand{\tikzmark}[1]{\tikz[overlay,remember picture,baseline=-0.5ex] \node (#1) {};}

\begin{document}
\begin{frame}{A Modern Exegesis of Lipsum}
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit,
vestibulum ut, placerat ac, adipiscing vitae, felis. Curabitur dictum
gravida mauris. Nam arcu libero, nonummy eget, consectetuer id,
vulputate a, magna. Donec vehicula augue eu neque. Pellentesque
habitant morbi tristique senectus et netus et malesuada fames ac turpis
egestas. Mauris ut leo. Cras viverra metus rhoncus sem. Nulla et lectus
vestibulum urna fringilla ultrices. Phasellus eu tellus sit amet tortor
gravida placerat. Integer\tikzmark{int} sapien est, iaculis in, pretium quis, viverra ac,
nunc. Praesent eget sem vel leo ultrices bibendum. Aenean\tikzmark{second} faucibus.
Morbi dolor nulla, malesuada eu, pulvinar at, mollis ac, nulla. Curabitur
auctor semper nulla. Donec varius orci eget risus. Duis nibh mi, congue
eu, accumsan eleifend, sagittis quis, diam. Duis eget orci sit amet orci
dignissim rutrum.
\mycallout<2>{int}{Example: 2 is integer, but $\pi$ not}
\mycallout<3>[opacity=1]{second}{Example: 2 is integer, but $\pi$ not}
  \begin{itemize}
    \item WDQGCBIOZBWIW\mycallout<4>{0,0.5}{Another bubble placed with coordinates}URZBBTBRTTVVUQRWXWTVEWQVY 
    \item BXWZTVWQTVCWRCQTVXTTQVRQXTRCVCVRTCVVTX
    \item AUXZWTCVWVWUTVRTVCUZTEVWTVCUTVTVERVCTV
  \end{itemize}
  \end{frame}
\end{document}

The result:

enter image description here

This solution is almost identical to Move TikZ cloud in a better position using beamer: you first mark the word in which the callout will appear, then you simply declare the callout on that position.

The \mycallout command is defined to fit your requirements: by default the text behind it is still visible even if I think should be better to make it opaque. For this reason, I let the possibility to the user to do this: in the optional second argument just set the opacity equal to 1, as did in the example.

Notice that two compilation runs are needed in order to achieve the result: the first one to compute the position of the markers, the second to draw the callout.

Explanations on the code

Let's analyze step by step the required TikZ code needed. A part from the libraries, at first we encounter

\tikzset{
    invisible/.style={opacity=0,text 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
    },
 }

This piece of code is taken from Mindmap tikzpicture in beamer (reveal step by step) (I've added a text opacity because it makes more robust the method): it is a way to show correctly TikZ-based animations. What I mean with correctly? TikZ-based animations may suffer of the so called jumping effect (here along the site you can find several question on this regard link to questions) and that code addresses it. What he actually does is to force the visibility of nodes and paths to be completely transparent when they should not be visible: you decide where nodes and paths should be visible by selecting overlay specifications by means of the key visible on=<overlay specifications>.

Let's now have a look to:

\NewDocumentCommand{\mycallout}{r<> O{opacity=0.8,text opacity=1} m m}{%
\tikz[remember picture, overlay]\node[align=center, fill=cyan!20, text width=2cm,
#2,visible on=<#1>,
draw,rectangle callout,anchor=pointer,callout relative pointer={(230:1cm)}]
at (#3) {#4};
}

This is the command responsible to create the callouts. As said in the comment he need some arguments:

  • a mandatory argument with delimiters <> to decide the right overlay specifications (similarly as you insert them with Beamer) that actually are the ones in which the visibility, as stated in the previous paragraph, is not transparent, but nodes or paths are opaque;
  • a second optional argument in which it is possible to select the opacity of the background and of the text to be put in the callout;
  • the third argument is mandatory: it is the anchor in which the pointer of the callout starts (it could be simply a node or a coordinate);
  • the fourth argument is mandatory: it is the text of the callout.

The node is realized with the syntax \tikz[options]\node[options]at(pos){text};; the options to be passed to \tikz are remember picture,overlay because the callout should be drawn in overlay and remember picture permits to remember previous nodes, marked for example with the \tikzmark command. The options passed to the node are simply the ones needed to create a callout draw,rectangle callout,anchor=pointer,callout relative pointer={(230:1cm)}, to fix the aspect of it align=center, fill=cyan!20, text width=2cm, and to set its visibility #2,visible on=<#1>, (recall that #2 by default is opacity=0.8,text opacity=1). Notice that, actually, the code used for overlays set itself the opacity of nodes (complete opaque or transparent), thus to not have problems the opacity of the callout should be declared before.

Finally we have the \tikzmark command:

\newcommand{\tikzmark}[1]{\tikz[overlay,remember picture,baseline=-0.5ex] \node (#1) {};}

It simply defines a void node with a label: the node is aligned with a baseline that place it vertically in the middle of a line. The node it will be remembered by means of the label you give to it and is used subsequently as the starting point in which the callout pointers.


Interactive word explanation

After a suggestion in chat by Speravir, here is an interactive solution: it is based on the ocgx package and some ideas are stolen from Interactive PDF, Latex and Article of the Future.

The code:

\documentclass[10pt]{beamer}
\usepackage{lmodern}
\usepackage{xparse}
\usepackage{tikz}
\usetikzlibrary{shapes.callouts,ocgx}

\newcommand{\tikzmark}[1]{\tikz[overlay,remember picture,baseline=0.5ex] \node (#1) {};}

% \explainword: #1= identifier to mark the word, #2 text
\NewDocumentCommand{\explainword}{r[] m}{
    \switchocg{#1}{#2}\tikzmark{#1}
}

\tikzset{my callout style/.style={
        draw,rectangle callout,anchor=pointer,callout relative pointer={(230:1cm)},
        rounded corners,align=center,text width=2cm,fill=cyan!20, 
    }
}

% \mycallout: #1 opacity style, #2 pointer base position, #3= text
\NewDocumentCommand{\mycallout}{O{opacity=0.8,text opacity=1} m m}{%
\begin{tikzpicture}[remember picture, overlay]
 \begin{scope}[ocg={ref=#2,status=invisible,name={#3}}]
\node[my callout style,#1]at (#2) {#3};
\end{scope}
\end{tikzpicture}
}

\begin{document}
\begin{frame}{A Modern Exegesis of Lipsum}
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut purus elit,
vestibulum ut, placerat ac, adipiscing vitae, felis. Curabitur dictum
gravida mauris. Nam arcu libero, nonummy eget, consectetuer id,
vulputate a, magna. Donec vehicula augue eu neque. Pellentesque
habitant morbi tristique senectus et netus et malesuada fames ac turpis
egestas. Mauris ut leo. Cras viverra metus rhoncus sem. Nulla et lectus
vestibulum urna fringilla ultrices. Phasellus eu tellus sit amet tortor
gravida placerat. \explainword[int]{Integer} sapien est, iaculis in, pretium quis, viverra ac,
nunc. Praesent eget sem vel leo ultrices bibendum. \explainword[second]{Aenean} faucibus.
Morbi dolor nulla, malesuada eu, pulvinar at, mollis ac, nulla. Curabitur
auctor semper nulla. Donec varius orci eget risus. Duis nibh mi, congue
eu, accumsan eleifend, sagittis quis, diam. Duis eget orci sit amet orci
dignissim rutrum.
\mycallout{int}{Example: 2 is integer, but $\pi$ not}
\tikzset{my callout style/.append style={fill=orange!20}}
\mycallout[opacity=1]{second}{Example: 2 is integer, but $\pi$ not}
  \begin{itemize}
    \item WDQGCBIOZBWIWURZBBTBRTTVVUQRWXWTVEWQVY 
    \item BXWZTVWQTVCWRCQTVXTTQVRQXTRCVCVRTCVVTX
    \item AUXZWTCVWVWUTVRTVCUZTEVWTVCUTVTVERVCTV
  \end{itemize}
\end{frame}
\end{document}

How it works? Now there's no need of overlay specifications, since the command \explainword is realized in such a way that it actually is an ocgx button able to make visible the callout when one clicks on the word. It needs two arguments: the first one is the identifier (for the \tikzmark macro and for the ocgx button) and the second one the text/word to be explained.

When both words in the example are clicked the result is:

enter image description here

Note

This requires always two compilation runs and, for me, the solution works only with Adobe Reader.

BTW: I've organized a little better the style of the callout and now it could be customized more easily (see as reference the second work explained).