The difficulty is that the externalisation library looks for \end{tikzpicture}
to determine the end of the picture that it is "externalising". It does this without expansion so the \end{tikzpicture}
has to appear at the same time as the \begin{tikzpicture}
. That's why:
\newenvironment{mytikz}{\begin{tikzpicture}}{\end{tikzpicture}}
doesn't work. When one types
\begin{mytikz}
\node {hello world};
\end{mytikz}
then the \begin{mytikz}
gets expanded all the way to \begin{tikzpicture}
(and beyond) at which point TeX starts gobbling stuff. It meets the \end{mytikz}
without expanding it and so never realises that it is the \end{tikzpicture}
that it was looking for.
The environ package gets around this by converting the environment to a command. So when TeX see \begin{mytikz}
, before it expands that (fully, that is, it has to expand it just enough to know that it was defined using the environ
package), it goes looking for the \end{mytikz}
. Then it slurps in the contents in to an internal(ish) macro and dumps the corresponding code in to the stream. That means that when TeX finally sees the \begin{tikzpicture}
, then the correct \end{tikzpicture}
has also been inserted into the stream at the correct place.
So we want to keep this feature, but at the same time add in the argument handling features of the xargs
package. The trick here is to realise that the argument handling part does not actually have to be connected to the environment - it just has to look like it to the user. (This is quite common in TeX/LaTeX commands. Many appear to take an argument but in fact do nothing of the sort.) If we declare an environment using \NewEnviron
then whatever appears after the \begin{myenv}
gets put in to a special macro called \BODY
. That is, if we have:
\NewEnviron{myenv}{something first \BODY\ something last}
then
\begin{myenv}
in the middle
\end{myenv}
gets replaced by something first in the middle something last
in the stream (almost ..., and I'm not worrying about \par
here). The point is that this also works for
\begin{myenv}[some][optional]{or}{mandatory}[arguments]
in the middle
\end{myenv}
in that this produces something first [some][optional]{or}{mandatory}[arguments] in the middle something last
. So if something first
happens to be a macro, it will "see" the [some][optional]{or}{mandatory}[arguments]
and think that they were intended for it.
The "almost" here is that actually what is put in the stream is something first \BODY\ something last
so we need to expand \BODY
first to get at the arguments.
Putting all of this together, we get:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{external}
\tikzexternalize
\usepackage{environ}
\usepackage{xargs}
\newcommandx{\startmytikz}[1][1=]{%
\begin{figure}[htp]
\centering
\begin{tikzpicture}[#1]}
\NewEnviron{mytikz}{\expandafter\startmytikz\BODY
\end{tikzpicture}
\end{figure}}
\begin{document}
\tikzset{external/force remake=true}
\begin{mytikz}[every path/.style={red}]
\draw(0,0) circle (1cm);
\node {hello world};
\end{mytikz}
\end{document}
Of course, one can wrap all of this in to a single definition if one wishes:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{external}
\tikzexternalize
\usepackage{environ}
\usepackage{xargs}
\newcommandx{\NewEnvironx}[5][2,3]{%
\expandafter\newcommandx\csname start#1\endcsname[#2][#3]{#4}%
\NewEnviron{#1}{\csname start#1\expandafter\endcsname\BODY #5}}
\NewEnvironx{mytikz}[1][1=]{%
\begin{figure}[htp]
\centering
\begin{tikzpicture}[#1]}
{\end{tikzpicture}
\end{figure}}
\begin{document}
\tikzset{external/force remake=true}
\begin{mytikz}[every path/.style={red}]
\draw(0,0) circle (1cm);
\node {hello world};
\end{mytikz}
\end{document}
Best Answer
The
tikztimingtable
is unfortunately not compatible with theexternal
library. The\texttiming
and\timing
macros will work however. The reason for the incompatibility is because thetikzpicture
is nested insidetikztimingtable
which is not supported byexternal
as described in section 32.2 Requirements of the v2.10 TikZ/PGF manual. The error occurs because theexternal
library can't find the\end{tikzpicture}
because it is inside the\end{tikztimingtable}
.One workaround to avoid errors is to disable the externalization for
tikztimingtable
s as described in e.g. tikzexternalize only (or not) for flagged graphics. You can add a\tikzexternaldisable
macro inside thefigure
before thetikztimingtable
. However, then you will get this benefit only for othertikzpicture
s. If you only havetikztimingtable
s you can avoid usingexternal
altogether.An alternative to
external
is thestandalone
class and package. With this you must place the code in question in an file of its own, where you can have a full preamble. This file can then be compiled by itself, i.e. standalone, which is very nice for larger pictures which must be recompiled often during the creation process. With thestandalone
package you can then include the standalone file without removing the preamble. It also allows automatic generation of PDF images from the standalone files. See the manual and search formode
.