ベイジアンネットワーク、マルコフモデルといった因果推論、確率モデリングを実施するときや、人間関係をグラフ化したいときに、ノードとパスにより構成されるネットワークを構築したいときがあります。情報科学の分野では、これをグラフ、パスに矢印があるものを有向グラフ、パスに矢印がないものを無向グラフと呼びます。ここでは、pythonを活用し、グラフを作成する方法について説明します。
まずは、矢印のあるグラフの作成です。attrにより全てのノードの情報を決定します。ここでは、枠線が黒の四角形として設定しています。その後、パス関係の記述で、s01からs02へパスを引く、パスの名前は0.8、というようにグラフの接続関係を記述します。
最後に、もし必要であれば、ノードの色や形を変更します。下の例では、s03とs02のノードを円にし、枠の色を青にしたり、赤で塗りつぶししたりしています。
パスのスタイルを変更したい場合は、「パス関係の記述」を参照してください。
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)
次は、方向のないグラフ(無向グラフ)の書き方です。DigraphをGraphに変えるだけです。
# 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)
グラフを格納する変数を定義するところで、engine引数に指定された文字列を入れることで、グラフのレイアウトを変更することができます。どれがいいかは状況により異なるので、色々試してみるといいです。
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)