tikzcd 中的多列:对齐和箭头处理不佳

tikzcd 中的多列:对齐和箭头处理不佳

我一直在尝试使用这个很棒的答案https://tex.stackexchange.com/a/21167/116348在 tikzcd 环境中提供多列。但是我有两个问题:

  • 对齐不正确(我希望多列单元格水平居中,但它太靠左了)
  • 连接箭头会产生不好的结果(它似乎指向了没有多面体时盒子所在的位置)
  • 它不适用于多行,或多列和多行。

在此处输入图片描述

有什么想法可以改进它吗?

平均能量损失

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{cd}
\usetikzlibrary{backgrounds,positioning}
\usetikzlibrary{shapes,shapes.geometric,shapes.misc}
\usepackage{xparse}

\usetikzlibrary{matrix}

\makeatletter
%%% https://tex.stackexchange.com/a/21167/116348
\newdimen\multi@col@width
\newdimen\multi@col@margin
\newcount\multi@col@count
\multi@col@width=0pt

\tikzset{
  multicol/.code={%
    \global\multi@col@count=#1\relax
    \global\let\orig@pgfmatrixendcode=\pgfmatrixendcode
    \global\let\orig@pgfmatrixemptycode=\pgfmatrixemptycode
    \def\pgfmatrixendcode##1{\orig@pgfmatrixendcode%
      ##1%
      \pgfutil@tempdima=\pgf@picmaxx
      \global\multi@col@margin=\pgf@picminx
      \advance\pgfutil@tempdima by -\pgf@picminx
      \divide\pgfutil@tempdima by #1\relax
      \global\multi@col@width=\pgfutil@tempdima
      \pgf@picmaxx=.5\multi@col@width
      \pgf@picminx=-.5\multi@col@width
      \global\pgf@picmaxx=\pgf@picmaxx
      \global\pgf@picminx=\pgf@picminx
      %% Proposed fix does not help (it actually breaks the initial example)
      % \gdef\multi@adjust@position{%
      % \setbox\pgf@matrix@cell=\hbox\bgroup
      % \hfil\hskip-1.5\multi@col@margin
      % \hfil\hskip-.5\multi@col@width
      \gdef\multi@adjust@position{%
        \setbox\pgf@matrix@cell=\hbox\bgroup
        \hfil\hskip-\multi@col@margin
        \hfil\hskip-.5\multi@col@width
        \box\pgf@matrix@cell
        \egroup
      }%
      \gdef\multi@temp{\aftergroup\multi@adjust@position}%
      \aftergroup\multi@temp
    }
    \gdef\pgfmatrixemptycode{%
      \orig@pgfmatrixemptycode
      \global\advance\multi@col@count by -1\relax
      \global\pgf@picmaxx=.5\multi@col@width
      \global\pgf@picminx=-.5\multi@col@width
      \ifnum\multi@col@count=1\relax
      \global\let\pgfmatrixemptycode=\orig@pgfmatrixemptycode
      \fi
    }
  }
}
\makeatother

\begin{document}

\tikzstyle{Z}=[fill=green]

Works but poorly aligned:

\begin{tikzcd}
  |[Z]| \beta & |[Z,multicol=2]|\alpha+\beta+\delta+2\pi &&|[Z]| x\\
  |[Z]| \beta \ar[r] & |[Z]| \beta \ar[r] & |[Z]| \beta \ar[r] & |[Z]| \beta
\end{tikzcd}\\


Arrows are not exactly the expected ones:

\begin{tikzcd}
  |[Z]| \beta \ar[r] & |[Z,multicol=2]|\alpha+\beta+\delta+2\pi \ar[rr] &&|[Z]| x\\
  |[Z]| \beta \ar[r] & |[Z]| \beta \ar[r] & |[Z]| \beta \ar[r] & |[Z]| \beta
\end{tikzcd}


\begin{tikzpicture}
  \matrix[matrix of nodes,nodes={draw}] {
    A &|[multicol=3]| A long entry spanning three columns &&&  A \\
    A B &|[multicol=2]| A shorter entry &&  A & D E F \\
    A B & A B & A B C D E F & A B\\
  };
\end{tikzpicture}

\end{document}

编辑

为了阐明我想要什么,这里是初稿:

在此处输入图片描述

如果我们想要一个更严格的定义,我会尝试用优化程序来写它:尝试找到较小的数字,使得:

  • 所有正常(非多列)节点的中心锚点都按网格图案对齐
  • 多列节点的中心垂直对齐,与其邻居节点位于同一行(多行类似)
  • column sep节点的每个右侧应该距离其右邻居的左侧至少(此值可能会根据每列而变化)并且我们在此段上放置两个分离坐标,距离columnsep(类似于底部/行分离)
  • 给定列的所有列分隔坐标都应垂直对齐(行类似)
  • 所有节点的中心应位于其最近的左侧和右侧分离坐标的中间(行类似)

希望这足够有约束力 ^^

实际上我在这里只考虑多列或多行节点,但我想我们可以为共享多行和多线的节点定义类似的规则(也许将它们视为多个堆叠的多列行,并添加额外的约束以将顶部节点与底部节点对齐)。

答案1

更新的解决方案:

\multi这是一个可以在 中使用的宏tikzcd。它可用于跨多行和/或多列的单元格。用法是。注意必须使用\multi[<name>]{<span>}{<content>}选项。nodes in empty cells

<name>是可选的(默认= A),并且仅当您的图表中有多个带箭头的多单元格时才需要。可以在此处添加选项来影响单元格,例如颜色或对齐方式(必须在名称之后)。

<span>是一串由rldu字符组成的字符串,表示多单元格位置。例如,在下图中,单元3-3格是带有跨度选项 的多单元格。通过将多单元格放置在带有跨度选项 的dr位置,您将获得相同的结果。4-4ul

from可以使用和to命名的多单元将指向多单元的箭头添加到图表中。

在此处输入图片描述

以下是代码:

\documentclass{article}

\usepackage{tikz-cd}

\newcommand{\multi}[3][A]{\arrow[#2, phantom, "#3"{name=#1, inner sep=1ex}]}

\begin{document}

\begin{tikzcd}[nodes in empty cells]
a_{11}\arrow[dr] & \multi{r}{\mbox{wide multi cell}} & & a_{14}\\
\multi[B, align=center]{d}{tall\\multi\\cell} & a_{22}\arrow[r]\arrow[d] & a_{23}\arrow[r] & a_{24}\\
 & a_{32}\arrow[d] & \multi[C, align=center]{dr}{tall and wide\\multi cell\\rows and columns} &\\
a_{41} & a_{42} & &
\arrow[from=1-1, to=A]
\arrow[from=A, to=1-4]
\arrow[from=1-1, to=B]
\arrow[from=B, to=4-1]
\arrow[from=2-2, to=C]
\end{tikzcd}

\end{document}

请注意,column seprow sep可能仍需要手动设置。如果多单元格太高或太宽,它将与相邻单元格重叠。此外,宏不要求多单元格覆盖的单元格为空。如果您想将单元格放置在已填充单元格的交叉点处,这可能会很有用。

旧解决方案:

这是另一种更简单的方法。将多单元格的内容放在phantom箭头上。给它一个 a name,然后在末尾添加arrowsto和命名的内容。from

为了简化这一点,我创建了一个名为 的 2 参数样式multi,可用于箭头中。示例用法:

X \arrow[rrr, multi={<contents>}{<name>}] & & & Y

这会将 置于单元格和单元格<contents>之间的中心。如果您使用作为名称,则可以使用。XYA\arrow[from=1-1, to=A]

请注意column sep不会自动调整。

在此处输入图片描述

\documentclass{article}

\usepackage{tikz-cd}
\tikzcdset{multi/.style 2 args={phantom, "#1"{name=#2, inner sep=1ex}}}

\begin{document}

\begin{tikzcd}
\beta\arrow[rrr, multi={\sqrt{\alpha+\beta}}{A}] & & & x\\
\beta\arrow[r] & \beta+2\arrow[r] & \beta\arrow[r] & \beta
\arrow[from=1-1, to=A]
\arrow[from=A, to=1-4]
\end{tikzcd}

\vspace{1cm}
\begin{tikzcd}[column sep=11mm]
\beta\arrow[rrr, multi={\alpha+\beta+\delta+\theta+2\pi}{B}] & & & x\\
\beta\arrow[r] & \beta+2\arrow[r] & \beta\arrow[r] & \beta
\arrow[from=1-1, to=B]
\arrow[from=B, to=1-4]
\end{tikzcd}

\end{document}

答案2

解决这个问题的一种方法可能是使用\tikzcd@savedpaths存储路径,然后只在以后执行路径。因此,这个想法本质上是首先绘制不带多列单元的矩阵,然后在矩阵布局完成后,将其放置在它所属的位置。

以下只是一种初步方法。它带有另一种可能不太好的语法,但语法问题可能在第二步中可以解决:

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{cd, calc}

\makeatletter
\newcommand{\spancell}[5][]{
    \pgfutil@g@addto@macro\tikzcd@savedpaths{%
        \node[#1] at ($(#2)!0.5!(#3)$) (#5) {$#4$};
    }
}
\makeatother

\tikzcdset{
    nodes in empty cells,
    every matrix/.append style={
        name=m
    },
    /tikz/Z/.style={
        fill=green
    }
}

\begin{document}

\begin{tikzcd}
  |[Z]| \beta & \spancell[Z]{m-1-2}{m-1-3}{\alpha+\beta+\delta+2\pi}{spancell-1} \ar[from=m-1-1,to=spancell-1] \ar[from=spancell-1,rr] & &|[Z]| x \\
  |[Z]| \beta \ar[r] & |[Z]| \beta \ar[r] & |[Z]| \beta \ar[r] & |[Z]| \beta
\end{tikzcd}

\end{document}

在此处输入图片描述

至于如果节点相对较宽则拉伸两个相关列,一个想法可以是检索该节点的宽度,将其除以二,并将两列的最小宽度设置为该宽度。

相关内容