igraph разрешить перекрывающиеся узлы с переменным размером узла r
Я создаю сетевую визуализацию одного "центрального" узла, окруженного примерно 600 узлами, используя igraph в R.
Узлы перекрываются, и я могу решить, используя ответ на этот вопрос (используя 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://stackru.com/questions/39290909/igraph-resolving-tight-overlapping-nodes
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")
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)
(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())
(scale_g <- no_scale_g+
scale_size(range = c(1, 3)))
Вы можете настроить параметры масштабирования, чтобы избежать перекрытия. Это не идеально, но для статических графиков это довольно близко.
Похоже, это связано со следующим сообщением, в котором упоминается функция пакета qgraph для компоновки, у которой есть аргумент для repulse.rad. Чтобы использовать его, вам сначала нужно преобразовать объект igraph-network 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()
Вы можете настроить
area
а также
repulse.rad
параметры к вашему удовлетворению.
Я думаю, что изменение макета должно быть лучшим способом действительно гарантировать отсутствие перекрытия, в то время как я должен признать, что стиль «фейерверк» с некоторым перекрытием также довольно хорош!