PythonのGraphviz グラフレイアウトの変更#
公開日
この記事ではPythonのGraphvizでグラフのレイアウトを変更する方法を解説します。 レイアウトエンジンと、ノードの配置方向の変更について順に示します。
レイアウトエンジンの変更#
Graphvizには複数のレイアウトエンジン(描画用プログラム)が実装されており、それを切り替えることでレイアウトを変更します。
レイアウトエンジンを変更する方法はいくつかありますが、ここでは2つ説明します。
1つはGraph
(無向グラフ)やDigraph
(有向グラフ)のengine
オプションで指定する方法です。
from graphviz import Digraph
graph = Digraph(engine="neato")
graph.edge("node1", "node2")
graph.edge("node1", "node3")
graph.edge("node2", "node4")
graph.edge("node2", "node5")
graph
もう1つはrender()
メソッドのengine
オプションで指定する方法です。
from IPython.display import Image
Image(graph.render(engine="dot", format="png"))
指定できるレイアウトエンジンは以下の通りです。
dot
: 階層的なレイアウト(デフォルト)neato
: ばねモデル。ノード数が100程度以下の無効グラフ向けfdp
: ばねモデル。neatoより大規模な無向グラフ向け。サブグラフ向けsfdp
: fdpをより大規模な無向グラフに対応させたものcirco
: 円形レイアウト。ネットワーク構造などの描画向けtwopi
: 放射状レイアウトosage
: 格子状レイアウト。クラスター構造の描画向けpatchwork
: タイル状レイアウト
「ばねモデル」とは隣接するノード同士が適度に離れるモデルのことです。
なお、利用可能なレイアウトエンジンの一覧はgraphviz.ENGINES
でも確認できます。
import graphviz
print(graphviz.ENGINES)
{'osage', 'circo', 'fdp', 'neato', 'dot', 'patchwork', 'twopi', 'sfdp'}
以下に各レイアウトエンジンのサンプルを示します。
dot#
dot
は階層構造に適したレイアウトエンジンです。
graph = Digraph(engine="dot")
graph.edge("node1", "node2")
graph.edge("node1", "node3")
graph.edge("node2", "node4")
graph.edge("node2", "node5")
graph.edge("node3", "node6")
graph
neato#
neato
はばねモデルを用いたレイアウトエンジンで、比較的小規模なグラフ(ノード数100程度以下)の無効グラフに適しています。
from graphviz import Graph
graph = Graph(engine="neato")
graph.edge("node1", "node2")
graph.edge("node2", "node3")
graph.edge("node3", "node4")
graph.edge("node4", "node5")
graph.edge("node5", "node2")
graph
fdp#
fdp
(Force-Directed Placement) はばねモデルを用いたレイアウトエンジンで、neatoより大規模な無向グラフ向けです。また、サブグラフ(クラスター)を含む場合にも適しています。
graph = Graph(engine="fdp")
graph.edge("node1", "node2")
graph.edge("node2", "node3")
graph.edge("node3", "node4")
graph.edge("node4", "node5")
graph.edge("node5", "node2")
graph
sfdp#
sfdp
(Scalable Force-Directed Placement) はfdp
を大規模な無向グラフに対応させたレイアウトエンジンです。
graph = Graph(engine="sfdp")
graph.edge("node1", "node2")
graph.edge("node2", "node3")
graph.edge("node3", "node4")
graph.edge("node4", "node5")
graph.edge("node5", "node2")
graph
circo#
circo
は円形の構造を描画するのに適したレイアウトエンジンです。ネットワーク構造などの描画に向いています。
graph = Graph(engine="circo")
graph.edge("node1", "node2")
graph.edge("node2", "node3")
graph.edge("node3", "node4")
graph.edge("node4", "node5")
graph.edge("node5", "node6")
graph.edge("node6", "node1")
graph.edge("node1", "node10")
graph.edge("node10", "node11")
graph.edge("node11", "node12")
graph.edge("node12", "node13")
graph.edge("node13", "node14")
graph.edge("node14", "node15")
graph.edge("node15", "node16")
graph.edge("node16", "node11")
graph
twopi#
twopi
は放射状の構造を描画するのに適したレイアウトエンジンです。
中心ノード(以下ではnode0
)から放射状にノードが配置されます。
graph = Graph(engine="twopi")
graph.edge("node0", "node1")
graph.edge("node0", "node2")
graph.edge("node0", "node3")
graph.edge("node0", "node4")
graph.edge("node0", "node5")
graph.edge("node0", "node6")
graph.edge("node1", "node11")
graph.edge("node2", "node12")
graph.edge("node3", "node13")
graph.edge("node4", "node14")
graph.edge("node5", "node15")
graph
osage#
osage
は格子状の構造を描画するのに適したレイアウトエンジンです。
graph = Graph(engine="osage")
graph.edge("node1", "node2")
graph.edge("node2", "node3")
graph.edge("node3", "node4")
graph.edge("node4", "node5")
graph.edge("node5", "node6")
graph.edge("node6", "node7")
graph.edge("node7", "node8")
graph.edge("node8", "node9")
graph
patchwork#
patchwork
はタイル状にノードを配置するレイアウトエンジンです。
ノード間の関係は図示されません。
各ノードのarea
属性でノードの面積を指定します(デフォルト値は1
)。
株式会社の時価総額の可視化などに用いられることがあります。
なお、タイルの色を変更する場合、ノードの属性をstyle="filled"
として、fillcolor
で色を指定します。
graph = Graph(engine="patchwork")
graph.attr("node", style="filled")
graph.node("A Airline", area="25", fillcolor="springgreen")
graph.node("B Bank", area="20", fillcolor="orangered")
graph.node("C Computer", area="15", fillcolor="orangered")
graph.node("D Development ", area="10")
graph
ノード配置方向の変更#
ノードを配置する方向を変更するには、グラフのrankdir
パラメータを変更します。
rankdir
には以下の4つを指定できます。
TB
: 上から下 (top to bottom, デフォルト値)BT
: 下から上 (bottom to top)LR
: 左から右 (left to right)RL
: 右から左 (right to left)
Pythonのgraphvizの場合、グラフオブジェクトのattr
属性でrankdir
パラメータを指定します。
以下に例を示します。
graph = Digraph(engine="dot")
graph.edge("node1", "node2")
graph.edge("node1", "node3")
graph.edge("node2", "node4")
graph.edge("node2", "node5")
graph.edge("node3", "node6")
graph.attr(rankdir="TB")
graph
graph.attr(rankdir="BT")
graph
graph.attr(rankdir="LR")
graph
graph.attr(rankdir="RL")
graph