我想用 Latex 和森林绘制决策树。因此,我找到了以下相关问题,请参阅 如何绘制正确的决策树
所选答案基本满足了我的需求。但是,我无法重现输出。
\documentclass[margin=10pt]{standalone}
\usepackage{tikz,forest}
\usetikzlibrary{arrows.meta}
\forestset{
.style={
for tree={
base=bottom,
child anchor=north,
align=center,
s sep+=1cm,
straight edge/.style={
edge path={\noexpand\path[\forestoption{edge},thick,-{Latex}]
(!u.parent anchor) -- (.child anchor);}
},
if n children={0}
{tier=word, draw, thick, rectangle}
{draw, diamond, thick, aspect=2},
if n=1{%
edge path={\noexpand\path[\forestoption{edge},thick,-{Latex}]
(!u.parent anchor) -| (.child anchor) node[pos=.2, above] {Y};}
}{
edge path={\noexpand\path[\forestoption{edge},thick,-{Latex}]
(!u.parent anchor) -| (.child anchor) node[pos=.2, above] {N};}
}
}
}
}
\begin{document}
\begin{forest}
[$x_2$, tikz={\draw[{Latex}-, thick] (.north) --++ (0,1);}
[$x_1$
[1]
[0]
]
[$x_3$
[$x_1$
[1]
[0]
]
[0]
]
]
\end{forest}
\end{document}
使用提供的源代码,结果是:
然而,将语句集成for tree
到森林块中效果更好,但不会产生预期的输出。箭头与节点重叠。
有关所用版本的一些信息
操作系统:Ubuntu 17.10
森林:v2.1.5
Tikz:v3.0.1a
我已经查看了森林的当前文档,但没有发现森林当前版本发生变化的内容。
所以,我的主要问题是:
- 我如何陈述森林树木的全球配置?
- 为什么
\forestset
不能正常工作?
提前致谢。
答案1
.style
从未得到支持,而且据我了解(来自 Forest 手册,其中详细记录了这一变化),它从未正常工作过。在 Forest 的当前版本中,它根本不起作用,但是default preamble
,正如 Jasper Habicht 提到的,它可以工作。
如果您希望将此作为默认样式,我假设您会多次使用它。在这种情况下,我会简化代码并尝试使其尽可能灵活和自动化。特别是,我会尝试避免硬编码尺寸以避免冲突,而是通过以forest
找出合理布局的方式来处理问题。
我认为,这可以通过利用一些提供的专用增长方向感知锚点来实现。(其中许多在软件包的 1 版中并不存在。)
例如,您可能会考虑以下内容。
\forestset{
default preamble={
before typesetting nodes={
!r.replace by={[, coordinate, append]}
这将自动添加一个假根,这样上面的箭头就不需要手动绘制了。这有助于防止在编辑过程中出现线宽和距离等不一致的情况。
},
where n children=0{
tier=word,
}{
diamond, aspect=2,
},
这本质上是原始代码,经过精简,用于将终端节点与其他节点区别对待。
where level=0{}{
不要对第一个节点(这是实际的、原始的根)做任何事情,因为我们不想在这里使用标签。
if n=1{
edge label={node[pos=.2, above] {Y}},
}{
edge label={node[pos=.2, above] {N}},
}
这将设置标签。我不知道为什么您提供的代码没有使用,edge label
因为这个功能根本不是新的,而且在版本 1 中肯定可用。
},
for tree={
edge+={thick, -Latex},
一致的边缘。
math content,
这都是数学,所以我们不必一直打字$...$
。
s sep'+=1cm,
比原来快一点(在版本 1 中不可用)
draw,
thick,
edge path'={ (!u) -| (.parent)},
这可以避免摆弄硬编码的节点微调以使事物分散。edge path'
在版本 1 中不可用。它包装其参数以构造完整路径,包括edge label
(由于某种原因,您的问题中的代码将其消除)。.parent
此处指的是当前节点(即子节点)的锚点。它是其边界上朝向其父节点的一个点。(嗯,通常如此。)
通过使用!u
而不是特定的锚点,我们得到 Ti钾Z 来确定在菱形的边界上绘制的位置。这意味着我们不需要对左右分支进行不同的定义。这也意味着我们不必对指南针方向进行硬编码,因为这将根据树的生长方向等自动调整,就像这样.parent
做一样。
}
}
}
我们就完成了。
完整代码:
\documentclass[border=10pt]{standalone}
\usepackage{forest}
\usetikzlibrary{arrows.meta}
\forestset{
default preamble={
before typesetting nodes={
!r.replace by={[, coordinate, append]}
},
where n children=0{
tier=word,
}{
diamond, aspect=2,
},
where level=0{}{
if n=1{
edge label={node[pos=.2, above] {Y}},
}{
edge label={node[pos=.2, above] {N}},
}
},
for tree={
edge+={thick, -Latex},
math content,
s sep'+=1cm,
draw,
thick,
edge path'={ (!u) -| (.parent)},
}
}
}
\begin{document}
\begin{forest}
[x_2
[x_1
[1]
[0]
]
[x_3
[x_1
[1]
[0]
]
[0]
]
]
\end{forest}
\end{document}
答案2
首先,根据软件包文档,森林的正确默认样式(至少在 2+ 版本中)是default preamble
使用\forestset
。
(编辑:我刚刚读到您正在使用该forest
软件包的 2+ 版本。默认设置确实已从 1 版更改,这可能是代码未产生所需输出的原因。)
其次,为了使箭头不与节点重叠,您要么必须改变菱形的外观以使节点稍微窄一些,要么必须增加最低级别节点的距离。
\documentclass[margin=10pt]{standalone}
\usepackage{tikz,forest}
\usetikzlibrary{arrows.meta}
\forestset{
default preamble={
for tree={
base=bottom,
child anchor=north,
align=center,
s sep+=1cm, % or use: s sep +=1.5 cm ...
straight edge/.style={
edge path={\noexpand\path[\forestoption{edge},thick,-{Latex}]
(!u.parent anchor) -- (.child anchor);}
},
if n children={0}
{tier=word, draw, thick, rectangle}
{draw, diamond, aspect=1.25, thick}, % ... and retain: aspect=2
if n=1{%
edge path={\noexpand\path[\forestoption{edge},thick,-{Latex}]
(!u.parent anchor) -| (.child anchor) node[pos=.2, above] {Y};}
}{
edge path={\noexpand\path[\forestoption{edge},thick,-{Latex}]
(!u.parent anchor) -| (.child anchor) node[pos=.2, above] {N};}
}
}
}
}
\begin{document}
\begin{forest}
[$x_2$, tikz={\draw[{Latex}-, thick] (.north) --++ (0,1);}
[$x_1$
[1]
[0]
]
[$x_3$
[$x_1$
[1]
[0]
]
[0]
]
]
\end{forest}
\end{document}
使用s sep+=1cm
和aspect=1.25
:
…或者与s sep+=1.5cm
和aspect=2
: