いろいろ倉庫

KNIME、EXCEL、R、Pythonなどの備忘録

【Python】Pyvisでインタラクティブなネットワーク図を描いてみたい

・お題:先日、networkxを使ってエッジリストからネットワーク図を描いてみた。エッジが見づらいことがあったので、インタラクティブにグラフを動かせるようにしたい。

 

・調べてみると、pyvisというライブラリでインタラクティブなネットワークグラフを描けるらしい。さっそく使ってみる。

pyvis.readthedocs.io

・pyvisのインストールは済んでいるとする。

・まずはデータを準備する。先日と全く同じでOK。

import pandas as pd
df=pd.DataFrame({"from":["A","A","A","B"],
                "to":["B","C","D","C"],
                "weight":[4,2,0.5,1]})

・表のうち、fromをsource、toをtargetとして、networkxのグラフに取り込む。

import networkx as nx
G = nx.from_pandas_edgelist(df,source="from", target="to")

・次に、これをpyvisに取り込む。

from pyvis.network import Network
vis_g = Network()
vis_g.from_nx(G)

・これだけでもグラフを作成することはできる。コードを実行すると、ワーキングディレクトリにhtmlが保存された。これを開くと確かにノードを引っ張るとぷるんぷるんグラフが動いて楽しいが、なんだかとても簡素な印象を受ける。ここからちょっと工夫したい。

vis_g.show("test1.html")

・それぞれの属性がどういう風に入っているのか確認してみた。それぞれのノードとエッジは辞書になっており、属性を一つ一つ指定できるらしい。ということは、この辞書を書き換えれば表示も変えられるはず。。

vis_g.nodes

[{'color': '#97c2fc', 'size': 10, 'id': 'A', 'label': 'A', 'shape': 'dot'},
 {'color': '#97c2fc', 'size': 10, 'id': 'B', 'label': 'B', 'shape': 'dot'},
 {'color': '#97c2fc', 'size': 10, 'id': 'C', 'label': 'C', 'shape': 'dot'},
 {'color': '#97c2fc', 'size': 10, 'id': 'D', 'label': 'D', 'shape': 'dot'}]

vis_g.edges

[{'width': 1, 'from': 'A', 'to': 'B'},
 {'width': 1, 'from': 'A', 'to': 'C'},
 {'width': 1, 'from': 'A', 'to': 'D'},
 {'width': 1, 'from': 'B', 'to': 'C'}]

・ノードの大きさと色をdegree、エッジの太さをweightから持ってきたい。それぞれのリストを作成する。

sizes = [n*10 for n in list(dict(nx.degree(G)).values())]#ノードの大きさ

from sklearn.preprocessing import minmax_scale
colors=minmax_scale(list(dict(nx.degree(G)).values()))#色を0-1で表した。

import matplotlib.pyplot as plt

from matplotlib.colors import rgb2hex
cmap = plt.get_cmap("cool")
colorcodes=[rgb2hex(cmap(n)) for n in colors]#pyvisでcolor mapの設定方法が分からなかったので、カラーコードに変換して色名とする。

・これで、ノードの大きさのリスト(sizes)とノードの色のリスト(colorcodes)は以下のようになった。

sizes

[30, 20, 20, 10]

colorcodes

['#ff00ff', '#807fff', '#807fff', '#00ffff']

・次に、これらをノードとエッジの属性に放り込む。

for n in range(len(vis_g.nodes)):
    vis_g.nodes[n]["size"]=sizes[n]
    vis_g.nodes[n]["color"]=colorcodes[n]

for n in range(len(vis_g.edges)):
    vis_g.edges[n]["width"]=df["weight"][n]

・これで、グラフの属性が書き換わったことになるので、図示してみる。

vis_g.show("test2.html")

・もちろんこれもぷるんぷるん動かせる。

・もっとササっとできるやり方がありそうな気がするが、一応目的を達成することはできた。

 

 

おわり。