PyLearnTIPS01: 有向・無向グラフの作成

ベイジアンネットワーク、マルコフモデルといった因果推論、確率モデリングを実施するときや、人間関係をグラフ化したいときに、ノードとパスにより構成されるネットワークを構築したいときがあります。情報科学の分野では、これをグラフ、パスに矢印があるものを有向グラフ、パスに矢印がないものを無向グラフと呼びます。ここでは、pythonを活用し、グラフを作成する方法について説明します。

有向グラフ

まずは、矢印のあるグラフの作成です。attrにより全てのノードの情報を決定します。ここでは、枠線が黒の四角形として設定しています。その後、パス関係の記述で、s01からs02へパスを引く、パスの名前は0.8、というようにグラフの接続関係を記述します。

最後に、もし必要であれば、ノードの色や形を変更します。下の例では、s03とs02のノードを円にし、枠の色を青にしたり、赤で塗りつぶししたりしています。

パスのスタイルを変更したい場合は、「パス関係の記述」を参照してください。

In [23]:
from graphviz import Digraph

G = Digraph(format="pdf") # 拡張子の設定 (pdf/pngなど)

# 全ノードの設定
G.attr("node", shape="square", color="black")
# shape = square: 四角形/cicle: 円 

# パス関係の記述
G.edge("s01", "s02", label="0.8") 
G.edge("s02", "s03", label="0.4", style='dashed') # パスを破線に
G.edge("s03", "s01", label="0.2", penwidth="3") # パスを少し太く
G.edge("s02", "s02", label="自分自身") # 自分自身へのパス

# S03の枠線を青、太さを3に変更
G.node("s03", shape="circle", color="blue", penwidth="3")

# S02を赤で塗りつぶし(filled)に変更
G.node("s02", shape="circle", style="filled", color="red")

# ファイル名を指定して保存(拡張子不要)
G.render("graphs")

# jupyter上で可視化
display(G)
%3 s01 s01 s02 s02 s01->s02 0.8 s02->s02 自分自身 s03 s03 s02->s03 0.4 s03->s01 0.2

無向グラフ

次は、方向のないグラフ(無向グラフ)の書き方です。DigraphをGraphに変えるだけです。

In [24]:
# DigraphをGraphに変更
from graphviz import Graph
nG = Graph(format="pdf") # 拡張子の設定 (pdf/pngなど)

### 以下は有向グラフと同じ ###
nG.attr("node", shape="square", color="black")
nG.edge("s01", "s02", label="0.8") 
nG.edge("s02", "s03", label="0.4", style='dashed') # パスを破線に
nG.edge("s03", "s01", label="0.2", penwidth="3") # パスを少し太く
nG.edge("s02", "s02", label="自分自身") # 自分自身へのパス
nG.node("s03", shape="circle", color="blue", penwidth="3")
nG.node("s02", shape="circle", style="filled", color="red")
nG.render("ngraphs")
display(nG)
%3 s01 s01 s02 s02 s01--s02 0.8 s02--s02 自分自身 s03 s03 s02--s03 0.4 s03--s01 0.2

レイアウトの変更

グラフを格納する変数を定義するところで、engine引数に指定された文字列を入れることで、グラフのレイアウトを変更することができます。どれがいいかは状況により異なるので、色々試してみるといいです。

In [29]:
from graphviz import Graph

# レイアウト一覧
# circo, dot, fdp, neato, nop, nop1, nop2, osage, patchwork, sfdp, twopi
nG = Graph(format="pdf", engine='neato') # neato

### 以下は前の例と同じ ###
nG.attr("node", shape="square", color="black")
nG.edge("s01", "s02", label="0.8") 
nG.edge("s02", "s03", label="0.4", style='dashed') # パスを破線に
nG.edge("s03", "s01", label="0.2", penwidth="3") # パスを少し太く
nG.edge("s02", "s02", label="自分自身") # 自分自身へのパス
nG.node("s03", shape="circle", color="blue", penwidth="3")
nG.node("s02", shape="circle", style="filled", color="red")
nG.render("ngraphs")
display(nG)
%3 s01 s01 s02 s02 s01--s02 0.8 s02--s02 自分自身 s03 s03 s02--s03 0.4 s03--s01 0.2