はじめに
networkxはネットワークの処理には便利ですが、頂点の位置決め (レイアウト) はあまり上手ではないため、通常は他のツールを併用することが多いと思います。以下ではnetworkxだけで枝の重みに応じた頂点配置を持つグラフを描画する方法の一つを説明します。
ポイントは、枝に'weight'という名前の属性を付けることです。負の値があっても構いません。
主な手順
以下では重み行列Wが既にあると仮定して説明します。
- networkxのGraphオブジェクトを作ります。
G = nx.Graph()
- Gに枝を追加します。属性名は'weight'として下さい。枝を追加すれば頂点も一緒に追加されます。
for i, j in zip(*np.triu_indices_from(W, 1)): G.add_edge(i, j, weight=W[i,j])
- ネットワークを描画します。枝の重みに応じて枝の色を変えたい場合は、edge_colorオプションに重みの配列を入れて下さい。重みの配列は
nx.get_edge_attributes()
関数で取得できます。weights = nx.get_edge_attributes(G, 'weight').values() nx.draw_networkx(G, edge_color = weights)
スタイルの調整
nx.draw_networkx()
のオプションでスタイルを適宜調整して下さい。一部紛らわしい名前のものもあります。
名前 | 意味 |
---|---|
node_size | 頂点の大きさ |
node_color | 頂点の色 |
edgecolors | 頂点の輪郭の色 (枝の色ではない) |
linewidths | 頂点の輪郭の線の太さ (枝の太さではない) |
with_labels | 頂点のラベルを書くかどうか |
font_size | フォントの大きさ |
font_color | フォントの色 |
edge_color | 枝の色、または、枝の重みの数値が並んだ配列 |
edge_cmap | 枝の色のカラーマップ |
width | 枝の太さ |
サンプルコード
以下はサンプルコードです。重み行列は適当に作った人工データの相関行列としました。
import numpy as np
import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
import seaborn as sns
def plot_weighted_network():
# generate a sample weight matrix
n1 = 10
n2 = 20
n = n1 + n2
np.random.seed(12345)
X = np.random.randn(n, 20)
v = 0.6 * X[0]
X[:n1] += v
X[n1:] -= v
W = np.corrcoef(X)
# plot heatmap
fig, (ax,ax2) = plt.subplots(figsize=(8,4), ncols=2)
sns.heatmap(W, cmap='RdBu_r', ax=ax)
ax.set_aspect('equal')
# ---------- draw weighted network ----------
# Step 1: generate a 'Graph' object
G = nx.Graph()
# Step 2: add edges to G
for i, j in zip(*np.triu_indices_from(W, 1)):
G.add_edge(i, j, weight=W[i,j])
# Step 3: draw network
weights = nx.get_edge_attributes(G, 'weight').values()
np.random.seed(12345)
nx.draw_networkx(G,
node_size = 150,
node_color = 'w',
edgecolors = 'k', # node border color
linewidths = 1, # node border width
with_labels = True,
font_size = 8,
font_color = 'k',
edge_color = weights,
edge_cmap = plt.cm.RdBu_r,
edge_vmin = -1,
edge_vmax = 1,
width = 0.5, # edge width
ax = ax2)
# show
fig.tight_layout()
fig.show()
fig.savefig('tmp.png')
if __name__ == '__main__':
plot_weighted_network()
出力例
正の結合をしている頂点同士が近くに配置され、負の結合をしている頂点同士は遠くに配置されました。非負重みの場合も同様で、強い結合では近く、弱い結合では遠くに配置されます。
alpha (透過度) は設定していませんが、枝を細くすると同様の効果が得られるようです。
問題点としては、一部の頂点の位置が近過ぎてラベルが読めなくなっていることが挙げられます。また、上側のグループが横方向に広がり過ぎており、本来のネットワークコミュニティ構造がやや分かりづらくなっています。
おわりに
やはりnetworkxでは限界があるようですので、きちんとした図を作りたい場合はCytoscapeやpyvisを使った方が良いと思います。あまり時間をかけずに重み付きグラフを視覚化したい場合に利用して下さい。