R语言绘图包13--共表达网络的绘制:igraph


R语言绘图包系列:


网络图,是一种包含了节点V(即网络参与者,也称顶点)与边E(即节点之间的连接关系)的数学结构,记作G={V,E}。可以使用一个矩阵来存放节点之间的连接关系,这个矩阵称为邻接矩阵。如果网络中两个节点之间的边是有方向的,即从节点u出发指向节点v,这就是一个有向网络(有向图),否则称为无向网络(无向图)。网络的边也可以赋予权重,称为加权网络。

1. igraph绘图

1.1 基础绘图
###安装并载入演示数据集
library(devtools)
install_github("kassambara/navdata")
library("navdata")
###载入数据集
data("phone.call") #示例集来自于navdata包(是一个假想的数据集,里边有一个不存在的国家Slovania)
这个数据集表示的是在某段时间内欧洲部分国家领导人之间的通话次数。由数据可见,这是一个由source指向destination,以通话次数为权重的有向加权网络。

igraph有特定的网络(图)对象类“igraph”。建立一个图的最简单的方法是用函数graph.formula()手工输入节点的对应关系,考虑到实际上的网络规模都是比较大的,我们几乎不会用到这种方法。更常用的方式有两种:

  • 从数据框(节点列表和边列表)建立网络对象

这种方法需要我们先建立两个数据框:
边列表:包含节点标签和节点的其他属性
节点列表:包含节点之间联系(也就是边)和边的属性
此时,可以使用graph_from_data_frame()建立igraph对象。

  • 从邻接矩阵建立网络对象

如果数据集是表示节点连接关系的矩阵形式(比如说就像相关系数矩阵那样),可以使用graph_from_adjacency_matrix()建立igraph对象
对于phone.call这个数据集,要创建节点列表,需要将source和destination这两列包含的各个国家的名称提取出来,即提取独特的行观测,这使用dplyr包的distinct函数来实现。然后,我们创建一个新变量location,表示这些节点的地理位置:

library(tidyverse)
name<-data.frame(c(phone.call$source,phone.call$destination))
nodes<-name%>%
    distinct()%>%
mutate(location=c("western","western","central","nordic","southeastern",
     "southeastern","southeastern","southern","sourthern",
     "western","western","central","central","central","central","central"))
colnames(nodes)<-c("label","location")

下面来看边列表。数据集phone.call的前两列分别表示了边出发和终结的节点。所以这个数据集就是边列表的形式,第三列n.call可以作为边的权重。我们把这些列的名称改成更直观的名字:

edges<-phone.call%>%rename(from=source,to=destination,weight=n.call)

现在可以创建一个igraph对象了:

library(igraph)

net_pc<-graph_from_data_frame(
   d=edges,vertices=nodes,
   directed=TRUE)

net_pc

可以看到输出的igraph对象:

3f802ae是这个对象的名称,DNW- 16 18 --表示这是一个有向(D)、有命名(N)且加权(W)的网络,它有16个节点和18条边。它具有的节点属性是name , location ,具有的边属性是weight。

我们可以通过V()和E()对节点和边的属性进行访问,如:

V(net_pc)
# + 16/16 vertices, named, from 3f802ae:
#  [1] France         Belgium        Germany        Danemark      
#  [5] Croatia        Slovenia       Hungary        Spain         
#  [9] Italy          Netherlands    UK             Austria       
# [13] Poland         Switzerland    Czech republic Slovania     
V(net_pc)$location 
# [1] "western"      "western"      "central"      "nordic"      
#  [5] "southeastern" "southeastern" "southeastern" "southern"    
#  [9] "sourthern"    "western"      "western"      "central"     
# [13] "central"      "central"      "central"      "central"     

这种方法也可以用于指定或修正相应的节点和边的属性,这在igraph可视化中是很常用的。

还可以从net_pc这个网络中提取边列表或者邻接矩阵:

###提取边列表
as_edgelist(net_pc, names=T) 
      [,1]       [,2]            
#  [1,] "France"   "Germany"       
#  [2,] "Belgium"  "France"        
#  [3,] "France"   "Spain"         
#  [4,] "France"   "Italy"         
#  [5,] "France"   "Netherlands"   
#  [6,] "France"   "UK"            
#  [7,] "Germany"  "Austria"       
#  [8,] "Germany"  "Poland"        
#  [9,] "Belgium"  "Germany"       
# [10,] "Germany"  "Switzerland"   
# [11,] "Germany"  "Czech republic"
# [12,] "Germany"  "Netherlands"   
# [13,] "Danemark" "Germany"       
# [14,] "Croatia"  "Germany"       
# [15,] "Croatia"  "Slovania"      
# [16,] "Croatia"  "Hungary"       
# [17,] "Slovenia" "Germany"       
# [18,] "Hungary"  "Slovania"     
###提取邻接矩阵
as_adjacency_matrix(net_pc, attr="weight")
# 16 x 16 sparse Matrix of class "dgCMatrix"
#   [[ suppressing 16 column names ‘France’, ‘Belgium’, ‘Germany’ ... ]]
                                                
# France         . . 9 . . . . 3 4 2 3 . . . . .  
# Belgium        4 . 3 . . . . . . . . . . . . .  
# Germany        . . . . . . . . . 2 . 2 2 2 2 .  
# Danemark       . . 2 . . . . . . . . . . . . .  
# Croatia        . . 2 . . . 2 . . . . . . . . 2.0
# Slovenia       . . 2 . . . . . . . . . . . . .  
# Hungary        . . . . . . . . . . . . . . . 2.5
# Spain          . . . . . . . . . . . . . . . .  
# Italy          . . . . . . . . . . . . . . . .  
# Netherlands    . . . . . . . . . . . . . . . .  
# UK             . . . . . . . . . . . . . . . .  
# Austria        . . . . . . . . . . . . . . . .  
# Poland         . . . . . . . . . . . . . . . .  
# Switzerland    . . . . . . . . . . . . . . . .  
# Czech republic . . . . . . . . . . . . . . . .  
# Slovania       . . . . . . . . . . . . . . . .  

现在可以看一下这个网络了(图3):

plot(net_pc)
1.2 可视化基础

igraph的plot函数中提供了大量的参数用于展示节点、边以及图形的各种属性,其中涉及节点的参数是以vertex.开头的,涉及边的参数是以edge.开头的。

除了在plot()中指定节点和边的参数之外,还可以使用前面提到的V()E(),直接在igraph对象中添加相应的属性。这两种方法的区别在于,在plot()中指定的参数并不会改变图的属性。比如,我们先按照位置指定节点的颜色,按照权重指定边的宽度(这两个属性会保存在net_pc对象中),然后在plot()的参数中指定节点的大小(与节点的度成比例,节点度是与这个节点相连的边的个数)、节点标记的大小和位置、边的颜色、箭头的大小和边的弯曲程度

###计算节点的度
deg<-degree(net_pc,mode="all")
###设置颜色
vcolor<-c("orange","red","lightblue","tomato","yellow")
###指定节点的颜色
V(net_pc)$color<-vcolor[factor(V(net_pc)$location)]
###指定边的颜色
E(net_pc)$width<-E(net_pc)$weight/2

plot(net_pc,vertex.size=3*deg,
vertex.label.cex=.7,vertex.label.dist=1,
edge.color="gray50",edge.arrow.size=.4, edge.curved=.1)
###添加图例
legend(x=1.5,y=1.5,levels(factor(V(net_pc)$location)),pch=21,col="#777777",pt.bg=vcolor)
1.3 网络布局

网络布局指的是确定网络中每个节点坐标的方法。

igraph中提供了多种布局算法,其中最有用的是几种力导向(Force-directed)布局算法。力导向布局试图得到一个美观的图形,其中的边在长度上相似,并且尽可能少地交叉。它们把图形模拟成一个物理系统。节点是带电粒子,当它们靠得太近时会互相排斥。这些边充当弹簧,将连接的节点吸引在一起。结果,节点在图示区域中均匀分布,并且布局直观,因为共享更多连接的节点彼此更接近。这些算法的缺点是速度很慢,因此在大于1000个顶点的图中使用的频率较低。

使用力导向布局时,可以使用niter参数控制要执行的迭代次数。默认设置为500次迭代。对于大型的图,可以降低该数字以更快地获得结果,并检查它们是否合理。

Fruchterman-Reingold是最常用的力导向布局算法:

l <- layout_with_fr(net_pc) 
plot(net_pc, layout=l)

Fruchterman Reingold布局具有随机性,不同的运行将导致略有不同的布局配置。将布局保存在对象l当中,可以使我们多次获得完全相同的结果(也可以实现指定随机数种子seed())。

我们通过一张图来展示所有的(用于单模图的)布局方式:

layouts <- grep("^layout_", ls("package:igraph"), value=TRUE)[-1]
# Remove layouts that do not apply to our graph.
layouts <- layouts[!grepl("bipartite|merge|norm|sugiyama|tree", layouts)]
par(mfrow=c(5,3), mar=c(1,1,1,1)) 
for (layout in layouts) {
print(layout)
l <- do.call(layout, list(net_pc))
plot(net_pc, vertex.label="",edge.arrow.mode=0, layout=l, main=layout) }

参考:R语言网络数据可视化(1):igraph基础

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

推荐阅读更多精彩内容