モチベーション
ネットワークを可視化するためにnetworkxを使っていたのですが、ノード数が多くなるとnetworkxで自動計算されるレイアウトだと見やすさに限界が出ます(ノードが重なり合ってつぶれてしまう)。そこで、networkxで生成したグラフを流用してより柔軟な可視化が可能なCytoscapeを用いた可視化を試してみます。
手順
ゴールは相関係数をもとにした各要素間のネットワークの可視化です。相関係数の計算とnetworkxでの可視化までは以下を参照しています。
改めて手順を確認すると
-
相関係数行列を作成する
# 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)
-
networkxを用いてグラフを作成する
G = nx.Graph() # Wは相関係数行列 for i, j in zip(*np.triu_indices_from(W, 1)): G.add_edge(i, j, weight=W[i,j])
-
networkxでCytoscapeが対応している形式のjsonを生成する
- 吐き出されるjsonをCytoscapeで読んでも解釈されなかった
-
(上記の変換がうまくできなかったため)jsonのデータをもとにcsvに変換する
import pandas as pd # 空のDataFrameを用意する out = pd.DataFrame() for e in nx.cytoscape_data(G)["elements"]["edges"]: # "edges"の中に含まれるsource, target, weightの情報をDataFrameに追加する out = pd.concat( [ out, pd.DataFrame( { "from": [e["data"]["source"]], "to": [e["data"]["target"]], "weight": [e["data"]["weight"]], } ) ] ) out.reset_index(inplace=True, drop=True) # indexの振り直し out.to_csv("network.csv")
-
Cytoscapeでcsvを読み込む
-
重みによってエッジの色を変更する
1, 2の手順は参照先で説明されているのでコード以外は割愛します
コード全体
import numpy as np
import pandas as pd
import networkx as nx
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)
G = nx.Graph()
for i, j in zip(*np.triu_indices_from(W, 1)):
G.add_edge(i, j, weight=W[i, j])
# ここまで流用
# ここからCytoscape用出力
out = pd.DataFrame()
for e in nx.cytoscape_data(G)["elements"]["edges"]:
out = pd.concat(
[
out,
pd.DataFrame(
{
"from": [e["data"]["source"]],
"to": [e["data"]["target"]],
"weight": [e["data"]["weight"]],
}
)
]
)
out.reset_index(inplace=True, drop=True)
out.to_csv("network.csv")
tips
エッジの足切り
for i, j in zip(*np.triu_indices_from(W, 1)):
# 相関係数の閾値をもとに足切りできる
if abs(weight[i, j]) > 0.8:
G.add_edge(i, j, weight=W[i, j])
おわりに
ノードはnetworkxを用いた場合に比べて個々が目視で分かるようになりました。
一方でエッジが多すぎて埋もれるものも出てしまいました。
理想はweightベースにエッジの長さがコントロールできれば良いのですが、一旦はノードのつぶれを改善できたので良いことにします。