2
0

More than 1 year has passed since last update.

networkxで重み付きグラフを描画する方法

Last updated at Posted at 2022-10-17

はじめに

networkxはネットワークの処理には便利ですが、頂点の位置決め (レイアウト) はあまり上手ではないため、通常は他のツールを併用することが多いと思います。以下ではnetworkxだけで枝の重みに応じた頂点配置を持つグラフを描画する方法の一つを説明します。

ポイントは、枝に'weight'という名前の属性を付けることです。負の値があっても構いません。

主な手順

以下では重み行列Wが既にあると仮定して説明します。

  1. networkxのGraphオブジェクトを作ります。
    G = nx.Graph()
    
  2. Gに枝を追加します。属性名は'weight'として下さい。枝を追加すれば頂点も一緒に追加されます。
     for i, j in zip(*np.triu_indices_from(W, 1)):
         G.add_edge(i, j, weight=W[i,j])
    
  3. ネットワークを描画します。枝の重みに応じて枝の色を変えたい場合は、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()

出力例

fig_weighted_network.png

正の結合をしている頂点同士が近くに配置され、負の結合をしている頂点同士は遠くに配置されました。非負重みの場合も同様で、強い結合では近く、弱い結合では遠くに配置されます。

alpha (透過度) は設定していませんが、枝を細くすると同様の効果が得られるようです。

問題点としては、一部の頂点の位置が近過ぎてラベルが読めなくなっていることが挙げられます。また、上側のグループが横方向に広がり過ぎており、本来のネットワークコミュニティ構造がやや分かりづらくなっています。

おわりに

やはりnetworkxでは限界があるようですので、きちんとした図を作りたい場合はCytoscapeやpyvisを使った方が良いと思います。あまり時間をかけずに重み付きグラフを視覚化したい場合に利用して下さい。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0