Pythonのネットワーク計算用パッケージnetworkxのグラフの頂点を一様に配置する関数を作りました。以下の図のように各頂点が互いに重ならないような配置が出てきます。
比較用にバネモデルの場合を載せます。パラメータkで多少は調節出来ますが限界があります。
以下が最小限のソースコードです。
import numpy as np
import networkx as nx
from scipy.cluster.hierarchy import distance
def uniform_layout(G, alpha=0.1, n_iter=None, seed=None, **kwargs):
pos = nx.spring_layout(G, seed=seed, **kwargs)
X = np.array(list(pos.values()))
if n_iter == None:
n_iter = 10 * len(G)
for _ in range(n_iter):
D = distance.squareform(distance.pdist(X))
np.fill_diagonal(D, None)
X += alpha * (X - X[np.nanargmin(D, axis=0)])
X = X.clip(-1,1)
return dict(zip(pos.keys(), X))
Gistに説明付きバージョンも置きました。
https://gist.github.com/okumakito/3c0f8166a99e6b617dca2c5556a6ebfa
使い方は他のnetowrkxのレイアウト関数と同様です。
>>> pos = uniform_layout(G)
>>> nx.draw_networkx(G, pos=pos)
円形バージョン (2024/04/28追記)
描画領域を正方形でなく円形にしたバージョンも用意しました。上記の最小限のコードで
X = X.clip(-1,1)
の部分を以下に変えるだけです。
X = (X.T / np.linalg.norm(X,axis=1).clip(1,None)).T
Gist版の方はオプションで切り替えられるようにしました。
>>> pos = uniform_layout(G, circle=True)
>>> nx.draw_networkx(G, pos=pos)
見た目は以下のようになります。