3

In order to build complex tizkpictures, I use saveboxes to "import" sub-parts of my figure.
It works great, except when I want to externalize the computation of my figures. In this case, compilation succeed, but I get the following error in my figures (there should be an imported drawing within the orange-filled-with-red-border node): enter image description here

Question: How to enable the externalization of tikzpictures with the use of saveboxes?


MWE (works great until you uncomment \tikzexternalize)

\documentclass{article}
    \usepackage{tikz}
    \usetikzlibrary{external}
%       \tikzexternalize
\begin{document}
    %savebox definition
    \newsavebox{\myBox}
    \begin{lrbox}{\myBox}
        \begin{tikzpicture}
            \draw (0,0) -- (1,1);
        \end{tikzpicture}
    \end{lrbox}
    %drawing the picture
    \begin{tikzpicture}
        \node[draw = red, fill = orange] {\usebox{\myBox}};
    \end{tikzpicture}
\end{document}

Note: tikzexternalize and savebox error seems a pretty similar question, but suggested solution ("put[ing] the definition of [the savebox] after \begin{document}") obviously does not work in the MWE above. (Same solution accepted in pgfmathdeclarefunction with savebox and tikzexternalize: tikzpicture optimized away).

Edit: It doesn't work neither when the savebox is defined within the main tikzpicture environment.

  • If putting them after \begin{document} does not help, did you try to put them after \begin{tikzpicture}? – Symbol 1 Apr 10 '17 at 20:36
  • @Symbol1 It works only if there is no tikzpicture environment in the savebox (i.e. \tikz commands only). I've updated the MWE accordingly. – ebosi Apr 10 '17 at 20:46
  • it can probably be made to work but why bother? If you are externalizing the images then they are just re-imported as a single chunk of pdf anyway so nothing saved by boxing them. – David Carlisle Apr 10 '17 at 20:49
  • Good point. But what is the difficulty for you to use \begin{tikzpicture} instead of \tikz{}? As long as I can tell they are the same. (except you have verbatim/listings things inside, of course.) – Symbol 1 Apr 10 '17 at 20:50
  • @DavidCarlisle I am actually importing several "chunks" in a main figure, and then add some elements using nodes defined in some of these saveboxes. I thus cannot simply include pdf images instead. – ebosi Apr 10 '17 at 20:52
3

Edit

In light of the fact that the OP needs to access coordinates within the nested pictures, I recommend using Symbol 1's \scopenode solution. However, as it stands, any fill in the enclosing node will obliterate the content.

However, you can modify the macro to put the contents of the enclosing node behind the material it encloses. For example,

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{external,backgrounds}
\tikzexternalize
\tikzset{external/prefix=ffigurau/}
\makeatletter
\pgfdeclarelayer{scopenode}
\pgfsetlayers{background,scopenode,main}
\tikzset{%
  % adapted from tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibrarybackgrounds.code.tex
  on scopenode layer/.style={%
    execute at begin scope={%
      \pgfonlayer{scopenode}%
      \let\tikz@options=\pgfutil@empty%
      \tikzset{every on scopenode layer/.try,#1}%
      \tikz@options%
    },
    execute at end scope={\endpgfonlayer}
  },
}
% ateb Symbol 1: https://tex.stackexchange.com/a/362360/
\newbox\tikz@sand@box
\newcount\tikz@scope@depth
\tikz@scope@depth111\relax
\def\scopenode[#1]#2{% name=<enw>, at=<man>, anchor=<angor>
  \begin{pgfinterruptboundingbox}%
    \advance\tikz@scope@depth111\relax%
    % process the user option
    \begin{scope}[name=tempscopenodename,at={(0,0)},anchor=center,#1]%
      % try to extract positioning information: name, at, anchor
      \global\let\tikz@fig@name\tikz@fig@name%
      \global\let\tikz@node@at\tikz@node@at%
      \global\let\tikz@anchor\tikz@anchor%
    \end{scope}%
    \let\tikz@scopenode@name\tikz@fig@name%
    \let\tikz@scopenode@at\tikz@node@at%
    \let\tikz@scopenode@anchor\tikz@anchor%
    % try to typeset this scope
    % we only need bounding box information
    % the box itself will be discard
    \setbox\tikz@sand@box=\hbox{%
      \begin{scope}[local bounding box=tikz@sand@box\the\tikz@scope@depth,#1]%
        #2%
      \end{scope}%
    }%
    % goodbye. haha
    \setbox\tikz@sand@box=\hbox{}%
    % now typeset again
    \begin{scope}[local bounding box=\tikz@scopenode@name]%
      % use the bounding box information to reposition the scope
      \pgftransformshift{\pgfpointanchor{tikz@sand@box\the\tikz@scope@depth}{\tikz@scopenode@anchor}%
        \pgf@x-\pgf@x\pgf@y-\pgf@y}%
      \pgftransformshift{\tikz@scopenode@at}%
      \begin{scope}[#1]%
        #2
      \end{scope}%
    \end{scope}%
    \pgfkeys{/pgf/freeze local bounding box=\tikz@scopenode@name}%
    \global\let\tikz@scopenode@name@smuggle\tikz@scopenode@name%
  \end{pgfinterruptboundingbox}%
  % make up the bounding box
  \path(\tikz@scopenode@name@smuggle.south west)(\tikz@scopenode@name@smuggle.north east);%
  % draw something, not necessary
  \begin{scope}[on scopenode layer]%
    \draw[#1](\tikz@scopenode@name@smuggle.south west)rectangle(\tikz@scopenode@name@smuggle.north east);%
  \end{scope}%
}
\makeatother
\begin{document}
\begin{tikzpicture}
  \filldraw [blue] circle (5pt);
  \scopenode[draw=red, fill=orange, name=bob, at={(2,2)}, anchor=south west]{%
    \draw (0,0) coordinate (a) -- (1,1) coordinate (b);
  }
  \scopenode[draw=blue, fill=yellow, name=gog, at={(-2,-2)}, anchor=north east]{%
    \draw [magenta] (1,1) coordinate (c) -- (0,0) coordinate (d);
  }
  \draw [->] (a) [bend right] to (c);
  \draw [->] (d) [bend right] to (b);
\end{tikzpicture}
\end{document}

<code>\scopenode</code> with layering

Original Answer & Explanation

When compiling externalised images, TikZ ignores all other pictures in the document (and 'expensive' commands, as well). This is designed to speed compilation by 'optimising away' irrelevant, but resource-hungry typesetting tasks.

You can always switch it off if you really need to do things this way.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{external}
\tikzexternalize
\tikzset{%
  external/prefix=ffigurau/,
  external/optimize=false,
}
\begin{document}
%savebox definition
\newsavebox{\myBox}
\begin{lrbox}{\myBox}
  \begin{tikzpicture}
    \draw (0,0) -- (1,1);
  \end{tikzpicture}
\end{lrbox}
%drawing the picture
\begin{tikzpicture}
  \node[draw = red, fill = orange] {\usebox{\myBox}};
\end{tikzpicture}
\end{document}

However, if you have many pictures (and why else would you want to use externalisation?) this will greatly slow compilation whenever a picture needs to be compiled. For each new or changed picture, all pictures will be compiled and all 'expensive' commands executed.

I don't see why you can't do the following instead. This code uses the save box, but only to prevent the picture being typeset in the main document. Otherwise, the save box is simply ignored.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{external}
\tikzexternalize
\tikzset{%
  external/prefix=ffigurau/,
}
\begin{document}
%savebox definition
\newsavebox{\myBox}
\tikzsetnextfilename{mybox}
\begin{lrbox}{\myBox}
  \begin{tikzpicture}
    \draw (0,0) -- (1,1);
  \end{tikzpicture}
\end{lrbox}
%drawing the picture
\begin{tikzpicture}
  \node[draw = red, fill = orange] {\includegraphics{ffigurau/mybox}};
\end{tikzpicture}
\end{document}

It makes no sense to say you can't include the image here as that is literally what you are doing when you externalise it anyway. (The save box effectively just does \includegraphics{...} and then you \usebox{...}, so you might just as well \includegraphics{...} directly.

| improve this answer | |
  • You basically detail two solutions: (1) disabling externalization (either globally, or on a ad-hoc basis as you explained here (my bad, I found this question only later)). It works great, but in that case you lose benefits of externalization. Or (2) including saveboxes as pdf images. In this case however, one cannot later use (in the main tikzpicture) coordinates defined in the savebox (yet I want to access them - it was however not made explicit in my question). So I have solution for each case, even if not optimal (extern+reusing coord). – ebosi Apr 11 '17 at 13:47
  • @ebo Neither solution disables externalisation either locally or globally. The first solution disables optimisation of externalisation, but it does not disable externalisation. – cfr Apr 11 '17 at 15:11
  • @ebo If you need access to the coordinates, why aren't you using the \scopenode solution? – cfr Apr 11 '17 at 15:12
  • @ebo It is one of the answers to your earlier question. It was written to address the particular issue you raised. I didn't try it, but it looked to be by far the most sophisticated answer there and its author is certainly an expert on PGF/TikZ. – cfr Apr 11 '17 at 15:18
  • Let us continue this discussion in chat. – ebosi Apr 11 '17 at 15:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.