# combining forest externalization with beamer overlays

The answer here for revealing a forest tree in beamer bottom-up works beautifully. But it appears to be incompatible with externalization. The following example successfully compiles (with --shell-escape switched on), but the resulting pdf is just one slide: the slides with the revealed nodes are missing (the crucial changes are the second and third lines, i.e., \usepackage[external]{forest} and tikzexternalize).

\documentclass{beamer}
\usepackage[external]{forest}
\tikzexternalize

\tikzset{% set up for transitions using tikz with beamer overlays
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
},
}
\forestset{%
declare toks={no node before}{1},
declare toks={no edge before}{1},
not before/.style={
no node before=#1,
for children={
no edge before=#1,
}
},
bottom up/.style={% based on Qrrbrbirlbel's answer at https://tex.stackexchange.com/a/112895/
/tikz/visible on=<\forestoption{no node before}->,
/tikz/every label/.append style={visible on=<\forestoption{no node before}->},
/tikz/every edge label/.append style={visible on=<\forestoption{no edge before}->},
edge={/tikz/visible on=<\forestoption{no edge before}->},
}
}

\begin{document}
\begin{frame}
\centering
\begin{forest}
/tikz/every label/.append style={text height=1ex, label distance=5pt},
for tree={
circle,
draw,
very thick,
edge={very thick},
s sep+=10pt,
fill=white!25,
minimum size=20pt,
bottom up,
}
[, label=above:{car, bus, cat, dot}, not before=3
[, label=above left:{car, bus}, not before=2
[, label=below:car]
[, label=below:bus]
]
[, label=above right:{cat, dog}, not before=2
[, label=below:cat]
[, label=below:dog]
]
]
\end{forest}
\end{frame}
\end{document}


Is there any way to have your cake and eat it too? Or are beamer overlays and forest/tikz externalization incompatible in a deep way that makes this impossible?

Editing to add: interestingly, the externalized pdf produced by the above has three pages with the relevant overlay transitions. But those transitions are not reflected in the main document.

• related question: tex.stackexchange.com/questions/183023/… – user36296 Sep 26 '17 at 18:14
• @cfr I included a link to your answer in the post, and a description of what I changed in your code. Can you clarify what I can fix in my post? – Simon C Sep 26 '17 at 22:53
• @SimonC Sorry, I missed that and I found my local copy didn't have a note of the link. I'll delete my comment. – cfr Sep 26 '17 at 22:55
• @SimonC Are you interested in a workaround? Are you using pdfTeX? – cfr Sep 26 '17 at 23:21
• Sure. Yes, I'm using pdfTeX. – Simon C Sep 26 '17 at 23:23

This is a workaround. It is driver-dependent - as written, it requires pdfTeX.

Note that, as written, this will almost certainly mess up externalised TikZ pictures which are not Forest trees. So the effect may need to be limited to local use, if that's a concern.

\documentclass{beamer}
\usepackage[external]{forest}
\tikzsetexternalprefix{ffigurau/}
\tikzset{%
/pgf/images/include external/.code={%
\pdfximage{#1.pdf}%
\foreach \i in {1,...,\the\pdflastximagepages}%
{\includegraphics<\i>[page=\i]{#1}}%
},
}
\tikzexternalize

\tikzset{% set up for transitions using tikz with beamer overlays
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
},
}
\forestset{%
declare toks={no node before}{1},
declare toks={no edge before}{1},
not before/.style={
no node before=#1,
for children={
no edge before=#1,
}
},
bottom up/.style={% based on Qrrbrbirlbel's answer at https://tex.stackexchange.com/a/112895/
/tikz/visible on=<\forestoption{no node before}->,
/tikz/every label/.append style={visible on=<\forestoption{no node before}->},
/tikz/every edge label/.append style={visible on=<\forestoption{no edge before}->},
edge={/tikz/visible on=<\forestoption{no edge before}->},
}
}

\begin{document}
\begin{frame}
\centering
\begin{forest}
/tikz/every label/.append style={text height=1ex, label distance=5pt},
for tree={
circle,
draw,
very thick,
edge={very thick},
s sep+=10pt,
fill=white!25,
minimum size=20pt,
bottom up,
}
[, label=above:{car, bus, cat, dot}, not before=3
[, label=above left:{car, bus}, not before=2
[, label=below:car]
[, label=below:bus]
]
[, label=above right:{cat, dog}, not before=2
[, label=below:cat]
[, label=below:dog]
]
]
\end{forest}
\end{frame}
\end{document}


## Notes

The code redefines the command used to include the externalised image.

\tikzset{%
/pgf/images/include external/.code={%
\pdfximage{#1.pdf}%
\foreach \i in {1,...,\the\pdflastximagepages}%
{\includegraphics<\i>[page=\i]{#1}}%
},
}


This is not engine/driver-neutral because \pdfximage is not always defined. pdfTeX defines it, but other engines will not. (I can't check right now what does. Obviously TeX won't and XeTeX almost certainly not, while LuaTeX probably doesn't any more, even if it used to.)

\pdfximage{#1.pdf} sets the externalised file. \the\pdflastximagepages gives the total number of pages in the PDF. The loop then iterates over the pages, including each one on a distinct slide. For this, it uses the Beamer-modified syntax for \includegraphics, which supports an overlay specification.

So the externalisation itself doesn't get fixed: you don't get one externalised tree per slide. But the resulting frame ends up more-or-less correct because we include the PDF one page at a time using \includegraphics's page key.

• This does work for me! Would you be able to add some brief comments indicating what's different from the code in the original post, and why it works? – Simon C Sep 26 '17 at 23:30
• @SimonC Does this help? – cfr Sep 28 '17 at 1:15