サーバサイドにおけるmatplotlibによる作図Tips


「計算を行い結果を作図して確認」という作業において計算をリモートで実行するケースも多い．この作業フローについて思い浮かぶ選択肢は以下の通り．

1. 計算結果の出力データ（ログ）をファイルに保存．（テキストベースだったり，シリアライズしたものだったり．）それをクライアントに転送し，別のプログラムで作図，確認する．
2. Jupyter Notebookを使う．サーバにてJupyter Notebookサービスを動かし，クライアントからWeb Browserで接続，もちろん図もBrowser上で確認．
3. サーバとリモートデスクトップ接続して，一連の作業を行う．
4. サーバサイドで作図，図のファイル出力まで行う．PNG，PDF等イメージファイルをクライアントPCで見る．

これまでは選択肢1, 2を選ぶことが多かったが，今回，**選択肢4**のサーバサイドでの作図についてTipsを紹介したい．

## 最初の失敗

「matplotlib.pylotにsavefig()があったよな」とやると，

```text
Traceback 
... （略）
RuntimeError: Invalid DISPLAY variable
```
のようにエラーとなる．表示先となるDISPLAYが設定されていないことに起因するものと思われる．ネットを検索し，matplotlibのbackendを指定することで対策となる．

```py
import numpy as np
import matplotlib as mpl
mpl.use('Agg')
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
from matplotlib import cm

def sphere_func(x, y):
    z = x * x + y * y
    
    return z

def contr3d1():
    ndiv = 200
    xp = np.linspace(-4., 4., ndiv)
    yp = np.linspace(-4., 4., ndiv)
    
    xx, yy = np.meshgrid(xp, yp, sparse=True)
    
    zp = sphere_func(xx, yy)
    
    fig = plt.figure()
    ax = fig.gca(projection='3d')
    ax.plot_surface(xx, yy, zp, 
        rstride=6, cstride=6, alpha=0.7, cmap=cm.rainbow)
    ax.set_zlim(-1.0, 40.)
    
    # plt.show()
    
    fig.savefig('sphere_3d.png')

if __name__ == '__main__':
    contr3d1()
```

プログラムの冒頭，モジュールをimportするところで，matplotlibがAGG(Anti-Grain Geometry engine)を使う指定をする．

```py
import matplotlib as mpl
mpl.use('Agg')
import matplotlib.pyplot as plt
```

ポイントは，matplotlib.pyplotをインポートする前にこのステートメント`mpl.use('Agg')`を入れることである．これで無事，savefig() が正常動作した．

## matplotlibのbackendsを指定する

今回，'AGG'を指定したが，matplotlibドキュメントによるとこのbackendsにはいくつかの種類を使うことができるようである．

**Non-interactive backends（matplotlibドキュメントから引用）**

| Renderere | Filetypes  | Description |
|:------------|:-----------|:------------|
| AGG           | png | raster grapahics - high quality images using the Anti-Grain Geometry engine |
| PS              | ps eps   | vector graphics - Postscript output |
| PDS           | pdf         | vector graphics - Portable Document Format |
| SVG          | svg         | vector graphics - Scalable Vector Graphics |
| Cairo        | png ps pdf svg ... | vector graphics - Cairo graphics |
| GDK        | png jpg tiff ... | raster graphics - the Gimp Drawing Kit |

試しに'SVG'を指定して実行させてみたが正常にSVGファイルを出力した．

（プログラミング環境は，OS Ubuntu-14.04 LTS, Python 2.7.11, Anaconda 2.4.1で一連のライブラリ(numpy, matplotlib他)を入れています．）

## 意外だったVisual Studio Codeの図形表示機能
無事，図形ファイルが出力できた．図形表示のツールは好みのものを使えばいいが，ここでは，Visual Studio Codeをお勧めしたい．ご承知の通りVisual Studio Codeはテキストエディタなのでテキストの扱いがメインであるが，Folder単位でopenできて，その中でアクティブにFileを切り替えながら作業を進めることができる．偶然，画像ファイル(png)を指定した（触った）ところ画像表示されたことで，この機能に気づくことができた．

（サーバのサービス(smb)でFile共有しています．クライアント(windows)側のVisual Studio CodeにてサーバのFolderをopenしています．）

**Fig. Visual Studio Code（普通にコードを表示）**
![matplotlib_snap1.png](https://qiita-image-store.s3.amazonaws.com/0/74152/d4c1161f-c144-d2ed-9ccc-86356b0edac2.png)

**Fig. Visual Studio Code（画像ファイル(png)を表示）**
![matplotlib_snap2.png](https://qiita-image-store.s3.amazonaws.com/0/74152/3d2f0f91-d67d-c779-636a-53dc05cecf03.png)
画像ファイル(png)を見ることができます．

**Fig. Visual Studio Code (SVGファイルを表示）（おまけ）**
![matplotlib_snap3.png](https://qiita-image-store.s3.amazonaws.com/0/74152/16c20432-d47e-4534-0ff8-108001d2838d.png)
レンダリングされるかなと一瞬思いましたが，SVGはテキストでした．

このようにテキストエディタの作業から離れることなく図形の確認ができるのでとても便利である．

なぜエディタで画像表示機能をサポートしているのか？少し疑問だったが，Markdown編集のプレビュー機能を入れるにあたり，画像表示機能を入れる必要があったのでは，と想像している．

（Visual Studio Codeは，version 0.10.8 を使用しました．）

## 参考文献 (web site)

- $DISPLAYが未定義でmatplotlibがコケる問題を再発させない方法 - Qiita
http://qiita.com/nishio/items/0a8949262d86c181668b
- Matplotlib Document
http://matplotlib.org/faq/usage_faq.html#what-is-a-backend
- Matplotlib: display plot on a remote machine - stackoverflow
http://stackoverflow.com/questions/3453188/matplotlib-display-plot-on-a-remote-machine
- How to save a figure remotely with pylab? - stackoverflow
http://stackoverflow.com/questions/4706451/how-to-save-a-figure-remotely-with-pylab
- Microsoft - Visual Studio Code https://code.visualstudio.com/