我生成了一棵树,它由两棵子树组成,每棵子树都包含很多子树。默认情况下,森林会将它们并排呈现。但是,树的宽度会延伸页面,缩小后页面会变得难以阅读。
因此,我考虑将根节点的一棵子树放在另一棵子树的下方。如何在不改变所有子节点方向的情况下实现这一点?
简单示例:
第一棵树的 LaTeX 代码:
\documentclass{article}
\usepackage{forest}
\begin{document}
\begin{forest}
[A
[B [B1] [B2]]
[C [C1] [C2]]
]
\end{forest}
\end{document}
复杂示例:
(注意:为了使示例正常运行,请将linguistics
选项添加到森林包中)
[proc [body
[decls
[decl [decl\_tbl\_var
[var\_name ['v1']]
[tbl\_type\_def [col\_list\_def
[col\_elem ['b1 INT', roof]]
[col\_elem ['b2 DOUBLE', roof]]
[col\_elem
[col\_name ['c1']]
[datatype ['INT']]
]
]]
]]
[decl [decl\_tbl\_var
[var\_name ['v2']]
[tbl\_type\_def [col\_list\_def
[col\_elem
[col\_name ['c1']]
[datatype ['INT']]
]
[col\_elem ['c2 DOUBLE', roof]]
]]
]]
]
[stmts
[stmt\_assign
[var ['v1']]
[expr [subquery
[select\_clause [attrs
[attr ['a1 b1', roof]]
[attr ['SUM('a2 * a3') b2', roof]]
[attr ['a4'] [alias ['c1']]]
]]
[from\_clause [tables ['t1']]]
[group\_by\_clause [group\_by\_expr\_list
[expr ['a1']]
[grouping\_set [grouping\_expr\_list
[grouping\_expr [expr ['a1']]]
[grouping\_expr [expr ['a4']]]
]]
]]
]]
]
[stmt\_assign
[var ['v2']]
[expr [subquery
[select\_clause [attrs
[attr ['a4'] [alias ['c1']]]
[attr ['SUM (a2 * a3) c2', roof]]
]]
[from\_clause [tables ['t1']]]
[group\_by\_clause [group\_by\_expr\_list [expr ['a4']]]]
]]
]
]
]]
在这个例子中,我想将stmts
子树移动到子树下方decls
。
答案1
最简单的方法就是改变树的结构。例如,
\documentclass{standalone}
\usepackage{forest}
\begin{document}
\begin{forest}
[A
[B [B1] [, no edge, coordinate [C, edge path'={(!uuu.parent anchor) -| (!uul.east |- .east) -- (.east)} [C1] [C2]]] [B2]]
]
\end{forest}
\end{document}
根据您需要的频率,您可以使其更加自动化,即不明确更改树的结构,而是让 Forest 为您完成。
在这种情况下,森林肯定会失去对事物的追踪,因此您需要注意确保事物不会相互交叉(例如,边与节点、节点与节点等)。
因此,这需要做更多的工作,但非常可行,尤其是在像这样的相对简单的情况下,您只需将一些子树移动到其兄弟子树下,并以相当一致(如此算法化)的方式更改边缘。因此,自动化需要明确森林应该做什么,但一旦您定义了例程,您就可以在任何需要的地方应用它。
但是,如果您只需要这样做几次,那么更容易的是自己重构树并定义一种样式来适应edge path
不可见的父级的改变。
例如,手动方法可能如下所示:
\documentclass{standalone}
\usepackage{forest}
\begin{document}
\begin{forest}
move me down/.style={
edge path'={(!uuu.parent anchor) -| (!uul.east |- .east) -- (.east)},
!u.no edge,
!u.coordinate,
}
[A
[B [B1] [ [C, move me down [C1] [C2]]] [B2]]
]
\end{forest}
\end{document}
这显然会产生与前面的代码相同的输出。
编辑
已编辑因为当提供代表性示例时,原始方法不起作用(叹气)。
基本上,你把movies
树的前言放进去,告诉 Forest 你想要这种风格。然后你把选项添加move me down
到你想要移动的子树的根节点。也就是说,在合理的范围内。例如,我不建议尝试将一个子树移动到另一棵移动的子树之下。我没有尝试过,但我想那不会成功。
然而,风格能处理具有不同层数的相邻子树。当移动的子树向下移动时,它将移动到其相邻子树的下方,无论该子树有 2 个层还是(理论上)77 个层。
请注意,如果事情变得复杂,您不能指望 Forest 能够确定位置,因为事情已经非常棘手了。
例如,
\begin{forest}
movies
[A
[B [B1] [B2]] [C, move me down [C1] [C2]]
[B [B1] [q[x[y[z]]]B2]] [C, move me down [C1v] [Cg2]]
]
\end{forest}
生产
以下是当前示例的代码:
\begin{forest}
movies
[proc [body
[decls
[decl [decl\_tbl\_var
[var\_name ['v1']]
[tbl\_type\_def [col\_list\_def
[col\_elem ['b1 INT', roof]]
[col\_elem ['b2 DOUBLE', roof]]
[col\_elem
[col\_name ['c1']]
[datatype ['INT']]
]
]]
]]
[decl [decl\_tbl\_var
[var\_name ['v2']]
[tbl\_type\_def [col\_list\_def
[col\_elem
[col\_name ['c1']]
[datatype ['INT']]
]
[col\_elem ['c2 DOUBLE', roof]]
]]
]]
]
[stmts, move me down
[stmt\_assign
[var ['v1']]
[expr [subquery
[select\_clause [attrs
[attr ['a1 b1', roof]]
[attr ['SUM('a2 * a3') b2', roof]]
[attr ['a4'] [alias ['c1']]]
]]
[from\_clause [tables ['t1']]]
[group\_by\_clause [group\_by\_expr\_list
[expr ['a1']]
[grouping\_set [grouping\_expr\_list
[grouping\_expr [expr ['a1']]]
[grouping\_expr [expr ['a4']]]
]]
]]
]]
]
[stmt\_assign
[var ['v2']]
[expr [subquery
[select\_clause [attrs
[attr ['a4'] [alias ['c1']]]
[attr ['SUM (a2 * a3) c2', roof]]
]]
[from\_clause [tables ['t1']]]
[group\_by\_clause [group\_by\_expr\_list [expr ['a4']]]]
]]
]
]
]]
\end{forest}
产生
完整代码:
\documentclass[border=10pt]{standalone}
\usepackage[linguistics,edges]{forest}
\forestset{%
declare toks={move me}{},
declare toks={bio}{},
declare toks={symud}{},
movies/.style={
forked edges,
},
move me down/.style={
before typesetting nodes={
if nodewalk valid={p2}{
if={>O_={!u.n children}{2}}{!u.calign=first}{},
temptoksa/.option=name,
bio/.option=!u.name,
for nodewalk={p,descendants}{
if n children=0{
append={[, phantom, tier/.register=temptoksa]},
}{}
},
for nodewalk={
group={p2}
}{
symud/.register=temptoksa,
insert before={[, move me/.option=!n.symud, tier/.option=!n.symud, no edge, before packing={
append/.option=move me,
}]}
},
replace by/.process={Ow{name}{[, no edge, coordinate, tier=##1, before computing xy={
for nodewalk={
p,
tempdimc/.option=s,
while nodewalk valid={l}{l,tempdimc+/.option=s, typeset node, if n children=0{tempdimc+/.option=max x}{}}
}{},
s/.register=tempdimc,
s+/.option=s sep,
}, name=##1-MT, append]}},
edge path'/.process={
OOw2 {bio}{name}
{(##1.parent anchor) -- ++(\forestoption{fork sep},0) |- (##2-MT) -| (.east) }%
},
}{},
},
}
}
\begin{document}
\begin{forest}
movies
[proc [body
[decls
[decl [decl\_tbl\_var
[var\_name ['v1']]
[tbl\_type\_def [col\_list\_def
[col\_elem ['b1 INT', roof]]
[col\_elem ['b2 DOUBLE', roof]]
[col\_elem
[col\_name ['c1']]
[datatype ['INT']]
]
]]
]]
[decl [decl\_tbl\_var
[var\_name ['v2']]
[tbl\_type\_def [col\_list\_def
[col\_elem
[col\_name ['c1']]
[datatype ['INT']]
]
[col\_elem ['c2 DOUBLE', roof]]
]]
]]
]
[stmts, move me down
[stmt\_assign
[var ['v1']]
[expr [subquery
[select\_clause [attrs
[attr ['a1 b1', roof]]
[attr ['SUM('a2 * a3') b2', roof]]
[attr ['a4'] [alias ['c1']]]
]]
[from\_clause [tables ['t1']]]
[group\_by\_clause [group\_by\_expr\_list
[expr ['a1']]
[grouping\_set [grouping\_expr\_list
[grouping\_expr [expr ['a1']]]
[grouping\_expr [expr ['a4']]]
]]
]]
]]
]
[stmt\_assign
[var ['v2']]
[expr [subquery
[select\_clause [attrs
[attr ['a4'] [alias ['c1']]]
[attr ['SUM (a2 * a3) c2', roof]]
]]
[from\_clause [tables ['t1']]]
[group\_by\_clause [group\_by\_expr\_list [expr ['a4']]]]
]]
]
]
]]
\end{forest}
\end{document}
我不建议在没有的情况下尝试这一点,forked edges
因为即使在最好的情况下,方线也肯定会切断其他东西。