在森林中的多行模式 ( align=center
) 下,节点周围有额外的垂直空间。下面的第一棵树不是多行模式。第二棵树是多行模式,节点文本上方和下方都有额外的空间,即使只有一行。我怎样才能让第二棵树看起来像第一棵树?(我的实际树中的许多节点确实有多行,这就是我使用多行的原因。)
\documentclass{standalone}
\usepackage{forest}
\begin{document}
\begin{forest}
[A, for tree={parent anchor=south, child anchor=north, draw}
[B]
[C
[D]
[E]
]
]
\end{forest}
\begin{forest}
[A, for tree={parent anchor=south, child anchor=north, align=center, draw}
[B]
[C
[D]
[E]
]
]
\end{forest}
\end{document}
我尝试减少inner ysep
,它最初似乎有帮助(节点文本周围的空间较小但仍然偏离中心),但后来我遇到了一些节点重叠的问题:
\documentclass{standalone}
\usepackage{forest}
\begin{document}
\begin{forest}
[A, for tree={draw, parent anchor=south, child anchor=north, align=center, inner ysep=1pt }
[B\\long node]
[C
[D\\long multiline, triangle]
]
]
\end{forest}
\end{document}
我还应该提到,我没有使用方框draw
来框住真实树中的节点,只是使用裸节点文本。我在这里使用它是因为它可以清楚地表明,问题在于节点大小,而不是边缘位置。这个额外的空间使边缘看起来离节点更远,而不是节点更高。
答案1
这是一个 hack。它提供了照原样没有任何保证。我甚至不保证它与森林、多行节点或 TeX。在这一点上,如果不清楚,我应该声明我什么都不保证。如果代码拨打了 CIA、MI5 和 KGB 的电话,并向他们提供你的猫以换取一管 Smarties,不要说我没有警告过你。
买者自负...
想法如下:
如果我们将 放入
tabular
未使用align
来创建多行节点的树中的节点中,我们将获得与使用 相同的结果align
。但是,tabular
本身不会添加垂直空间,因此我们不能将该空间设置为 0,因为它已经为零。如果我们将 放入
minipage
同一棵树中的节点中,则间距与将 的内容单独放入节点中相同minipage
。(假设节点只有一行。)因此,如果我们可以将多行节点创建为
minipage
s 而不是tabular
s,那么它就可以按预期工作。(亲爱的读者,是否符合预期,就留给您自己决定吧。)
这并不像听起来那么简单,因为minipage
与 不同,tabular
需要宽度,而我们不想为树中的所有节点设置宽度。
当然,有更简单的方法可以做到这一点,而且毫无疑问还有更有效的方法。尤其是 TeX 专家可能会做得更好。
在这一点上,请温柔的读者再次阅读上面有关保证以及对所有读者的猫(无论多么温柔)的危险的声明。
我们首先为squat multiline
这种树创建一种新样式:
\forestset{
squat multiline/.style={
我们需要一些定制森林选项:
declare dimen={thiswidth}{0pt},
declare autowrapped toks={thiscontent}{},
现在我们开始操作节点。我们循环执行此操作,以确保在为每个节点处理下一组密钥之前,为每个节点处理完每组密钥。
for tree={
delay={
这是第一轮:
thiscontent/.wrap pgfmath arg={##1}{content()},
实际上,这会保存节点的内容。基本上,它会复制它。我们延迟此操作,否则当我们尝试复制它时,内容将不会被设置。
},
现在进入下一轮:
delay+={
content/.wrap value={\begin{tabular}{@{}c@{}}##1\\\end{tabular}},
这会将内容包装在tabular
类似于 使用的环境中align=center
。我们将使用它来获取 的宽度minipage
。
typeset node,
我们现在排版节点,比平时更早,因为接下来我们需要获取宽度。
},
决赛轮:
before typesetting nodes={
我们thiswidth
使用节点当前的宽度进行设置。
thiswidth/.wrap pgfmath arg={##1}{int(abs(max_x()-min_x()))},
minipage
现在我们重置宽度为 的a 中节点的内容thiswidth
。我们使用来自的内容的副本,thiscontent
因为否则我们也会得到tabular
包装器。
content/.wrap pgfmath arg={\begin{minipage}[t]{\dimexpr\forestove{thiswidth}}\centering ##1\end{minipage}}{thiscontent()},
我们已经得到了一批,inner xsep
因为它在我们最初排版节点时就已包含。因此我们将其设置为 0,以避免得到两倍于通常的数量:
inner xsep=0pt,
我们需要告诉森林重新排版节点:
typeset node,
},
只是原始示例中的常见锚点:
parent anchor=south,
child anchor=north,
},
}
}
现在我们可以使用新的样式了。第一个例子比较了默认间距与squat multiline
节点内容相同时使用的间距:
\begin{forest}
for tree={draw}
[, phantom
[A, for tree={parent anchor=south, child anchor=north}
[B]
[C
[D]
[E]
]
]
[A, squat multiline
[B]
[C
[D]
[E]
]
]
]
\end{forest}
然后是具有较大节点和屋顶的示例:
\begin{forest}
for tree={draw},
squat multiline
[A,
[B\\long node]
[C
[D\\long multiline, triangle]
]
]
\end{forest}
这种风格似乎并不是造成这里屋顶轻微错位的原因,当我将默认风格与绘制的节点进行比较时,也遇到了同样的问题。
比较:
无论如何,我认为屋顶的组合不太draw
可能是理想的,并且错位只会被注意到,因为节点是为了说明目的而绘制的。
完整代码:
\documentclass[multi,tikz,border=10pt]{standalone}
\usepackage{forest}
\begin{document}
\forestset{
squat multiline/.style={
declare dimen={thiswidth}{0pt},
declare autowrapped toks={thiscontent}{},
for tree={
delay={
thiscontent/.wrap pgfmath arg={##1}{content()},
},
delay+={
content/.wrap value={\begin{tabular}{@{}c@{}}##1\\\end{tabular}},
typeset node,
},
before typesetting nodes={
thiswidth/.wrap pgfmath arg={##1}{int(abs(max_x()-min_x()))},
content/.wrap pgfmath arg={\begin{minipage}[t]{\dimexpr\forestove{thiswidth}}\centering ##1\end{minipage}}{thiscontent()},
inner xsep=0pt,
typeset node,
},
parent anchor=south,
child anchor=north,
},
}
}
\begin{forest}
for tree={draw}
[, phantom
[A, for tree={parent anchor=south, child anchor=north}
[B]
[C
[D]
[E]
]
]
[A, squat multiline
[B]
[C
[D]
[E]
]
]
]
\end{forest}
\begin{forest}
for tree={draw},
squat multiline
[A,
[B\\long node]
[C
[D\\long multiline, triangle]
]
]
\end{forest}
\end{document}