networkx + Cytoscape 构建及可视化网络图

本次笔记内容:

  • 网络图的简要结构
  • 以相关系数表为例:networkx构建网络结构
  • Cytoscape可视化网络图
  • co-XXX network
网络图的简要结构

网络结构由点及连接点的线组成,反映了点所代表的元素之间的关系。网络图使得我们对各元素之间的关系有一个直观的认识。

  • 点:
    点的大小可以表示该元素所包含的样本数/数值大小等;
    点的颜色及形状可以表示该元素的类别属性。
  • 线:
    线的粗细可以表示两元素之间关联的大小(比如相关系数的大小);
    线的颜色可以表示两元素之间关联的方向(比如相关系数的正负),或者你自定义的某些类别;
    线可以包含箭头,同样可以表明方向;
    线的形状可以为直线或曲线,曲线可以在两个元素之间不重合。以上需根据具体科学目的自定义其属性。
以相关系数表为例network绘制网络图

这里用的networkx是Python一个模块。我们用它来定义构成网络图的点,线,及点线的各种属性。
安装networkx : $ pip install networkx

以下为一个基础示例,可以快速了解一下:

import networkx as nx
import matplotlib.pylab as plt
G = nx.Graph()   # 生成一个空的network对象

G.add_node('a',group='t1', your_group='your_group1' )  # 添加每个点(node), group就是node的类别属性,你可以自定义每个node的属性。
G.add_node('b',group='t1', ) 
G.add_node('c',group='t2')  
print(G.node(data=True))
# 点以list储存,是有顺序的,其属性以字典储存。
# [('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两点之间的连线weight为0.5,填充颜色为#CD5C5C
print(G.edge(data=True))
# [('a', 'b', {'weight': 0.5, 'graphics': {'fill': '#CD5C5C'}})]
# 注意以上network各属性的存储方式,可以通过for循环来批量设置点和线的属性。

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

nx.write_gml(G, 'XXX.gml')
# 网络结构可以存储为.gml等格式,作为Cytoscape的input
# 另外,gml格式不允许类别名称出现下划线‘_’,即group不可以是group_a这样的写法。

以下以sklearn中 wine recognition dataset为例,
先构建相关系数矩阵:

import networkx as nx
import matplotlib.pylab as plt
from sklearn import datasets
import pandas as pd
from scipy.stats.stats import pearsonr  # 用来计算pearson相关系数

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() # 是一个wine_df.columns对wine_df.columns的对称table

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

然后构建网络结构:

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'))]
   很冗余,能写的更elegent请告诉我
   '''
   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]: # 把那些自己对自己的去掉
           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)
# 这时候的raw_edges_list是含有重复edges的,即包含(node1,node2,XX)和(node2,node1,XX)
# 后面的操作直到edge_weight_final都是为了去除重复edges...可以说是相当ugly了,如果有什么好的办法请告诉我...

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 = 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:   # 给正负相关系数添上不同的颜色
        G.add_edge(node1, node2, weight=abs(weight), graphics={'fill':'#CD5C5C'})
    else:
        G.add_edge(node1, node2, weight=abs(weight), graphics={'fill':'#4682B4'})

# 画图
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就是网络结构了,接下来把它导入Cytoscape可视化

线的粗细为相关系数的大小(不太明显,因为相关系数差不多),红色为正相关,蓝色为负相关。networkx确实也可以很好的可视化网络图,但Cytoscape的功能更完备。

Cytoscape可视化网络图

Cytoscape是一个免费软件,可以在win,macOS及Linux系统上使用。其下载和安装对java有要求,可以参考其官网下载指南

安装好Cytoscape后,打开并导入(import)上述构建的.gml格式网络结构:

得到:

设置layout : layout是用算法将网络的形态改变,调整成合适的样子。以下为两种不同layout的效果。可以看到我们在Python里设置的edges颜色在这里出现了。
Control Panel中Style栏用于设置字体大小,node框性状及颜色,如果node有分组信息可以按组批量设置。建议自己都点着试试,很容易上手。
Table Panel中包括node table, edge table和network table。
一篇超级详细的Cytoscape中文攻略可以参考。

按照weight的大小定义线的width,注意在style的edge栏里设置。

在style里还可以设置网络图的appearance:

导出为pdf:

co-XXX network

现在好像很流行画co-abundance/co-occurrence network,如果你找出来组间差异物种有很多,想看看这么多差异物种之间有没有什么关联。于是可以画个co-XXX network。比方说如下两篇文章的图:

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

需要注意的是这种图是把两个(或多个)network合并在一起绘制的。两点之间除了直线连接还有曲线(避免与直线重合)。这意味着两点之间不只一个edge. 上述示例代码仍然适用,但需要使用MultiGraph()

import networkx as nx
Gm = nx.MultiGraph()
Gm.add_edge('XXX from corr_1')
Gm.add_edge('XXX from corr_2') 
# 具体内容和上述示例代码是差不多的

在Cytoscape中,如果需要设置edge的弯曲,在Stlye,Edge页面,点击Properties展开按钮,找到Bend, 可以按照提示设置边的曲率。


最后跑个题,安利一下Atom, 一个text editor. 在win上用的话可以扔掉Notepad++了。而且我感觉没用到很高级的功能的话,pycharm都可以扔掉了...R, python, js等各种语言的代码都可以往里塞,可以自行下载海量packages来满足五花八门的需求,界面如下:

像ipython一样逐行输出:


图也可以plot出来,在代表颜色的字符串上直接print出颜色(太炫了!!看这个Q萌的界面!颜控爱了!!(´Д` ))

参考:
networkx官方tutorial
network.draw的细节
一篇超级详细的Cytoscape中文攻略
Cytoscape tutorials官网
知乎专栏上一个atom的介绍
Atom官方使用指南

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,904评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,581评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,527评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,463评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,546评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,572评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,582评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,330评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,776评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,087评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,257评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,923评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,571评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,192评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,436评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,145评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容