答案1
我用了cfr 的精彩回答您似乎在问题中提到了这一点,并将其进一步扩展,以便可以在两个级别之间添加另一个节点:
\documentclass[border=10pt]{standalone}
% ateb: https://tex.stackexchange.com/a/703351/ i gwestiwn Arian: https://tex.stackexchange.com/q/703321/
\usepackage{forest}
\usetikzlibrary{arrows.meta}
\begin{document}
\begin{forest}
for tree={
circle,
fill=black,
edge={{Latex[length=6pt,width=3pt]}-},
grow'=north,
calign=fixed edge angles,
inner sep=0.5pt,
},
before typesetting nodes={
for tree={
my label/.option=content,
content={.},
}
},
additional/.style={
edge path/.process={ O+nn= ? p w1 {level}{0} {_{below}} {On= ? {n}{1} {left}{right}} {
\noexpand\path
(!u.parent anchor) -- (.child anchor)
node[midway, circle, fill=black, inner sep=0.5pt, label={##1:$#1$}] (m) {.};
\noexpand\path[\forestoption{edge}]
(!u.parent anchor) -- (m);
\noexpand\path[\forestoption{edge}]
(m) -- (.child anchor)
\forestoption{edge label};
}
}
},
my label/.style={
label/.process={ O+nn= ? p w1 {level}{0} {_{below}} {On= ? {n}{1} {left}{right}} {##1:{$#1$}} },
},
[g
[e
[c,additional={c'}
[a ]
[b ]
]
[d ]
]
[f,additional={f'} ]
]
\end{forest}
\end{document}
手动添加级别数字可能最容易。您只需在环境的最后放置\node
s即可。forest
是坐标默认等于级别,因此放置节点相当容易:
\documentclass[border=10pt]{standalone}
% ateb: https://tex.stackexchange.com/a/703351/ i gwestiwn Arian: https://tex.stackexchange.com/q/703321/
\usepackage{forest}
\usetikzlibrary{arrows.meta}
\begin{document}
\begin{forest}
for tree={
circle,
fill=black,
edge={{Latex[length=6pt,width=3pt]}-},
grow'=north,
calign=fixed edge angles,
inner sep=0.5pt,
},
before typesetting nodes={
for tree={
my label/.option=content,
content={.},
}
},
additional/.style={
edge path/.process={ O+nn= ? p w1 {level}{0} {_{below}} {On= ? {n}{1} {left}{right}} {
\noexpand\path
(!u.parent anchor) -- (.child anchor)
node[midway, circle, fill=black, inner sep=0.5pt, label={##1:$#1$}] (m) {.};
\noexpand\path[\forestoption{edge}]
(!u.parent anchor) -- (m);
\noexpand\path[\forestoption{edge}]
(m) -- (.child anchor)
\forestoption{edge label};
}
}
},
my label/.style={
label/.process={ O+nn= ? p w1 {level}{0} {_{below}} {On= ? {n}{1} {left}{right}} {##1:{$#1$}} },
},
[g
[e
[c,additional={c'}
[a ]
[b ]
]
[d ]
]
[f,additional={f'} ]
]
\foreach \l in {1,...,4} {
\node at (2,{\l-1}) {$\l$};
}
\node at (2,0.5) {$1\frac{1}{2}$};
\node at (2,1.5) {$2\frac{1}{2}$};
\node at (2,3.5) {Level};
\end{forest}
\end{document}
自动化解决方案会更加棘手,尤其是考虑到中间节点。
答案2
这个答案既尝试回答这个新问题,也纠正了我的答案到前一个. 虽然在原始示例,试图延伸我之前的回答画出树这个问题说明了一个问题。
暂时忽略中间节点和层标签,扩展树的基本结构的明显方法是
[g
[e
[c,
[a ]
[b_2 [, phantom][b_1]]
]
[d_3, [, phantom][d_2 [, phantom][d_1]]]
]
[f_5 [, phantom][f_4, [, phantom][f_3 [, phantom][f_2 [, phantom][f_1]]]] ]
]
结合我之前的回答的序言,我们发现了这个问题:
我们希望以下节点集水平对齐:
- b1--d1--f2
- a--b2--d2--f3
- c--b3--d3--f4
- d--f5
但是,只有最后一对是水平对齐的。在前三组节点中,f 节点低于其同层节点。
这是因为forest
尝试同时对齐层上的节点并确保fixed edge angles
直线。它执行其中一项,但在执行另一项时,它会部分撤消第一项。删除任何一个选项都会使我们离期望的结果越来越远。
基本上,将节点与层对齐和使用之间存在冲突fixed edge angles
。可以解决这个问题,但我不知道有什么现成的解决方案,所以它有点复杂。
这可能无法处理所有极端情况,但它应该能够更好地处理更多数量的边(和节点!)树。
\begin{forest}
aligned tree,
label tiers,
[g
[e
[c, double here
[a ]
[b_2 [, phantom][b_1]]
]
[d_3, double here [, phantom][d_2 [, phantom][d_1]]]
]
[f_5 [, phantom][f_4, double here [, phantom][f_3 [, phantom][f_2 [, phantom][f_1]]]] ]
]
\end{forest}
aligned tree
是我之前回答中发布的代码的修改版本,为了方便起见,将其变成了一种样式。当前版本declare
的自定义forest
选项并不总是在环境中起作用forest
,因此我发现事先设置好一切会更容易。
label tiers
标记级别,如果适用,则标记半级别。格式由样式定义决定,显然可以根据需要进行调整。
double here
导致插入一个附加节点。此节点不是树结构的一部分。它只是作为从父节点绘制边的一部分而构建的。因此,它与Jasper Habicht 的回答。
完整代码:
\documentclass[11pt]{book}
% atebion: https://tex.stackexchange.com/a/703530/ a https://tex.stackexchange.com/a/703351/ i gwestiwn Arian: https://tex.stackexchange.com/q/703321/
\usepackage{amsmath}
\usepackage{forest}
\usetikzlibrary{arrows.meta}
\forestset{%
declare toks={double content}{},
declare boolean={doubled level}{0},
my label/.style={%
label/.process={ O+nn= ? p w1 {level}{0} {_{below}} {On= ? {n}{1} {left}{right}} {##1:{$#1$}} },
},
my double label/.style 2 args={%
edge path'={%
(!u.parent anchor) edge node (a) [pos=1,inner sep=.5pt,circle,fill,label=#2:{$#1$}] {.} ($(!u.parent anchor)!.5!(.child anchor)$) (a) -- (.child anchor)
},
},
aligned tree/.style={%
for tree={
circle,
fill=black,
edge={{Latex[length=6pt,width=3pt]}-},
grow'=north,
calign=fixed angles,
inner sep=0.5pt,
},
before typesetting nodes={
for tree={%
my label/.option=content,
content={.},
tier/.process={Ow+n{level}{##1+1}},
},
},
align to tier,
},
double here/.style={%
content+={'},
double content/.option=content,
double content+={'},
before typesetting nodes={%
my double label/.process={ O Od< ? {double content} {x}{0pt} {left}{right} },
tempcountb/.option=level,
sort by={>O+n{id}},
for nodewalk={%
filter={root',descendants}{>O+nR={level}{tempcountb}},
}{doubled level},
},
},
align to tier/.style={%
before computing xy={%
tempdima/.max={l}{tree},
tempdimb/.max={s}{tree},
for descendants={%
l/.register=tempdima,
if={>Od>{s}{0pt}}{s/.register=tempdimb}{s=-\foresteregister{tempdimb}},
},
},
},
label tiers/.style={%
before drawing tree={%
tempcounta/.max={level}{tree},
tikz+={\node [level label,anchor=south west] (x) at ([xshift=15pt,yshift=5pt]current bounding box.north east) {Levels};},
for nodewalk={%
do until={>OR={level}{tempcounta}}{fake=next leaf},
do until={>O!{phantom}}{fake=next on tier},
current and ancestors
}{%
tikz+/.process={Ow{tier}{\node (tier label ##1) [level label] at (.center -| x.center) {$##1$};}},
if={>O{doubled level}}{%
tikz+/.process={Ow{level}{%
\path (!u.center -| x.center) -- (.center -| x.center) node [level label,midway] {$##1\frac{1}{2}$} ;
}%
}
}{},
},
},
},
/tikz/level label/.style={anchor=center,font=\sffamily},
}
\begin{document}
\begin{forest}
aligned tree,
label tiers,
[g
[e
[c, double here
[a ]
[b_2 [, phantom][b_1]]
]
[d_3, double here [, phantom][d_2 [, phantom][d_1]]]
]
[f_5 [, phantom][f_4, double here [, phantom][f_3 [, phantom][f_2 [, phantom][f_1]]]] ]
]
\end{forest}
\end{document}