PythonとGraphvizでグラフを描く_2

# 前回までのおさらい

前回ではコミックの登場人物を題材に有向グラフを描いてみました。
今回はこのグラフをより詳しくしていきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186560/97946982-480e-4e60-1330-4b8eedfd436d.png)

## とりあえずノードを増やす

```python:example2.py
import graphviz

dot = graphviz.Digraph(format= 'png', 
comment = "今世は当主になります　～2話まで　人物相関図")
dot.attr('node', fontname = 'Meiryo UI')
dot.attr('edge', fontname = 'Meiryo UI')

dot.node('L', 'ルーラック・ロンバルディ\n現当主')

dot.node('F', 'フィレンティア・ロンバルディ\n主人公')
dot.node('G', 'ギャラハン・ロンバルディ')
dot.node('E', 'フィレンティアの母')

dot.node('La', 'ローレルズ・ロンバルディ')

dot.node('B', 'ビエーゼ・ロンバルディ')
dot.node('BS', 'セラル・ロンバルディ')
dot.node('R', 'ラビニ・アンゲナス\n皇后')
dot.node('S1', '第1王子')
dot.node('S2', '第2王子')

dot.edge('L', 'G', label = '三男')
dot.edge('L', 'B', label = '長男')
dot.edge('F', 'G', label = '父')
dot.edge('F', 'E', label = '母')

dot.edge('B', 'BS', '妻')
dot.edge('BS', 'R', 'いとこ')
dot.edge('R', 'S1', '息子')
dot.edge('B', 'S1', '支持')

dot.edge('F', 'S2', '支援したい')
dot.edge('F', 'L', '次期当主になりたい')

dot.render('./example2.gv', view=True)
```

![example2.gv.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186560/0d041fcb-ffee-b184-12e3-077e5595a70b.png)

とりあえずこれで2話時点までで分かる人物相関図が出来ました。しかし、いくつか改善したい点があります。

## 改善点

* 注目させたいノードのスタイルを変えたい
* 全体的な見せ方を変えたい
* いとこのエッジを双方向にしたい
* 勢力ごとに見た目を変えたい

### ノードのスタイルを変えたい

ノードのスタイルを変えたい時はshapeを変更することで出来ます。主人公のノードを変えてみます。

```python
dot.node('F', 'フィレンティア・ロンバルディ\n主人公', shape='doubleoctagon')
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186560/43bd8008-6384-e020-5c55-30cc139eff7b.png)

図のように二重線の八角形に出来ました。
ほかに使えるものは[こちらで確認できます。](https://graphviz.org/doc/info/shapes.html#record)


### 全体的な見せ方を変えたい

グラフの見せ方、つまりどのようにノードを配置するかなどはレイアウトエンジンを変更することで実現可能です。
デフォルトでは dot が指定されており、これは階層型のグラフの表現に適しています。
小説や漫画の登場人物紹介には適しているとは言いがたいですね。
これを変えてみましょう。

```python
dot = graphviz.Digraph(format= 'png', 
engine='circo',
comment = "今世は当主になります　～2話まで　人物相関図")
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186560/ec3f01ee-7185-6dd3-7a25-c5f480a45e48.png)

engineにはほかにも

dot（デフォルト）, neato, twopi, circo, fdp, osage, patchwork, sfdp　があります。
今回は詳しく説明しません。

### いとこのエッジを双方向にしたい

セラルからラビニに伸びているいとこのエッジの矢印を双方向にします。これはedgeのdir属性によって実現できます。

```python
dot.edge('BS', 'R', 'いとこ', dir='both')
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186560/6d7d6e6e-7dc2-cc41-4549-3e11809cc073.png)

bothをnoneにすれば矢印は消えます。
backにすれば矢印の向きが逆になります。
省略時のデフォルトはforwardです。

### 勢力ごとに見た目を変えたい

このような場合はGraph, Digraphオブジェクトのsubgraph()メソッドを用いて行います。
engineがcircoのままですと背景色が意図した通りに変わらなかったためdotに戻しています。

```python
import graphviz

dot = graphviz.Digraph(format= 'png', 
comment = "今世は当主になります　～2話まで　人物相関図")
dot.attr('node', fontname = 'Meiryo UI')
dot.attr('edge', fontname = 'Meiryo UI')


dot.node('L', 'ルーラック・ロンバルディ\n現当主')

dot.node('F', 'フィレンティア・ロンバルディ\n主人公', shape='doubleoctagon')
dot.node('G', 'ギャラハン・ロンバルディ')
dot.node('E', 'フィレンティアの母')

dot.node('La', 'ローレルズ・ロンバルディ')


dot.node('S2', '第2王子')

dot.edge('L', 'G', label = '三男')

dot.edge('F', 'G', label = '父')
dot.edge('F', 'E', label = '母')


dot.edge('F', 'S2', '支援したい')
dot.edge('F', 'L', '次期当主になりたい')
dot.edge('L', 'B', '息子')

empress = graphviz.Digraph(name='cluster_empress', node_attr={'shape': 'box'})

empress.attr(style='filled', color='darkorchid1')

empress.node('B', 'ビエーゼ・ロンバルディ')
empress.node('BS', 'セラル・ロンバルディ')
empress.node('R', 'ラビニ・アンゲナス\n皇后')
empress.node('S1', '第1王子')
empress.edge('B', 'BS', '妻')
empress.edge('BS', 'R', 'いとこ', dir='back')
empress.edge('R', 'S1', '息子')
empress.edge('B', 'S1', '支持')
empress.attr(label='皇后派')
empress.attr('graph', fontname = 'Meiryo UI')

dot.subgraph(empress)
dot.render('./example2.gv', view=True)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186560/67f185d1-a7da-a94e-f650-bb126f16f644.png)

イメージとしては親になるdotオブジェクトに対して別な有向グラフオブジェクトempressを用意して、そこに関係者のノードとエッジを入れ込んでいます。
皇后派のノードは背景色を紫にして、ノードの形も長方形にしています。
グラフやノードの背景色は自由に変更可能です。
[色はこちらから探せます](https://graphviz.org/doc/info/colors.html)

では今回はここまで