# Automagically scale Tikz-Picture AND use Externalization

I need to scale Tikz pictures automatically, and I do this using the following custom environment:

% Automagically scale a Tikz picture, so it has the desired (given) width.
% Does NOT scale line width/text width! Needs the package "environ"!
%
% Usage:
%
% \begin{myscaletikzwidth}{\textwidth}
%   \begin{tikzpicture}[scale=\tikzscale]
%     ..
%   \end{tikzpicture}
% \end{myscaletikzwidth}
%
\makeatletter
\newsavebox{\measure@tikzpicture}
\NewEnviron{myscaletikzwidth}[1]{%
\def\tikz@width{#1}%
\def\tikzscale{1}\begin{lrbox}{\measure@tikzpicture}%
\BODY
\end{lrbox}%
\pgfmathparse{#1/\wd\measure@tikzpicture}%
\edef\tikzscale{\pgfmathresult}%
\BODY
}
\makeatother


(I got that code from another topic on Stackexchange.)

This code works perfectly fine, however it doesn't work anymore, when I turn on externalization (graphics will then be created in their original size).

How can I make auto-scaling work in conjunction with externalization?

I am using the modern externalization approach that has been introduced with newer Tikz versions ("\tikzexternalize").

Maybe some hack with writing "\def\tikzscale{MyDeterminedScaleFactor}" to an external file and inputting that file afterwards?

-

The problem is that the external library will automatically assign names for each encountered tikzpicture - but in your case, you effectively have one name and two pictures.

One could think about a solution which assigns individual file names for each of the two involved pictures - but that is a waste of time because you are never interested in the first one.

So, I propose the following solution: we check if we are currently generating an external picture. If so, we will always typeset the first (which is necessary to determine the picture's size) and we will externalize the second one. If we are currently NOT exporting the (current) picture, we can safely assume that there is an external picture ready at hand - and use it.

Here is the modification. It requires that \usetikzlibrary{external} has been loaded (although it does not necessarily need to be active).

% Automagically scale a Tikz picture, so it has the desired (given) width.
% Does NOT scale line width/text width! Needs the package "environ"!
%
% Usage:
%
% \begin{myscaletikzwidth}{\textwidth}
%   \begin{tikzpicture}[scale=\tikzscale]
%     ..
%   \end{tikzpicture}
% \end{myscaletikzwidth}
%
\makeatletter
\newsavebox{\measure@tikzpicture}
\NewEnviron{myscaletikzwidth}[1]{%
\tikzifexternalizingnext{%
\def\tikz@width{#1}%
\def\tikzscale{1}\begin{lrbox}{\measure@tikzpicture}%
\tikzset{external/export next=false,external/optimize=false}% force translation of this BODY (and do not optimize it away as it would usually do):
\BODY
\end{lrbox}%
\pgfmathparse{#1/\wd\measure@tikzpicture}%
\edef\tikzscale{\pgfmathresult}%
\BODY
}{% this will re-use an existing external graphics:
\BODY
}%
}
\makeatother


EDIT: You are right, there are problems with the todonotes package. It is (unfortunately) incompatible with the tikz external image. Apparently,

\usepackage{todonotes}
\makeatletter
\renewcommand{\todo}[2][]{%
\tikzexternaldisable\@todo[#1]{#2}\tikzexternalenable%
}
\makeatother


helps here.

-
Thanks for your quick help! Your code works fine when everything is kept in a single file. However, my setup was slightly more complicated: - Code split across many files - I used "todonotes" (which uses Tikz), and I did not want that graphics to be externalized - I used "\tikzsetnextfilename{...}" on my images - Tikz pictures are stored in seperate files (each starting with "\begin{tikzpicture}...") Doesn't sound too difficult, but there were a few hours of that typical LaTeX-pain-in-the-ass-fun, until everything worked. Thanks for your answer, it helped me a lot on that way! – kopierkatze Sep 21 '11 at 23:42
I edited my answer to show some work-around for todonotes (which is, indeed, incompatible with image externalization). – Christian Feuersänger Sep 23 '11 at 19:28
@kopierkatze, a similar approach is uses in the tikzscale package (also proposed by Christian), which simplifies your code from a user perspective. – Patrick Häcker Oct 31 '12 at 14:40