In igraph
, after applying a modularization algorithm to find graph communites, i would like to draw a network layout which clearly makes visible the distinct communities and their connections. Something like "group attributes layout" in Cytoscape: i want to show the members of each group/community close to each other, and keep some distance between groups/communities. I couldn't find any function in igraph
providing this feature out of the box. While posting this question i have already found out a simple d.i.y solution, i going to post it as an answer. But i am wondering if there is any better possibility, or more elaborated solution?
4 回答
受 Antoine 建议的启发,我创建了这个函数:
edge.weights <- function(community, network, weight.within = 100, weight.between = 1) {
bridges <- crossing(communities = community, graph = network)
weights <- ifelse(test = bridges, yes = weight.between, no = weight.within)
return(weights)
}
该功能也是如此;只需将您的社区对象放在社区插槽中,您的图形在网络中。我会离开weight.between = 1
并调整weight.within
值。
然后将权重转移到weight
节点中的槽:
E(graph)$weight <- edge.weights(community, graph)
最后使用一种使用权重的布局算法,例如( inlayout_with_fr
的新名称)。fruchterman.reingold
igraph 1.0.1
我以 Zachary 的空手道俱乐部网络为例。
library(igraph)
library(igraphdata)
#I load the network
data(karate)
#for reproducible purposes
set.seed(23548723)
karateLayout <- layout_with_fr(karate)
par(mar = c(0,0,2,0))
plot(karate, vertex.size = 10, vertex.color = "steelblue4", edge.width = 1,
vertex.label = NA, edge.color = "darkgrey", layout = karateLayout,
main = "Zachary's karate club network" )
我通过使用以下功能对模块化进行多级优化来检测社区cluster_louvain
:
Communitykarate <- cluster_louvain(karate)
接下来是个人偏好而不是默认值:
prettyColors <- c("turquoise4", "azure4", "olivedrab","deeppink4")
communityColors <- prettyColors[membership(Communitykarate)]
使用颜色突出显示社区的图表是:
plot(x = Communitykarate, y = karate, edge.width = 1, vertex.size = 10,
vertex.label = NA, mark.groups = NULL, layout = karateLayout, col = communityColors,
main = "Communities in Zachary's karate club network",
edge.color = c("darkgrey","tomato2")crossing(Communitykarate, karate) + 1])
现在,这个问题存在的意义。
E(karate)$weight <- edge.weights(Communitykarate, karate)
# I use the original layout as a base for the new one
karateLayoutA <- layout_with_fr(karate, karateLayout)
# the graph with the nodes grouped
plot(x = Communitykarate, y = karate, edge.width = 1, vertex.size = 10,
mark.groups = NULL, layout = karateLayoutA, vertex.label = NA, col = communityColors,
c("darkgrey","tomato2")[crossing(Communitykarate, karate) + 1],
main = "Communities in Zachary's karate club network (grouped)")
如果您尝试增加体重,您将拥有:
E(karate)$weight <- edge.weights(Communitykarate, karate, weight.within = 1000)
karateLayoutB <- layout_with_fr(karate, karateLayout)
plot(x = Communitykarate, y = karate, edge.width = 1, vertex.size = 10,
mark.groups = NULL, layout = karateLayoutB, vertex.label = NA, col = communityColors,
c("darkgrey","tomato2")[crossing(Communitykarate, karate) + 1],
main = "Communities in Zachary's karate club network (grouped)")
为了扩展 Gabor 的建议,我创建了这个函数:
weight.community=function(row,membership,weigth.within,weight.between){
if(as.numeric(membership[which(names(membership)==row[1])])==as.numeric(membership[which(names(membership)==row[2])])){
weight=weigth.within
}else{
weight=weight.between
}
return(weight)
}
只需将其应用于图形边矩阵的行(由get.edgelist(your_graph))
设置新边权重(成员资格是任何社区检测算法结果的成员资格向量):
E(g)$weight=apply(get.edgelist(g),1,weight.community,membership,10,1)
然后,只需使用接受边缘权重的布局算法,例如 Gabor 建议的 fruchterman.reingold。您可以调整权重参数以获得所需的图形。例如:
E(g)$weight=apply(get.edgelist(g),1,weight.community,membership,10,1)
g$layout=layout.fruchterman.reingold(g,weights=E(g)$weight)
plot(g)
E(g)$weight=apply(get.edgelist(g),1,weight.community,membership,1000,1)
g$layout=layout.fruchterman.reingold(g,weights=E(g)$weight)
plot(g)
注 1:边缘的透明度/颜色是我的图表的其他参数。我按社区对节点进行了着色,以表明它确实有效。
注意 2:确保使用membership(comm)
和 不,社区检测算法的结果在comm$membership
哪里(例如, )。原因是在第一种情况下,你得到一个带有名字的数字向量(我们想要的),而在第二种情况下,你得到一个没有名字的同一个向量。comm
comm=leading.eigenvector.community(g)
要获得多个社区检测算法的共识,请参阅此功能。
该函数layout.modular
根据任何 igraph 社区检测方法的结果为图提供分组布局:
c <- fastgreedy.community(G)
layout.modular <- function(G,c){
nm <- length(levels(as.factor(c$membership)))
gr <- 2
while(gr^2<nm){
gr <- gr+1
}
i <- j <- 0
for(cc in levels(as.factor(c$membership))){
F <- delete.vertices(G,c$membership!=cc)
F$layout <- layout.kamada.kawai(F)
F$layout <- layout.norm(F$layout, i,i+0.5,j,j+0.5)
G$layout[c$membership==cc,] <- F$layout
if(i==gr){
i <- 0
if(j==gr){
j <- 0
}else{
j <- j+1
}
}else{
i <- i+1
}
}
return(G$layout)
}
G$layout <- layout.modular(G,c)
V(G)$color <- rainbow(length(levels(as.factor(c$membership))))[c$membership]
plot(G)
一种解决方案是基于模块化设置图的边权重。将模块内边缘设置为较大的权重,将模块边缘设置为较小的权重。然后调用layout.fruchterman.reingold()
,或任何支持边缘权重的算法。
您可能需要对实际重量值进行一些调整,因为这取决于您的图表。