LaTeX の中で図を描くための言語 TikZ は、名前そのものが警告になっています。ドイツ語の TikZ ist kein Zeichenprogramm(TikZ は作図プログラムではない)という再帰的な頭字語で、マウスで図形をドラッグする道具ではないと最初に断っているわけです。代わりに \draw (0,0) -- (2,1); と本文と同じファイルに書けば、図は周囲の段落と同じフォント・同じ品質で組み上がります。手軽さを捨てて正確さと再現性を取る——このページでは、最初の一図の描き方から、座標とノードの考え方、そしてコンパイルが遅くなる理由とその対処までを追います。
なぜ「作図プログラムではない」のか——TikZ と PGF の関係
名前は GNU 流の冗談です。マニュアルは「gnu’s Not Unix」の伝統に連なる再帰的な頭字語だと自分で説明し、読者に何を期待すべきかをあらかじめ釘刺しています。マウスの代わりに手に入るのは、TeX 的なやり方を絵に持ち込んだときの利点——正確な配置、マクロによる使い回し、本文と揃った文字組み——であり、代わりに手放すのが WYSIWYG です。図をひとつ直すたびに再コンパイルが要る、という不便さも含めて、マニュアルは最初の数ページで正直に列挙しています。
その下で実際に線を引いているのが PGF です。名前は「portable graphics format(可搬なグラフィックス形式)」の頭字語で、由来ははっきりしています。作者は、pdfLaTeX でも従来の PostScript 経由の LaTeX でも同じように使えるグラフィックスマクロを書こうとしました。出力先の違いを吸収する層が要る——だから「portable」なのです。そのままでは書くのが骨の折れる低水準の層なので、その上に人が読み書きできる文法をかぶせたのが TikZ です。実務では「PGF/TikZ」とひとまとめに呼ばれますが、私たちが実際にタイプするのはほぼ TikZ 側だけで、\usepackage{tikz} と書けば PGF も一緒に読み込まれます。
両方を書いたのは Till Tantau です。学部生のころ TeX をいじりはじめてプレゼン用の beamer クラスを作り、その後、博士論文に載せる図のために TikZ を書いた——本人がそう語っています。LaTeX の発表スライドと作図言語という、まったく別に見える二つの定番が同じ人物から出ているわけです。もうひとつ、TikZ が「小さなパッケージ」ではないことを示す数字があります。バージョン 3.1.10 のマニュアル pgfmanual.pdf は 1,321 ページ。しかも表紙そのものが TikZ で描かれたフラクタルの樹とコッホ雪片の風景で、それを生成するソースコードが同じページに並べて刷られています。
導入で悩むところはほとんどありません。プリアンブルに \usepackage{tikz} の一行を書けば、pdfLaTeX・LuaLaTeX・XeLaTeX ではそのまま動きます。手当てが要るのは DVI を経由する場合だけで、pLaTeX や upLaTeX ならクラスオプションにドライバ(通常は dvipdfmx)を指定します。次が動く最小の文書です。
\documentclass{article} % with pLaTeX: \documentclass[dvipdfmx]{jsarticle}
\usepackage{tikz}
\begin{document}
A line and a circle:
\begin{tikzpicture}
\draw (0,0) -- (2,1);
\draw (2.8,0.5) circle [radius=0.5cm];
\end{tikzpicture}
\end{document}最初の一図——tikzpicture 環境と、忘れると必ず刺さるセミコロン
図はすべて \begin{tikzpicture} … \end{tikzpicture} の中に描き、作図コマンドはひとつ残らずセミコロン ; で終えます。環境は一枚の絵を載せる画用紙で、環境名のあとの角括弧に書いたオプションは絵全体に効きます——[scale=2] なら二倍、[thick] なら全部の線が太くなります。一行で済む小さな絵なら環境を開かず、\tikz{...} や、命令ひとつだけの \tikz \draw ...; という行内形も使えます。
% inline: one command, no environment
\tikz \draw (0,0) -- (1.5,0);
% environment: one canvas, several commands, shared options
\begin{tikzpicture}[scale=1.2, thick]
\draw (-1.5,0) -- (1.5,0);
\draw (0,-1.5) -- (0,1.5);
\end{tikzpicture}セミコロンをひとつ落とすと ! Package tikz Error: Giving up on this path. Did you forget a semicolon? が出ます。厄介なのは、報告される行番号が 壊した行ではなく、その次の行 になることです。TikZ はパスの続きになりうるトークンを読めるだけ読み進め、続きになりようのないもの——たいていは次の \draw——にぶつかって初めて音を上げるからです。エラーが \draw の行を指していたら、疑うべきは ひとつ上の行の末尾 です。
座標とパス——\draw・\fill・--・circle の使い分け
TikZ の作図は パス——点から点へどう進むかを書いた経路——を中心に回り、それをどう見せるかは命令の名前が決めます。\draw は経路を線でなぞり、\fill は閉じた経路の内側を塗り、\filldraw は塗ってから枠線も引き、\path は何も描かずに経路だけを定義します。最後のひとつは無駄に見えますが、あとで参照する座標やノードを黙って置いておくのに使います。同じ座標列を書いて命令名だけ差し替えれば、線画が塗りに変わる——この直交性が TikZ の設計の骨です。
点の書き方は三通り。直交座標 (x,y) は既定の単位がセンチメートルで、(1,2) は右へ 1 cm・上へ 2 cm、(1cm,2pt) のように単位を明示することもできます。極座標 (30:1cm) は「30 度の向きに 1 cm」。そして 名前付き座標 を \coordinate (P) at (1,1); のように置いておけば、以後 (P) と呼ぶだけで済みます。相対指定の + と ++ の違いは事故のもとなので押さえておいてください。++(1,0) は右へ 1 cm 進んで 現在地も更新 し、+(1,0) は同じ場所へ行きますが 現在地は動かしません。連続して ++ を並べれば折れ線が伸び、+ を並べれば同じ基準点から放射状に伸びます。
経路の進み方は パス操作 が決めます。-- は直前の点から次の点への直線、rectangle は二点を対角とする長方形、circle は中心からの円、ellipse は楕円、arc は円弧、grid は方眼。曲線は .. controls ..(ベジエ)か to[bend left] で描き、閉じた図形にしたいときは末尾に -- cycle を付けて始点へ戻します。形の引数はいまは角括弧のキー=値で書くのが作法で、circle [radius=10pt]、ellipse [x radius=20pt, y radius=10pt]、arc [start angle=0, end angle=30, radius=3mm]、grid [step=.5cm] のようになります。旧来の circle (10pt) という括弧記法も動きますが、新しく書くなら角括弧に揃えるほうが読みやすく、キーを足すのも楽です。
\begin{tikzpicture}
\draw[step=.5cm, gray, very thin] (-1.4,-1.4) grid (1.4,1.4);
\draw (0,0) circle [radius=1cm];
\draw (0,0) -- (30:1cm); % polar: 1 cm at 30 degrees
\fill[blue!20] (0,0) rectangle (0.5,0.5);
\draw[red] (-1.2,-1.2) -- ++(0.6,0) -- ++(0,0.6); % ++ carries the current point
\end{tikzpicture}できあがるのは、0.5 cm 刻みの薄い灰色の方眼を背景に、原点を中心とする半径 1 cm の円、原点から 30 度の向きに伸びる短い線分、原点まわりの 0.5 cm 角を淡い青で塗った正方形、そして左下から右へ 0.6 cm・上へ 0.6 cm と折れる赤いかぎ形、という一枚です。色の blue!20 は「青 20 %」、つまり残り 80 % を白と混ぜた淡い青を指します。red!50!black のように二色を指定すれば混色もでき、この記法は塗りにも線にもそのまま効きます。
ノード——文字と箱を置き、名前でつなぐ
ノード(node) は指定した座標に文字や箱を置く仕組みで、書式は \node[オプション] (名前) at (座標) {中身}; です。オプションには draw(枠を描く)、circle や rectangle(形)、fill=blue!20(塗り)などを並べます。要は、丸括弧に書いた 名前がこのノードの取っ手 になるということ。以後 (名前) で位置を参照でき、(名前.north)・(名前.east) のように アンカー を付ければ縁の一点を名指しできます。
ここから実務の型が出てきます。先に名前付きのノードを置き、あとから名前どうしを線でつなぐ。座標を直に書かずノード名で結べば、あとでノードを 1 cm 動かしても線は自動的に追随します。しかも線はノードの縁で止まるので、円や箱にめり込みません。ノードはパスの途中にも置けて、\draw (a) -- (b) node[midway, above] {$f$}; と書けば線の中点の上にラベルが乗ります——矢印に名前を添える定番の書き方です。
\begin{tikzpicture}
\node (a) at (0,0) [draw, circle, fill=blue!20] {A};
\node (b) at (2.5,0) [draw, circle, fill=blue!20] {B};
\draw[->] (a) -- (b) node[midway, above] {$f$};
\draw[dashed] (a.south) -- (b.south); % .south is an anchor on the border
\end{tikzpicture}この絵は、淡い青の円に「A」「B」を入れたノードを 2.5 cm 離して並べ、A から B へ矢印を引いてその中点の上に $f$ を置き、さらに二つの円の下端どうしを破線で結んだものになります。ここで踏みやすい地雷がひとつ。ノードは参照する前に定義されていなければなりません。 まだ置いていない名前や綴りを間違えた名前を書くと ! Package pgf Error: No shape named ‘b’ is known. が出ます。名前は打ち間違えやすいので、エラーが出たら綴りと、その \node が本当に手前にあるかを確かめてください。
線のオプションと、使い回すためのスタイル(\tikzset)
線の見え方は角括弧の オプション で決まります。よく使うのは太さの thin / thick / very thick、色の red や blue!50、破線の dashed と点線の dotted、角を丸める rounded corners、そして矢印の ->(終端)・<-(始端)・<->(両端)です。矢印の扱いには面白い割り切りがあって、TikZ は - を含む未知のオプションをすべて矢印指定とみなします。だからキー名を打ち間違えると、綴りによって二種類の結末が待っています。- を含まない綴り間違いなら ! Package pgfkeys Error: I do not know the key ‘/tikz/thikc’ and I am going to ignore it. Perhaps you misspelled it. と教えてくれますが、- が混じっていると矢印の指定として解釈され、黙って妙な結果になることがあります。
| オプション | 意味 |
|---|---|
thick / very thick | 線を太く(ultra thick まで用意されています) |
red, fill=blue!50 | 線の色・塗りの色。!n で濃さ、red!50!black で混色 |
dashed / dotted | 破線・点線 |
rounded corners | 折れ線の角を丸める |
->, <-, <-> | 終端・始端・両端の矢じり |
scale=2 | その図(や経路)を 2 倍に拡大 |
node distance=1cm | positioning での相対配置の既定間隔 |
同じ装飾を三度書いたら、それは スタイル にする合図です。\tikzset{名前/.style={...}} でプリアンブルに定義しておけば、以後は名前ひとつを渡すだけで済み、見た目を変えたいときも定義の一箇所を直せば全部に効きます。図の中だけで通用させたいなら tikzpicture のオプションにその場で書いても構いません。every node/.style={...} のように「すべての◯◯」に効くスタイルもあり、フローチャートのようにノードの見た目を揃えたい図では欠かせません。
\tikzset{help lines/.style={color=blue!50, very thin}}
\begin{tikzpicture}
\draw[help lines] (0,0) grid (3,2);
\draw[thick, red, ->, rounded corners] (0,0) -- (1,2) -- (3,2);
\end{tikzpicture}この絵は、(0,0) から (3,2) までの薄い青の方眼の上に、原点から (1,2)、さらに (3,2) へ折れる赤い太線を引き、折れ角を丸めて終端に矢じりを付けたものです。方眼をスタイルにしてあるので、very thin を thin に書き換えれば、この図に限らず help lines を使ったすべての方眼が一度に変わります。
どの \usetikzlibrary を読み込めばよいか
TikZ の本体は意図的に小さく保たれ、専門的な機能は ライブラリ に切り出されています。必要なものだけを \usetikzlibrary{...} でプリアンブルから読み込みます(複数はカンマ区切り)。読み込まないと便利な書き方がそもそも存在せず、たとえば positioning を入れずに right=of a と書けば、先ほどの「知らないキー」エラーに直行します。最初の一年で本当に効くのは、だいたい次の顔ぶれです。
arrows.meta— 豊富で調整可能な矢じり(-{Stealth}、-{Latex}など)。旧来のarrowsとarrows.spacedはマニュアルで非推奨とされているので、新しく書くならこちらです。positioning— ノードの相対配置。right=of a、below=1cm of bと書け、node distanceで既定の間隔を決めます。calc— 座標の計算。($(a)+(1,0)$)は「a の右 1 cm」、($(a)!0.5!(b)$)は「a と b の中点」です。shapes— 円と四角の外側にある豊富なノード形状(ひし形・星・吹き出しなど)。shapes.geometricなどに細分されています。decorations— 経路を波線・ジグザグ・ブレースなどに装飾。decorations.pathmorphingほか。patterns— 塗りをハッチング(斜線・点)などの模様にする。fit— 複数のノードをちょうど囲む箱を自動で作る。図のグループ化に便利です。backgrounds— 図の背景レイヤーに枠や下地を描く。前面の要素と重ならずに済みます。matrix— ノードを格子状(行列状)に整列。graphdrawingは自動レイアウトですが、こちらは LuaTeX が必須です。
arrows.meta と positioning を組み合わせるだけで、実用的なフローチャートが書けます。座標を与えるのは最初のノードだけで、あとは「あれの右」「あれの下」と関係で並べるのが要点です。ノードを一つ挿し込んでも、座標を書き直す作業が発生しません。
\usepackage{tikz}
\usetikzlibrary{arrows.meta, positioning}
\begin{tikzpicture}[node distance=1cm, every node/.style={draw, rounded corners}]
\node (start) {Start};
\node (proc) [right=of start] {Process};
\node (end) [right=of proc] {End};
\draw[-{Stealth}] (start) -- (proc);
\draw[-{Stealth}] (proc) -- (end);
\end{tikzpicture}できるのは、角を丸めた枠に「Start」「Process」「End」を入れて 1 cm 間隔で左から右へ並べ、Stealth 型の鋭い矢じりで順につないだ横並びのフローチャートです。every node/.style が全ノードの見た目を一括で決め、node distance=1cm が right=of の既定間隔を決めています。この二つを図のオプションに書いておくのが、あとから手を入れやすい図の書き方です。
TikZ のコンパイルが遅い理由と、external/standalone の使い分け
遅いのは、計算を TeX 自身がマクロで やっているからです。座標の足し算も、角度から座標への変換も、ベジエ曲線の分割も、外部エンジンではなく組版処理の内側で走ります。しかも結果はキャッシュされないので、\draw の一本たりとも 毎回のコンパイルで最初から計算し直し になります。図が数枚なら気づきませんが、密な grid、点の多いプロット、ノードが数十個の図が積み重なると、体感できるほど遅くなります。マニュアル自身も、TeX 的なやり方の代償として「小さな変更に長い再コンパイルが伴う」ことを最初のほうで認めています。
定番の対策が external ライブラリ です。\usetikzlibrary{external} を読み込んで \tikzexternalize を宣言すると、各 tikzpicture は一度だけ個別の PDF に書き出されてキャッシュされます。ファイル名は自動で決まり、本体が main.tex なら main-figure0、main-figure1……となります。二度目以降の実行では、その図のソースが変わっていなければ計算をまるごと飛ばして、できあがった PDF を貼り込むだけ。図を直せば自動的に作り直されます。既定の mode=convert with system call は LaTeX が自分自身を呼び出して図を作るので、-shell-escape を付けて実行する必要があります(pdflatex -shell-escape main)。付け忘れると図が生成されないので、まずここを疑ってください。
\usepackage{tikz}
\usetikzlibrary{external}
\tikzexternalize % caches each picture as main-figure0.pdf, main-figure1.pdf, ...
% compile with: pdflatex -shell-escape mainもうひとつの道が standalone クラス です。図を独立した .tex に切り出し、\documentclass[tikz]{standalone} で単独にコンパイルすると、tikz オプションが tikz パッケージを読み込んだうえで、絵の実寸に切り詰めた 1 ページの PDF を作ってくれます(tikzpicture が複数あればページも複数になります)。あとは本文から \includegraphics{figure} で貼るだけ。判断の目安はこうです。図が本文と一緒に育つなら external——コードは本文のそばに置いたまま、キャッシュだけ手に入ります。図を他の文書やスライドと共有する、あるいは図だけを何十回も試行錯誤するなら standalone——数秒で回る小さな文書を単独で回せるほうが、結局は速く終わります。
% compiles on its own to a one-page PDF, cropped to the picture
\documentclass[tikz]{standalone}
\usetikzlibrary{arrows.meta}
\begin{document}
\begin{tikzpicture}
\draw[-{Stealth}, thick] (0,0) -- (2,1);
\end{tikzpicture}
\end{document}
% then in the main document: \includegraphics{figure}