[Tex/LaTex] Are the TikZ libraries cd and external incompatible with one another

tikz-cdtikz-externaltikz-pgf

Is there a way to use the TikZ libraries cd and external together?
This does not work:

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{cd, external}
\tikzexternalize

\begin{document}

\begin{tikzcd}
  A \arrow[rd] \arrow[r, "\varphi"] & B \\ & C
\end{tikzcd}

\end{document}

Error:

Runaway argument?

! File ended while scanning use of \tikzexternal@laTeX@collect@until@end@tikzpicture.

I’m using TikZ/PGF version 3.0.0 and tikz-cd version 0.9b.

Best Answer

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 tikzpictures 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 tikzpictures).

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}