我正在尝试绘制一棵组合树,从第 1 级的 n_1 条边开始,从第 2 级的 n_2 条边开始,...,从第 k 级的 n_k 条边开始。如下所示:
我从这个站点找到了二叉树的代码:
\documentclass[margin=10pt]{standalone}
\usepackage{tikz}
\usepackage{tikz-qtree}
\usetikzlibrary{trees,calc,arrows.meta,positioning,decorations.pathreplacing,bending}
\tikzset{
edge from parent/.style={draw, thick, blue!70!black},
no edge from this parent/.style={
every child/.append style={
edge from parent/.style={draw=none}}},
level 3/.style={yshift=5cm},
level 4/.style={level distance=5mm}
}
\begin{document}
\begin{tikzpicture}[
level/.style={sibling distance=40mm/#1},
text=black!70!black,>=latex,
font=\sffamily
]
\node (z){1}
child {node (a) {2}
child {node (b) {3}
child {node (b1) {$\vdots$}[no edge from this parent]
child {node (b11) {k}}
}
child {node (b2) {$\vdots$}[no edge from this parent]
child {node (b12) {k}}
}
}
child {node (g) {3}
child {node (g1) {$\vdots$}[no edge from this parent]
child {node (g11) {k}}
}
child {node (g2) {$\vdots$}[no edge from this parent]
child {node (g12) {k}}
}
}
}
%child{node(h) {2}[no edge from this parent]{2}}
child {node (d) {2}
child {node (e) {3}
child {node (e1) {$\vdots$}[no edge from this parent]
child {node (e11) {k}}
}
child {node (e2) {$\vdots$}[no edge from this parent]
child {node (e12) {k}}
}
}
child {node (f) {3}
child {node (f1) {$\vdots$}[no edge from this parent]
child {node (f11) {k}}
}
child {node (f2) {$\vdots$}[no edge from this parent]
child {node (f12) {k}
}
}
}
};
\node[left=5 of z] (ln1) {$n_1$ ways}[no edge from this parent]
child {node (ln2) {$n_2$ ways}[no edge from this parent]
child {node (ln3) {$n_3$ ways}[no edge from this parent]
child {node (ln4) {}[no edge from this parent]
child {node (ln5) {$n_k$ ways}}}}};
%\path (b12.north east) -- (g11.north west) node {$\cdots$};
%\path (e12.north east) -- (f11.north west) node [midway] {$\cdots$};
\coordinate (cd1) at ($(f12)+(1,0)$);
\coordinate (nb1) at ($(g12)!.5!(e11)$);
%\draw[blue!70!black,thick,<->,]
%(cd1) -- (cd1|-z.east) node [near start, fill=white] {log(n)};
\draw[black!70!black,dashed,thick,->]
($(z.west)+(-1em,0)$) -- (ln1);
\draw[black!70!black,dashed,thick,->]
($(a.west)+(-1em,0)$) -- (ln2.east);
\draw[black!70!black,dashed,thick,->]
($(b.west)+(-1em,0)$) -- (ln3);
\draw[black!70!black,dashed,thick,->]
($(b11.west)+(-1em,0)$) -- (ln5);
\draw[black!70!black,thick,decorate,decoration={brace,amplitude=10pt,mirror},->,-{latex[flex=1pt]}] (b11.south west) -- (f12.south east);
\end{tikzpicture}
我尝试编辑此代码以满足我的需求,但无法使代码正常工作。此外,我不确定此代码是否可以推广到带有 vdots 的 n 级。我还需要显示每个级别的边数。
请帮忙。
答案1
我注意到您的示例没有显示任何试图按您的意愿修改树的迹象。甚至节点的内容也没有改变以反映您的目标图像。
无论如何,虽然我不应该回答这个问题,但我还是要回答。至少,我回答了我感兴趣的方面。进一步的修改留给你,亲爱的读者,在闲暇时完成。
我认为,只要向 Forest 输入所需的数字,就可以自动绘制。但是,只有当我想绘制几个具有不同级别/兄弟等数量的图时,我才会费心这样做。
这里唯一棘手的部分是制作弧的样式,它测试我们是否处于第 1 级以及当前节点是否是其父节点的最后一个子节点,然后据此继续,并且修补的定义nice empty nodes
需要解决 Forestlinguistics
库中的错误,但这里也做了一些调整,以确保在构建树的过程中不会过早完成事情。(其中一些可以简化,因为我在玩的时候做了一些可能不再需要的事情。)
这里有一些关于弧的解释,它们不仅仅是错误解决方法的扩展。
mk arc/.style n args=2{
tikz+={
\draw [-{Stealth[bend]}] ($(!u.parent anchor)!1/5!(!u1.child anchor)$) [out=-30, in=-150] to ($(!u.parent anchor)!1/5!(!ul.child anchor)$) node [right] {$n_#1$ #2} ;
}
},
mk arc
只需要 2 个参数:一个下标数字和一个附加注释(可能为空)。然后,它会在当前节点的父节点的第一个子节点和最后一个子节点之间绘制带有箭头的弧,并附加相关标签。
make arc/.style={
if level=1{
mk arc={1}{options for choice 1}
}{
mk arc/.wrap 2 pgfmath args={{##1}{##2}}{(n_children()==0) ? ("k") : level()}{((n("!u"))==(n_children("!uu"))) ? strcat(strcat("options for choice $",((n_children()==0) ? ("k") : level())),"$") : ""}
},
},
make arc
mk arc
通过考虑我们在树中的位置来确定应该传递哪些参数。然后它将这些参数传递给mk arc
绘制和注释弧形箭头的函数。
完整代码:
\documentclass[border=10pt,tikz,multi]{standalone}
\usepackage[linguistics]{forest}
\usetikzlibrary{arrows.meta,bending,calc}
\forestset{%
mk arc/.style n args=2{
tikz+={
\draw [-{Stealth[bend]}] ($(!u.parent anchor)!1/5!(!u1.child anchor)$) [out=-30, in=-150] to ($(!u.parent anchor)!1/5!(!ul.child anchor)$) node [right] {$n_#1$ #2} ;
}
},
make arc/.style={
if level=1{
mk arc={1}{options for choice 1}
}{
mk arc/.wrap 2 pgfmath args={{##1}{##2}}{(n_children()==0) ? ("k") : level()}{((n("!u"))==(n_children("!uu"))) ? strcat(strcat("options for choice $",((n_children()==0) ? ("k") : level())),"$") : ""}
},
},
nice empty node/.style={% override buggy version of nice empty nodes supplied by Forest & modify for this case
delay={
if content={}{%
shape=coordinate,
for nodewalk={%
Nodewalk={%
on invalid=fake,
}{%
parent,
}{%
for children={anchor=north},
}
}{},
}{},
}
},
nice empty nodes/.style={%
before packing={
for tree={calign=fixed edge angles},
},
before typesetting nodes={
for tree={
nice empty node,
}
},
},
}
\begin{document}
\begin{forest}
nice empty nodes,
for tree={
fit=band,
},
[
[, make arc
[, make arc
[, edge=densely dotted
[, make arc]
[]
[]
[]
[]
]
[, phantom]
]
[[, edge=densely dotted]]
[[, edge=densely dotted]]
[[, edge=densely dotted]]
[[, edge=densely dotted]]
[[, edge=densely dotted]]
[[, edge=densely dotted]]
]
[[, edge=densely dotted]]
[[, edge=densely dotted]]
[[, edge=densely dotted]]
[
[[, edge=densely dotted]]
[[, edge=densely dotted]]
[[, edge=densely dotted]]
[[, edge=densely dotted]]
[[, edge=densely dotted]]
[[, edge=densely dotted]]
[, make arc
[, phantom]
[, edge=densely dotted
[, make arc]
[]
[]
[]
[, label=-45:$n_1\cdot n_2 \cdot\ldots n_k$]
]
]
]
]
\end{forest}
\end{document}