NetworkX と PyGraphviz / Gephi で日本語ラベル付きエッジを持つグラフを可視化

# はじめに

NetworkX は matplotlib を使うこともできますが、PyGraphviz や Gephi でグラフを描画したほうがいろいろと細かい設定ができるようです。

ここでは、Python 上の NetworkX で日本語ラベル付きエッジを持つようなグラフを作成したあとに、[AGraphクラスのオブジェクト (dot 形式)](https://pygraphviz.github.io/documentation/latest/reference/agraph.html) へ変換して pygraphviz で描画結果をファイル出力し、それと同時に GraphML ファイルを出力する例を紹介します。出力された GraphML ファイルは Gephi へ入力して可視化することが可能です。

ついでにインストール方法をまとめておきます。

# インストール

## NetworkX

```shell-session
> pip install networkx
```

## PyGraphviz

そのまま pip で入れようとすると `fatal error: 'graphviz/cgraph.h' file not found` などの[エラーが出る](https://pod.hatenablog.com/entry/2015/03/07/163911)ので、[こちらのページ](https://hytmachineworks.hatenablog.com/entry/2019/02/04/001411)に従ってインストールします。

Graphviz は別途インストールし、パスは通しておくとします。ポイントは PyGraphviz を [conda 用にパッケージ化してくれている方](https://stackoverflow.com/questions/40809758/howto-install-pygraphviz-on-windows-10-64bit/55202558#55202558)がいるので、そのチャネルを指定して以下を実行する点です。

```shell-session
> conda install -c alubbock pygraphviz
```

## Gephi

https://gephi.org/ からインストールします。

- GraphML をダブルクリックで開きたい場合は拡張子の指定でチェックボックスを選んでおきます。
- [Java JRE](https://java.com/ja/download/)も必要です。 

# エッジのプロパティ

NetworkX 側のエッジ追加の際に、以下のように `label` を加えておきます。

```python
import pygraphviz as pgv
import networkx as nx

G = nx.Graph()

# 小文字の label にすれば Graphviz 側でラベルとして認識される
# Gephi 側では大文字・小文字どちらでもOK
G.add_edges_from([('ノード1', 'ノード2', {'label': 'エッジ', 'weight': 0.2})])
print(list(G.nodes))

# 属性を追加することも可能 (NetworkX 2.0 からは node ではなく nodes)
G.nodes['ノード1']['style'] = 'solid,filled'
G.nodes['ノード1']['fillcolor'] = '#ccccff'
G.nodes['ノード1']['shape'] = 'egg'

G.nodes['ノード2']['color'] = '#ff9999'
G.nodes['ノード2']['fontcolor'] = 'red'

G.edges['ノード1', 'ノード2']['style'] = 'dotted'
G.edges['ノード1', 'ノード2']['fontsize'] = 10
G.edges['ノード1', 'ノード2']['fontcolor'] = '#00cc66'

nx.write_graphml(G, "test.graphml")  # Gephi 用に GraphML ファイルを出力

# GraphViz用にAGraphへ変換して描画
ag = nx.nx_agraph.to_agraph(G)
ag.node_attr.update(fontname="MS Gothic")  # Windowsで MS Gothic を使う場合
ag.edge_attr.update(fontname="MS Gothic")
print(ag)  # dot言語で確認できる
ag.draw('test.pdf', prog='fdp')  # レイアウトは fdp を指定してみます
```

ノードやエッジに `color` など [dot 言語のそのほかの属性](https://qiita.com/rubytomato@github/items/51779135bc4b77c8c20d))も加えておけば、Graphviz の方で反映されます。


## Graphviz の出力結果

### 描画結果

![testgraph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55780/299cf8e8-1758-b2de-8d26-7cb01f93ecba.png)


### AGraph の print

```dot
['ノード1', 'ノード2']
strict graph "" {
	node [fontname="MS Gothic"];
	edge [fontname="MS Gothic"];
	ノード1	[fillcolor="#ccccff",
		shape=egg,
		style="solid,filled"];
	ノード2	[color="#ff9999",
		fontcolor=red];
	ノード1 -- ノード2	[fontcolor="#00cc66",
		fontsize=10,
		label=エッジ,
		style=dotted,
		weight=0.2];
}
```



## Gephi で可視化

### 読み込みと設定

1. Gephi を立ち上げ「開く」から GraphML ファイル（上記の例では `test.graphml`）を開きます。（インストール時に拡張子を加えていたならば GraphML ファイルをダブルクリックしてもOK。）
2. 「データ工房」ボタンをクリックし、「ノード」タブと「辺」タブから Label が正しく表示されていることを確認します。
3. プレビューの「設定」タブにて以下の設定をします。
    - `ノードラベル > ラベルの表示` をチェック
    - `ノードラベル > フォント` を日本語フォントへ
    - `辺ラベル > ラベルを短縮` をチェック（「ラベルを短縮」は２つありますが1つ目の方です。これはおそらく「ラベルを表示」の間違いと思われます。）
    - `辺ラベル > フォント` を日本語フォントへ
4. 「更新」ボタンを押します。

### 描画結果

エクスポートでpngへ．そのままだと端が欠けている．エッジ属性も Label が dotted になってしまったので，エッジ属性はすべて外して再度 GraphML ファイルを出力しました．（いまいち再現性がない？）

ひとまず日本語は表示されたということで・・

<img alt="exportedGephi.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/55780/484af9fa-1f3f-070e-aa28-f69aa68b4caf.png" width=400>

# 参考

- dot言語でそのほかの属性を付ける場合は、[こちらのQiitaの記事](https://qiita.com/rubytomato@github/items/51779135bc4b77c8c20d)を参考にするのがよさそうです。
- NetworkX と PyGraphViz の連携は[こちら](https://qiita.com/genyajoe/items/dff6051a3bccf8f17370)を参考にしました。
- [Graphvis のレイアウトサンプル](http://melborne.github.io/2013/04/02/graphviz-layouts/)