グラフ・プロット(PGFPlots / gnuplot)

実験データや数式のグラフを、外部の作図ソフトで描いて画像として貼り込む——その必要はありません。LaTeX には、文書の中で データから直接グラフを組む 仕組みがあります。主役は TikZ/PGF の上に作られた **pgfplots**。関数・座標・データファイルから折れ線や散布図・棒グラフ・3D 曲面までを、本文と同じフォント・同じ線の太さで描けます。このページでは pgfplotsaxis 環境と \addplot を軸に、外部の gnuplot を計算機として呼ぶ方法、そして RPython(matplotlib) で描いたグラフを TikZ コードとして取り込む方法までを扱います。

なぜ文書内でグラフを組むのか

Excel やお絵かきソフトで作った PNG を貼ると、たいてい文書から浮きます。軸ラベルの書体が本文と違い、数式は画像化されてぼやけ、拡大すると線がギザギザになります。データを直したら作り直して貼り替える手間もかかります。**pgfplots** は逆の発想で、グラフそのものを LaTeX に組ませます。軸の数字も凡例も本文と同じフォントで、線はベクタなので何倍に拡大しても滑らか。ラベルには $\sin x$ のような 数式をそのまま 書けます。

もう一つの利点が データとの分離 です。座標を本文に直書きするのではなく、.dat.csv のデータファイルを読ませておけば、データを更新して再コンパイルするだけでグラフが追従します。論文・スライド・付録で同じ数値を何度でも使い回せ、転記ミスも起きません。これは「データから表を組む」発想(→ 関連ページ)とまったく同じで、pgfplots には表用の姉妹パッケージ pgfplotstable も付属します。

pgfplotsTikZ/PGF の上 に作られています。だから図全体は tikzpicture 環境の中に置かれ、TikZ の座標やノード・装飾もそのまま併用できます。TikZ そのものの基本(\draw、座標系、ノード)は「TikZ の基本」ページに譲り、ここではグラフ作図に特化します。

`pgfplots` の骨組み — `axis` と `\addplot`

まずプリアンブルで読み込み、互換性レベル を宣言します。\pgfplotsset{compat=1.18} のように書くと、その版の既定の挙動(軸の見た目や目盛りの付き方など)に固定され、将来 pgfplots が更新されても図が勝手に変わりません。新規文書では、入れている版に応じてできるだけ新しい番号を指定するのが定石です。

latex
\usepackage{pgfplots}
\pgfplotsset{compat=1.18}

本文では、tikzpicture の中に **axis 環境 を一つ置き、その中で \addplot** を呼ぶたびに曲線が一本ずつ重なっていきます。座標軸・目盛り・格子・凡例は axis のオプションで、各曲線の色やマーカーは \addplot のオプションで指定します。最小の例を見てみましょう。

latex
\begin{tikzpicture}
  \begin{axis}[
    xlabel = {$x$},
    ylabel = {$f(x)$},
    title  = {A parabola},
    grid   = major,
  ]
    \addplot[blue, domain=-3:3, samples=100] {x^2};
    \addlegendentry{$x^2$}
  \end{axis}
\end{tikzpicture}

これは区間 −3 ≤ x ≤ 3 で放物線 y = x² を 100 点で標本化し、青い滑らかな曲線として描きます。軸には x と f(x) のラベル、上部に「A parabola」という題、grid=major で主目盛りに沿った薄い格子が入り、\addlegendentry が凡例「x²」を添えます。要点を順に押さえましょう。

  • ラベルや題は波括弧で。 xlabel={$x$} のように {…} で囲むと、中に数式やカンマを安全に書けます。
  • **関数は ^ で冪、三角関数は既定で度数法。** \addplot {x^2} の数式は pgf の内部パーサが評価します。\sin などは引数を「度」で受け取るため、ラジアンで渡すには sin(deg(x))deg() で包みます。
  • domainsamples。** 関数プロットは domain=a:b の区間を samples=N 点で標本化します(既定はおおむね区間 −5:5・25 点)。曲線が角ばるときは samples を増やします。
  • 凡例は二通り。 曲線ごとに \addlegendentry{…} を置くか、axis のオプションに legend entries={A,B,...} をまとめて書きます。位置は legend pos=north west などで。

よく使う axis オプションをまとめます。これらは axis[...] の中に、カンマ区切りで並べます。

オプション働き
xlabel= / ylabel=横軸・縦軸のラベル。xlabel={$x$} のように波括弧で囲み、数式も書ける
title=グラフ上部に置く題
xmin= xmax= ymin= ymax=描画範囲(軸の上下限)を固定する
grid=格子線を引く。grid=major は主目盛り、grid=both は副目盛りにも
legend pos=凡例の位置。north west ほか、outer north east で枠外にも置ける
xtick=目盛りを打つ位置を明示する(例 xtick={0,1,2})。xtick=data でデータ点に合わせる
width= / height=図の寸法を指定する
ybar縦棒グラフにする(後述)。横棒は xbar

データの与え方 — 関数・座標・ファイル

\addplot には、大きく三通りのデータの渡し方があります。一つめは、これまで見た 数式(関数)から{...} の中に式を書くと、domain の範囲を標本化して曲線にします。

latex
\addplot[red, domain=0:2*pi, samples=200] {sin(deg(x))};

これは 0 から 2π まで正弦曲線を引きます。x はラジアン値なので、度数法で動く \sin に渡す前に deg() で度へ変換しているのが要点です。

二つめは インラインの座標からcoordinates {...}(x,y) の組を並べると、その点を順につないだ折れ線(や、マーカーだけの散布図)になります。実測値が数個のときに手軽です。

latex
\addplot[mark=*, blue] coordinates {
  (0,0) (1,1) (2,4) (3,9) (4,16)
};

ここでは 5 点を青い線で結び、各点に丸マーカー(mark=*)を打ちます。線を消して点だけにしたいときは only marks、線種は dashed などで変えられます。

三つめが、実務で最も重要な データファイルから です。table {ファイル名} で、空白区切りのテキストを読み込みます。先頭行が列名(ヘッダ)で、既定では 1 列目を x、2 列目を y として描きます。次のような data.dat があるとします。

data.dat
x   y
0   0.0
1   0.8
2   0.9
3   0.1
4  -0.8
5  -1.0
latex
\begin{tikzpicture}
  \begin{axis}[xlabel={$x$}, ylabel={$y$}, grid=major]
    \addplot[mark=square, teal] table {data.dat};
    % 列名で明示するなら:
    % \addplot table[x=x, y=y] {data.dat};
  \end{axis}
\end{tikzpicture}

列名で明示したいときは table[x=x, y=y] {data.dat} のように 列名を指定 します(列名は大文字小文字を区別します)。区切りがカンマの CSV なら table[col sep=comma]{...}#% で始まる行はコメントとして読み飛ばされます。データの整形や計算列まで踏み込むなら、姉妹パッケージ **pgfplotstable** が使えます(→ 関連「データから表」)。

棒グラフ・対数軸・3D

同じ axis\addplot の枠組みで、見せ方を変えられます。棒グラフaxisybar(縦棒)を与えるだけ。複数の \addplot を重ねれば、自動で横にずれて並んだ群(クラスタ)棒になります。

latex
\begin{tikzpicture}
  \begin{axis}[
    ybar,
    xlabel = {Year}, ylabel = {Count},
    symbolic x coords = {2023, 2024, 2025},
    xtick = data,
  ]
    \addplot coordinates {(2023,40) (2024,55) (2025,72)};
  \end{axis}
\end{tikzpicture}

ここでは年(文字列)を横軸ラベルにするため symbolic x coords を使い、xtick=data で各データ点に目盛りを合わせています。横棒にしたいときは xbar を使います。

対数軸 は、axis を別の環境名に差し替えるだけで得られます。両対数なら loglogaxis、横軸だけ対数なら semilogxaxis、縦軸だけなら semilogyaxis。中の \addplot の書き方は変わりません。

latex
\begin{tikzpicture}
  \begin{loglogaxis}[xlabel={$x$}, ylabel={$y$}]
    \addplot[domain=1:1000, samples=50] {1/x};
  \end{loglogaxis}
\end{tikzpicture}

3D には **\addplot3** を使い、axis は自動的に三次元になります。曲面なら surf、メッシュなら mesh を指定し、関数は xy の二変数で書きます。座標やデータファイルからの 3D も同様に \addplot3 で扱えます。

latex
\begin{tikzpicture}
  \begin{axis}[xlabel={$x$}, ylabel={$y$}, zlabel={$z$}]
    \addplot3[surf, samples=30, domain=-3:3]
      {exp(-x^2 - y^2)};
  \end{axis}
\end{tikzpicture}

これは釣鐘状のガウス曲面 z = e^(−x²−y²) を、30×30 の格子で標本化して色付きの曲面として描きます。視点は view={方位角}{仰角} で回せます。

gnuplot を計算機として使う

pgfplots 自前のパーサは便利ですが、複雑な式や大量の標本では非力なことがあります。そこで \addplot gnuplot {...} と書くと、外部プログラム gnuplot に数値計算を肩代わりさせ、結果の座標だけを読み込んで pgfplots が描画します。gnuplot を「卓上計算機」として使うわけです。

latex
\begin{tikzpicture}
  \begin{axis}[xlabel={$x$}, ylabel={$y$}]
    \addplot[blue] gnuplot[domain=0:10] {sin(x)};
  \end{axis}
\end{tikzpicture}

重要な注意が二つあります。一つは **--shell-escape が必須** なこと。LaTeX が外部コマンド(gnuplot)を起動するため、pdflatex --shell-escape document のように 外部コマンド実行を許可 してコンパイルしないと動きません(-write18 とも呼ばれます)。処理の過程で gnuplot 用の中間ファイルが生成され、計算結果がそこに書き出されて読み戻されます。

もう一つは 文法の違い。gnuplot に渡す式は gnuplot の数学エンジンが評価するので、冪は pgfplots^ ではなく gnuplot 流の **** を使い、三角関数は ラジアン** が既定です。つまり同じ「sin の曲線」でも、pgfplots 内蔵なら {sin(deg(x))}、gnuplot 経由なら {sin(x)} と書き分けます。--shell-escape はセキュリティ上の理由で既定では無効なので、必要なときだけ付けるのが安全です。

R・Python のグラフを取り込む

すでに R や Python で解析していて、その描画をそのまま使いたい——けれど画像貼り込みのアラ(書体の不一致、数式のぼやけ)は避けたい。そんなときは、各ツールから TikZ/pgfplots のコード を書き出させると、グラフが文書の一部として組まれ、フォントも数式も本文と揃います。

R では **tikzDevice パッケージが、R の標準のグラフィックス出力(base プロットや ggplot2 を含む)を TikZ コード** として書き出す「グラフィックスデバイス」を提供します。tikz() でデバイスを開き、いつもの作図コードを実行して dev.off() で閉じると、.tex ファイルが得られます。文字列の幅やフォント計量を LaTeX に問い合わせて配置するため、出力は本文の書体に正確に合い、軸ラベルに LaTeX の数式を書くこともできます。standAlone=TRUE にすれば、単体でコンパイルできる完結した文書として出せます。

R
library(tikzDevice)
tikz("plot.tex", width = 4, height = 3)
plot(cars$speed, cars$dist,
     xlab = "Speed", ylab = "Distance")
dev.off()

Python(matplotlib)では **tikzplotlib**(旧称 matplotlib2tikz)が、matplotlib.pyplot で作った図を pgfplots コードに変換します。tikzplotlib.save("figure.tex") で書き出し、LaTeX 側では \input{figure.tex} で取り込みます。なお tikzplotlib は現在メンテナンスが止まっており、フォーク版の **matplot2tikz** が後継として開発されています。新規に始めるなら matplot2tikz を検討するとよいでしょう(API はほぼ同じ)。

python
import matplotlib.pyplot as plt
import tikzplotlib  # or: import matplot2tikz

plt.plot([0, 1, 2, 3], [0, 1, 4, 9])
plt.xlabel("$x$")
plt.ylabel("$x^2$")
tikzplotlib.save("figure.tex")

いずれの経路でも、出力された .tex は内部で pgfplots を使うため、文書側でも \usepackage{pgfplots}\pgfplotsset{compat=...} が必要です。生成コードを手で微調整できるのも、画像ファイルにはない利点です。

パフォーマンスと外部化

pgfplots は美しい反面、大量のデータ点では遅く、メモリも食います。数万点を超えるような散布図では、コンパイルが長くなったり、TeX のメモリ上限に達したりすることがあります。対策はいくつかあります。

  • 点を間引く。 each nth point=k で k 点ごとに描く、filter discard if not などで範囲外を捨てる。
  • 外部化(externalization)。 \usepgfplotslibrary{external}\tikzexternalize を使うと、各図を一度だけ別 PDF にコンパイルして以後は貼り込むだけにでき、本文の再コンパイルが軽くなります(--shell-escape が必要)。
  • メモリの大きいエンジン。 LuaLaTeX はメモリ制限が緩く、大きな図に向きます。
  • 前段で描いておく。 どうしても重いなら、R や Python・gnuplot で描いた結果を取り込む(前節)方が現実的なこともあります。

なお、外部化や gnuplot のように --shell-escape を要する機能は、CI やコンテナでビルドするときに有効化が必要です。Docker / CI での導入は関連ページを参照してください。