将 tikzpictures 的 tikz-cd 外部化

将 tikzpictures 的 tikz-cd 外部化

众所周知,tikzexternalize 和 tikz-cd 不能很好地互相配合:TikZ 库 cd 和 external 是否彼此不兼容?。现在,我有一个 tikzcd,其条目是 tikzpictures。我能以某种方式将 tikz-cd 中的图片外部化吗?

\documentclass{scrartcl}
\usepackage[svgnames]{xcolor}
\usepackage{tikz,tikz-cd,xstring}
\newcommand{\FilteredBall}[1][abcfghxy]{
    \begin{tikzpicture}[every node/.append style={inner sep=1pt}, baseline={(0,-0.2)}]%(current bounding box.center)]
        %\fill[white] (0,0) circle (2);
        \begin{scope}[gray]
            \draw[dashed] (2,0) arc (0:180:2 and 0.6);
            \draw (0,0) circle (2) ;
            \draw (-2,0) arc (180:360:2 and 0.6);
        \end{scope}
        \begin{scope}[opacity=.5]
            \IfSubStr{#1}{f}{
                \begin{scope}
                    \clip (0,2) arc (90:-90:2) arc (-90:90:.6 and 2);
                    \shade[ball color=red!70] (0,0) circle[radius=2];
                \end{scope}
                \begin{scope}
                    \clip (0,2) arc (90:-90:2) arc (-90:90:1.2 and 2);
                    \shade[ball color=red!70] (0,0) circle[radius=2];
                \end{scope}
            }{}
            \IfSubStr{#1}{g}{
                \begin{scope}
                    \clip (0,2) arc (90:-90:-2 and 2) arc (-90:90:.6 and 2);
                    \shade[ball color=blue!60] (0,0) circle[radius=2];
                \end{scope}
                \begin{scope}
                    \clip (0,2) arc (90:-90:-2 and 2) arc (-90:90:-1.3 and 2);
                    \shade[ball color=blue!60] (0,0) circle[radius=2];
                \end{scope}
            }{}
            \IfSubStr{#1}{h}{
                \begin{scope}
                    \clip (0,2) arc (90:-90:-1.2 and 2) arc (-90:90:1.2 and 2);
                    \shade[ball color=green!70] (0,0) circle[radius=2];
                \end{scope}
            }{}
        \end{scope}
        \begin{scope}[thick]
            \IfSubStr{#1}{a}{\draw[red] (0,2) arc (90:-90:-1.3 and 2) node[below left, pos=.9] {$a$};}{}
            \IfSubStr{#1}{b}{\draw[blue] (0,2) arc (90:-90:1.2 and 2) node[below right, pos=.9] {$b$};}{}
            \IfSubStr{#1}{c}{
                \IfSubStr{#1}{h}{
                    \draw[Aqua, densely dotted] (0,2) arc (90:270:-0.6 and 2) node[left=-2pt, midway] {$c$};
                }{
                    \draw[Aqua] (0,2) arc (90:270:-0.6 and 2) node[left=-2pt, midway] {$c$};
                }
            }{}
        \end{scope}
        \IfSubStr{#1}{x}{\fill (0,2) circle (0.15);}{}
        \IfSubStr{#1}{y}{\fill (0,-2) circle (0.15);}{}
        \path
        (0,2) arc (90:-90:2) node[text=red, pos=.4, above right]                   {\IfSubStr{#1}{f}{$f$}{\phantom{{$f$}}}}
        (0,2) arc (90:-90:-2 and 2) node[text=blue!50!black, pos=.6,, below left]  {\IfSubStr{#1}{g}{$g$}{\phantom{{$g$}}}}
        (-.4, .65) node[text=green!50!black]                                        {\IfSubStr{#1}{h}{$h$}{\phantom{{$h$}}}}
        (0,2) node[above]                                                          {\IfSubStr{#1}{x}{$x$}{\phantom{{$x$}}}}
        (0,-2) node[below]                                                         {\IfSubStr{#1}{y}{$y$}{\phantom{{$y$}}}};
    \end{tikzpicture}
}
\begin{document}
    \begin{equation}
        \tikzset{every node/.append style={outer sep=2pt}, x=2mm, y=2mm}
        \begin{tikzcd}[row sep=tiny, column sep=tiny]
            \FilteredBall[xya] \rar["\subseteq", phantom] &
            \FilteredBall[xyabh] \rar["\subseteq", phantom] &
            \FilteredBall[xyabchg] \rar["\subseteq", phantom] &
            \FilteredBall[xyabcfgh]
            \\
            \FilteredBall[xya] \rar["\subseteq", phantom] &
            \FilteredBall[xyab] \rar["\subseteq", phantom] \uar["\subseteq", phantom, sloped]  &
            \FilteredBall[xyabcg] \rar["\subseteq", phantom] \uar["\subseteq", phantom, sloped]  &
            \FilteredBall[xyabcfg] \uar["\subseteq", phantom, sloped]  &
            \\
            \FilteredBall[xy] \rar["\subseteq", phantom] \uar["\subseteq", phantom, sloped] &
            \FilteredBall[xyb] \rar["\subseteq", phantom] \uar["\subseteq", phantom, sloped] &
            \FilteredBall[xybc] \rar["\subseteq", phantom] \uar["\subseteq", phantom, sloped] &
            \FilteredBall[xybcf] \uar["\subseteq", phantom, sloped] \\
            \FilteredBall[xy] \rar["\subseteq", phantom] \uar["\subseteq", phantom, sloped] &
            \FilteredBall[xy] \rar["\subseteq", phantom] \uar["\subseteq", phantom, sloped]&
            \FilteredBall[xyc] \rar["\subseteq", phantom] \uar["\subseteq", phantom, sloped] &
            \FilteredBall[xyc] \uar["\subseteq", phantom, sloped].
        \end{tikzcd}
    \end{equation}
\end{document}

编辑 以下代码基于 Qrrbrbirlbel 的回答,试图将图片与数学混合在一起。红色水平箭头显然是错误的,应该与黑色箭头相同:

\documentclass{scrartcl}
\usepackage[svgnames]{xcolor}
\usepackage{tikz,tikz-cd,xstring}
\usetikzlibrary{fit, external}
%\tikzexternalize
\makeatletter
\pgfkeys{% https://tex.stackexchange.com/a/665688/16595
    /utils/temp/.initial/.expand once=\tikzcd,
    /utils/temp/.prefix=\ifx\path\tikz@command@path % we're inside a tikzpicture
    \let\tikzpicture\scope
    \let\endtikzpicture\endscope
    \else % we're not inside a tikzpicture, disable externalizing
    \tikzexternaldisable
    \fi,/utils/temp/.get=\tikzcd}
\makeatother
\tikzset{
    cd vcenter/.style={baseline={([yshift=-axis_height]\tikzcdmatrixname)}},
    matrix bb node/.style={
        fit=(current bounding box), inner sep=0pt,%inner sep=+.3333em, 
        outer sep=+0pt, shape=rectangle, draw,%path only,
        name=\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn},
    add bb node/.style={execute at end cell={\node[draw,matrix bb node]{};}}}
\tikzcdset{
    no matrix of nodes/.style={
        /tikz/add bb node,
        /tikz/matrix of nodes/.code=,
        /tikz/matrix of math nodes/.code=}}
\newcommand{\FilteredBall}[1][abcfghxy]{
%   \tikzset{}
    %\fill[white] (0,0) circle (2);
    \begin{scope}[every node/.append style={inner sep=2pt}]
        \begin{scope}[gray]
            \draw[dashed] (2,0) arc (0:180:2 and 0.6);
            \draw (0,0) circle (2) ;
            \draw (-2,0) arc (180:360:2 and 0.6);
        \end{scope}
        \begin{scope}[opacity=.5]
            \IfSubStr{#1}{f}{
                \begin{scope}
                    \clip (0,2) arc (90:-90:2) arc (-90:90:.6 and 2);
                    \shade[ball color=red!70] (0,0) circle[radius=2];
                \end{scope}
                \begin{scope}
                    \clip (0,2) arc (90:-90:2) arc (-90:90:1.2 and 2);
                    \shade[ball color=red!70] (0,0) circle[radius=2];
                \end{scope}
            }{}
            \IfSubStr{#1}{g}{
                \begin{scope}
                    \clip (0,2) arc (90:-90:-2 and 2) arc (-90:90:.6 and 2);
                    \shade[ball color=blue!60] (0,0) circle[radius=2];
                \end{scope}
                \begin{scope}
                    \clip (0,2) arc (90:-90:-2 and 2) arc (-90:90:-1.3 and 2);
                    \shade[ball color=blue!60] (0,0) circle[radius=2];
                \end{scope}
            }{}
            \IfSubStr{#1}{h}{
                \begin{scope}
                    \clip (0,2) arc (90:-90:-1.2 and 2) arc (-90:90:1.2 and 2);
                    \shade[ball color=green!70] (0,0) circle[radius=2];
                \end{scope}
            }{}
        \end{scope}
        \begin{scope}[thick]
            \IfSubStr{#1}{a}{\draw[red] (0,2) arc (90:-90:-1.3 and 2) node[below left, pos=.9] {$a$};}{}
            \IfSubStr{#1}{b}{\draw[blue] (0,2) arc (90:-90:1.2 and 2) node[below right, pos=.9] {$b$};}{}
            \IfSubStr{#1}{c}{
                \IfSubStr{#1}{h}{
                    \draw[Aqua, densely dotted] (0,2) arc (90:270:-0.6 and 2) node[left=-2pt, midway] {$c$};
                }{
                    \draw[Aqua] (0,2) arc (90:270:-0.6 and 2) node[left=-2pt, midway] {$c$};
                }
            }{}
        \end{scope}
        \IfSubStr{#1}{x}{\fill (0,2) circle (0.15);}{}
        \IfSubStr{#1}{y}{\fill (0,-2) circle (0.15);}{}
        \path
        (0,2) arc (90:-90:2) node[text=red, pos=.4, above right]                   {\IfSubStr{#1}{f}{$f$}{\phantom{{$f$}}}}
        (0,2) arc (90:-90:-2 and 2) node[text=blue!50!black, pos=.6,, below left]  {\IfSubStr{#1}{g}{$g$}{\phantom{{$g$}}}}
        (-.4, .65) node[text=green!50!black]                                        {\IfSubStr{#1}{h}{$h$}{\phantom{{$h$}}}}
        (0,2) node[above]                                                          {\IfSubStr{#1}{x}{$x$}{\phantom{{$x$}}}}
        (0,-2) node[below]                                                         {\IfSubStr{#1}{y}{$y$}{\phantom{{$y$}}}};
    \end{scope}
}
\begin{document}
    \begin{equation}
        \begin{tikzpicture}[x=2mm, y=2mm, cd vcenter]
            \begin{tikzcd}[row sep=tiny, column sep=tiny, no matrix of nodes]
                \FilteredBall[xya] \rar["\subseteq", phantom] &
                \FilteredBall[xyabh] \rar["\subseteq", phantom] &
                \FilteredBall[xyabchg] \rar["\subseteq", phantom] &
                \FilteredBall[xyabcfgh]
                \\
                \FilteredBall[xya] \rar["\subseteq", phantom] &
                \FilteredBall[xyab] \rar["\subseteq", phantom] \uar["\subseteq", phantom, sloped]  &
                \FilteredBall[xyabcg] \rar["\subseteq", phantom] \uar["\subseteq", phantom, sloped]  &
                \FilteredBall[xyabcfg] \uar["\subseteq", phantom, sloped]  &
                \\
                \FilteredBall[xy] \rar["\subseteq", phantom] \uar["\subseteq", phantom, sloped] &
                \FilteredBall[xyb] \rar["\subseteq", phantom] \uar["\subseteq", phantom, sloped] &
                \FilteredBall[xybc] \rar["\subseteq", phantom] \uar["\subseteq", phantom, sloped] &
                \FilteredBall[xybcf] \uar["\subseteq", phantom, sloped] \\
                \node[name=A]{$0_{0_{0_0}}$}; \rar[red] \uar &
                \node[name=B]{$0^{0^{0^0}}$}; \rar["\subseteq", phantom] \uar["\subseteq", phantom, sloped]&
%               \FilteredBall[xy] \draw (current bounding box.base) node (B){} circle(2pt); \rar["\subseteq", phantom] \uar["\subseteq", phantom, sloped]&
                \FilteredBall[xyc] \rar["\subseteq", phantom] \uar["\subseteq", phantom, sloped] &
                \FilteredBall[xyc] \uar["\subseteq", phantom, sloped].
                \ar[from=A, to=B]
            \end{tikzcd}
        \end{tikzpicture}
    \end{equation}
\end{document}

答案1

由于您实际上并不使用matrix of (math) nodes该 TikZ-CD 安装,因此我会禁用它,然后您可以\FilteredBall在每个单元格中使用您的,而不必使用嵌套tikzpictures。使用我的答案如何解决 tikz-cd 与外部不兼容的问题您可以将环境放入可以外部化的tikzcd内部。tikzpicture

我添加了以下/tikz/cd vcenter密钥我的答案花括号之间的 TikZcd 存在问题使得矩阵垂直居中。

fit在每个具有适当名称的单元格末尾创建一个带有库的节点,以便 TikZ-CD 用 绘制“箭头” \subseteq。此节点围绕单元格的当前边界框,封装单元格中尚未使用选项 绘制的所有内容overlay

由于您phantom已将每个节点都设为相同大小,因此所有单元格都具有相同的大小,因此只需这样做即可使箭头正交绘制。如果单元格大小不相同,则这将稍微复杂一些。

调整该节点的inner xsep/或/以获得球之间的正确间距。inner yseprow sepcolumn sep

更新

由于我们已禁用,因此此 TikZ-CD 内的普通节点现在不太可用matrix of (math) nodes。不过,当使用单元格内的非唯一节点时,它们并不容易解决,这仍然是可能的,但单元格中的任何内容都需要以\path或它的某些变体开头。允许可选参数并以 开头的命令在这里不起作用。(不过,在某些情况下,在开头\begin{scope}有一个空的会有所帮助。)\path;

在这里我们使用一个普通的\node但带有键的方法matrix node,以便它应用 TikZ-CD 期望的正确命名方案来与其\arrow命令一起工作。

TikZ-CD 设置了自己的形状,该形状具有一个固定高度高于基线的asymmetrical rectangle欺骗性锚点,在放置节点时,其作用与锚点非常相似。我相信这对您而言是可取的,并且不会改变它。形状的真正力量来自于连接节点,其中水平线指向该假中心锚点,该锚点现在与正常数学模式箭头的高度相同(也是括号尖端的位置)。centeraxis_heightmidasymmetrical rectangle{}

如果单元格仅具有普通节点(TikZ-CD 也应如此使用),则必须使用密钥no bb node暂时禁用它。好吧,它将变成一个未命名的坐标,但这几乎是一样的。真正禁用它需要更多工作。

说到边界框节点。我添加了一个特殊fit键来调整 Case 2 的边界框节点我自己的答案在细胞内安装一个asymmetrical rectangle包裹一切但水平对称于细胞中心的装置,并center在细胞中心有自己的锚点——包括在方向,这就是为什么它也要axis_height考虑。这是必要的,以便垂直箭头真正垂直。

代码

\documentclass{scrartcl}
\usepackage[svgnames]{xcolor}
\usepackage{tikz,tikz-cd,xstring}
\usetikzlibrary{fit, external}
%\tikzexternalize
\makeatletter
\tikzcdset{
  fit/.code={% tikz-cd uses an asymmetrical rectangle …
    \pgf@process{\pgfpointanchor{\tikz@pp@name{#1}}{east}}\pgf@xa=2\pgf@x
    \pgf@process{\pgfpointanchor{\tikz@pp@name{#1}}{west}}\pgf@x=-2\pgf@x
    \ifdim\pgf@xa>\pgf@x \pgf@x=\pgf@xa \fi
    \pgfkeysalso{/tikz/text width/.expanded=+\the\pgf@x}%
    \pgf@process{\pgfpointdiff{\pgfpointanchor{\tikz@pp@name{#1}}{south}}
                              {\pgfpointanchor{\tikz@pp@name{#1}}{north}}}%
    \pgf@ya=.5\pgf@y \pgf@yb=\pgf@ya
    \pgfmathaddtolength\pgf@ya{axis_height}%
    \pgfmathaddtolength\pgf@yb{-axis_height}%
    \pgfkeysalso{/tikz/text height/.expanded=+\the\pgf@ya,
                 /tikz/text depth/.expanded=+\the\pgf@yb}},
  /utils/temp/.initial/.expand once=\tikzcd,
  /utils/temp/.prefix=% https://tex.stackexchange.com/a/665688/16595
    \ifx\path\tikz@command@path
      \let\tikzpicture\scope \let\endtikzpicture\endscope
    \else \tikzexternaldisable \fi,/utils/temp/.get=\tikzcd}
\makeatother
\tikzset{
  matrix node/.style={
    name=\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn},
  cd vcenter/.style={baseline={([yshift=-axis_height]\tikzcdmatrixname)}},
  matrix bb node/.style={
    commutative diagrams/fit=current bounding box, inner sep=0pt,
    outer sep=+0pt, shape=asymmetrical rectangle, path only,  matrix node},
  add bb node/.style={execute at end cell={\node[matrix bb node]{};}},
  no bb node/.style={matrix bb node/.style={shape=coordinate}}}
\tikzcdset{
  no matrix of nodes/.style={
    /tikz/add bb node,
    /tikz/matrix of nodes/.code=,
    /tikz/matrix of math nodes/.code=}}
\newcommand{\FilteredBall}[1][abcfghxy]{
%   \tikzset{}
    %\fill[white] (0,0) circle (2);
    \begin{scope}[every node/.append style={inner sep=2pt}]
        \begin{scope}[gray]
            \draw[dashed] (2,0) arc (0:180:2 and 0.6);
            \draw (0,0) circle (2) ;
            \draw (-2,0) arc (180:360:2 and 0.6);
        \end{scope}
        \begin{scope}[opacity=.5]
            \IfSubStr{#1}{f}{
                \begin{scope}
                    \clip (0,2) arc (90:-90:2) arc (-90:90:.6 and 2);
                    \shade[ball color=red!70] (0,0) circle[radius=2];
                \end{scope}
                \begin{scope}
                    \clip (0,2) arc (90:-90:2) arc (-90:90:1.2 and 2);
                    \shade[ball color=red!70] (0,0) circle[radius=2];
                \end{scope}
            }{}
            \IfSubStr{#1}{g}{
                \begin{scope}
                    \clip (0,2) arc (90:-90:-2 and 2) arc (-90:90:.6 and 2);
                    \shade[ball color=blue!60] (0,0) circle[radius=2];
                \end{scope}
                \begin{scope}
                    \clip (0,2) arc (90:-90:-2 and 2) arc (-90:90:-1.3 and 2);
                    \shade[ball color=blue!60] (0,0) circle[radius=2];
                \end{scope}
            }{}
            \IfSubStr{#1}{h}{
                \begin{scope}
                    \clip (0,2) arc (90:-90:-1.2 and 2) arc (-90:90:1.2 and 2);
                    \shade[ball color=green!70] (0,0) circle[radius=2];
                \end{scope}
            }{}
        \end{scope}
        \begin{scope}[thick]
            \IfSubStr{#1}{a}{\draw[red] (0,2) arc (90:-90:-1.3 and 2) node[below left, pos=.9] {$a$};}{}
            \IfSubStr{#1}{b}{\draw[blue] (0,2) arc (90:-90:1.2 and 2) node[below right, pos=.9] {$b$};}{}
            \IfSubStr{#1}{c}{
                \IfSubStr{#1}{h}{
                    \draw[Aqua, densely dotted] (0,2) arc (90:270:-0.6 and 2) node[left=-2pt, midway] {$c$};
                }{
                    \draw[Aqua] (0,2) arc (90:270:-0.6 and 2) node[left=-2pt, midway] {$c$};
                }
            }{}
        \end{scope}
        \IfSubStr{#1}{x}{\fill (0,2) circle (0.15);}{}
        \IfSubStr{#1}{y}{\fill (0,-2) circle (0.15);}{}
        \path
        (0,2) arc (90:-90:2) node[text=red, pos=.4, above right]                   {\IfSubStr{#1}{f}{$f$}{\phantom{{$f$}}}}
        (0,2) arc (90:-90:-2 and 2) node[text=blue!50!black, pos=.6,, below left]  {\IfSubStr{#1}{g}{$g$}{\phantom{{$g$}}}}
        (-.4, .65) node[text=green!50!black]                                        {\IfSubStr{#1}{h}{$h$}{\phantom{{$h$}}}}
        (0,2) node[above]                                                          {\IfSubStr{#1}{x}{$x$}{\phantom{{$x$}}}}
        (0,-2) node[below]                                                         {\IfSubStr{#1}{y}{$y$}{\phantom{{$y$}}}};
    \end{scope}
}
\begin{document}
\begin{equation}
\begin{tikzpicture}[x=2mm, y=2mm, cd vcenter]
\begin{tikzcd}[row sep=tiny, column sep=tiny, no matrix of nodes]
\FilteredBall[xya] \rar["\subseteq", phantom] &
\FilteredBall[xyabh] \rar["\subseteq", phantom] &
\FilteredBall[xyabchg] \rar["\subseteq", phantom] &
\FilteredBall[xyabcfgh]
\\
\FilteredBall[xya] \rar["\subseteq", phantom] &
\FilteredBall[xyab] \rar["\subseteq", phantom] \uar["\subseteq", phantom, sloped]  &
\FilteredBall[xyabcg] \rar["\subseteq", phantom] \uar["\subseteq", phantom, sloped]  &
\FilteredBall[xyabcfg] \uar["\subseteq", phantom, sloped]  &
\\
\FilteredBall[xy] \rar["\subseteq", phantom] \uar["\subseteq", phantom, sloped] &
\FilteredBall[xyb] \rar["\subseteq", phantom] \uar["\subseteq", phantom, sloped] &
\FilteredBall[xybc] \rar["\subseteq", phantom] \uar["\subseteq", phantom, sloped] &
\FilteredBall[xybcf] \uar["\subseteq", phantom, sloped] \\
\tikzset{no bb node} \node[matrix node]{$0_{0_{0_0}}$}; \rar[red] \uar &
\tikzset{no bb node} \node[matrix node]{$0^{0^{0^0}}$}; \rar["\subseteq", phantom] \uar["\subseteq", phantom, sloped]&
%&               \FilteredBall[xy] \draw (current bounding box.base) node (B){} circle(2pt); \rar["\subseteq", phantom] \uar["\subseteq", phantom, sloped]&
\FilteredBall[xyc] \rar["\subseteq", phantom] \uar["\subseteq", phantom, sloped] &
\FilteredBall[xyc] \uar["\subseteq", phantom, sloped].
\end{tikzcd}
\end{tikzpicture}
\end{equation}
\end{document}

输出

在此处输入图片描述

相关内容