我使用 Forest 版本 1 创建了下图:
\documentclass[tikz,border=10pt]{standalone}
\usepackage{forest-1}% forest v.1
\begin{document}
\begin{forest}
for tree={
font=\sffamily\scriptsize,
line width=1pt,
draw,
anchor=west,
child anchor=west,
parent anchor=east,
grow'=east,
align=center,
edge path={
\noexpand\path[line width=1pt, ->, \forestoption{edge}]
(!u.parent anchor) -| +(5pt,0) -- +(5pt,0) |- (.child anchor) \forestoption{edge label};
},
for={Lu}{if={n_children==1}{l sep+=10pt}{}},
},
where level={1}{s+=-20pt}{},
[Here\\Village, name=pc
[There village\\your bird, name=arid
]
[, phantom
[Bananas, name=fb, xshift=-15pt, where n children=0{tier=sk}{}
[Pineapple, name=sf
[Middling\\villages?, name=solar
[Current\\paper, name=cp, edge label={node [font=\sffamily\scriptsize, near end, auto, xshift=-1.5pt] {Imprudent}}
]
]
[Creative\\endearments?, name=apple
[Fantastic\\imaginations, name=su, edge label={node [font=\sffamily\scriptsize, near end, auto, xshift=-1.5pt] {Basic}}
]
]
[Heathen\\hopscotch?, name=pear
[Beneficent\\benevolence, name=cl, edge label={node [font=\sffamily\scriptsize, near end, xshift=-1.5pt, below] {Higher}}, edge={draw=none}
]
]
]
[Zoological, name=gf
[Orange\\kangaroos?, name=star
[Strawberry\\seeker, name=rs, edge label={node [font=\sffamily\scriptsize, near end, xshift=-1.5pt, below] {Lower}}
]
]
[Fragility of\\foundations?, name=hercules
[Memorial\\cooks, name=ws, edge label={node [font=\sffamily\scriptsize, near end, xshift=-1.5pt, below] {Earthling}}
]
]
[Best\\antelopes?, name=astro
[Stellar\\horizons, name=ca, edge label={node [font=\sffamily\scriptsize, near end, xshift=-1.5pt, below] {Martian}}
]
]
]
]
]
[Bad hollows\\spotty slugs, name=avid
]
]
\begin{scope}[line width=1pt, ->]
\draw (solar.east) -- (solar.east -| apple.east) -| +(5pt,0) -- +(5pt,0) |- (su.west);
\draw (apple.east) -| +(5pt,0) -- +(5pt,0) |- (cp.west);
\draw (pear.east) -- (pear.east -| apple.east) -| +(5pt,0) -- +(5pt,0) |- (cp.west);
\draw (pear.east) -- (pear.east -| apple.east) -| +(5pt,0) -- +(5pt,0) |- (su.west);
\draw (star.east) -- (star.east -| apple.east) -| +(5pt,0) -- +(5pt,0) |- (cl.west);
\draw (star.east) -- (star.east -| apple.east) -| +(5pt,0) -- +(5pt,0) |- (ws.west);
\draw (star.east) -- (star.east -| apple.east) -| +(5pt,0) -- +(5pt,0) |- (ca.west);
\draw (astro.east) -- (astro.east -| apple.east) -| +(5pt,0) -- +(5pt,0) |- (cl.west);
\draw (astro.east) -- (astro.east -| apple.east) -| +(5pt,0) -- +(5pt,0) |- (rs.west);
\draw (astro.east) -- (astro.east -| apple.east) -| +(5pt,0) -- +(5pt,0) |- (ws.west);
\draw (hercules.east) -- (hercules.east -| apple.east) -| +(5pt,0) -- +(5pt,0) |- (cl.west);
\draw (hercules.east) -- (hercules.east -| apple.east) -| +(5pt,0) -- +(5pt,0) |- (rs.west);
\draw (hercules.east) -- (hercules.east -| apple.east) -| +(5pt,0) -- +(5pt,0) |- (ca.west);
\draw (avid.north) -- (avid.north |- fb.south);
\draw (arid.south -| avid.north) -- (avid.north |- fb.north);
\end{scope}
\end{forest}
\end{document}
该代码无法与 Forest v.2 或更新版本编译,因为
for={Lu}{if={n_children==1}{l sep+=10pt}{}},
不再是有效代码:for
已被升级删除。
手册告诉我该键已重命名为for group
(第 85 页):
这些键已被重命名:
old new compat key (all but the last are in -most) ... for for group 1.0-for ...
我今天最终从幻灯片中删去了这张图表,因为我无法根据手册中的说明弄清楚如何更新当前森林的图表。
最初,我尝试过,
for group={Lu}{if={n_children==1}{l sep+=10pt}{}},
然而,事情进展得并不顺利:
! Package pgfkeys Error: I do not know the key '/tikz/{Lu}{if={n_children==1}{l
sep+=10pt}{}}' and I am going to ignore it. Perhaps you misspelled it.
See the pgfkeys package documentation for explanation.
我认为这意味着 Forest 解析for group=
,然后尝试传递{Lu}{if ...}
给 Ti钾Z 作为单个键。我不知道为什么。我预计它会寻找一些东西,group
因此如果没有其他的话,会从 Forest 中得到某种错误。
点击有关 的信息链接for group
,我最终进入第 30 页,其中包含有关 的信息for <step>
。因为这包括以下示例
for nodewalk={uu2}{blue}
和
for n=2{circle,draw}
我需要用 做什么不同的事情并不明显for group
。
该group
步骤记录在第 50-1 页。
步
group=<nodewalk>
将其
<nodewalk>
视为(外部)节点行走的单个步骤,即外部每一步键列表仅在嵌入节点行走结束时执行。嵌入<nodewalk>
从外部节点行走继承历史。使用此键相当于编写Nodewalk={every step=independent,history=inherited}<nodewalk>{}, current
→ 可以安全地修改的每一步键列表
<nodewalk>
。→ 对于组也进行了定义。
现在,我必须承认,嵌入式节点遍历对我来说仍然有点神秘,当我在手册的这一部分中找到我认为我需要的东西时,我的心就会沉下去。
但是,如果group
以这种方式定义,我不确定如何for group
有意义,因为for Nodewalk
似乎没有意义。也就是说,似乎group
只能是内部节点行走中的一步,而不是外部节点行走中的一步。
因此我尝试
for nodewalk={group={Lu}}{if={n_children==1}{l sep+=10pt}{}},
这尝试用作group
内部嵌入式节点行走中的一步。如果我理解正确的话,这将导致最后一步成为外部节点行走中的当前步骤,然后我的条件应该以与版本 1 中的原始代码相同的方式应用。
但是我收到另一个错误
! Package forest Error: nodewalk stepped to the invalid node
(forest) nodewalk stack: ",root',tree,group,last leaf".
See the forest package documentation for explanation.
这是一个 Forest 错误,虽然比较好,但我不确定我是否理解了它。看起来好像L
发生在外部 nodewalk 中,在之后group
。但Lu
应该是group
,所以我不确定这是什么意思。
然而,这可能仅仅是由于 Forest 从 1 版到 2 版的另一个变化:即,现在不存在的步骤会导致错误,而以前不会这样。
我尝试
for nodewalk={on invalid=fake,group={Lu}}{if={n_children==1}{l sep+=10pt}{}},
但是,我无法on invalid
以这种方式在外部节点中使用。我不完全理解为什么,但我知道它不起作用。
因此我尝试
for nodewalk={%
Nodewalk={on invalid=fake}{group={Lu}}{if={n_children==1}{l sep+=10pt}{}}
}{},
这让我
! Package forest Error: nodewalk stepped to the invalid node
(forest) nodewalk stack: ",root',tree,Nodewalk,group,last leaf".
想到我可能需要on invalid
小组内部,我尝试
for nodewalk={%
Nodewalk={on invalid=fake}{group={on invalid=fake,Lu}}{if={n_children==1}{l sep+=10pt}{}}
}{},
这抱怨说这f
不是on invalid
再次有效的选择。
我放弃了,我把电话线改成了
\usepackage[compat=1.0-for]{forest}
并恢复
for={Lu}{if={n_children==1}{l sep+=10pt}{}},
这再次让我产生了关于无效性的抱怨:
! Package forest Error: nodewalk stepped to the invalid node
(forest) nodewalk stack: ",root',tree,last leaf".
所以我尝试
\usepackage[compat=1.0-for,compat=1.0-forstep]{forest}
这给了我一个错误,我不知道该怎么办
! Undefined control sequence.
\forest@forstepwrapper ...dewalk@config@oninvalid
}}\forest@marshal
我放弃了,并从课堂演示文稿中剪掉了该图表。
如果我使用
\usepackage[compat=1.0-all]{forest}
那么我的代码确实可以用版本 2 进行编译,但是它看起来与使用版本 1 获得的结果完全不同:
这几乎不是人们希望兼容密钥能够实现的功能!
另一方面,使用compat=1.0-most
仍然会产生无效错误。
在这种情况下应如何应用升级说明,以及如何从手册中的更改列表或其他修订中确定这一点?
为什么兼容性密钥在这里会失败,并且为什么在这种情况下会如此引人注目compat=1.0-all
?
答案1
首先快速回答一下,只是为了让示例编译。分析如下。
使用以下方式加载包
\makeatletter
\def\forest@nodewalk@config@oninvalid{fake}
\makeatother
\usepackage[compat={1.0-for,1.0-forstep}]{forest}
并替换for={Lu}{...}
为for={last leaf',u}
。结果将不会是确切地相同,但足够接近。
快速编辑 1,固定l
右侧叶子的距离。for={Lu}{if={n_children==1}{l sep+=10pt}{}}
用替换for last leaf={for parent={if={n_children==1}{l sep+=10pt}{}}}
。(这仍然需要compat=1.0-forstep
。)
快速编辑 2,修复s
根子节点的距离。替换where level={1}{s+=-20pt}{}
为s sep+=20pt
。
完整的 v2 代码产生的结果与 v1 完全相同:
\documentclass[tikz,border=10pt]{standalone}
\makeatletter
\def\forest@nodewalk@config@oninvalid{fake}
\makeatother
\usepackage[compat=1.0-forstep]{forest}
\begin{document}
\begin{forest}
for tree={
font=\sffamily\scriptsize,
line width=1pt,
draw,
anchor=west,
child anchor=west,
parent anchor=east,
grow'=east,
align=center,
edge path={
\noexpand\path[line width=1pt, ->, \forestoption{edge}]
(!u.parent anchor) -| +(5pt,0) -- +(5pt,0) |- (.child anchor) \forestoption{edge label};
},
% for={last leaf',u}{if={n_children==1}{l sep+=10pt}{}},
for last leaf={for parent={if={n_children==1}{l sep+=10pt}{}}},
},
% where level={1}{s+=-20pt}{}
s sep+=20pt,
[Here\\Village, name=pc
[There village\\your bird, name=arid
]
[, phantom
[Bananas, name=fb, xshift=-15pt, where n children=0{tier=sk}{}
[Pineapple, name=sf
[Middling\\villages?, name=solar
[Current\\paper, name=cp, edge label={node [font=\sffamily\scriptsize, near end, auto, xshift=-1.5pt] {Imprudent}}
]
]
[Creative\\endearments?, name=apple
[Fantastic\\imaginations, name=su, edge label={node [font=\sffamily\scriptsize, near end, auto, xshift=-1.5pt] {Basic}}
]
]
[Heathen\\hopscotch?, name=pear
[Beneficent\\benevolence, name=cl, edge label={node [font=\sffamily\scriptsize, near end, xshift=-1.5pt, below] {Higher}}, edge={draw=none}
]
]
]
[Zoological, name=gf
[Orange\\kangaroos?, name=star
[Strawberry\\seeker, name=rs, edge label={node [font=\sffamily\scriptsize, near end, xshift=-1.5pt, below] {Lower}}
]
]
[Fragility of\\foundations?, name=hercules
[Memorial\\cooks, name=ws, edge label={node [font=\sffamily\scriptsize, near end, xshift=-1.5pt, below] {Earthling}}
]
]
[Best\\antelopes?, name=astro
[Stellar\\horizons, name=ca, edge label={node [font=\sffamily\scriptsize, near end, xshift=-1.5pt, below] {Martian}}
]
]
]
]
]
[Bad hollows\\spotty slugs, name=avid
]
]
\begin{scope}[line width=1pt, ->]
\draw (solar.east) -- (solar.east -| apple.east) -| +(5pt,0) -- +(5pt,0) |- (su.west);
\draw (apple.east) -| +(5pt,0) -- +(5pt,0) |- (cp.west);
\draw (pear.east) -- (pear.east -| apple.east) -| +(5pt,0) -- +(5pt,0) |- (cp.west);
\draw (pear.east) -- (pear.east -| apple.east) -| +(5pt,0) -- +(5pt,0) |- (su.west);
\draw (star.east) -- (star.east -| apple.east) -| +(5pt,0) -- +(5pt,0) |- (cl.west);
\draw (star.east) -- (star.east -| apple.east) -| +(5pt,0) -- +(5pt,0) |- (ws.west);
\draw (star.east) -- (star.east -| apple.east) -| +(5pt,0) -- +(5pt,0) |- (ca.west);
\draw (astro.east) -- (astro.east -| apple.east) -| +(5pt,0) -- +(5pt,0) |- (cl.west);
\draw (astro.east) -- (astro.east -| apple.east) -| +(5pt,0) -- +(5pt,0) |- (rs.west);
\draw (astro.east) -- (astro.east -| apple.east) -| +(5pt,0) -- +(5pt,0) |- (ws.west);
\draw (hercules.east) -- (hercules.east -| apple.east) -| +(5pt,0) -- +(5pt,0) |- (cl.west);
\draw (hercules.east) -- (hercules.east -| apple.east) -| +(5pt,0) -- +(5pt,0) |- (rs.west);
\draw (hercules.east) -- (hercules.east -| apple.east) -| +(5pt,0) -- +(5pt,0) |- (ca.west);
\draw (avid.north) -- (avid.north |- fb.south);
\draw (arid.south -| avid.north) -- (avid.north |- fb.north);
\end{scope}
\end{forest}
\end{document}
分析
OP 勇敢地试图抵抗我的包裹,但却被至少四个错误所挫败。
中的一个错误
compat=1.0-forstep
。兼容模式应该保存和恢复的内部宏\forest@nodewalk@config@oninvalid
在程序包加载期间未初始化。解决方法是在加载程序包之前定义此宏,如本答案顶部所示。的实施不完整
compat=1.0-forstep
。虽然此兼容键使森林默默地忽略了步骤(上文,L
)到无效节点,但进一步的步骤(上文,u
)会导致错误,这与 v1 不同。上面的快速编辑 1 中给出了解决方法。中的一个错误
for group
。虽然group
nodewalk 中需要一个参数,但实际上for group
不需要。这个错误还会影响next on tier
,previous on tier
(我发现它实际上还包含两个错误......)compat=1.0-stages
(包含在 中),在 v2.0.2 中引入了一个错误compat=1.0-all
:给定的选项根本无法处理。
OP 在战斗中犯了一个错误:试图on invalid
错误地使用。这个键接受的参数不止一个,而是两个:模式和在此模式下要执行的键。(但这里的文档也有部分错误!)
最后细节:where level={1}{s+=-20pt}{}
由于 v1 中的一个错误,它只能工作。增加兄弟节点之间的 s 距离的正确方法是增加s sep
其父节点的 s 距离,如上面的快速编辑 2 所示。
为了使代码在 v2 中工作compat
,请将原始代码替换for={Lu}{...}
为
if n children={0}{for parent={if={n_children==1}{l sep+=30pt}{}}}{}