树结构 (forest/qtree)

句法树、分类体系、决策树、B 树——在 LaTeX 中绘制分叉图,大致有三类工具。最强大也最现代的是 forest;快速绘制语言学句法树的标准工具是 qtree / tikz-qtree;如果是小型树且不想增加额外包,则可用 原生 TikZ。三者的共同点是,都能用嵌套结构描述“父节点长出子节点”,而无需计算任何坐标。本页说明它们的取舍和写法。

三种做法

树本质上是 嵌套(递归)结构:有一个根,下面挂着子节点,子节点再有孙节点,如此类推。如果能用括号的嵌套来反映这种嵌套,就能不指定任何坐标地生成树。三种工具都基于这个想法,但书写手感和功能范围不同。

  • forest — 最灵活的包,建立在 TikZ 和 pgfkeys 之上。在 带标签的括号记法 [root [child] [child]] 上,可以叠加每个节点的选项和整棵树的样式,并能根据各节点内容的复杂度 自动打包间距。适合语言学树,也适合一般树。
  • qtree / tikz-qtree — 面向语言学句法树的最快标准。写法如 \Tree [.S [.NP ... ] [.VP ... ] ],其中 .label 表示非终结(分支)节点。tikz-qtree 用 TikZ 重新实现同样记法,输出更漂亮,也更容易调整。
  • 原生 TikZtrees 库)— 使用 child / node 机制,如 \node {root} child {node {a}} child {node {b}};。不需要额外包,适合现场画小树。

简而言之,forest 最灵活,适合复杂树;qtree / tikz-qtree 最适合快速绘制成分结构树。原生 TikZ 不增加依赖,适合小任务。下面依次来看。

forest:用方括号写现代树

forest(Sašo Živanović,CTAN)是建立在 TikZ 和 pgfkeys 之上的树绘图包。在导言区加载后,在 forest 环境中用 带标签的括号记法 写树。每个节点用方括号 [ ] 包住,其子节点列在这些括号内部;括号的嵌套 *就是* 树的嵌套。面向语言学时,加 linguistics 选项会让枝在两个子节点的 上方汇合

document.tex
\usepackage[linguistics]{forest}

\begin{forest}
[CP
  [C]
  [IP
    [I]
    [VP
      [V]
      [NP]
    ]
  ]
]
\end{forest}

这个例子绘制一棵树:根 CP 下有 C 和 IP,IP 下有 I 和 VP,VP 下又分出 V 和 NP。把它压成一行 [CP[C][IP[I][VP[V][NP]]]] 也会得到同一棵树,但复杂起来后括号很难对应,所以惯例是像上面那样 用换行和缩进显示层级。有一个陷阱:源代码中出现空行会让 forest 解析失败(空行会被视为段落分隔)。缩进本身则可以自由使用。

forest 的真正优势在于 自动布局。它会根据每个节点所支配内容的复杂度来放置节点,并在水平方向上 打包 以避免重叠,因此复杂的树也往往能直接得到可用外观。想手动调整间距时,把 for tree={...} 应用于整棵树或某个子树。最常用的三个设置是 s sep(水平间距)、l(层级之间的垂直距离)和 inner sep(节点周围的内边距)。

document.tex
\usepackage[linguistics]{forest}

\begin{forest}
for tree={s sep=10mm, inner sep=0, l=0}
[CP
  [C]
  [IP, for tree={s sep=20mm}
    [I, name=src]
    [VP
      [V]
      [DP, roof, name=tgt][the woman]]
  ]
]
\draw[->] (src) to[out=south west, in=south] (tgt);
\end{forest}

这个例子包含了多个惯用法。开头的 for tree={...} 设置整棵树的间距;像 [IP, for tree={s sep=20mm} 这样 在节点标签后放逗号,可以只覆盖该子树的间距。roof 会在该节点标签上加一个 三角形(屋顶),用于省略内部结构、把词组作为一个整体表示。给节点加 name= 后,可以在树的闭括号后写 \draw[->] (src) to[...] (tgt); 来画 移动箭头(在 forest 中可以直接使用 TikZ 命令)。如果标签本身要包含逗号,就像 {NP, PP} 一样 用花括号包住,以便与布局指令区分。

如果不想每次都重复同一套外观,可以在导言区用 \forestset{default preamble={for tree={...}}} 定义 默认样式。由于 forest 基于 TikZ/pgf,节点形状、颜色、箭头、强调等细节外观都可以直接沿用 TikZ 文档中的知识(基础见“TikZ 基础”)。

qtree / tikz-qtree:句法树的最短写法

快速绘制语言学的成分结构(constituency)树时,长期标准是 qtree。在导言区写 \usepackage{qtree},正文中在 \Tree 后跟一个括号表示的树。记法核心是:前面带句点 . 的标签表示非终结(分支)节点,没有句点的裸词则是 叶子(终结)

latex
\Tree [.S [.NP Kim ] [.VP [.V saw ] NP ] ]

这一行会画出一棵树:根 S 下分出 NP 和 VP;NP 的叶子是 Kim;VP 下有 V(叶子 saw)和 NP。写法有几条规则:树必须 紧跟在 \Tree 后;非终结标签以句点开头(如 .S);并且 闭括号 ] 前必须有空白(如 saw ])。qtree 还有不少便利功能:NP_iN^0 会在树中自动按数学模式排成上下标,X\1X$'$(X′)的缩写,\qroof{...} 会在短语上加 三角屋顶(如 \qroof{out of style}.PP)。若要取消自动居中,使用选项 \usepackage[nocenter]{qtree}

tikz-qtree(David Chiang)把这种 \Tree 记法 在 TikZ 上重新实现。加载 \usepackage{tikz}\usepackage{tikz-qtree} 后,同样的 \Tree [.S ... ] 可原样使用,输出则达到 TikZ 品质。对于简单树,它与 qtree 几乎完全兼容;由于可使用 TikZ 的样式机制,箭头和分支也更容易调整。例如 \tikzset{grow'=right} 会让树从 左向右 生长,而不是自上而下。原始 qtree 只靠字体度量画线,而 tikz-qtree 用 TikZ 绘制,所以线条更平滑,后续装饰也容易。

原生 TikZ:child 与 node

如果是小树且不想增加包,TikZ 自带的 child 机制 就足够了。放置一个节点后接上 child {...},其中的内容会作为子节点排布,并自动画出从父到子的边。child 内通常写 node {...},再继续嵌套 child 就能生成孙节点。

latex
\begin{tikzpicture}[level distance=12mm, sibling distance=24mm]
  \node {root}
    child { node {a} }
    child { node {b}
      child { node {c} }
      child { node {d} }
    };
\end{tikzpicture}

这个例子自上而下绘制一棵树:根 root 下有 a 和 b,b 下又分出 c 和 d。注意整棵树只有一个 分号 ;,放在 \node ... ; 的末尾。布局由两个距离决定:父层与子层之间的垂直距离是 level distance(默认 15 mm),并排兄弟之间的间距是 sibling distance(默认 15 mm)。若要按层调整,用 level ⟨n⟩/.style,例如 level 1/.style={sibling distance=4cm}。树的生长方向可用 [grow=right] 等改变,边的画法由 edge from parent 控制(例如直角连接可用 edge from parent fork down)。

原生 TikZ 很方便,但不像 forest 那样有 自动打包。子节点数量或深度增加时,需要手动调整 sibling distance 来避免重叠。它足以应付几层的小树;但对于复杂句法树,或希望间距随内容自动调整的树,forest 更省力。

如何选择

拿不准时可按这个原则。总体而言,新画树时先考虑 forest:它有自动布局,覆盖从语言学到一般树的广泛用途,装饰也能使用 TikZ 的全部能力。只想快速画一棵句法树时,qtree / tikz-qtree\Tree 记法最短;若希望输出更精致,选 tikz-qtree几层小树且不想增加依赖时,原生 TikZ 的 child 就足够。

工具记法适合用途
forest[root [child] [child]](方括号)复杂树、自动布局、语言学和一般树
qtree\Tree [.S [.NP ... ] ... ]最快绘制句法树;基于字体,轻量
tikz-qtree\Tree(与 qtree 相同)TikZ 品质的句法树,更易调整
TikZ (trees)\node {r} child {node {a}}小树;不想增加额外包时

它们都在 CTAN 上,并随 TeX Live 和 MiKTeX 提供。foresttikz-qtree 位于 CTAN 的 graphics/pgf/contrib/ 下,依赖 TikZ/pgf。要查看各包的完整细节,最可靠的方法是在本机运行 texdoc foresttexdoc tikz-qtreetexdoc qtree