igraph如何解决节点重叠问题,而节点大小不同且使用的是R语言。

5
我正在使用R中的igraph创建一个由单个“中心”节点围绕着约600个节点的网络可视化。
这些节点重叠在一起,可以通过解决这个问题的答案(使用qgraph)来解决。
然而,此解决方案似乎仅适用于所有节点尺寸相同的节点。在我的网络中,节点大小是不同的。是否有一种方法可以通过考虑节点大小来确定它们之间的距离以避免重叠?
以下是示例代码:
# create network
net <- graph_from_data_frame(d=links, vertices=nodes, directed=T)

# set colors
colrs <- c("#8DD3C7", "#FFFFB3")
V(net)$color <- colrs[V(net)$type]
# no labels
V(net)$label <- NA

# create a network graph with non-overlapping nodes:
# using https://dev59.com/61kS5IYBdhLWcg3w6qTU
e <- get.edgelist(net,names = F) 
l <- qgraph.layout.fruchtermanreingold(e,vcount=vcount(net))
plot(net,layout=l,vertex.size=4,edge.arrow.mode=0,vertex.label=NA)

这是结果:

不重叠的网络——节点大小相等

但是现在当我改变节点大小时:
# setting node size based on data
V(net)$size <- V(net)$nodesize; 
# plot result 
plot(net,layout=l,edge.arrow.mode=0,vertex.label=NA)

当节点重叠时:

重叠节点-大小不同的节点

感谢您的任何帮助!

*编辑-添加示例数据集:前50个节点*

节点数据:

dput(head(nodes,50))

structure(list(id = c("s01", "s02", "s03", "s04", "s05", "s06", "s07", "s08", 
"s09", "s10", "s11", "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", 
"s20", "s21", "s22", "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", 
"s31", "s32", "s33", "s34", "s35", "s36", "s37", "s38", "s39", "s40", "s41", 
"s42", "s43", "s44", "s45", "s46", "s47", "s48", "s49", "s50"), nodesize = 
c(50, 2.025, 2.025, 3.5, 1, 0.725, 2.875, 1.6, 0.175, 2.175, 0, 0.675, 0.5, 
15.7, 1.4, 0.4, 1.375, 0.425, 0.55, 7, 10.375, 1.125, 0.325, 0.925, 3.6, 0.525, 
0.9, 0.1, 0.5, 2.3, 1.825, 1.95, 0.325, 0.9, 3, 0.475, 0.1, 2.975, 6.1, 9.225,
 0.65, 3.05, 2.925, 6.35, 0.7, 0.2, 0.6, 1.7, 1.675, 1.425), type = c(1L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L)), row.names = c(NA, 50L), class = 
"data.frame")

链接数据:

dput(head(links,49))

structure(list(from = c("s01", "s01", "s01", "s01", "s01", "s01",
"s01", "s01", "s01", "s01", "s01", "s01", "s01", "s01", "s01", 
"s01", "s01", "s01", "s01", "s01", "s01", "s01", "s01", "s01", 
"s01", "s01", "s01", "s01", "s01", "s01", "s01", "s01", "s01", 
"s01", "s01", "s01", "s01", "s01", "s01", "s01", "s01", "s01", 
"s01", "s01", "s01", "s01", "s01", "s01", "s01"), to = c("s02", 
"s03", "s04", "s05", "s06", "s07", "s08", "s09", "s10", "s11", 
"s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", 
"s21", "s22", "s23", "s24", "s25", "s26", "s27", "s28", "s29", 
"s30", "s31", "s32", "s33", "s34", "s35", "s36", "s37", "s38", 
"s39", "s40", "s41", "s42", "s43", "s44", "s45", "s46", "s47", 
"s48", "s49", "s50")), row.names = c(NA, 49L), class = "data.frame")

1
你能添加一些数据以使你的示例可重现吗? - s__
我使用的数据在GitHub上: https://github.com/sara-maria/networkvisdata/tree/master - Sam
使用dput将您的数据(或部分数据)转换为易于我们处理的格式。 - Ben G
感谢提供 dput() 信息:我已相应添加了样本数据,希望能够正常工作! - Sam
2个回答

2
我认为,考虑到你的图形是“星形”图,你不太可能找到另一种布局算法。大多数算法都会将最连接的节点推向中心。
有一个新的包,graphlayouts,其中包括layout_with_stress,可以产生大致相同的结果。一种可能有效的方法是调整节点大小的比例尺。一种简单的方法是调整节点大小的比例尺,以便它们不重叠。 ggraph库可以帮助实现这一点。
library(tidyverse)
library(igraph)
library(ggraph)
library(tidygraph)
library(graphlayouts)
library(scales)


g <- make_star(600) 

par(mar = rep(0,4))

V(g)$size <- sample(1:10, vcount(g), T)

plot(g, 
     vertex.label = NA, 
     layout = l)

Base Plot

(no_scale_g <- g %>% 
  as_tbl_graph() %>% 
  activate(nodes) %>% 
  mutate(size = sample(1:10, vcount(g), replace = T)) %>% 
  ggraph(., layout = 'stress')+
  geom_edge_fan(aes(alpha = ..index..), 
                show.legend = F, 
                check_overlap = T)+
  geom_node_point(aes(size = size, 
                      color = size))+
  coord_equal())

ggraph no scale

(scale_g <- no_scale_g+
  scale_size(range = c(1, 3)))

ggraph with node scaling

你可以调整缩放参数以确保没有重叠。虽然不是完美的解决方案,但对于静态图表来说,这足够接近了。

1
这似乎与以下帖子有关,该帖子提到了qgraph包的布局函数,其中有一个参数repulse.rad。 要使用它,您首先需要通过以下方式将igraph网络对象g转换为边缘列表
## Transform to edgelist with names = FALSE, otherwise it crashed for me
e <- get.edgelist(g, names = FALSE)

layout <- qgraph.layout.fruchtermanreingold(e, vcount = vcount(g),
  area = 6*(vcount(g)^2), repulse.rad = vcount(g)^3)

## Plot via igraph
plot.igraph(network, vertex.label = NA, layout = fixedLayout)

## Or plot via ggraph
ggraph(network, layout = fixedLayout) +
    geom_edge_link(color = "lightgrey", width = 0.3) +
    geom_node_point(size = 3) +
    theme_void()

你可以调整arearepulse.rad参数以满足你的需求。

我认为修改布局应该是真正“保证”没有重叠的最佳方式,尽管我必须承认,“烟花”样式有一些重叠也相当不错!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接