[Tex/LaTex] Beamer overlays, tikz external and custom file name

beameroverlaystikz-externaltikz-pgf

This is a follow-up question from Use tikz external feature with beamer \only . Andrew's answer there is excellent, and does the job (almost) perfectly.

The rough edge I have found was when I tried to use \tikzsetnextfilename together with it.

Why would I want to do that? Because in beamer, one might need to reorder one's slides, or to add an overlay, etc. In this case, most pictures will need to be regenerated, even if they weren't changed.

What is the problem? The following M(n)WE shows the usual way of using \tikzsetnextfilename.

\documentclass{beamer}

\usepackage{tikz}

\usetikzlibrary{external}

\makeatletter
\tikzset{
  beamer externalizing/.style={%
    execute at end picture={%
      \tikzifexternalizing{%
        \ifbeamer@anotherslide
        \pgfexternalstorecommand{\string\global\string\beamer@anotherslidetrue}%
        \fi
      }{}%
    }%
  },
  external/optimize=false
}
\makeatother

\tikzset{every picture/.style={beamer externalizing}}

\tikzexternalize

\begin{document}

\begin{frame}
  \tikzsetnextfilename{figure}
  \only<1>{Image 1:}
  \only<2>{Image 2:}
  \begin{tikzpicture}
    \only<1>{\node {Overlay 1};}
    \only<2>{\node {Overlay 2};}
  \end{tikzpicture}
\end{frame}

\end{document}

This doesn't work. I'm not pro enough with latex, beamer and tikz mechanics, but I suspect that the problem is tikz externalize trying to generate the two pictures with the same file name.

And indeed, the following code snippet does work.

\documentclass{beamer}

\usepackage{tikz}

\usetikzlibrary{external}

\makeatletter
\tikzset{
  beamer externalizing/.style={%
    execute at end picture={%
      \tikzifexternalizing{%
        \ifbeamer@anotherslide
        \pgfexternalstorecommand{\string\global\string\beamer@anotherslidetrue}%
        \fi
      }{}%
    }%
  },
  external/optimize=false
}
\makeatother

\tikzset{every picture/.style={beamer externalizing}}

\tikzexternalize

\begin{document}

\begin{frame}
  \only<1>{\tikzsetnextfilename{figure-1}}
  \only<2>{\tikzsetnextfilename{figure-2}}
  \only<1>{Image 1:}
  \only<2>{Image 2:}
  \begin{tikzpicture}
    \only<1>{\node {Overlay 1};}
    \only<2>{\node {Overlay 2};}
  \end{tikzpicture}
\end{frame}

\end{document}

Now it is still far from perfect. For example, it requires to know precisely how many overlays are needed for every picture.

Hence the question : is there a better, more natural way of achieving this?
If not, is there a way to make this method transparent to the user (so that he doesn't need to count the overlays himself)?

Best Answer

You can automatically add the overlay number to the file name using the code from Accessing the current overlay number in beamer. If you only want to do this for some pictures, then use like:

  \tikzsetnextfilename{figure-\overlaynumber}

To add it to every picture you could make it part of the prefix:

\tikzexternalize[prefix=picture-\overlaynumber-]

Using the suffix notation, (\tikzset{external/figure name/.add={}{-\overlaynumber}}) doesn't seem to work as the figure name is overriden by the \tikzsetnextfilename. If you want to automatically add a suffix you'd have to hack \tikzsetnextfilename:

\let\orig@tikzsetnextfilename=\tikzsetnextfilename
\renewcommand\tikzsetnextfilename[1]{\orig@tikzsetnextfilename{#1-\overlaynumber}}

(inside the \makeatletter ... \makeatother bit).

Although the most hackish, this one ends up with the nicest file names so it's the one I've gone for.

\documentclass{beamer}
%\url{https://tex.stackexchange.com/q/119428/86}
\usepackage{tikz}

\usetikzlibrary{external}

\makeatletter
\newcommand*{\overlaynumber}{\number\beamer@slideinframe}
\tikzset{
  beamer externalizing/.style={%
    execute at end picture={%
      \tikzifexternalizing{%
        \ifbeamer@anotherslide
        \pgfexternalstorecommand{\string\global\string\beamer@anotherslidetrue}%
        \fi
      }{}%
    }%
  },
  external/optimize=false
}
\let\orig@tikzsetnextfilename=\tikzsetnextfilename
\renewcommand\tikzsetnextfilename[1]{\orig@tikzsetnextfilename{#1-\overlaynumber}}
\makeatother

\tikzset{every picture/.style={beamer externalizing}}

\tikzexternalize

\begin{document}

\begin{frame}
  \tikzsetnextfilename{figure}
  \only<1>{Image 1:}
  \only<2>{Image 2:}
  \begin{tikzpicture}
    \only<1>{\node {Overlay 1};}
    \only<2>{\node {Overlay 2};}
  \end{tikzpicture}
\end{frame}

\end{document}