1

I have just discovered externalize and want to use it in my document that contains lots of trees with shaded arrows. The arrows are shaded with some "hack" that I found on this site (unfortunately I can't seem to find the source at the moment). It works perfectly fine---albeit slow---when used in my document, but fails when externalised.

I get this error

! Extra }, or forgotten \endgroup.
\pgf@externalend ->\unskip \egroup \egroup 
                                           {\def \pgf@external@trim {0}\def ...
l.88   \end{forest}

Unfortunately I am no Tex-Expert and can't seem to figure out what's going wrong. Here is a MWE:

\documentclass[a4paper,12pt, twoside,dvipsnames]{article}

\usepackage[dvipsnames]{xcolor}

\usepackage{tikz}
\usetikzlibrary{external}
\tikzexternalize[mode=list and make, prefix=ext-tikz/]
\usepackage[external]{forest}

\usetikzlibrary{fadings, arrows.meta}


\makeatletter
\newif\iftikz@shading@path

\tikzset{
    % There are three circumstances in which the fading sep is needed:
    % 1. Arrows which do not update the bounding box (which is most of them).
    % 2. Line caps/joins and mitres that extend outside the natural bounding 
    %    box of the path (these are not calculated by PGF).
    % 3. Other reasons that haven't been anticipated.
    fading xsep/.store in=\pgfpathfadingxsep,
    fading ysep/.store in=\pgfpathfadingysep,
    fading sep/.style={fading xsep=#1, fading ysep=#1},
    fading sep=0.0cm,
    shading path/.code={%
        % Prevent this stuff happning recursively.
        \iftikz@shading@path%
        \else%
            \tikz@shading@pathtrue%
            % \tikz@addmode installs the `modes' (e.g., fill, draw, shade) 
            % to be applied to the path. It isn't usualy for doing more
            % changes to the path's construction.
            \tikz@addmode{%
                \pgfgetpath\pgf@currentfadingpath%
                % Get the boudning box of the current path size including the fading sep
                \pgfextract@process\pgf@fadingpath@southwest{\pgfpointadd{\pgfqpoint{\pgf@pathminx}{\pgf@pathminy}}%
                    {\pgfpoint{-\pgfpathfadingxsep}{-\pgfpathfadingysep}}}%%
                \pgfextract@process\pgf@fadingpath@northeast{\pgfpointadd{\pgfqpoint{\pgf@pathmaxx}{\pgf@pathmaxy}}%
                    {\pgfpoint{\pgfpathfadingxsep}{\pgfpathfadingysep}}}%
                % Clear the path
                \pgfsetpath\pgfutil@empty%                          
                % Interrupt the path and picture to create a fading.
                \pgfinterruptpath%
                \pgfinterruptpicture%
                    \begin{tikzfadingfrompicture}[name=.]
                        \path [shade=none,fill=none, #1] \pgfextra{%
                            % Set the softpath. Any transformations in #1 will have no effect.
                            % This will *not* update the bounding box...
                            \pgfsetpath\pgf@currentfadingpath%
                            % ...so it is done manually.
                            \pgf@fadingpath@southwest
                            \expandafter\pgf@protocolsizes{\the\pgf@x}{\the\pgf@y}%
                            \pgf@fadingpath@northeast%
                            \expandafter\pgf@protocolsizes{\the\pgf@x}{\the\pgf@y}%
                        };
                        % Now get the bounding of the picture.
                        \xdef\pgf@fadingboundingbox@southwest{\noexpand\pgfqpoint{\the\pgf@picminx}{\the\pgf@picminy}}%
                        \xdef\pgf@fadingboundingbox@northeast{\noexpand\pgfqpoint{\the\pgf@picmaxx}{\the\pgf@picmaxy}}%
                        %
                    \end{tikzfadingfrompicture}%
                \endpgfinterruptpicture%
                \endpgfinterruptpath%
                % Install a rectangle that covers the shaded/faded path picture.                                
                \pgfpathrectanglecorners{\pgf@fadingboundingbox@southwest}{\pgf@fadingboundingbox@northeast}%
                % Make the fading happen.
                \def\tikz@path@fading{.}%
                \tikz@mode@fade@pathtrue%
                \tikz@fade@adjustfalse%10pt
                % Shift the fading to the mid point of the rectangle
                \pgfpointscale{0.5}{\pgfpointadd{\pgf@fadingboundingbox@southwest}{\pgf@fadingboundingbox@northeast}}%
                \edef\tikz@fade@transform{shift={(\the\pgf@x,\the\pgf@y)}}%
            }%
        \fi%
    }
}

\begin{document}

\begingroup
    \centering
    \begin{forest}
        [, phantom, for children={fit=band}, s sep'+=60pt
            [ 2, name=l1 ]
            [ 2, name=r1 ]
        ]
        \path [left color=orange, right color=MidnightBlue, shading path={draw=transparent!0, dashed, -Latex}] (l1) .. controls ++(0,-1) and ++(0,-1) .. (r1);
    \end{forest}
\endgroup

\end{document}

I tried to reduce the example as much as possible, but it still remains a lot of code. The tikzset part is copied from this site, and I honestly have no idea what it does - it works though, unless forest is externalised.

Edit: The issue seems to be limited to forest, this tikzpicture can be externalised without problems:

\begin{tikzpicture}
    \path [left color=orange, right color=MidnightBlue, shading path={draw=transparent!0, dashed, -Latex}] (0,1) .. controls ++(0,-1) and ++(0,-1) .. (1,1);
\end{tikzpicture}
fsperrle
  • 185
  • 8
  • Forest and externalisation do not always mix well, even under more auspicious conditions. I really don't think it is surprising this would fail. I'm not sure how the fading from picture stuff is implemented, but I'd worry it may be optimised away. I'd suggest disabling externalisation for trees which use this feature. – cfr Feb 21 '18 at 03:09
  • Although that's probably not why if you can use the arrow in tikzpicture environments, I guess. Does it work with externalisation there? Or is it a Forest-specific issue? – cfr Feb 21 '18 at 03:12
  • @cfr It seems to be limited to forest. A single shaded arrow in a tikzpicture could be externalised without problems. I added an example to the question. – fsperrle Feb 21 '18 at 09:43
  • If you really need it and can't just disable externalisation for affected trees, I'd suggest emailing Forest's author. If you could find the source of the hack, you could also ask that person. – cfr Feb 22 '18 at 00:53
  • https://tex.stackexchange.com/a/137438/ is likely your source? – cfr Feb 22 '18 at 01:22
  • By the way, I find it best to comment code with the source, where applicable. That way, I can find the original source again later and also know who to attribute it to, if required. This is especially useful if I later think the code is involved in some problem I'm now experiencing and I can easily check if the original has been updated or what provided with relevant caveats etc. – cfr Feb 22 '18 at 19:39
  • I replaced all the shaded arrows with "normal" ones for now during the writing process where I have to compile frequently, and will switch back later for the final version that I will submit. And yes, the response you linked is the source. I typically mark them as well, but apparently I was in a hurry that day and did not do so. – fsperrle Feb 23 '18 at 12:23
  • Oh, yes. That happens to me to and drives me bananas. I just suggested it because I think a lot of people don't do it at all and I very quickly learnt that I needed to! I do recommend emailing Forest's author, by the way. He may say, 'no way could this work' but he may say 'just do this'. If you do, please link this question so we can all learn the answer. – cfr Feb 23 '18 at 23:28

0 Answers0