pythonでgraphを扱うライブラリnetworkxを使う(その１:環境構築)

pythonでGraphまわりを扱うために,networkxをdockerで使えるようにした時のメモ。

# 行ったこと
1.  Dockerfileを使ってpullしたimageをカスタマイズ
2.  dockerからmatplotlibの表示をpop up

### ホストの環境
```souece:OS
$ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.6 LTS"
```
### dockerの環境
[こちらで構築した環境](https://qiita.com/iwankoTG/items/05b39c9c42ad278917a0)を使っています。

# 1.  Dockerfileを使ってpullしたimageをカスタマイズ
dockerのimageは必要なものをnvidia-dockerからpullしてきて使っていたが、graphを扱うnetworkxなどをinstallしたものが必要になったため、Dockerfileを作成しました。
Dockerfileの作成にあたっては、[こちらのブログ](https://knowledge.sakura.ad.jp/15253/)などを参考にしました。

```souece:
$ docker images
REPOSITORY                    TAG                            IMAGE ID            CREATED              SIZE
nvcr.io/nvidia/tensorflow     19.12-tf1-py3                  af027926c1a0        3 months ago         8.32GB
nvcr.io/nvidia/tensorflow     18.06-py3                      0d13c9061269        22 months ago        3.4GB
```
pullしてあるimageから、使用するimageとしてnvcr.io/nvidia/tensorflow:19.12-tf1-py3を選択して、以下のようなDockerfileを作成します。


```souece:Dockerfile
FROM nvcr.io/nvidia/tensorflow:19.12-tf1-py3  

ARG DEBIAN_FRONTEND=noninteractive
             
RUN apt-get update && \
    pip install networkx
```
networkxはインストール時にgeographic areaなどを選択して入力するステップがあるが、２行目の「ARG DEBIAN_FRONTEND=noninteractive」を追加すると、docker buildの際に入力操作が不要になります。

上記のDockerfileを作成した後、docker buildをします。

```souece:
$cd **/work/  [Dockerfileのあるフォルダ]
$docker build -t [repository名]:[tag名] . 
例）$docker build -t test:1 . 
```
build処理が終了するとdocker imageが生成されます。

```souece:
$ docker images
REPOSITORY                    TAG                            IMAGE ID            CREATED              SIZE
test                          1                              ca131395a6b9        About a minute ago   8.38GB
nvcr.io/nvidia/tensorflow     19.12-tf1-py3                  af027926c1a0        3 months ago         8.32GB
nvcr.io/nvidia/tensorflow     18.06-py3                      0d13c9061269        22 months ago        3.4GB
```
生成したimageからコンテナを作成すると、networkxが含まれたコンテナとなっていることが確認できました。

```souece:
$docker run --gpus all -it --rm test:1
                                                                                                                                                
================
== TensorFlow ==
================

NVIDIA Release 19.12-tf1 (build 9258376)
TensorFlow Version 1.15.0

Container image Copyright (c) 
（省略）....

# python
Python 3.6.9 (default, Nov  7 2019, 10:44:02) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import networkx
>>> 
```

#2.  dockerからmatplotlibの表示をpop up
次に、graphの構造などをmatplotlibで出力しながら確認したかったので、出力がpop upするように設定しました。行ったことは主に次の３つです。
 ・2.1 matplotlibのbackendの指定.
 ・2.2 tkinterのインストール
 ・2.3 出力先の設定.

### 2.1 matplotlibのbackendの指定.
matplotlibのbackendはデフォルトでAggになっているそうですが、これをTkAggに変更します。変更の方法としては、matplotlibrcを変更する方法などもあるようですが、ここではpythonのコードの中に記載しました。

```souece:sample.py
import matplotlib
matplotlib.use('TkAgg')
```

###2.2 tkinterのインストール
TkAggを指定すると、「tkinterというモジュールがありません」というエラーメッセージがでます。そこでtkinterをインストールするのですが、pip installではなく、apt-get install を使います。こちらもDockerfileに追加します。

```souece:Dockerfile2
FROM nvcr.io/nvidia/tensorflow:19.12-tf1-py3  

ARG DEBIAN_FRONTEND=noninteractive
             
RUN apt-get update && \
    apt-get install -y python3-tk && \
    pip install networkx
```
dockerfileを変更したので、1と同様にdocker buildによりimageを作り直します。

###2.3 出力先の設定
最後に、画像のpop upが可能となるように設定します。

```souece:
$xhost +
$docker run --gpus all -it -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY test:1
```
こうして、以下の簡単なサンプルコードを実行すると、グラフ構造がpop upされます。また、同じグラフがtemp.pngとしてpythonを実行したフォルダに出力されます。

```souece:sample.py
import matplotlib
import matplotlib.pyplot as plt
import networkx as nx

matplotlib.use('TkAgg')
G = nx.DiGraph()
nx.add_path(G, [3, 5, 7, 1, 0, 2, 5, 8, 9, 6])
nx.add_path(G, [3, 0, 2, 4, 2, 7, 1, 9, 4, 5])

nx.draw_networkx(G)
plt.savefig('temp.png')
plt.show()
```
```souece:
# python sample.py
```
![Figure_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616171/dfb41368-bf1b-3416-0841-e28ec84ce10d.png)

###2.4 参考資料
以下の記事を参考にさせていただきました。
1. [NVIDIAが入っているPCにおいてdocker上でopenGLなプログラムを起動して手元で見る．](https://qiita.com/eisoku9618/items/c2cca0f0bf764def2efd)
2. [stackoverflow](https://stackoverflow.com/questions/56656777/userwarning-matplotlib-is-currently-using-agg-which-is-a-non-gui-backend-so)

###2.5 関連記事
・[pythonでgraphを扱うライブラリnetworkxを使う(その1:環境構築)](https://qiita.com/iwankoTG/items/be0ae8a59f61578ad3b4)
・[pythonでgraphを扱うライブラリnetworkxを使う(その2:チュートリアル)](https://qiita.com/iwankoTG/items/40d77ebf854cf28a6c05)