サムネがコーヒーの記事は書きかけです。

ネットワークグラフ生成 python

この記事では、以下のような点の集合に対して、特定条件のもと相互関係を可視化する方法について考えていきます。

ネットワーク可視化の基礎

networkxというモジュールを使用して、グラフを可視化します。

fig = plt.figure()
G = nx.Graph()
G.add_nodes_from(["A", "B", "C", "D", "E", "F"])
G.add_edges_from([("A", "B"), ("B", "C"), ("B", "F"),("C", "D"), ("C", "E"), ("C", "F"), ("B", "F")])
nx.draw(G, with_labels=True, node_color = "red", edge_color = "gray", node_size = 300, width = 1)

plt.savefig("a.png",dpi = 500)

これを利用して上記の点の集合を可視化していきます。

データの加工

csvファイルからデータを抽出して、ndarrayに変換するところまでを一つのクラスにします。

このとき、エクセル上では左下半分を埋めていないため、転置行列を使用してデータを補完します。

class Data:
    def __init__(self,file) -> None:  
        fp = open(file)   
        self.lines = [fp.readlines() for i in range(len([None for i in open(file,"rb")]))]
        self.n = len(self.lines)-1
        self.arr = np.array([[int(0) if i == "" else int(i) for i in self.lines[0][j].split(",")[1:]] for j in range(1,self.n)])
        self.arr = np.append(self.arr, np.array([0 for i in range(self.n)]).reshape(1, self.n), axis=0)
        self.Pn = [i.replace("\n","") for i in self.lines[0][0].split(",")[1:]]
        self.arr += np.transpose(self.arr)
        pass 
    def get_array(self):
        return self.arr

試しに、取得したデータを出力してみます。

>>>self.arr
[[ 0 15 20 60 20  7 10 25 11  8]
 [15  0 25 45 40 15 15 28 23  5]
 [20 25  0 15 30 20 20 30  8 16]
 [60 45 15  0  5  1 25 12  4 27]
 [20 40 30  5  0  1 40 27 25  5]
 [ 7 15 20  1  1  0 20  8 20  4]
 [10 15 20 25 40 20  0 10 15 24]
 [25 28 30 12 27  8 10  0 12 28]
 [11 23  8  4 25 20 15 12  0 30]
 [ 8  5 16 27  5  4 24 28 30  0]]

点クラス

それぞれの点が保持できる情報を定義します。

class Pn:
    def __init__(self,name,next) -> None:
        self.name = name
        self.next = next
    
    def __repr__(self) -> str:
        return "{}".format(self.next)
    
    def get_name(self):
        return self.name
    def get_next(self):
        return self.next

グラフクラス

上記で作成したデータを保持したクラスをオーバーライドして、ネットワーククラスを作成します。

ループ中に条件分岐することでノード同士の到達時間に応じて接続するかどうかを決めることができます。

class Graph(Data):
    def __init__(self, file) -> None:
        self.fig = plt.figure()
        self.G = nx.Graph()
        super().__init__(file)
        self.G.add_nodes_from(self.Pn)
        print(self.arr)
        self.P = [Pn(self.Pn[i],[f"P{j+1}" for j in range(self.n) if 0<self.arr[i][j]<15  ])for i in range(self.n)]
        
        print(self.P[1])
    def draw(self) -> None:
        
        nx.draw(self.G, with_labels=True,node_color = "steelblue", edge_color = "black", node_size = 500, width = 3)
    
    def show(self) -> None:
        plt.show()
    
    def save(self,name,dpi = 500) -> None:
        self.fig.savefig(name,dpi = dpi)

    def set_edges(self) -> None:
        self.G.add_edges_from([(i,j) for i in self.Pn for j in self.P[int(i[1:])-1].get_next()])

コード全体像

import networkx as nx
import matplotlib.pyplot as plt
import numpy as np 


class Pn:
    def __init__(self,name,next) -> None:
        self.name = name
        self.next = next
    def __repr__(self) -> str:
        return "{}".format(self.next)
    def get_name(self):
        return self.name
    def get_next(self):
        return self.next

class Data:
    def __init__(self,file) -> None:  
        fp = open(file)   
        self.lines = [fp.readlines() for i in range(len([None for i in open(file,"rb")]))]
        self.n = len(self.lines)-1
        self.arr = np.array([[int(0) if i == "" else int(i) for i in self.lines[0][j].split(",")[1:]] for j in range(1,self.n)])
        self.arr = np.append(self.arr, np.array([0 for i in range(self.n)]).reshape(1, self.n), axis=0)
        self.Pn = [i.replace("\n","") for i in self.lines[0][0].split(",")[1:]]
        self.arr += np.transpose(self.arr)
        pass 
    def get_array(self):
        return self.arr

class Graph(Data):
    def __init__(self, file) -> None:
        self.fig = plt.figure()
        self.G = nx.Graph()
        super().__init__(file)
        self.G.add_nodes_from(self.Pn)
        print(self.arr)
        self.lim = 8
        self.P = [Pn(self.Pn[i],[f"P{j+1}" for j in range(self.n) if 0<self.arr[i][j]<self.lim ])for i in range(self.n)]
        
    def draw(self) -> None:
        
        nx.draw(self.G, with_labels=True,node_color = "red", edge_color = "black", node_size = 300, width = 2,font_size = 8)
    
    def show(self) -> None:
        plt.show()
    
    def save(self,name,dpi = 500) -> None:
        self.fig.savefig(name,dpi = dpi)

    def set_edges(self) -> None:
        self.G.add_edges_from([(i,j) for i in self.Pn for j in self.P[int(i[1:])-1].get_next()])



  
graph = Graph("Book1.csv")
graph.set_edges()
graph.draw()
graph.save("result.png")

実行結果

graph = Graph("Book1.csv")
graph.set_edges()
graph.draw()
graph.save("result.png")

このグラフには方向の情報がついていないため、次は点クラスに方向の情報を持たせるように実装します。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です