すごいグラフを描こう!

# はじめに
これは"すごい"グラフを描く方法を広めることを目的とした記事です.
ここでは,下に示すようなグラフを"すごい"グラフと呼称しています.このようなグラフの作成方法や,gnuplotの便利な使い方についても説明出来たらと思っています.
私は物理学実験のレポートで次のようなグラフを作成しました。[^1]

[^1]:ただしここでの"すごい"グラフとは,科学的なものを表すグラフとしての作法を守っていることを保証するものではありません.単に"それっぽい"あるいは"きれいな"くらいの意味しか持っていないことをわかっておいてください.これらのグラフも,特段指摘を受けることはありませんでしたが,あまり良くないものである可能性も否定はできません.

<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729740/a48ff73f-965a-3850-c5dd-2561cb898b61.png width=70%>
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729740/5df4a16f-2cb1-512d-c870-cb7cab75ce70.png width=70%>
大雑把なワークフローとしては、
gnuplotでグラフ作成→TeX(Tikz)で実行してブラッシュアップ
という感じです。
もちろん上記のようなグラフは,gnuplotだけでも作成できないことはないのですが,この方法でグラフを作成することには二つの利点があります.

* グラフをvector画像として取得できる
* カスタマイズ性が非常に高い

1つめの利点について,(これは私のいい加減な理解ですが)vector画像と言うのは点と点の関係を記述することによって描画される画像で、1つ1つのピクセルごとに色を指定するbitmap形式(png画像やjpg画像がこれに該当します)と比べて多くの場合非常に軽量になるうえ、拡大しても「ガビガビ」になりません.(点と点の関係が相似変換されるだけであるからです.)ちなみに上記画像は,Qiitaがpdf画像を受け入れていないようなので仕方なくスクショして貼り付けています(そのためただのpng画像になっています)

2つめの利点について,tikzコードを直接いじることで、軸ラベルの位置を自在に変えることができたり、やろうと思えば点ごとにそれが何のデータなのか示すこともできます.そして何より、TeXで綺麗にレンダリングされた数式をグラフ中で用いることができます!

## 前提
さて、あまり導入ばかり喋っていても仕方がないので本題に移りたいわけですが、混乱を防ぐために、前提を書いておきます。まず次の環境を前提とします。

* PCのOSがWindows(10,11)であること
* 最新版のgnuplotがPCにインストールされていること
* TeXLiveでTeXをインストールしていること

さらに,用いるTeX文書クラスはjsarticle,コンパイラはuplatex,dviドライバをdvipdfmxであるとします.実際には作業をVScode上で行います.

:::note 
前提に関する情報：
PCのOSとしてWindowsを指定しているのは,筆者がWindows上での動作しか確認していないからです.また,グラフ作成作業の最後にpdfcropというコマンドラインアプリケーションを使用するのですが、TeXLiveによるインストールをした場合は,わざわざチェックを外したりしていなければこのコマンドラインアプリがインストールされます.TeXLiveによるインストールを指定しているのは,このためです.
gnuplotのバージョンに関して,どのバージョンであれば問題なく動作するのかということは検証していません.最新版であれば大丈夫なはずです.
:::

## 目標設定
とりあえず,どんなグラフを作るのかということを決めておきましょう.次のグラフを作成することを目標としておきます.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729740/68f166fa-6a34-086b-f8e2-062e83686240.png)

# グラフのつくりかた
## 下準備
まず適当な場所に作業するフォルダを作ってください.このフォルダはあとから消しても大丈夫なので,気にならないのであればDocument直下とかでもいいです.そのフォルダの名前を仮に,hogeとしておきます.
gnuplotを開き,そのフォルダに移動し,そこで
```gnuplot:gnuplot
set terminal tikz createstyle
```
を実行してください.
`Terminal type is now 'tikz'`とか,`Options are …`というメッセージが出てくると思いますが問題ありません.
hogeの中に次の4つのファイルが生成されたと思います.
`gnuplot-lua-tikz-common.tex`
`gnuplot-lua-tikz.sty`
`gnuplot-lua-tikz.tex`
`t-gnuplot-lua-tikz.tex`

これらのファイルのうち,
`gnuplot-lua-tikz.sty`を`"C:\texlive\texmf-local\tex\latex\local"`に
他3つを`C:\texlive\texmf-local\tex\plain\local"`に
入れてください.
そしてターミナルを開き,
```powershell:
mktexlsr
```
を実行してください.ターミナルを開く場所はどこでもよいです.
これで下準備は完了です.hogeは中に入ってるファイルごと消去してかまいません.また,この作業は次回以降必要ありません.(1回したらもうそれでok)

## 作業の流れ
作業の流れについて説明しておきます.

gnuplotでグラフを作成
→
gnuplotによってtikzコード生成
→
TeXでそのコードを実行
→
pdfcropで必要部分だけ切り取り

という流れです.

## gnuplotにおける作業
まず,作業用のフォルダを都合の良い場所に作成してください.ここではフォルダの名前はGaussとしたとします.gnuplotを開いてこのフォルダに移動して,

```gnuplot:gnuplot
set terminal tikz
set output "gauss.tex" 
```

を実行します.Gaussの中に`gauss.tex`が生成されていると思います.さらに次の命令を実行します.

```gnuplot:gnuplot
set xrange [-pi:pi]
set xlabel "x"
set ylabel "y"
set title "$y=exp(-ax^2)$"
t1 = "a=1"
t2 = "a=2"
plot exp(-x**2) title t1, exp(-2*x**2) title t2
```

するとgauss.texにコードが書き込まれます.

::: note
ちなみにこれをoutputなどを指定せずにgnuplotウィンドウに出力すると,次のようになります.
![gauss.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729740/fb6f7ed3-31c4-4210-bd80-674275c0beca.png)

実行すればこのグラフとほとんど同じものを出力するようなtikzコードをgnuplotに吐かせる役割をしているのが前半の
`set terminal tikz`
`set output "gauss.tex" `
です.
:::

これで

gnuplotでグラフを作成
→
gnuplotによってtikzコード生成

の部分の作業は終わりです.

## TeXにおける作業
さて,フォルダーGaussにはgauss.texがあるわけですが,さらにgaussDo.texを作成して次の内容を書き込みます.

```LaTeX:gaussDo.tex
\documentclass[uplatex,dvipdfmx]{jsarticle}
\pagestyle{empty}
\usepackage{gnuplot-lua-tikz}
\begin{document}
\include{gauss.tex}
\end{document}
```
そしてビルドしてください.すると目標のグラフだけが貼り付けられた**ページ番号のない**pdfが得られたかと思います.たぶんpdfの名前はgaussDo.pdfだと思います.

:::note warn
`\include{gauss.tex}`だと,もしかすると上手くいかないことがあるかもしれません.その場合は`\input{gauss.tex}`とするか,`gauss.tex`を開いてCtrl+A→Ctrl+C→Ctrl+Vで全て持ってきてもよいでしょう.
:::

これで

TeXでそのコードを実行

の部分はおわりです.

## pdfcropによる仕上げ
さて,フォルダーgaussでターミナルを開き,
```powershell
pdfcrop  gaussDo.pdf
```
を実行します.すると,`gaussDo-crop.pdf`というpdfが生成され,それを開いてみると目標のグラフが書き込まれ__________ては**いません**ね.

:::note info
pdfcropは読み込んだpdfの描画範囲を読み取り,そこだけを切り取ってくれるものです.ページ番号があると,そこまで含めて切り取られてしまうので,結局役に立ちません.謎の`\pagestyle{empty}`はページ番号を消してpdfcropでちゃんとグラフだけを切り取ることができるようにしてくれていたわけですね.
:::

## 何がダメだったのか
もちろんエラーが起きたわけではありませんでした.作成されたものを次に示します.
![gaussDo-crop_page-0001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729740/8f5f94c6-9d4b-2ced-50a1-847072d89943.jpeg)

問題なのは,グラフタイトル,軸ラベル,凡例ですね.グラフタイトルに関してはexpがイタリックになってしまっていますし,逆に軸ラベルなどはイタリックになっておらず,かっこよくありません.
これを修正するには,もととなった`gauss.tex`をいじってやると良いです.`gauss.tex`を開いてCtrl+Fでxを検索してみます.するとおそらく一件しかヒットせず,
`\node[gp node center] at (6.633,0.215) {x};`
という部分が見つかるかと思います.この部分が軸ラベルであるxを描画しています.これを
`\node[gp node center] at (6.633,0.215) {$x$};`
と変更すれば実行した結果のxがイタリックになります.
近くにyやa=1に関してもあると思うので同様に変更してしまいましょう.
a=2は少し下に,y=exp(-ax^2)は一番下にあると思います.これを読んでいるようなあなたならわかるかと思いますが,expの方はy=\exp(-ax^2)としたらよいですね.

さて,この変更の下で`gaussDo.tex`をビルドしなおして`pdfcrop`ももう一回やりましょう.すると,目標のグラフが得られたはずです.めでたしめでたし.
![gaussDo-crop_page-0001 (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729740/6132c981-af8b-cea5-a3c5-b6f66a6e7c91.jpeg)



# gnuplotの良い使い方
gnuplotを使っていていちいち命令を書き込むのが面倒だと感じたことはありませんか?出力結果を微調整するために何回も打ち込み直すのは面倒です.**そんなときに役立つのがplotファイルです** 
この記事の流れでいえば,フォルダーGaussに`gauss.plot`というファイルを作ってgnuplotで実行したい命令を書き込んでおきます:

```gnuplot:gauss.plot
set terminal tikz
set output "gauss.tex" 
set xrange [-pi:pi]
set xlabel "x"
set ylabel "y"
set title "$y=exp(-ax^2)$"
t1 = "a=1"
t2 = "a=2"
plot exp(-x**2) title t1, exp(-2*x**2) title t2
```

フォルダーGaussでターミナルを開き,
```powershell
gnuplot gauss.plot
```
とすると,`gauss.plot`の内容がgnuplotで実行されます.あとは同じようにすれば目標のグラフを作成できます.仕上がりを変更したければこのplotファイルの中身を変更すればよいわけです.

ただし,この記事をここまで読んでいただいているとお分かりの通り,ある程度の手間がかかります.そのため,**gnuplotでpng画像として出力させるなど簡単な仕上がりを確認し,満足のいく出来になったところで**

```gnuplot:gauss.plot
set terminal tikz
set output "gauss.tex" 
```

**などとし,完成させることをお勧めします.**

# グラフのカスタマイズあれこれ
tikzは割となんでもできるわけですが,筆者が物理学実験の実験レポート用にグラフを作成する中で主に行っていたカスタマイズ作業についていくらか紹介してみたいと思います.

### 軸ラベルの位置調整
グラフによっては軸ラベルの位置が少し窮屈に感じるかもしれません.

この記事の`gauss.tex`でいうと,x軸のラベルであるxを出力しているのは,
`\node[gp node center] at (6.633,0.215) {$x$};`
の部分です.(変更後)`at (6.633,0.215)`の部分がその座標を記述しているので,少し下に下げたければたとえば
`\node[gp node center] at (6.633,0.015) {$x$};`
とすればよいです.

y軸のラベルについても,少し左に移動させたければ
`\node[gp node center,rotate=-270] at (0.292,4.405) {$y$};`
→
`\node[gp node center,rotate=-270] at (0.092,4.405) {$y$};`
とすればいい感じになります.[^2]

[^2]:0.2ずつ減らしていますが,特に数字自体に意味はありません.

### 凡例の位置調整
gnuplotの凡例は特段指定しなければ右上に配置されますが,この位置がかなり右上スレスレなのでたとえばこのグラフのように目盛り線とApproximation lineという文字が被っているというか,つっかえている感じになることがあります.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729740/31ae297c-b666-3b8b-c115-a5bc4a761ef7.png)
このような場合にはたとえばApproximation lineの文字を下に下げたくなります.この記事で作成したガウス関数のグラフでもよく見ると $a=1$ の部分が少しつっかえてしまっていますね.この部分に少し手を加えてみましょう.

`\node[gp node right] at (10.479,7.491) {$a=1$};`
→
`\node[gp node right] at (10.479,7.291) {$a=1$};`

とすると $a=1$ の部分が $a=2$ に重なってしまっていて,しかも紫色の線の位置も変わっていません.
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729740/0a70462b-5dba-02e5-f9cc-509236621b36.jpeg width=70%>
`gauss.tex`の
`\node[gp node right] at (10.479,7.291) {$a=1$};`
の行の2行下に
`\draw[gp path] (10.663,7.491)--(11.579,7.491);`
とあると思いますが,ここが凡例の紫色の線を描いている箇所です.これを
`\draw[gp path] (10.663,7.291)--(11.579,7.291);`
とすれば線の位置も下がります.

$a=2$についても同様に
`\node[gp node right] at (10.479,7.183) {$a=2$};`
→
`\node[gp node right] at (10.479,6.883) {$a=2$};`

`\draw[gp path] (10.663,7.183)--(11.579,7.183);`
→
`\draw[gp path] (10.663,6.883)--(11.579,6.883);`

とすれば…
![gaussDo-crop_page-0001 (4).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729740/cb992548-57c2-5efd-9a6c-aaa5e65fb9bd.jpeg)
よりいい感じになりましたね.上で述べた,軸ラベルの位置調整も同時に行ってみました.

:::note info
ある程度凡例や軸ラベルの位置を調整することはgnuplotのコマンドの方で可能です.gnuplotの方である程度整えておく方が良いかもしれません.
[gnuplot でx,y軸ラベルを動かす方法](https://hanjouchan.org/2020/12/14/gnuplot-%E3%81%A7xy%E8%BB%B8%E3%83%A9%E3%83%99%E3%83%AB%E3%82%92%E5%8B%95%E3%81%8B%E3%81%99%E6%96%B9%E6%B3%95/)
[gnuplotによるグラフ作成6～凡例の書式設定](https://atatat.hatenablog.com/entry/2020/07/23/090000)
:::

### 物理量の単位を書いてみる
人は(科学者は)単位というものさしを使って世界を観察します.物理量には単位がつきものです.仮に,この記事で作成したグラフのxの単位がmm,yの単位がkeVだとします.
`\node[gp node center] at (6.633,0.015) {$x$\,mm};`
としてもよいですが,3つ上の図のように単位を右下,左上に配置するこにとにしてみます.

`\node[gp node center] at (11.708,0.677) {$3$};`
とあるので,右下はおおよそ(11.7,0.68)という座標であることがわかります.少し調節して,
`\node[gp node center] at (11.710,0.277) {(mm)};`
と追記します.このコードを追加する場所はどこでもよいですが,私はいつも目盛りの一番右を描いているコードのすぐ下,この場合は`\node[gp node center] at (11.708,0.677) {$3$};`のすぐ下に置いています.

同様に,`\node[gp node right] at (1.136,7.825) {$1$};`
とあるのでそのすぐ下に
`\node[gp node right] at (0.636,7.825) {(keV)};`
と追加して,実行します.

:::note warn
コードを追記する際には最後に;を忘れないようにしましょう.マナー的な話ではなく,つけないとエラーが出ます.
:::

実行した結果:まぁいい感じ?
![gaussDo-crop_page-0001 (5).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729740/6f8e1dc0-56ae-8824-1c27-a4d5480312b6.jpeg)
**とはいっても,いまのグラフは単位を書くことを前提にしたものではないので,この単位を表示する行は以降消しておきます.**

### 補助線を描いてみる
この記事の最初に提示したグラフでは7cmのところに補助線を引いています.ここでは,y=0.5のラインに点線を引くことにします.

26行目に
`\node[gp node right] at (1.136,4.405) {$0.5$};`
とあるので,y=0.5のラインはtikzコードの座標で4.405です.
また,108行目に
`\draw[gp path] (1.320,7.825)--(1.320,0.985)--(11.947,0.985)--(11.947,7.825)--cycle;`
とあるのでグラフの枠の一番左は1.320で一番右は11.947です.つまり(1.320,4.405)~(11.947,4.405)に線を引けばよいので

適当な場所に
`\draw[dashed] (1.320,4.405)--(11.947,4.405);`
と書いて実行します.

結果:
![gaussDo-crop_page-0001 (6).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729740/c6db80e0-128f-90c7-277f-f01f9be4268e.jpeg)
gnuplot単体ではできない感じがあっていいですね.

### 矢印を付けてみる
`\draw[gp path,->] (0,0)--(1,1);`
などとして矢印を描くことができます.そのようにして友人[^3]が作成した図を次に示します.こんなものも作成できるのがこの方法の魅力です.
![plot_output_page-0001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729740/1bb2539f-6d9b-85cf-8489-cd5692a48135.jpeg)

[^3]:感謝を込めて,その友人のgithubページのリンクを貼っておきます:https://github.com/Gs-itisitcat

# さいごに
このグラフ作成方法で"すごい"グラフを作成される方が少しでも増えれば筆者としては嬉しい限りです.あなたも素敵なグラフ作成ライフを!

この次にデバッグ＆Q＆Aを載せておいたので,エラーが出てしまうという場合は参考にしてください.また,この記事に関して問題を発見した場合はこの記事のコメントか,筆者のツイッターアカウントDMまでお知らせください.

# デバッグ＆Q＆A
<details><summary>折り畳み</summary>

:::note info
Q：macOSの場合やTeXLive以外でインストールした場合はどうすればよいですか?
A：要はpdfcropが使えればよいので,pdfcropだけをインストールしてくればよいです.その方法は知りませんが,がんばってください()
:::
:::note warn
アンダースコアや^に注意するようにしましょう.
たとえば実験データをプロットする際にExperiment_data.csvがあってそれをプロットするということがあると思います.
`plot "Experiment_data.csv"`
とした場合に特に指定しない限り,gnuplotはこのデータの凡例をそのままExperiment_data.csvとします.これをtikzコードに変換して実行しようとすると,エラーが起きます.これは,_(アンダースコア)が数式環境でしか使用できないためです.名前が決まっていない場合は
`plot "Experiment_data.csv" title ""`
とするなどして回避するようにしましょう.

同じように,タイトルに^を使用している場合はエラーが出ます.上の例でグラフタイトルを`$y=exp(-ax^2)$`としたのはこのエラーを回避するためです.

また,Åのような特殊な文字もtikzコード変換時に問題が生じる可能性があるので,使いたい場合はその文字を使わずに生成したtikzコードに直接書くことを推奨します.
:::
</details>