[python] NetworkXに基づくネットワークグラフ描画の実装
Implementation Network Graph Drawing Based Networkx
記事のディレクトリ
コードのダウンロードアドレス
ネットワーク図(または図やグラフ)は、エンティティのグループ間の相互接続を示します。各エンティティは、1つ以上のノードで表されます。ノード間の接続は、リンク(またはエッジ)で表されます。ネットワークの理論と実装は幅広い研究分野です。ネットワーク全体がこれに取り組むことができます。たとえば、ネットワークは有向または無向、加重または無加重にすることができます。多くの異なる入力形式があります。この領域をガイドするために、次の例を推奨される順序で実行することをお勧めします。このツールに関して、私は主に依存していることに注意してください NetworkX ライブラリ(バージョン2.4)。ただし、使用も検討する必要があることに注意してください グラフツール 、特に高次元ネットワークに関しては。この章の主な内容は次のとおりです。
- パンダの基本グリッドからパンダのデータフレームから基本ネットワークを描画
- カスタムNetworkXグラフの外観
- ネットワークレイアウトの可能性
- 有向または無向ネットワーク
- ネットワークノードに色をマッピングする
- ネットワークの端に色をマッピングします
- ネットワークチャートの背景色
- 相関行列からのネットワーク
NetworkXのインストール:
pip install networkx==2.4
この記事は以下を参照しています:
from IPython.core.interactiveshell import InteractiveShell InteractiveShell.ast_node_interactivity = 'all'
1.パンダのデータフレームから基本的なネットワークを描画します
この例は、おそらく実装できる最も基本的なネットワーク図です。ネットワークグラフはノードで構成されています。これらのノードは、エッジによって相互に接続されています。したがって、基本的な形式はデータフレームであり、各行は接続を記述します。ここでは、4本の線を使用して、このグラフの4つの接続を説明するデータフレームを作成します。したがって、接続にcsvファイルが付属している場合は、ファイルをロードして視覚化する準備をしてください。 FROMは開始点を表し、toは終了点を表します。
# libraries import module import pandas as pd import numpy as np import networkx as nx import matplotlib.pyplot as plt
# Build a dataframe with 4 connections df = pd.DataFrame({ 'from':['A', 'B', 'C','A'], 'to':['D', 'A', 'E','C']}) df # Build your graph # Draw a network diagram, the result may be different each time G=nx.from_pandas_edgelist(df, 'from', 'to') # Plot it nx.draw(G, with_labels=True) plt.show()
から | に | |
---|---|---|
0 | に | D |
1 | B | に |
二 | C | IS |
3 | に | C |
2.カスタムNetworkXグラフの外観カスタムNetworkXグラフの外観
それでは、チャートの外観をカスタマイズするためのパラメーターを見てみましょう。カスタマイズは、ノード、ノードラベル、エッジの3つの主要なカテゴリに分類されます。
- ノード
- ラベル
- エッジ
- まとめすべて
## Nodes # libraries Load library import pandas as pd import numpy as np import networkx as nx import matplotlib.pyplot as plt # Build a dataframe with your connections df = pd.DataFrame({ 'from':['A', 'B', 'C','A'], 'to':['D', 'A', 'E','C']}) df # Build your graph G=nx.from_pandas_edgelist(df, 'from', 'to') # Graph with Custom nodes: Custom table # with_labels Whether to display labels, node_size node size, node_color node color, node_shape node shape, alpha transparency, linewidths line width nx.draw(G, with_labels=True, node_size=1500, node_color='skyblue', node_shape='s', alpha=0.5, linewidths=10) plt.show()
から | に | |
---|---|---|
0 | に | D |
1 | B | に |
二 | C | IS |
3 | に | C |
## Labels Labels # libraries import pandas as pd import numpy as np import networkx as nx import matplotlib.pyplot as plt # Build a dataframe with your connections df = pd.DataFrame({ 'from':['A', 'B', 'C','A'], 'to':['D', 'A', 'E','C']}) df # Build your graph G=nx.from_pandas_edgelist(df, 'from', 'to') # Custom the edges: # font_size label font size, font_color label font color, font_weight font form nx.draw(G, with_labels=True, node_size=1500, font_size=25, font_color='yellow', font_weight='bold') plt.show()
から | に | |
---|---|---|
0 | に | D |
1 | B | に |
二 | C | IS |
3 | に | C |
## Edges # libraries import pandas as pd import numpy as np import networkx as nx import matplotlib.pyplot as plt # Build a dataframe with your connections df = pd.DataFrame({ 'from':['A', 'B', 'C','A'], 'to':['D', 'A', 'E','C']}) df # Build your graph G=nx.from_pandas_edgelist(df, 'from', 'to') # Chart with Custom edges: # width side line width, edge_color side line color nx.draw(G, with_labels=True, width=10, edge_color='skyblue', style='solid')
から | に | |
---|---|---|
0 | に | D |
1 | B | に |
二 | C | IS |
3 | に | C |
## Summary All # libraries import pandas as pd import numpy as np import networkx as nx import matplotlib.pyplot as plt # Build a dataframe with your connections df = pd.DataFrame({ 'from':['A', 'B', 'C','A'], 'to':['D', 'A', 'E','C']}) df # Build your graph G=nx.from_pandas_edgelist(df, 'from', 'to') # All together we can do something fancy nx.draw(G, with_labels=True, node_size=1500, node_color='skyblue', node_shape='o', alpha=0.5, linewidths=4, font_size=25, font_color='grey', font_weight='bold', width=2, edge_color='grey')
から | に | |
---|---|---|
0 | に | D |
1 | B | に |
二 | C | IS |
3 | に | C |
3.ネットワークレイアウトの可能性
実際、各ノードの最適な位置を計算するアルゴリズムがあります。 NetworkXは、いくつかのアルゴリズムを開発および提案しています。このページでは、同じ小さなデータセットを取得し、それに異なるレイアウトアルゴリズムを適用することで、この概念を説明します。どちらが最適かわからない場合は、デフォルトでデフォルトとして設定してください。デフォルトのSpringレイアウト
# libraries import pandas as pd import numpy as np import networkx as nx import matplotlib.pyplot as plt # Build a dataframe with your connections df = pd.DataFrame({ 'from':['A', 'B', 'C','A','E','F','E','G','G','D','F'], 'to':['D', 'A', 'E','C','A','F','G','D','B','G','C']}) df # Build your graph G=nx.from_pandas_edgelist(df, 'from', 'to')
から | に | |
---|---|---|
0 | に | D |
1 | B | に |
二 | C | IS |
3 | に | C |
4 | IS | に |
5 | F | F |
6 | IS | G |
7 | G | D |
8 | G | B |
9 | D | G |
10 | F | C |
# Fruchterman Reingold Fruchterman Reingold guide layout algorithm layout nx.draw(G, with_labels=True, node_size=1500, node_color='skyblue', pos=nx.fruchterman_reingold_layout(G)) plt.title('fruchterman_reingold')
Text(0.5, 1.0, 'fruchterman_reingold')
# Circular circular layout nx.draw(G, with_labels=True, node_size=1500, node_color='skyblue', pos=nx.circular_layout(G)) plt.title('circular')
Text(0.5, 1.0, 'circular')
# Random random layout nx.draw(G, with_labels=True, node_size=1500, node_color='skyblue', pos=nx.random_layout(G)) plt.title('random')
Text(0.5, 1.0, 'random')
# Spectral Spectral layout nx.draw(G, with_labels=True, node_size=1500, node_color='skyblue', pos=nx.spectral_layout(G)) plt.title('spectral')
Text(0.5, 1.0, 'spectral')
# Spring Jump layout nx.draw(G, with_labels=True, node_size=1500, node_color='skyblue', pos=nx.spring_layout(G)) plt.title('spring')
Text(0.5, 1.0, 'spring')
4.有向または無向ネットワーク
ネットワークグラフは、有向ネットワークと無向ネットワークの2つの主要なカテゴリに分類できます。方向性がある場合は、2つのノード間にフローの概念があり、他の場所に移動する場所が残ります。お金がA社からB社に流れるように。これが、方向を示す左側のチャートの矢印を(ある程度)見ることができる理由です。たとえば、トラフィックはBからAに流れます。無向の場合、これら2つのノード間には1つのリンクしかありません。たとえば、AさんとBさんは友達です。
グラフを生成するときは、ニーズに合った関数を使用する必要があります。無向(デフォルト)の場合はGraph()、有向グラフの場合はDiGraphです。
# libraries import pandas as pd import numpy as np import networkx as nx import matplotlib.pyplot as plt ## DIRECTED directed graph # Build a dataframe with your connections # This time a pair can appear 2 times, in one side or in the other! df = pd.DataFrame({ 'from':['D', 'A', 'B', 'C','A'], 'to':['A', 'D', 'A', 'E','C']}) df # Build your graph. Note that we use the DiGraph function to create the graph! # create_using=nx.DiGraph() creates a directed graph, the default is an undirected graph G=nx.from_pandas_edgelist(df, 'from', 'to', create_using=nx.DiGraph()) # Make the graph directed graph nx.draw(G, with_labels=True, node_size=1500, alpha=0.3, arrows=True)
から | に | |
---|---|---|
0 | D | に |
1 | に | D |
二 | B | に |
3 | C | IS |
4 | に | C |
# UNDIRECTED Undirected graph # Build a dataframe with your connections # This time a pair can appear 2 times, in one side or in the other! df = pd.DataFrame({ 'from':['D', 'A', 'B', 'C','A'], 'to':['A', 'D', 'A', 'E','C']}) df # Build your graph. Note that we use the Graph function to create the graph! G=nx.from_pandas_edgelist(df, 'from', 'to', create_using=nx.Graph()) # Make the graph nx.draw(G, with_labels=True, node_size=1500, alpha=0.3, arrows=True) plt.title('UN-Directed')
から | に | |
---|---|---|
0 | D | に |
1 | に | D |
二 | B | に |
3 | C | IS |
4 | に | C |
Text(0.5, 1.0, 'UN-Directed')
5.ネットワークノードに色をマッピングします
一般的なタスクは、ネットワークグラフの各ノードをその機能に従って色付けすることです(これをマッピング色と呼びます)。これにより、より多くの情報をチャートに表示できます。 2つの可能性があります:
- マップするフィーチャは数値です。次に、連続カラースケールを使用します。左の写真では、AはCよりも暗く、Bよりも暗くなっています。
- この機能は分類されています。右の写真では、AとBは同じグループに属しており、DとEはグループ化されており、Cは彼のグループに単独で存在しています。分類カラースケールを使用しました。
通常、2つのテーブルを使用します。最初のものはノード間のリンクを提供します。 2つ目は、各ノードの機能を提供します。これらの2つのファイルは次のようにリンクできます。
- 連続カラー
- 分類色
## Continuous color scale Continuous color scale # libraries import pandas as pd import numpy as np import networkx as nx import matplotlib.pyplot as plt # Build a dataframe with your connections df = pd.DataFrame({ 'from':['A', 'B', 'C','A'], 'to':['D', 'A', 'E','C']}) # And a data frame with characteristics for your nodes carac = pd.DataFrame({ 'ID':['A', 'B', 'C','D','E'], 'myvalue':['123','25','76','12','34'] }) # Settings carac # Build your graph G =nx.from_pandas_edgelist(df, 'from', 'to', create_using=nx.Graph() ) # The order of the node for networkX is the following order: # Node order G.nodes() # Thus, we cannot give directly the 'myvalue' column to netowrkX, we need to arrange the order! # Here is the tricky part: I need to reorder carac, to assign the good color to each node # Set the color according to myvalue and match the node order and ID number carac = carac.set_index('ID') carac =carac.reindex(G.nodes()) carac # Plot it, providing a continuous color scale with cmap: # node_color sets the color, the input must be a float array or an int value cmap color bar nx.draw(G, with_labels=True, node_color=np.array(carac['myvalue'].values,dtype='float32'), cmap=plt.cm.Blues)
ID | myvalue | |
---|---|---|
0 | に | 123 |
1 | B | 25 |
二 | C | 76 |
3 | D | 12 |
4 | IS | 3. 4 |
NodeView(('A', 'D', 'B', 'C', 'E'))
myvalue | |
---|---|
ID | |
に | 123 |
D | 12 |
B | 25 |
C | 76 |
IS | 3. 4 |
## Categorical color scale Continuous color # libraries import pandas as pd import numpy as np import networkx as nx import matplotlib.pyplot as plt # Build a dataframe with your connections df = pd.DataFrame({ 'from':['A', 'B', 'C','A'], 'to':['D', 'A', 'E','C']}) # And a data frame with characteristics for your nodes carac = pd.DataFrame({ 'ID':['A', 'B', 'C','D','E'], 'myvalue':['group1','group1','group2','group3','group3'] }) # Build your graph # Create graph G=nx.from_pandas_edgelist(df, 'from', 'to', create_using=nx.Graph() ) # The order of the node for networkX is the following order: # Print node order G.nodes() # Thus, we cannot give directly the 'myvalue' column to netowrkX, we need to arrange the order! # Here is the tricky part: I need to reorder carac to assign the good color to each node carac= carac.set_index('ID') # Set the value according to the node order carac=carac.reindex(G.nodes()) # And I need to transform my categorical column in a numerical value: group1->1, group2->2... # Set category carac['myvalue']=pd.Categorical(carac['myvalue']) carac['myvalue'].cat.codes # Custom the nodes: nx.draw(G, with_labels=True, node_color=carac['myvalue'].cat.codes, cmap=plt.cm.Set1, node_size=1500)
NodeView(('A', 'D', 'B', 'C', 'E')) ID A 0 D 2 B 0 C 1 E 2 dtype: int8
6.ネットワークの端に色をマッピングします
ネットワークのエッジごとに関数があると仮定します。たとえば、この関数は、このリンクで表される金額(デジタル値)、またはそれが発生する大陸(カテゴリ値)の場合があります。この変数に基づいてエッジを異なるものにする必要があります。
- 数値
- カテゴリカル
## numerical # libraries import pandas as pd import numpy as np import networkx as nx import matplotlib.pyplot as plt # Build a dataframe with your connections # value Set link value df = pd.DataFrame({ 'from':['A', 'B', 'C','A'], 'to':['D', 'A', 'E','C'], 'value':[1, 10, 5, 5]}) df # Build your graph G=nx.from_pandas_edgelist(df, 'from', 'to', create_using=nx.Graph() ) # Custom the nodes: #edge_color Set the color of the edge nx.draw(G, with_labels=True, node_color='skyblue', node_size=1500, edge_color=df['value'], width=10.0, edge_cmap=plt.cm.Blues)
から | に | 値 | |
---|---|---|---|
0 | に | D | 1 |
1 | B | に | 10 |
二 | C | IS | 5 |
3 | に | C | 5 |
## categorical # libraries import pandas as pd import numpy as np import networkx as nx import matplotlib.pyplot as plt # Build a dataframe with your connections # value setting type df = pd.DataFrame({ 'from':['A', 'B', 'C','A'], 'to':['D', 'A', 'E','C'], 'value':['typeA', 'typeA', 'typeB', 'typeB']}) df # And I need to transform my categorical column in a numerical value typeA->1, typeB->2... # Convert to category df['value']=pd.Categorical(df['value']) df['value'].cat.codes # Build your graph G=nx.from_pandas_edgelist(df, 'from', 'to', create_using=nx.Graph() ) # Custom the nodes: nx.draw(G, with_labels=True, node_color='skyblue', node_size=1500, edge_color=df['value'].cat.codes, width=10.0, edge_cmap=plt.cm.Set2)
から | に | 値 | |
---|---|---|---|
0 | に | D | typeA |
1 | B | に | typeA |
二 | C | IS | typeB |
3 | に | C | typeB |
0 0 1 0 2 1 3 1 dtype: int8
7.ネットワークチャートの背景色
fig.set_facecolor()を使用して、ネットワーク図の背景色を変更できます。 pngの背景色を維持したい場合は、fig.get_facecolorを追加する必要があることに注意してください。
# libraries import pandas as pd import numpy as np import networkx as nx import matplotlib.pyplot as plt # Build a dataframe with your connections df = pd.DataFrame({ 'from':['A', 'B', 'C','A'], 'to':['D', 'A', 'E','C'] }) df # Build your graph G=nx.from_pandas_edgelist(df, 'from', 'to', create_using=nx.Graph() ) # Custom the nodes: fig = plt.figure() nx.draw(G, with_labels=True, node_color='skyblue', node_size=1500, edge_color='white') # Set background color fig.set_facecolor('#00000F') # If you want to save the figure to png: # To save the image, you need to set facecolor=fig.get_facecolor(), otherwise the background color is white # plt.savefig('yourname.png', facecolor=fig.get_facecolor(),dpi=300)
から | に | |
---|---|---|
0 | に | D |
1 | B | に |
二 | C | IS |
3 | に | C |
8.相関行列からのネットワーク
このページでは、相関ネットワーク(相関行列に基づくネットワーク)の描画方法について説明します。 10人の人がいて、お互いの親密な関係を知っているとします。これらの関係は、ネットワークで表すことができます。誰もがノードです。 2人が十分に接近している場合(しきい値を設定)、それらはエッジによってリンクされます。それは人口統計学的構造を示します!
# libraries import pandas as pd import numpy as np import networkx as nx import matplotlib.pyplot as plt # I build a data set: 10 individuals and 5 variables for each ind1=[5,10,3,4,8,10,12,1,9,4] ind5=[1,1,13,4,18,5,2,11,3,8] # Build matrix df = pd.DataFrame({ 'A':ind1, 'B':ind1 + np.random.randint(10, size=(10)) , 'C':ind1 + np.random.randint(10, size=(10)) , 'D':ind1 + np.random.randint(5, size=(10)) , 'E':ind1 + np.random.randint(5, size=(10)), 'F':ind5, 'G':ind5 + np.random.randint(5, size=(10)) , 'H':ind5 + np.random.randint(5, size=(10)), 'I':ind5 + np.random.randint(5, size=(10)), 'J':ind5 + np.random.randint(5, size=(10))}) df # Calculate the correlation between individuals. We have to transpose first, because the corr function calculate the pairwise correlations between columns. # Calculate correlation corr = df.corr() corr # Transform it in a links data frame (3 columns only): # Flatten the correlation coefficient matrix links = corr.stack().reset_index() # Set column name links.columns = ['var1', 'var2','value'] #links # Keep only correlation over a threshold and remove self correlation (cors (A,A)=1) # Eliminate rows with the same number and rows with correlation coefficient less than 0.8 links_filtered=links.loc[ (links['value'] > 0.8) & (links['var1'] != links['var2']) ] #links_filtered # Build your graph # Drawing G=nx.from_pandas_edgelist(links_filtered, 'var1', 'var2') # Plot the network: nx.draw(G, with_labels=True, node_color='orange', node_size=500, edge_color='black', linewidths=5, font_size=15)
に | B | C | D | IS | F | G | H | 私 | J | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 5 | 13 | 6 | 8 | 8 | 1 | 4 | 二 | 1 | 3 |
1 | 10 | 19 | 10 | 14 | 12 | 1 | 3 | 4 | 4 | 5 |
二 | 3 | 9 | 3 | 5 | 3 | 13 | 17 | 13 | 14 | 15 |
3 | 4 | 6 | 5 | 4 | 5 | 4 | 7 | 4 | 7 | 4 |
4 | 8 | 13 | 9 | 12 | 10 | 18 | 19 | 19 | 20 | 19 |
5 | 10 | 13 | 13 | 十一 | 十一 | 5 | 8 | 9 | 7 | 9 |
6 | 12 | 16 | 14 | 15 | 13 | 二 | 二 | 3 | 6 | 3 |
7 | 1 | 7 | 6 | 3 | 4 | 十一 | 14 | 14 | 14 | 十一 |
8 | 9 | 十一 | 9 | 9 | 9 | 3 | 4 | 5 | 7 | 5 |
9 | 4 | 9 | 4 | 7 | 4 | 8 | 8 | 8 | 10 | 8 |
に | B | C | D | IS | F | G | H | 私 | J | |
---|---|---|---|---|---|---|---|---|---|---|
に | 1.000000 | 0.816480 | 0.901905 | 0.936634 | 0.949857 | -0.409401 | -0.505922 | -0.327200 | -0.325622 | -0.276172 |
B | 0.816480 | 1.000000 | 0.706978 | 0.928908 | 0.876425 | -0.380840 | -0.440560 | -0.291830 | -0.369119 | -0.214817 |
C | 0.901905 | 0.706978 | 1.000000 | 0.830659 | 0.926892 | -0.343944 | -0.416735 | -0.200915 | -0.245105 | -0.230368 |
D | 0.936634 | 0.928908 | 0.830659 | 1.000000 | 0.939070 | -0.282163 | -0.397256 | -0.212778 | -0.229146 | -0.151093 |
IS | 0.949857 | 0.876425 | 0.926892 | 0.939070 | 1.000000 | -0.412766 | -0.488815 | -0.301198 | -0.346611 | -0.278961 |
F | -0.409401 | -0.380840 | -0.343944 | -0.282163 | -0.412766 | 1.000000 | 0.972397 | 0.968543 | 0.975579 | 0.965554 |
G | -0.505922 | -0.440560 | -0.416735 | -0.397256 | -0.488815 | 0.972397 | 1.000000 | 0.952668 | 0.923379 | 0.957782 |
H | -0.327200 | -0.291830 | -0.200915 | -0.212778 | -0.301198 | 0.968543 | 0.952668 | 1.000000 | 0.956089 | 0.973569 |
私 | -0.325622 | -0.369119 | -0.245105 | -0.229146 | -0.346611 | 0.975579 | 0.923379 | 0.956089 | 1.000000 | 0.927947 |
J | -0.276172 | -0.214817 | -0.230368 | -0.151093 | -0.278961 | 0.965554 | 0.957782 | 0.973569 | 0.927947 | 1.000000 |