Are the TikZ libraries cd and external incompatible with one another?
This solution does not allow you to externalise diagrams produced using the tikzcd
environment but it does allow you to externalise other tikz
pictures in your document. It is based on a workaround mentioned in the tikz
manual in section 50.8.2 (pages 627-8). To make its use more convenient, etoolbox
is used to patch the tikzcd
environment. Essentially, this turns externalisation off at the beginning of tikzcd
environments and then switches it back on again at their ends.
\documentclass{article}
\usepackage{etoolbox,tikz}
\usetikzlibrary{external}
\tikzexternalize
\usetikzlibrary{cd}
\AtBeginEnvironment{tikzcd}{\tikzexternaldisable}
\AtEndEnvironment{tikzcd}{\tikzexternalenable}
\begin{document}
\begin{tikzpicture}
\node at (0,0) {node};
\end{tikzpicture}
\begin{tikzcd}
A \arrow[rd] \arrow[r, "\varphi"] & B \\ & C
\end{tikzcd}
\end{document}
On the first run, pdflatex --shell-escape <filename>.tex
includes this output:
===== 'mode=convert with system call': Invoking 'pdflatex -shell-escape -halt-o
n-error -interaction=batchmode -jobname "<filename>-figure0" "\def\tikzexternalreal
job{<filename>}\input{<filename>}"' ========
<filename>-figure0.pdf
looks like this:
Subsequent runs include the output:
===== Image '<filename>-figure0' is up-to-date. ======
The PDF combines the externalised image from <filename>-figure0.pdf
with the one produced from tikzcd
on the fly:
How helpful this is will depend on what proportion of your pictures are tikzcd
. If the answer is 100%, it will obviously be of no use at all. On the other hand, if the answer is less than 100%, there may be something to be said for it.
The problem is the same as that in Problem with environment expansion and the Tikz external library. in that TeX does not see the \end{tikzpicture}
inside the \end{tikzcd}
. The solution in Problem with environment expansion and the Tikz external library. is to pack everything inside a macro to ensure that the customised end-of-environment is expanded before TeX starts gobbling so that the hidden \end{tikzpicture}
is revealed. The adaptation of that in the question above is not the same because it adds an extra \end{tikzpicture}
instead of unpacking the hidden one, and this leads to nesting of TikZ pictures which is Not A Good Idea.
(Nonetheless, just because something is not a good idea doesn't mean that it isn't the best idea, just that it should be used with extreme caution.)
If all your pictures are tikzcd
environments then it seems that the right solution might be to tell TeX to look for tikzcd
instead of tikzpicture
. This is a reasonable thing to try to do because the first thing that \begin{tikzcd}
does is to start a tikzpicture
and the last thing that \end{tikzcd}
does is to end it. However, my experiments at trying to change all tikzpicture
s in the externalisation code to tikzcd
didn't work so I'm abandoning this for the time being (what would be nice would be an adaptation of the externalisation library that worked for any environment, not just tikzpicture
s).
Here's an adaptation of your adaptation of my answer to the linked question which instead of wrapping the tikzcd
environment in a tikzpicture
simply exposes the inner tikzpicture
. Well, except that it doesn't since the inner tikzpicture
is written as \tikzpicture ... \endtikzpicture
which wouldn't match so we have to redefine the tikzcd
environment to make the \tikzpicture
and \endtikzpicture
into \begin{tikzpicture}
and \end{tikzpicture}
. Elegant, it ain't, but it does avoid the nesting issue.
\documentclass{article}
%\url{https://tex.stackexchange.com/q/171931/86}
\usepackage{tikz}
\usepackage{environ}
\usetikzlibrary{cd,external}
\tikzexternalize
\makeatletter
\def\tikzcd@[#1]{%
\begin{tikzpicture}[/tikz/commutative diagrams/.cd,every diagram,#1]%
\ifx\arrow\tikzcd@arrow%
\pgfutil@packageerror{tikz-cd}{Diagrams cannot be nested}{}
\fi%
\let\arrow\tikzcd@arrow%
\let\ar\tikzcd@arrow%
\def\rar{\tikzcd@xar{r}}%
\def\lar{\tikzcd@xar{l}}%
\def\dar{\tikzcd@xar{d}}%
\def\uar{\tikzcd@xar{u}}%
\def\urar{\tikzcd@xar{ur}}%
\def\ular{\tikzcd@xar{ul}}%
\def\drar{\tikzcd@xar{dr}}%
\def\dlar{\tikzcd@xar{dl}}%
\global\let\tikzcd@savedpaths\pgfutil@empty%
\matrix[/tikz/matrix of \iftikzcd@mathmode math \fi nodes,
/tikz/every cell/.append code={\tikzcdset{every cell}},
/tikz/commutative diagrams/.cd,every matrix]%
\bgroup}
\def\endtikzcd{%
\pgfmatrixendrow\egroup%
\pgfextra{\global\let\tikzcdmatrixname\tikzlastnode};%
\tikzcdset{\the\pgfmatrixcurrentrow-row diagram/.try}%
\begingroup%
\tikzcd@enablequotes%
\tikzcd@patcherrmsg%
\tikzcd@savedpaths%
\endgroup%
\end{tikzpicture}%
\ifnum0=`{}\fi}
\NewEnviron{mytikzcd}[1][]{%
\def\@temp{\tikzcd@[#1]\BODY}%
\expandafter\@temp\endtikzcd
}
\makeatother
\def\temp{&} \catcode`&=\active \let&=\temp
\begin{document}
\begin{mytikzcd}
A \arrow{rd} \arrow{r}{\phi} & B \\ & C
\end{mytikzcd}
\begin{mytikzcd}
A \arrow{rd} \arrow{r}{\phi} & B \\ & C
\end{mytikzcd}
\end{document}
Here’s one solution that works with the external
library and that I hadn’t thought of before.
We can put the tikzcd
environment inside a tizkpicture
’s node:
\begin{tikzpicture}
\node {\begin{tikzcd}
A \arrow[rd] \arrow[r, "\varphi"] & B \\ & C
\end{tikzcd}};
\end{tikzpicture}
To get spacing and alignment right, the following options seem to work:
\begin{tikzpicture}[baseline=(current bounding box.west)]
\node[inner sep=0, outer sep=0] {\begin{tikzcd}
A \arrow[rd] \arrow[r, "\varphi"] & B \\ & C
\end{tikzcd}};
\end{tikzpicture}
So combining this with Andrew Stacey’s excellent answer to a related question, we get:
\documentclass{article}
\usepackage{tikz, environ}
\usetikzlibrary{cd, external}
\tikzexternalize
\def\temp{&} \catcode`&=\active \let&=\temp
\NewEnviron{mycd}[1][]{%
\begin{tikzpicture}[baseline=(current bounding box.west)]
\node[inner sep=0, outer sep=0] {\begin{tikzcd}[#1]
\BODY
\end{tikzcd}};
\end{tikzpicture}}
\begin{document}
\begin{equation}
\begin{mycd}[row sep=huge]
A \arrow[rd] \arrow[r, "\varphi"] & B \\ & C
\end{mycd}
\end{equation}
\end{document}
It still feels like a dirty hack to me. Is there a better solution?