gnuplotのepslatexを使ってTeXへちゃんとした数式入りのグラフを挿入する

学会への投稿などで忙殺されてるうちに季節は春になり,鯖とかホタルイカとかが結構旬になってきましたね.
お魚が食べたいです.

さて,(少なくとも僕たちの界隈では)学会準備シーズンということで僕も日々涙目になりながらいくつかの原稿を書いてます.
そんなとき,gnuplotで生成した図の凡例やラベルに複雑かつ綺麗な数式を書いてTeX原稿に貼り付けたい!とか,グラフ中に日本語が使いたい!とかの需要は極めて多くあるんですが,やりたいことのシンプルさのわりにえっらい作業量が多くて困る.

20130319_top_bad20130319_top_good

その中でもよく使われるのがpsfragで,epsをTeXソース貼り付けてコンパイルするとき,強引にeps中の特定文字列をTeXの記述に置換してコンパイルすることで・・・というかなり強引なやり方です.

これで普通にうまくいくならそれでOKなのですが,手元の環境でうまくいったことがない・・・後述するTeX Liveとの相性なんだと思いますが.

ということで,psfragを使わないepslatexによる方法を解説します.
この方法はpsfragのように追加のスタイルが必要ないこと,また記述の柔軟性がかなり高いという大きなメリットがあります.

一方,psfragのメリットは使えるフィールドがgnuplotに限られないことが大きいです.psfragなら例えばtgifで描いた図のラベルを数式に出来たりします.
あと作業量はやっぱりpsfragの方が少なくて済むので,手元の環境で動けばpsfragで構わないだろうとは思います.適切に使い分けてください.

TeX環境はTeX Liveがおすすめ

まず,TeXの環境構築についてはTeX Liveがおすすめです.記述は古いですがこちらのやり方で,よく使う最新の環境が一式,一発で入ります.
さかな前線 » TeX Live 2011のインストール
Ubuntu等の標準パッケージはいろいろやりづらいのでやめたほうがいいと思います.

epslatexの概要

  • epslatexとはgnuplotの出力形式の一つで,terminalにepslatexを指定する
  • 出力は文字の入っていないepsと,そのepsを読み込んで文字情報を追記するための小さなtexファイル
  • そのtexをごにょごにょしてコンパイルすると,数式の入った図が得られる
  • なので,labelによる参照だろうが文字の大きさ変更だろうが何でもできる自由度
  • graphicxなど基本的なパッケージだけで使える

TeXソースに直接図を埋め込む場合のやり方

一般的な解説では,psfragにせよepslatexにせよ

  1. gnuplotで(数式の入ってない)図を生成
  2. 単体のtexソースを書いて(数式の入った)eps化
  3. tex原稿本体に普通のやり方で埋め込み

というやり方について述べたものが多いです(次節ではその説明をしてますw).
ただTeX原稿に埋め込むことが目的の場合に関しては,数式の入ったepsを経由する必要はなくて,本節ではそれについて説明します.

#経験あれば容易に推測がつくからわざわざ説明しないだけでしょうがw

gnuplotのプロットファイルを書いて図を生成しましょう

次のようなファイルを書きます.plot.pltというファイル名とします.
描画するのは矩形波をフーリエ級数展開したものです.

#plot.plt
set terminal epslatex color 12  #←ここ!
set output "figure.eps"

set xrange [-10:10]
set yrange [-2:2]
set xlabel "t"
set ylabel "f(t)"

plot (sin(x) + sin(3 * x) / 3 + sin(5 * x) / 5 + sin(7 * x) / 7 + sin(9 * x) / 9)*4/pi title "eq1"

通常のplotファイルですが,2行目で出力形式をepslatexにしてることが注目.なおcolorは色付き,12はデフォルト文字サイズです.

これで図を出力します.ちょっと警告が出ますがスルーでOKです.

% gnuplot plot.plt
plot.plt, line 9: warning: Resetting primary output file to figure.tex,
                  PostScript output to figure.eps
% ls
figure.eps  figure.tex  plot.plt

するとepsとtexが出力されています.
epsを見るとグラフだけで文字が入っていないことをご確認ください.
これに文字を重畳するのが,texの側になるわけです.これによりtexの表現能力をまるごと享受できるわけですね.

凡例・ラベルを数式に置換しましょう

出力されたfigure.texの最後を見るとこんなかんじ.
各軸のラベルと凡例,そして数式本体が書かれています.頑張って目grepしてくださいw

      \put(5369,528){\makebox(0,0){\strut{} 5}}%
      \put(6767,528){\makebox(0,0){\strut{} 10}}%
      \put(192,2759){\rotatebox{-270}{\makebox(0,0){\strut{}f(t)}}}%
      \put(3971,168){\makebox(0,0){\strut{}t}}%
    }%
    \gplgaddtomacro\gplfronttext{%
      \csname LTb\endcsname%
      \put(5696,4568){\makebox(0,0)[r]{\strut{}eq1}}%
    }%
    \gplbacktext
    \put(0,0){\includegraphics{figure}}%
    \gplfronttext
  \end{picture}%
\endgroup

これを次のように書き換えます.
軸のラベルに対しては数式なのでドルマークつけるだけで,凡例にはグラフを表すやや複雑な式を書いています.

      \put(5369,528){\makebox(0,0){\strut{} 5}}%
      \put(6767,528){\makebox(0,0){\strut{} 10}}%
      \put(192,2759){\rotatebox{-270}{\makebox(0,0){\strut{}$f(t)$}}}%
      \put(3971,168){\makebox(0,0){\strut{}$t$}}%
    }%
    \gplgaddtomacro\gplfronttext{%
      \csname LTb\endcsname%
      \put(5696,4568){\makebox(0,0)[r]{\strut{}$f(t) = \sum_{k=1}^{5}{\frac{4}{\pi} \cdot \frac{1}{2k-1}\sin{(2k-1)t}}$}}%
    }%
    \gplbacktext
    \put(0,0){\includegraphics{figure}}%
    \gplfronttext
  \end{picture}%
\endgroup

これでひとまずおk.

そのままTeX原稿に埋め込みましょう

このようにして作ったtexとepsを,原稿本体のtexに埋め込みます.
原稿の任意の部分にfigure環境を書いて,いつものincludegraphicsの代わりにinputで拡張子なしの先ほど生成したtexを書きます.
大きさについてはresizeboxを使い,絶対値や相対値で縦または横あるいは両方を指定できます.

\documentclass[a4j]{jsarticle}
\usepackage{graphicx}

\begin{document}

\begin{center}
    \begin{figure}[h]
        \begin{center}
            %\resizebox{0.5\hsize}{!}{\input{figure}}  %相対値での指定も可能
            %\resizebox{50mm}{200mm}{\input{figure}}  %両方の指定も可能
            \resizebox{80mm}{!}{\input{figure}}
            \caption{矩形波のフーリエ変換($k \le 5$)}
        \end{center}
    \end{figure}
\end{center}

\end{document}

これで普通にtexコンパイルすると,

20130319_result1

こんなかんじで埋め込まれた原稿ができます.

自由度は結構ピカいち

図と一緒に生成させたtexをどうにでも弄れるので,例えばこんな図も難なく生成できます.
原稿本体側の数式へのreferenceができてること,日本語がナチュラルに使えてること,あとなぜか横軸の0がデカいことあたりに着目してくださいw
20130319_result2

このために,まずグラフ用のtexソースを次のように書き換えて,

      \put(2574,528){\makebox(0,0){\strut{}-5}}%
      \put(3972,528){\makebox(0,0){\strut{} \Huge{0}}}% 横軸の0をデカくするw
      \put(5369,528){\makebox(0,0){\strut{} 5}}%
      \put(6767,528){\makebox(0,0){\strut{} 10}}%
      \put(192,2759){\rotatebox{-270}{\makebox(0,0){\strut{}$f(t)$}}}%
      \put(3971,168){\makebox(0,0){\strut{}$t$}}%
    }%
    \gplgaddtomacro\gplfronttext{%
      \csname LTb\endcsname%
      \put(5696,4568){\makebox(0,0)[r]{\strut{}式(\ref{eq:fourier_box})}}% 本文中の数式への参照にする
    }%
    \gplbacktext
    \put(0,0){\includegraphics{figure}}%
    \gplfronttext
  \end{picture}%
\endgroup

原稿本体の方のtexもこんなかんじに.

\documentclass[a4j]{jsarticle}
\usepackage{graphicx}

\begin{document}

矩形波を$k=5$までフーリエ級数展開することにより,次式を得る.
\begin{equation}
    f(t) = \sum_{k=1}^{5}{\frac{4}{\pi} \cdot \frac{1}{2k-1}\sin{(2n-1)t}} \label{eq:fourier_box}
\end{equation}

\begin{center}
    \begin{figure}[h]
        \begin{center}
            \resizebox{80mm}{!}{\input{figure}}
            \caption{矩形波のフーリエ変換($k \le 5$)}
        \end{center}
    \end{figure}
\end{center}

\end{document}

こんなかんじで,この自由度の高さは嬉しいことも多いはず.

グラフ単体の画像ファイルが欲しい場合のやり方

上の例はグラフを原稿本体の一部として埋め込むためのやり方なんですが,(例えばpptに貼り付けたいなどで)図単体がeps画像として欲しい場合もあります.
gnuplotで出力するところまでは一緒で,出てきたtexの書き換えからが異なります.

グラフ用のtexの書き換え

まず,gnuplotで吐いたfigure.texに対して,頭に追記します.

\documentclass[a4paper,12pt]{article}
\usepackage{graphicx}
\pagestyle{empty}
\begin{document}
\begin{figure}
% GNUPLOT: LaTeX picture with Postscript
\begingroup
  \makeatletter
  \providecommand\color[2][]{%

また,末尾にも追記します.

    \gplbacktext
    \put(0,0){\includegraphics{figure}}%
    \gplfronttext
  \end{picture}%
\endgroup
\end{figure}
\end{document}

これでfigure.texがひとつの完全な(単独のコンパイル可能な)texソースとなります.
※ここではgnuplotの吐いたtexをそのまま編集してますが,別の小さいtexを一つ作ってそこで\input{figure}として次以降やることもできます.

dviをps経由でepsへ変換

書き換えたtexをコンパイルしたdviをpsに変換し,それをepsにするという少しめんどくさい作業になりますが完全にルーチンワークです.
これで,次のコマンドを順次実行していきます.

% platex figure.tex
% dvips figure.dvi
% ps2epsi figure.ps figure2.eps

これで生成されたepsを見ると,数式のついたepsになってます.
dvipsにはいくつかパラメータがありますが,基本的にはデフォルトで問題ないかと.
あと環境によってdvipskだったりps2epsだったり,微妙にプログラム名が違うことがあるぽいですがそこは各自の環境に合わせて適切におねがいします.

これをtexに貼るもよし,png化してパワポとかに貼るもよしです.

#要ImageMagick
% convert figure2.eps figure.png
% convert -density 300x300 figure2.eps figure.png #高精細なpngが得られます.

生成したPNGがこれ.透過になってるので使いやすいですね.
20130319_result3

あまり関係ない細かい話 〜凡例をディスプレイ数式モードで表示〜

グラフの凡例の数式はインライン数式モードになってて,総和\Sigmaがごちゃごちゃして個人的に好きじゃない(´・ω・`)
gnuplotの吐いたfigure.texを書き換えるとき,

       \put(5696,4568){\makebox(0,0)[r]{\strut{}$\displaystyle f(t) = \sum_{k=1}^{5}{\frac{4}{\pi} \cdot \frac{1}{2k-1}\sin{(2k-1)t}}$}}%

と言う風に強制的にディスプレイ数式モードにすればいいのですが,そうすると数式がでかくなり,こんなふうになってしまいます・・・

20130319_result_display_mode

なので,強引な対処法としては例えば,plot.pltを次のように書き換えて

set terminal epslatex color 12
set output "figure.eps"

set key title " "  #凡例タイトルを空にすると,凡例の上に若干のスペースが確保できる
set xrange [-10:10]
set yrange [-2:2]
set xlabel "t"
set ylabel "f(t)"

plot (sin(x) + sin(3 * x) / 3 + sin(5 * x) / 5 + sin(7 * x) / 7 + sin(9 * x) / 9)*4/pi title "eq1"

後は(\displaystyleを指定する以外)全く同じようにすれば,この場合は運良くちょうどいいかんじになります.対症療法感MAXですがw

20130319_result_display_mode2

gnuplotで凡例の絶対位置を直接指定する方法(>set key x,y)もあるらしいんですが手元のgnuplot 4.6ではできませんでした(´・ω・`)

まとめ

ということで,

  • gnuplotでterminalをepslatexに,ファイル名をhoge.epsにしてグラフ描画するとhoge.epsとhoge.texが生成される
  • hoge.texを適切に書き換えることで,凡例やラベルに任意のtex記述ができる
  • 原稿本体ソースで直接呼び出して数式入りグラフの埋め込まれた原稿を得る
  • 単体でもpsを経由しepsにすることで数式入りグラフの画像を直接得る

ことを解説しました.

この世界,Contribute or Dieなのでみなさんがんばりましょうか><。 ←

2 thoughts on “gnuplotのepslatexを使ってTeXへちゃんとした数式入りのグラフを挿入する

  1. すごい…
    epslatexなんてあったんですね!
    感動しすぎて言葉も出ません.
    今までの苦労は何だったのか…

  2. 僕もこれを知った時はなんで今まで知らなかったのかとせつなかったのをよく覚えてますw
    にしてもTeXの図表周りは今に至るまで残念なままですねぇ…

コメントを残す

メールアドレスが公開されることはありません。