我正在尝试生成一棵树,将每个节点的内容设置为一个表。
我的尝试是这样的
\documentclass{article}
\usepackage{forest}
\tikzset{
table/.style={%
rectangle split, rectangle split parts=#1,
draw, minimum width=1cm,
rectangle split part align={center}
},
}
% Test with this, got an '! Missing \cr inserted.' error
\newcommand{\vals}[3]{#1\nodepart{two}#2\nodepart{three}#3}
% I suspected of a expansion problem, try this
% Now it compiles, but it doesn't produce the parts of the node
\newcommand{\valsnx}[3]{#1\noexpand\nodepart{two}#2\noexpand\nodepart{three}#3}
\begin{document}
\begin{forest}
for tree={
parent anchor=south, child anchor=north,
font=\ttfamily,
align=center,
align=center,
node options={table=3},
},
[
% [{a\nodepart{two}b\nodepart{three}c}]% doesn't work either
% [\vals{a}{b}{c}]% doesn't work
[\valsnx{a}{b}{c}]% works but doesn't produce the \nodepart structure I'm looking for
[]
]
\end{forest}
\end{document}
我正在使用rectangle split
来生成类似表格的节点。但是,当我尝试生成使用 拆分的内容时,\nodepart
我得到了! Missing \cr inserted.
。
我怀疑是扩展问题。有些行中的内容表明,在解析森林时,我的宏\vals
被扩展,然后\nodeparts
在随后解析森林时被扩展,因此产生了错误。尝试\noexpand
在宏中放置一个(以及放在宏本身上,如\noexpand\vals
),但没有成功。
有人可以解释一下我遗漏了什么吗?我该如何解决?
答案1
此代码是为森林版本 1. 它无需修改就可以与版本 2 一起编译,并且输出相同(据我所知)。
为什么要给自己找麻烦?align
设置表格标题。多行节点只是表格中的森林树。center
,left
并right
设置一个适当的表格标题。
如果你不想使用默认选项,你可以使用其他选项。例如,我定义了一个新的森林风格,forest table
:
\forestset{
forest table/.style={
align={|C{#1}|},
inner sep=0pt,
before typesetting nodes={
if content={}{
shape=coordinate
}{},
},
draw
},
}
这里的关键设置是align
使用包中C
定义的自定义列类型列:\newcolumntype{}{}
array
\newcolumntype{C}[1]{>{\centering\arraybackslash}p{#1}}
如果你总是想要相同的宽度,你可以说
forest table/.style={
align={|C{10mm}|},
...
或者其他任何形式。
其余设置只是为了确保绘制的分支符合表格边界,从而使输出更漂亮(在我看来):
inner sep=0pt,
...
draw
并且空节点平滑地集成到绘制的边中:
before typesetting nodes={
if content={}{
shape=coordinate
}{},
},
然后,您可以在节点中使用\hline
等来创建水平线,并将命令定义为值的包装器,该包装器仅插入行结尾和规则。例如,我使用了
\newcommand{\vals}[3]{\hline#1\\\hline#2\\\hline#3\\\hline}
然后
\begin{forest}
for tree={
forest table=10mm
}
[
[\vals{a}{b}{c}]
]
\end{forest}
将产生一棵树如下:
如果您希望节点中有一个空表,同时还允许真正为空的节点,则此方法可以正常工作:
\begin{forest}
for tree={
parent anchor=south,
child anchor=north,
font=\ttfamily,
forest table=25mm,
edge path={
\noexpand\path [\forestoption{edge}] (!u.parent anchor) -- +(0,-5pt) -| (.child anchor)\forestoption{edge label};
}
},
[\vals{}{}{}
[\vals{a}{b}{c}
[
[\vals{Node above}{deliberately}{left empty}]
]
]
[\vals{d}{e}{f}]
]
\end{forest}
生产
虽然你的问题没有提到这一点,但你在评论中建议你希望空节点成为空表。这相对简单。我们可以用forest tables=<width>
与样式相同的方式定义样式forest table=<width>
。事实上,我们可以使用后者来定义前者。
像前面一样指定列的宽度,并将其传递给样式forest table
:
forest tables/.style={
forest table=#1,
如果节点没有内容,无论如何都在这里创建一个表格:
delay={
if content={}{
content={\vals{}{}{}},
}{}
}
这delay
确保如果节点确实有内容,它不会被空表覆盖。
}
然后
\begin{forest}
for tree={
parent anchor=south,
child anchor=north,
font=\ttfamily,
forest tables=10mm,
edge path={
\noexpand\path [\forestoption{edge}] (!u.parent anchor) -- +(0,-5pt) -| (.child anchor)\forestoption{edge label};
}
},
[
[\vals{a}{b}{c}
[
[\vals{Node above}{auto-}{filled}]
]
]
[\vals{d}{e}{f}]
]
\end{forest}
将产生
完整代码:
\documentclass[tikz,multi,border=5pt]{standalone}
\usepackage{array,forest}
\newcolumntype{C}[1]{>{\centering\arraybackslash}p{#1}}
\newcommand{\vals}[3]{\hline#1\\\hline#2\\\hline#3\\\hline}
\forestset{
forest table/.style={
align={|C{#1}|},
inner sep=0pt,
before typesetting nodes={
if content={}{
shape=coordinate
}{},
},
draw
},
forest tables/.style={
forest table=#1,
delay={
if content={}{
content={\vals{}{}{}},
}{}
}
}
}
\begin{document}
\begin{forest}
for tree={
forest table=10mm
}
[
[\vals{a}{b}{c}]
]
\end{forest}
\begin{forest}
for tree={
parent anchor=south,
child anchor=north,
font=\ttfamily,
forest table=25mm,
edge path={
\noexpand\path [\forestoption{edge}] (!u.parent anchor) -- +(0,-5pt) -| (.child anchor)\forestoption{edge label};
}
},
[\vals{}{}{}
[\vals{a}{b}{c}
[
[\vals{Node above}{deliberately}{left empty}]
]
]
[\vals{d}{e}{f}]
]
\end{forest}
\begin{forest}
for tree={
parent anchor=south,
child anchor=north,
font=\ttfamily,
forest tables=10mm,
edge path={
\noexpand\path [\forestoption{edge}] (!u.parent anchor) -- +(0,-5pt) -| (.child anchor)\forestoption{edge label};
}
},
[
[\vals{a}{b}{c}
[
[\vals{Node above}{auto-}{filled}]
]
]
[\vals{d}{e}{f}]
]
\end{forest}
\end{document}