我正在尝试创建一个简单的层次结构,但无法让forest
包完全按照我的要求执行。这是我目前所拥有的:
\documentclass[border=5pt]{standalone}
\usepackage{forest}
\begin{document}
\forestset{
nolabel/.style={% abbreviation for Edge Label
edge label={node[midway, font=\small, text=black,
fill=white, inner sep=2pt]{}},
}
}% end of forestset
\begin{forest}
for tree={
parent anchor=south,
child anchor=north,
anchor=north,
calign=first,
s sep = 0,
edge path={
\noexpand\path [draw, \forestoption{edge}]
(!u.east) +(-2pt,-5pt) -| node[fill,circle,inner sep=1.25pt] {} (.child anchor)\forestoption{edge label};
},
before typesetting nodes={
if n=1
{insert before={[,phantom]}}
{}
},
fit=band,
before computing xy={l=20pt},
}
[ $A$
[$a_1$]
[$\cdots$, nolabel]
[$a_2$
[$b_1^{(1)}$]
[$b_2^{(1)}$
[$c_1^{(2)}$]
[$c_2^{(2)}$]
[$c_3^{(2)}$]
]
[$b_3^{(1)}$
[$c_4^{(2)}$]
[$c_5^{(2)}$]
[$c_6^{(2)}$]
]
]
[$\cdots$, nolabel]
]
\end{forest}
\end{document}
使用no label
样式,我设法删除了省略号节点顶部的圆圈,但我仍然有边缘(红色圆圈)。我无法使用no edge
找到的选项将其删除在这篇文章中。另外,我不明白为什么第一层和第二层的边的长度不同(红色矩形),所以我想知道是否有解决方法可以使这些长度相等。
答案1
如果我们加载库,Forest 已经有一个绘制直边树的选项edges
。forked edges
然后启用树的样式。但是,在我们的例子中,我们不需要 3 部分路径,而只需要 2 部分路径。要消除第一个“腿”,我们可以设置fork sep'=0pt
。为了在不进行手动调整的情况下获得正确的对齐,我们可以设置parent anchor=south east
。
树有三种基本类型的节点:
- true
phantom
,自动插入; - 节点
\cdots
只需要路径的第二个“腿”,而不需要第三个,并且没有圆圈; - 其他节点需要第二条和第三条“腿”,以及圆圈。
Forest 已经将第一种类型与其他两种类型区分开来,因此我们只需创建一个选项来区分第二种和第三种。我这样称呼phantom edge
并不完全准确。(也许partial edge
会更好?)
declare boolean={phantom edge}{0},
默认情况下为 false。我们将其添加phantom edge
到需要此样式的节点。
处理圆/无圆的最直接的方法是利用选项,edge label
而不是将圆直接硬编码到边缘规范中。
edge label={node[midway,fill,circle,inner sep=1.25pt]{}},
我一开始是选择性地应用它,但最终决定普遍应用它并稍后选择性地覆盖该应用程序更有意义。
我们使用新的布尔值来调整edge path
和,edge label
同时插入真正的幻影。我们将其取出for tree
以使代码更清晰,并使用where
来if
覆盖整个树。
before typesetting nodes={%
where n=1{%
insert before={[,phantom]}
}{%
+content=\strut,
添加\strut
所有地方(除了真实的幻影)会让我们得到统一的节点高度。
if phantom edge={%
edge path'={(!u.parent anchor) -- (.child anchor -| !u.parent anchor)},
请注意使用edge path'
而不是 来edge path
简化代码并避免重复标准包装器。还请注意,使用child anchor
和parent anchor
会使代码更灵活一些,以防我们以后需要进行调整。
edge label={},
这将删除edge label
我们的第二种节点类型(即圆形节点)。
}{%
对于第三种类型,无需执行任何操作,因为它们只是使用我们已经设置的默认值。
},
},
},
对于父节点和子节点之间的分离,我将 的更改l
从 中移除for tree
。这确保为所有节点(包括插入节点)设置该选项,而原始代码并未将其应用于插入节点。l sep
也比 更接近我们在这里想要的l
,但我们需要更早一点设置它才能使其生效。
before packing={%
for tree={l sep'=-5pt},
},
由于我不明白的原因,这些变化不足以规范路径第三“段”的长度。但是,添加text height=1em
似乎for tree
有效,即使我不确定它在做什么。
最后,我将所有内容包装成一种样式tree lines
,以将树规范与用于排版的样式分开。
\forestset{%
declare boolean={phantom edge}{0},
tree lines/.style={%
forked edges,
for tree={%
fork sep'=0pt,
math content,
parent anchor=south east,
anchor=north,
calign=first,
s sep' = 0pt,
text height=1em,
fit=band,
edge label={node[midway,fill,circle,inner sep=1.25pt]{}},
},
before typesetting nodes={%
where n=1{%
insert before={[,phantom]}
}{%
+content=\strut,
if phantom edge={%
edge path'={(!u.parent anchor) -- (.child anchor -| !u.parent anchor)},
edge label={},
}{%
},
},
},
before packing={%
for tree={l sep'=-5pt},
},
},
}% end of forestset
完整代码:
\documentclass[border=5pt]{standalone}
% ateb: https://tex.stackexchange.com/a/704927/ addaswyd o gwestiwn aaragon: https://tex.stackexchange.com/q/598942/
\usepackage[edges]{forest}
\forestset{%
declare boolean={phantom edge}{0},
tree lines/.style={%
forked edges,
for tree={%
fork sep'=0pt,
math content,
parent anchor=south east,
anchor=north,
calign=first,
s sep' = 0pt,
text height=1em,
fit=band,
edge label={node[midway,fill,circle,inner sep=1.25pt]{}},
},
before typesetting nodes={%
where n=1{%
insert before={[,phantom]}
}{%
+content=\strut,
if phantom edge={%
edge path'={(!u.parent anchor) -- (.child anchor -| !u.parent anchor)},
edge label={},
}{%
},
},
},
before packing={%
for tree={l sep'=-5pt},
},
},
}% end of forestset
\begin{document}
\begin{forest}
tree lines,
[ A
[a_1]
[\cdots, phantom edge]
[a_2
[b_1^{(1)}]
[b_2^{(1)}
[c_1^{(2)}]
[c_2^{(2)}]
[c_3^{(2)}]
]
[b_3^{(1)}
[c_4^{(2)}]
[c_5^{(2)}]
[c_6^{(2)}]
]
]
[\cdots, phantom edge]
]
\end{forest}
\end{document}
答案2
您的nolabel
代码需要更改edge path
而不是edge label
。为起始坐标命名,例如ZZ
,然后使用正交坐标(ZZ-|.child anchor)
绘制水平部分但不绘制垂直部分。
为了使不同级别的垂直边缘保持一致,请添加minimum height=6mm, inner ysep=0pt
。
\documentclass{article}
\usepackage{forest}
\begin{document}
\forestset{
nolabel/.style={
edge path={
\noexpand\path [draw, \forestoption{edge}]
(!u.east) +(-2pt,-5pt) coordinate(ZZ) -- (ZZ-|.child anchor)\forestoption{edge label};
}
}
}% end of forestset
\begin{forest}
for tree={
anchor=north,
calign=first,
s sep = 0,
edge path={
\noexpand\path [draw, \forestoption{edge}]
(!u.east) +(-2pt,-5pt) -| node[fill,circle,inner sep=1.25pt] {} (.child anchor)\forestoption{edge label};
},
before typesetting nodes={
if n=1
{insert before={[,phantom]}}
{}
},
fit=band,
before computing xy={l=20pt},
minimum height=6mm, inner ysep=0pt
}
[ $A$
[$a_1$]
[$\cdots$, nolabel]
[$a_2$
[$b_1^{(1)}$]
[$b_2^{(1)}$
[$c_1^{(2)}$]
[$c_2^{(2)}$]
[$c_3^{(2)}$]
]
[$b_3^{(1)}$
[$c_4^{(2)}$]
[$c_5^{(2)}$]
[$c_6^{(2)}$]
]
]
[$\cdots$, nolabel]
]
\end{forest}
\end{document}