networkx + Cytoscape 構(gòu)建及可視化網(wǎng)絡(luò)圖

本次筆記內(nèi)容:

  • 網(wǎng)絡(luò)圖的簡(jiǎn)要結(jié)構(gòu)
  • 以相關(guān)系數(shù)表為例:networkx構(gòu)建網(wǎng)絡(luò)結(jié)構(gòu)
  • Cytoscape可視化網(wǎng)絡(luò)圖
  • co-XXX network
網(wǎng)絡(luò)圖的簡(jiǎn)要結(jié)構(gòu)

網(wǎng)絡(luò)結(jié)構(gòu)由點(diǎn)及連接點(diǎn)的線組成,反映了點(diǎn)所代表的元素之間的關(guān)系。網(wǎng)絡(luò)圖使得我們對(duì)各元素之間的關(guān)系有一個(gè)直觀的認(rèn)識(shí)。

  • 點(diǎn):
    點(diǎn)的大小可以表示該元素所包含的樣本數(shù)/數(shù)值大小等;
    點(diǎn)的顏色及形狀可以表示該元素的類(lèi)別屬性。
  • 線:
    線的粗細(xì)可以表示兩元素之間關(guān)聯(lián)的大?。ū热缦嚓P(guān)系數(shù)的大?。?;
    線的顏色可以表示兩元素之間關(guān)聯(lián)的方向(比如相關(guān)系數(shù)的正負(fù)),或者你自定義的某些類(lèi)別;
    線可以包含箭頭,同樣可以表明方向;
    線的形狀可以為直線或曲線,曲線可以在兩個(gè)元素之間不重合。以上需根據(jù)具體科學(xué)目的自定義其屬性。
以相關(guān)系數(shù)表為例network繪制網(wǎng)絡(luò)圖

這里用的networkx是Python一個(gè)模塊。我們用它來(lái)定義構(gòu)成網(wǎng)絡(luò)圖的點(diǎn),線,及點(diǎn)線的各種屬性。
安裝networkx : $ pip install networkx

以下為一個(gè)基礎(chǔ)示例,可以快速了解一下:

import networkx as nx
import matplotlib.pylab as plt
G = nx.Graph()   # 生成一個(gè)空的network對(duì)象

G.add_node('a',group='t1', your_group='your_group1' )  # 添加每個(gè)點(diǎn)(node), group就是node的類(lèi)別屬性,你可以自定義每個(gè)node的屬性。
G.add_node('b',group='t1', ) 
G.add_node('c',group='t2')  
print(G.node(data=True))
# 點(diǎn)以list儲(chǔ)存,是有順序的,其屬性以字典儲(chǔ)存。
# [('a', {'group': 't1', 'your_group': 'your_group1'}), ('b', {'group': 't1'}), ('c', {'group': 't2'})]

G.add_edge('a', 'b', weight=0.5,graphics={'fill' : '#CD5C5C'}) # 添加邊,a,b兩點(diǎn)之間的連線weight為0.5,填充顏色為#CD5C5C
print(G.edge(data=True))
# [('a', 'b', {'weight': 0.5, 'graphics': {'fill': '#CD5C5C'}})]
# 注意以上network各屬性的存儲(chǔ)方式,可以通過(guò)for循環(huán)來(lái)批量設(shè)置點(diǎn)和線的屬性。

node_color = ['yellow','yellow','orange']
nx.draw(G,node_color=node_color,node_size=200, with_labels=True)
plt.show()
# 可以結(jié)合matplotlib在python里可視化

nx.write_gml(G, 'XXX.gml')
# 網(wǎng)絡(luò)結(jié)構(gòu)可以存儲(chǔ)為.gml等格式,作為Cytoscape的input
# 另外,gml格式不允許類(lèi)別名稱出現(xiàn)下劃線‘_’,即group不可以是group_a這樣的寫(xiě)法。

以下以sklearn中 wine recognition dataset為例,
先構(gòu)建相關(guān)系數(shù)矩陣:

import networkx as nx
import matplotlib.pylab as plt
from sklearn import datasets
import pandas as pd
from scipy.stats.stats import pearsonr  # 用來(lái)計(jì)算pearson相關(guān)系數(shù)

wine_data = datasets.load_wine()
wine_df = pd.DataFrame(data=wine_data['data'],columns=wine_data['feature_names'])
wine_df.head() # 行為samples, 列為features
> alcohol   malic_acid  ash alcalinity_of_ash   magnesium   total_phenols   flavanoids  nonflavanoid_phenols    proanthocyanins color_intensity hue od280/od315_of_diluted_wines    proline 
0   14.23   1.71    2.43    15.6    127.0   2.80    3.06    0.28    2.29    5.64    1.04    3.92    1065.0  
1   13.20   1.78    2.14    11.2    100.0   2.65    2.76    0.26    1.28    4.38    1.05    3.40    1050.0  
2   13.16   2.36    2.67    18.6    101.0   2.80    3.24    0.30    2.81    5.68    1.03    3.17    1185.0  
3   14.37   1.95    2.50    16.8    113.0   3.85    3.49    0.24    2.18    7.80    0.86    3.45    1480.0  
4   13.24   2.59    2.87    21.0    118.0   2.80    2.69    0.39    1.82    4.32    1.04    2.93    735.0   

corr = pd.DataFrame()
corr_p = pd.DataFrame()
for i in wine_df.columns:
    for j in wine_df.columns:
        corr.loc[i,j] = pearsonr(wine_df[i], wine_df[j])[0]
        corr_p.loc[i,j] = pearsonr(wine_df[i], wine_df[j])[1]
corr.head() # 是一個(gè)wine_df.columns對(duì)wine_df.columns的對(duì)稱table

tep = abs(corr_p.values) < 0.05
temp.sum()   # 135,p<0.05的不少

然后構(gòu)建網(wǎng)絡(luò)結(jié)構(gòu):

def dataframe_to_tp(corr, row, corr_pvalue):
   '''
   :param corr: corr df
   :param row: like "alcohol" (single OTU index, for loop use)
   :param corr_pvalue: corr_p df
   :return: row_list: [('alcohol','ash', cor('alcohol','ash'))]
   很冗余,能寫(xiě)的更elegent請(qǐng)告訴我
   '''
   row_list = []
   for col in list(corr.columns):
       if (corr_pvalue.loc[row, col] < 0.05) & (abs(corr).loc[row,col] > 0.5):
           tp = (row, col, corr.loc[row, col])
           row_list.append(tp)
       else:
           pass
   for i in row_list:
       if i[0] == i[1]: # 把那些自己對(duì)自己的去掉
           row_list.remove(i)
   return row_list

print(dataframe_to_tp(corr, 'alcohol',corr_p))
# [('alcohol', 'color_intensity', 0.5463641950837036), ('alcohol', 'proline', 0.6437200371782135)]

raw_edges_list = [] # [(node1,node2,weight),(...),()]
for row in corr.index.values:
    raw_edges_list += dataframe_to_tp(corr, row, corr_p)
# 這時(shí)候的raw_edges_list是含有重復(fù)edges的,即包含(node1,node2,XX)和(node2,node1,XX)
# 后面的操作直到edge_weight_final都是為了去除重復(fù)edges...可以說(shuō)是相當(dāng)ugly了,如果有什么好的辦法請(qǐng)告訴我...

edge_dict = {}
for tp in raw_edges_list:
    edge_dict[(tp[0],tp[1])] = tp[2]

not_d_edge = []
for i in [set(i) for i in edge_dict.keys()]:
    if i not in not_d_edge:
       not_d_edge.append(i)

edge_weight_final = []
for edge in not_d_edge:
    final_edge = tuple(edge) + (edge_dict[tuple(edge)],)
    edge_weight_final.append(final_edge)

print(edge_weight_final) #看一下
# [('alcohol', 'color_intensity', 0.5463641950837036), 
# ('alcohol', 'proline', 0.6437200371782135), 
# ('hue', 'malic_acid', -0.5612956886649448), 
# ('total_phenols', 'flavanoids', 0.8645635000951146), # ('proanthocyanins', 'total_phenols', 0.6124130837800361), 
# ('od280/od315_of_diluted_wines', 'total_phenols', 0.699949364791186), 
# ('nonflavanoid_phenols', 'flavanoids', -0.5378996119051982), 
# ('proanthocyanins', 'flavanoids', 0.6526917686075154), 
# ('hue', 'flavanoids', 0.5434785664899897), 
# ('od280/od315_of_diluted_wines', 'flavanoids', 0.7871939018669516), 
# ('nonflavanoid_phenols', 'od280/od315_of_diluted_wines', -0.5032695960789115), 
# ('od280/od315_of_diluted_wines', 'proanthocyanins', 0.5190670956825231), 
# ('hue', 'color_intensity', -0.5218131932287576), 
# ('od280/od315_of_diluted_wines', 'hue', 0.5654682931826592)]



# 把做好的tuple list用于構(gòu)建網(wǎng)絡(luò):
G = nx.Graph()
# G.add_weighted_edges_from(weighted_edges_list)  這樣也可以
for tp in weighted_edges_list:
    node1 = tp[0]
    node2 = tp[1]
    weight = tp[2]
    if weight > 0:   # 給正負(fù)相關(guān)系數(shù)添上不同的顏色
        G.add_edge(node1, node2, weight=abs(weight), graphics={'fill':'#CD5C5C'})
    else:
        G.add_edge(node1, node2, weight=abs(weight), graphics={'fill':'#4682B4'})

# 畫(huà)圖
edge_width = [G[u][v]['weight']*10 for u,v in G.edges()]
color = [G[u][v]['graphics']['fill'] for u,v in G.edges()]
nx.draw(G,width=edge_width, pos = nx.circular_layout(G), edge_color=color, with_labels=True)
# 如下圖所示

nx.write_gml(G, 'XXX/wine.gml')
# wine.gml就是網(wǎng)絡(luò)結(jié)構(gòu)了,接下來(lái)把它導(dǎo)入Cytoscape可視化

線的粗細(xì)為相關(guān)系數(shù)的大?。ú惶黠@,因?yàn)橄嚓P(guān)系數(shù)差不多),紅色為正相關(guān),藍(lán)色為負(fù)相關(guān)。networkx確實(shí)也可以很好的可視化網(wǎng)絡(luò)圖,但Cytoscape的功能更完備。

Cytoscape可視化網(wǎng)絡(luò)圖

Cytoscape是一個(gè)免費(fèi)軟件,可以在win,macOS及Linux系統(tǒng)上使用。其下載和安裝對(duì)java有要求,可以參考其官網(wǎng)下載指南。

安裝好Cytoscape后,打開(kāi)并導(dǎo)入(import)上述構(gòu)建的.gml格式網(wǎng)絡(luò)結(jié)構(gòu):

得到:

設(shè)置layout : layout是用算法將網(wǎng)絡(luò)的形態(tài)改變,調(diào)整成合適的樣子。以下為兩種不同layout的效果??梢钥吹轿覀?cè)赑ython里設(shè)置的edges顏色在這里出現(xiàn)了。
Control Panel中Style欄用于設(shè)置字體大小,node框性狀及顏色,如果node有分組信息可以按組批量設(shè)置。建議自己都點(diǎn)著試試,很容易上手。
Table Panel中包括node table, edge table和network table。
一篇超級(jí)詳細(xì)的Cytoscape中文攻略可以參考。

按照weight的大小定義線的width,注意在style的edge欄里設(shè)置。

在style里還可以設(shè)置網(wǎng)絡(luò)圖的appearance:

導(dǎo)出為pdf:

co-XXX network

現(xiàn)在好像很流行畫(huà)co-abundance/co-occurrence network,如果你找出來(lái)組間差異物種有很多,想看看這么多差異物種之間有沒(méi)有什么關(guān)聯(lián)。于是可以畫(huà)個(gè)co-XXX network。比方說(shuō)如下兩篇文章的圖:

2017 Nat Med. Metformin alters the gut microbiome of individuals with treatment-naive type 2 diabetes, contributing to the therapeutic effects of the drug

2019 Gut. Tracing the accumulation of in vivo human oral microbiota elucidates microbial community dynamics at the gateway to the GI tract

需要注意的是這種圖是把兩個(gè)(或多個(gè))network合并在一起繪制的。兩點(diǎn)之間除了直線連接還有曲線(避免與直線重合)。這意味著兩點(diǎn)之間不只一個(gè)edge. 上述示例代碼仍然適用,但需要使用MultiGraph()

import networkx as nx
Gm = nx.MultiGraph()
Gm.add_edge('XXX from corr_1')
Gm.add_edge('XXX from corr_2') 
# 具體內(nèi)容和上述示例代碼是差不多的

在Cytoscape中,如果需要設(shè)置edge的彎曲,在Stlye,Edge頁(yè)面,點(diǎn)擊Properties展開(kāi)按鈕,找到Bend, 可以按照提示設(shè)置邊的曲率。


最后跑個(gè)題,安利一下Atom, 一個(gè)text editor. 在win上用的話可以扔掉Notepad++了。而且我感覺(jué)沒(méi)用到很高級(jí)的功能的話,pycharm都可以扔掉了...R, python, js等各種語(yǔ)言的代碼都可以往里塞,可以自行下載海量packages來(lái)滿足五花八門(mén)的需求,界面如下:

像ipython一樣逐行輸出:


圖也可以plot出來(lái),在代表顏色的字符串上直接print出顏色(太炫了?。】催@個(gè)Q萌的界面!顏控愛(ài)了!!(′Д` ))

參考:
networkx官方tutorial
network.draw的細(xì)節(jié)
一篇超級(jí)詳細(xì)的Cytoscape中文攻略
Cytoscape tutorials官網(wǎng)
知乎專(zhuān)欄上一個(gè)atom的介紹
Atom官方使用指南

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容