我正在尝试使用复制以下树forest
。
这就是我得到的
除了稍微放错位置的标签Pass
(我可以通过传递elo={xshift=<n>pt,yshift=<n>pt
到相关分支进行调整)之外,我更感兴趣的是获取正确的分支的方向/角度。
理想情况下,我希望
- 所有
Take
树枝都以一定程度生长-90
(而不是像现在这样稍微多一点,也不平行), - 分支
Pass
以程度增长0
(我现在可以通过手动将每个分支放到before computing xy={l=0,s=15mm}
其中来获得这个,这是在这个答案,但如果存在的话,我想知道一个不太麻烦的解决方案)。
平均能量损失
\documentclass[border=2pt]{standalone}
\usepackage{forest}
\forestset{
declare toks={elo}{}, % Edge Label Options
anchors/.style={anchor=#1,child anchor=#1,parent anchor=#1},
dot/.style={tikz={\draw[#1] (.child anchor) circle[radius=1.5pt];}},
decision edge label/.style n args=3{
edge label/.expanded={node[midway,auto=#1,anchor=#2,\forestoption{elo}]{\strut\unexpanded{#3}}}
},
decision/.style={if n=1
{decision edge label={left}{east}{#1}}
{decision edge label={right}{west}{#1}}
},
game tree/.style={
for tree={
s sep=0mm,l=15mm,
if n children=0{anchors=north}{
if n=1{anchors=south east}{anchors=south west}},
math content,
/tikz/font=\footnotesize,
},
anchors=south,
dot={fill=white},for descendants={dot={fill}},
delay={for descendants={split option={content}{;}{decision,content}}},
},
}
\begin{document}
\begin{forest}
game tree
[A,
[Take;{(4,2)},]
[Pass;B,before computing xy={l=0,s=15mm},elo={xshift=-10pt,yshift=5pt}
[Take;{(2,8)}]
[Pass;A,before computing xy={l=0,s=15mm}
[Take;{(16,4)}]
[Pass;B,before computing xy={l=0,s=15mm}
[Take;{(8,32)}]
[Pass;{(64,16)},before computing xy={l=0,s=15mm}]
]
]
]
]
\end{forest}
\end{document}
编辑
经过一番折腾,我终于弄对了角度(基本上是before computing xy
为每个分支指定角度)。但我这样做的方式似乎太过黑客化,几乎失去了forest
吸引力:自动定位节点以避免重叠。我可以用这么多代码在 TikZ 中绘制树。
\begin{forest}
game tree
[A,
[Take;{(4,2)},before computing xy={l=15mm,s=0mm}]
[Pass;B,before computing xy={l=0,s=15mm},elo={xshift=-10pt,yshift=5pt},anchors=south
[Take;{(2,8)},before computing xy={l=15mm,s=0mm}]
[Pass;A,before computing xy={l=0,s=15mm},elo={xshift=-10pt,yshift=5pt},anchors=south
[Take;{(16,4)},before computing xy={l=15mm,s=0mm}]
[Pass;B,before computing xy={l=0,s=15mm},elo={xshift=-10pt,yshift=5pt},anchors=south
[Take;{(8,32)},before computing xy={l=15mm,s=0mm}]
[Pass;{(64,16)},before computing xy={l=0,s=15mm},elo={xshift=-10pt,yshift=5pt}]
]
]
]
]
\end{forest}
我仍在寻找更有效的方法来实现这一目标。
答案1
这可能不是最有效的方法,但可能比手动放置所有内容更好。
关键思想是以反映预期结果的方式指定树的生长方向,而不是让它朝着不适当的方向生长,然后再覆盖它。
因此,将生长角度指定为 是有意义的-45
。
我们基本上希望每个子项+/-45
与生长方向成 度。这会将边缘置于0
和-90
。我们希望这些角度固定,因此我们需要calign=fixed edge angles
作为我们的放置策略。
然后,我们删除所有手动放置的内容,让 Forest 自行完成,只需edge label
适当调整 s 的位置即可。
在这种情况下,如果没有令人信服的理由不这样做,将content
节点的变成label
选项并将节点变成实心圆也更容易。这样就无需使用来tikz
绘制圆圈。
为了将根节点与其余节点一起处理,我们可以将内容更改为;A
。我们还需要为label
s 指定数学,因为这些不再由 覆盖math content
。事实上,math content
现在什么也不做,因为节点本身不包含任何内容:它全部被拆分成edge label
s 或label
s。
如果您的节点很大且大小不一,最好不要将内容转换为label
s。但是,在这棵树中,内容很小、紧凑且相对一致:成对的值below
无论如何都会出现,它们有足够的空间,其余的是可以轻松容纳的单个字母。如果您的真实树不是这样的,请告诉我,我可以修改答案以避免使用label
。
\documentclass[border=10pt,multi,tikz]{standalone}
\usepackage{forest}
\forestset{
decision edge label/.style n args=3{
edge label/.expanded={
node [midway, #1, anchor=#2] {\strut\unexpanded{#3}}
},
},
decision/.style={
if n=1{% Take
decision edge label={left}{east}{#1},
}{% Pass
decision edge label={above}{south}{#1},
}
},
game tree/.style={
for tree={
/tikz/font=\footnotesize,
grow=-45,
calign angle=45,
calign=fixed edge angles,
},
before typesetting nodes={
for tree={
split option={content}{;}{decision,node label},
delay={
content=,
circle,
draw,
if level=0{fill=white}{fill},
inner sep=1.5pt,
},
},
},
},
node label/.style={
if={
> O_= O_= | {n}{1}{n children}{0}%
}{
label=below:{$#1$},
}{
label=above:{$#1$},
},
},
}
\begin{document}
\begin{forest}
game tree,
[;A,
[Take;{(4,2)},]
[Pass;B
[Take;{(2,8)}]
[Pass;A
[Take;{(16,4)}]
[Pass;B
[Take;{(8,32)}]
[Pass;{(64,16)}]
]
]
]
]
\end{forest}
\end{document}
答案2
另一个解决方案istgame
包。你可以像 一样控制树的生长方向\setistgrowdirection{-45}
。
\documentclass{standalone}
\usepackage{istgame}
\begin{document}
\begin{istgame}[font=\footnotesize]
\setistgrowdirection{-45}
\xtdistance{15mm}{30mm}
\istroot(0)[initial node]{A}
\istb{Take}[l]{4,2}[b]
\istb{Pass}[a]
\endist
\istroot(1)(0-2){B}
\istb{Take}[l]{2,8}[b]
\istb{Pass}[a]
\endist
\istroot(2)(1-2){A}
\istb{Take}[l]{16,4}[b]
\istb{Pass}[a]
\endist
\istroot(3)(2-2){B}
\istb{Take}[l]{8,32}[b]
\istb{Pass}[a]{64,16}[r]
\endist
\end{istgame}
\end{document}