NetworkXを使ってみる(描画編)(Python)

2024/10/01に公開

こんにちは、沙代です。
秋っぽい日も増えて参りましたね。
グラフを画像化するのをあまりやったことがなかったので、まとめてみようと思いました。

MacOS Montery 12.6.2 (M1 Pro)
Python 3.10.0
matplotlib 3.9.2
networkx 3.3

環境構築してみる

分離して、使い捨てする場合、仮想環境を構築します。

mkdir tmp && cd tmp
pyenv local 3.10.0
python -m venv venv
. venv/bin/activate
pip install --upgrade pip
pip install matplotlib "networkx[default]" japanize-matplotlib jupyterlab

(jupyterlabは、人によってはいらないかもしれません)

動かしてみる

import networkx as nx
import matplotlib.pyplot as plt

# 無向グラフの作成
G = nx.Graph()

# ノードの追加
G.add_node(1)
G.add_node(2)
G.add_node(3)

# エッジの追加
G.add_edge(1, 2)
G.add_edge(2, 3)

# グラフの描画
nx.draw(G, with_labels=True, node_color='lightblue', node_size=500, font_size=10, font_color='black')

# グラフの表示
plt.show()

ちゃんと、「1」「2」「3」のノードが追加されていて、1-2, 2-3で結ばれていますね。

有効グラフにしてみる

import networkx as nx
import matplotlib.pyplot as plt

# 有向グラフの作成
G = nx.DiGraph()

# ノードの追加
G.add_node(1)
G.add_node(2)
G.add_node(3)

# エッジの追加
G.add_edge(1, 2)
G.add_edge(2, 3)

# グラフの描画
nx.draw(G, with_labels=True, node_color='lightblue', node_size=500, font_size=10, font_color='black')

# グラフの表示
plt.show()

G = nx.Graph()の代わりにG = nx.DiGraph()を使ってみます。

日本語ラベルを使ってみる

もし単純に日本語をラベルに使用しようとすると、上手に表示されません。

import networkx as nx
import matplotlib.pyplot as plt

# 有向グラフの作成
G = nx.DiGraph()

# ノードの追加
G.add_node("ぐり")
G.add_node("と")
G.add_node("ぐら")

# エッジの追加
G.add_edge("ぐり", "と")
G.add_edge("と", "ぐら")

# グラフの描画
nx.draw(G, with_labels=True, node_color='lightblue', node_size=500, font_size=10, font_color='black')

# グラフの表示
plt.show()

解決していきます。

私の手元では、"IPAexGothic"のフォントがありました。

import matplotlib

for f in matplotlib.font_manager.fontManager.ttflist:
    if "IPAexGothic" in f.name:
        print(f.name)
# Output: IPAexGothic

japanize-matplotlibと併せて、font_familyを指定して日本語化していきます。

import networkx as nx
import matplotlib.pyplot as plt
import japanize_matplotlib

# 有向グラフの作成
G = nx.DiGraph()

# ノードの追加
G.add_node("ぐり")
G.add_node("と")
G.add_node("ぐら")

# エッジの追加
G.add_edge("ぐり", "と")
G.add_edge("と", "ぐら")

# グラフの描画
nx.draw(G, with_labels=True, node_color='lightblue', node_size=500, font_size=10, font_color='black', font_family='IPAexGothic')

# グラフの表示
plt.show()

出来ました!

出力に再現性を持たせる

実は、毎回出力が異なってしまいます。
これは、spring_layoutという関数でseed値を指定した上でpositionを決定し、
それをnx.drawに渡すことで回避できます。

import networkx as nx
import matplotlib.pyplot as plt
import japanize_matplotlib

# 有向グラフの作成
G = nx.DiGraph()

# ノードの追加
G.add_node("ぐり")
G.add_node("と")
G.add_node("ぐら")

# エッジの追加
G.add_edge("ぐり", "と")
G.add_edge("と", "ぐら")

# spring_layout でノードの位置を決定
pos = nx.spring_layout(G, seed=42)

# グラフの描画
nx.draw(G, pos, with_labels=True, node_color='lightblue', node_size=500, font_size=10, font_color='black', font_family='IPAexGothic')

# グラフの表示
plt.show()

エッジに重みを持たせる

エッジに重み(weight)を持たせることで、重みが大きいエッジはより短くなり、重みが小さいエッジはより長く配置されます。

(差のあるところだけ再表示)
# エッジの追加と重みの設定
G.add_edge("ぐり", "と", weight=100)
G.add_edge("と", "ぐら", weight=0.5)

片付け

今回、仮想環境に(を)作成したので、以下のようにしてお片づけしました。

deactivate
cd .. && rm -rf tmp

参考にさせていただいたページ

https://networkx.org/documentation/stable/tutorial.html

Discussion