2

I am trying to externalize pgfplots, gnuplot and contour gnuplot in beamer. Towards this end I am using the visible on=<> facility of \usetikzlibrary{overlay-beamer-styles} (cf. this answer by user Daniel) as well as the automatic numbering solution from user Loop Space.

I created a MWE consisting of 3 frames each hosting 3 slides that contain (A) vanilla pgfplots (B) gnuplots (C) contour gnuplots.

Expected Behaviour: When externalizing, say the images of the second frame, images on other frames should be ignored.

Actual Behaviour: The contour plots get computed in every single overlay. In total 81 sets of contour plots get computed. If one deletes the first 2 frames (which do not contain contour plots), then still 27 sets of contours get computed.

How to fix this bug?

\documentclass{beamer}
\usepackage{tikz, pgfplots}
\pgfplotsset{compat=1.16}
\usepgfplotslibrary{external}
\usetikzlibrary{overlay-beamer-styles}

% automatic beamer numbering
%\url{https://tex.stackexchange.com/q/119428/86}
\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[only named=true]


\begin{document}
\begin{frame}{pgfplots}
\tikzsetnextfilename{pgfplots}
\begin{tikzpicture}
\begin{axis}
\addplot[visible on=<1-3>] {x};
\addplot[visible on=<2-3>] {exp(x)};
\addplot[visible on=<3-3>] {x*x};
\end{axis}
\end{tikzpicture}
\end{frame}

\begin{frame}{gnuplot}
\tikzsetnextfilename{gnuplot}
\begin{tikzpicture}
\begin{axis}
\addplot[visible on=<1-3>] gnuplot{x};
\addplot[visible on=<2-3>] gnuplot{exp(x)};
\addplot[visible on=<3-3>] gnuplot{x*x};
\end{axis}
\end{tikzpicture}
\end{frame}

\begin{frame}{gnuplot contour}
\tikzsetnextfilename{contour}
\begin{tikzpicture}
\begin{axis}[view={0}{90}, domain=-2:2]
  \addplot3[visible on=<1-3>,contour gnuplot={draw color=red,number=20, labels=false}] {x};
  \addplot3[visible on=<2-3>,contour gnuplot={draw color=blue,number=20, labels=false}] {y};
  \addplot3[visible on=<3-3>,contour gnuplot={draw color=black,number=20, labels=false}] {x^2+y^2};
\end{axis}
\end{tikzpicture}
\end{frame}
\end{document}
  • getting 9 contour on build – js bibra Jan 05 '20 at 15:05
  • @jsbibra I am compiling with pdflatex --shell-escape (version 3.14159265-2.6-1.40.20). After successful compilation there are a total of 312 files, 81 of the form contourmpX.table. i.e. gnuplot gets called internally 81 times instead of 9 times, which is a huge wast of resources – Hyperplane Jan 05 '20 at 15:18
  • @jsbibra The problem is not that the .pdf does not compile to what I want it to, but that gnuplot contour get called and computes the whole contour plot for every frame, even the ones the plot isn't even on. This makes compilation unfeasible for large documents (the actual contour plot I want to externalize is 9 slides and alone takes 2 mins to compile) – Hyperplane Jan 05 '20 at 15:21
  • the 9 contours are below are they as expected enter image description here enter image description here enter image description here enter image description here enter image description here [![enter image – js bibra Jan 05 '20 at 15:16

1 Answers1

2

The easiest way to get rid of some of those extra contour plots is to use \only instead of the visible on=<> key. This way the plots are only made on the indicated slides (with visible on=<>, they are generated on all slides but are displayed only on selected slides).

\begin{axis}[view={0}{90}, domain=-2:2]
  \addplot3[visible on=<1-3>,contour gnuplot={draw color=red,number=20, labels=false}] {x};
  \only<2-3>{\addplot3[contour gnuplot={draw color=blue,number=20, labels=false}] {y};}
  \only<3>{\addplot3[contour gnuplot={draw color=black,number=20, labels=false}] {x^2+y^2};}
\end{axis}

Getting rid of the contour plots generated while externalizing the frames the plots on other frames is trickier, but doable. I have added a solution for this problem to a different question (see here).

Below is a complete MWE that combines both solutions, produces only 10 contourmpX.table files and compiles much faster.

\documentclass{beamer}
\usepackage{tikz, pgfplots}
\pgfplotsset{compat=1.16}
\usepgfplotslibrary{external}
\usetikzlibrary{overlay-beamer-styles}

% automatic beamer numbering %\url{https://tex.stackexchange.com/q/119428/86} \makeatletter \newcommand*{\overlaynumber}{\number\beamer@slideinframe} \tikzset{ beamer externalizing/.style={% execute at end picture={% \tikzifexternalizing{% \ifbeamer@anotherslide \pgfexternalstorecommand{\string\global\string\beamer@anotherslidetrue}% \fi }{}% }% }, every picture/.style={beamer externalizing} }

% remove the `-\overlaynumber` suffix from the jobname
% the name is stored in `\job@no@suffix` and the number in `\job@suffix@number`
\def\strip@suffix#1{%
    \begingroup%
    \edef\@tempa{#1-}%
    \expandafter\endgroup%
    \expandafter\@strip@suffix\@tempa\relax%
}
\def\@strip@suffix#1-#2\relax{%
    \ifx\relax#2\relax%
        \edef\job@suffix@number{#1}%
        \def\next{\relax}%
    \else%
        \expandafter\ifx\expandafter\relax\job@no@suffix\relax%
            \def\job@no@suffix{#1}%
        \else%
            \edef\job@no@suffix{\job@no@suffix-#1}%
        \fi%
        \def\next{\@strip@suffix#2\relax}%
    \fi%
    \next%
}
% check if the next tikzpicture is the to-be-externalized one
% or has the same basename and precedes it
\def\if@is@current@pic#1{%
    \begingroup%
    \def\job@no@suffix{}%
    \strip@suffix\pgfactualjobname%
    \ifnum\job@suffix@number&lt;\overlaynumber\relax%
        \def\job@no@suffix{}%
    \fi%
    \edef\current@pic@basename{#1}%
    \edef\current@pic@basename{%
        \expandafter\detokenize\expandafter{\current@pic@basename}%
    }%
    \ifx\job@no@suffix\current@pic@basename%
        \expandafter\endgroup\expandafter\@firstoftwo%
    \else%
        \expandafter\endgroup\expandafter\@secondoftwo%
    \fi%
}

% add a `-\overlaynumber` suffix to the next tikzpicture name
% and disable tikz external optimization where needed
\let\orig@tikzsetnextfilename=\tikzsetnextfilename
\renewcommand\tikzsetnextfilename[1]{%
    \orig@tikzsetnextfilename{#1-\overlaynumber}%
    \tikzifexternalizing{
        \if@is@current@pic{\tikzexternal@filenameprefix#1}{%
            \tikzset{external/optimize=false}%
        }{%
            \tikzset{external/optimize=true}%
        }%
    }{}%
}

\makeatother

\tikzexternalize[only named=true]

\begin{document} \begin{frame}{pgfplots} \tikzsetnextfilename{pgfplots} \begin{tikzpicture} \begin{axis} \addplot[visible on=<1-3>] {x}; \addplot[visible on=<2-3>] {exp(x)}; \addplot[visible on=<3-3>] {x*x}; \end{axis} \end{tikzpicture} \end{frame}

\begin{frame}{gnuplot} \tikzsetnextfilename{gnuplot} \begin{tikzpicture} \begin{axis} \addplot[visible on=<1-3>] gnuplot{x}; \addplot[visible on=<2-3>] gnuplot{exp(x)}; \addplot[visible on=<3-3>] gnuplot{x*x}; \end{axis} \end{tikzpicture} \end{frame}

\begin{frame}{gnuplot contour} \tikzsetnextfilename{contour} \begin{tikzpicture} \begin{axis}[view={0}{90}, domain=-2:2] \addplot3[visible on=<1-3>,contour gnuplot={draw color=red,number=20, labels=false}] {x}; \only<2-3>{\addplot3[contour gnuplot={draw color=blue,number=20, labels=false}] {y};} \only<3>{\addplot3[contour gnuplot={draw color=black,number=20, labels=false}] {x^2+y^2};} \end{axis} \end{tikzpicture} \end{frame} \end{document}