木構造(forest / qtree)

構文木・分類体系・決定木・B 木——枝分かれする図を LaTeX で描く道具は、大きく三つあります。最も強力で現代的なのが **forest、言語学の構文木を手早く描く定番が qtreetikz-qtree、追加パッケージなしの小さな木なら 素の TikZ**。いずれも「親から子へ枝を伸ばす」入れ子構造を、座標を計算せずに記述できるのが共通点です。このページでその使い分けと書き方を見ていきます。

三つのアプローチ

木は本質的に 入れ子(再帰)構造 です。根があり、その下に子がぶら下がり、子がさらに孫を持つ——この入れ子をそのまま括弧の入れ子で書けると、座標を一つも指定せずに木が組めます。三つの道具はどれもこの発想に立ちますが、書き味と機能の幅が違います。

  • forest** — TikZ/pgfkeys の上に作られた、最も自由度の高いパッケージ。[root [child] [child]] という 角括弧(ラベル付きブラケット)記法 に、ノードごとのオプションと木全体のスタイルを重ねられ、各ノードの中身の複雑さに応じて 間隔を自動調整(パッキング) します。言語学にも一般の木にも向きます。
  • qtree / tikz-qtree** — 言語学の構文木に特化した、いちばん手早い定番。\Tree [.S [.NP ... ] [.VP ... ] ] と書き、.ラベル が非終端(枝分かれ)節点を表します。tikz-qtree は同じ記法を TikZ で再実装したもので、出力が美しく調整も利きます。
  • 素の TikZtrees ライブラリ)— \node {root} child {node {a}} child {node {b}}; という childnode の仕組み。追加パッケージなしで、小さな木をその場で描くのに向きます。

ひとことで言えば、**forest がいちばん柔軟で凝った木に向き、qtreetikz-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 1/.style={sibling distance=4cm} のように **level ⟨n⟩/.style** で指定します。木の伸びる向きは [grow=right] などで変えられ、枝の引き方は edge from parent(たとえば直角に折る edge from parent fork down)で制御します。

素の TikZ は手軽な反面、forest のような 自動パッキングがない ため、子の本数や深さが増えると sibling distance を手で調整して重なりを避ける必要があります。数段の小さな木には十分ですが、込み入った構文木や、内容に応じて間隔をそろえたい木では forest のほうが楽です。

どれを選ぶか

迷ったときの目安をまとめます。総じて、**新しく木を描くなら forest が第一候補——自動レイアウトが効き、言語学から一般の木まで幅広く、装飾も TikZ の全機能が使えます。構文木を一本さっと描くだけ**なら \Tree 記法の qtreetikz-qtree が最短で、とくに出力を整えたいなら 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 を引くのが確実です。