我一直在尝试使用这个很棒的答案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>
是一串由r
、l
、d
、u
字符组成的字符串,表示多单元格位置。例如,在下图中,单元3-3
格是带有跨度选项 的多单元格。通过将多单元格放置在带有跨度选项 的dr
位置,您将获得相同的结果。4-4
ul
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 sep
和row sep
可能仍需要手动设置。如果多单元格太高或太宽,它将与相邻单元格重叠。此外,宏不要求多单元格覆盖的单元格为空。如果您想将单元格放置在已填充单元格的交叉点处,这可能会很有用。
旧解决方案:
这是另一种更简单的方法。将多单元格的内容放在phantom
箭头上。给它一个 a name
,然后在末尾添加arrow
sto
和命名的内容。from
为了简化这一点,我创建了一个名为 的 2 参数样式multi
,可用于箭头中。示例用法:
X \arrow[rrr, multi={<contents>}{<name>}] & & & Y
这会将 置于单元格和单元格<contents>
之间的中心。如果您使用作为名称,则可以使用。X
Y
A
\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}
至于如果节点相对较宽则拉伸两个相关列,一个想法可以是检索该节点的宽度,将其除以二,并将两列的最小宽度设置为该宽度。