Ответ 1
Чтобы сделать это с помощью igraph
, я думаю, вам нужно будет вставить в функцию plot.igraph
, выяснить, где она генерирует кривые Безье для изогнутых ребер между вершинами, а затем использовать интерполяцию для получения точек вдоль этих ребер, С помощью этой информации вы можете рисовать сегменты стрелки вдоль краев графика.
Здесь другой подход, который не совсем то, что вы просили, но, надеюсь, может удовлетворить ваши потребности. Вместо igraph
я собираюсь использовать ggplot2
вместе с функцией ggnet2
из пакета GGally
.
Основной подход - получить координаты конечных точек каждого графа графа, а затем интерполировать точки вдоль каждого ребра, где мы будем рисовать сегменты стрелок. Обратите внимание, что ребра являются прямыми линиями, так как ggnet2
не поддерживает кривые края.
library(ggplot2)
library(GGally)
# Create an adjacency matrix that we'll turn into a network graph
m = matrix(c(0,1,0,0,
0,0,1,0,
1,0,0,1,
0,0,0,0), byrow=TRUE, nrow=4)
# Plot adjacency matrix as a directed network graph
set.seed(2)
p = ggnet2(network(m, directed=TRUE), label=TRUE, arrow.gap=0.03)
Вот как выглядит график:
Теперь мы хотим добавить стрелки вдоль каждого ребра. Для этого сначала нужно выяснить координаты конечных точек каждого ребра. Мы можем получить это из самого объекта графика, используя ggplot_build
:
gg = ggplot_build(p)
Данные графика хранятся в gg$data
:
gg$data
[[1]] x xend y yend PANEL group colour size linetype alpha 1 0.48473786 0.145219576 0.29929766 0.97320807 1 -1 grey50 0.25 solid 1 2 0.12773544 0.003986273 0.97026602 0.04720945 1 -1 grey50 0.25 solid 1 3 0.02670486 0.471530869 0.03114479 0.25883640 1 -1 grey50 0.25 solid 1 4 0.52459870 0.973637028 0.25818813 0.01431760 1 -1 grey50 0.25 solid 1 [[2]] alpha colour shape size x y PANEL group fill stroke 1 1 grey75 19 9 0.1317217 1.00000000 1 1 NA 0.5 2 1 grey75 19 9 0.0000000 0.01747546 1 1 NA 0.5 3 1 grey75 19 9 0.4982357 0.27250573 1 1 NA 0.5 4 1 grey75 19 9 1.0000000 0.00000000 1 1 NA 0.5 [[3]] x y PANEL group colour size angle hjust vjust alpha family fontface lineheight label 1 0.1317217 1.00000000 1 -1 black 4.5 0 0.5 0.5 1 1 1.2 1 2 0.0000000 0.01747546 1 -1 black 4.5 0 0.5 0.5 1 1 1.2 2 3 0.4982357 0.27250573 1 -1 black 4.5 0 0.5 0.5 1 1 1.2 3 4 1.0000000 0.00000000 1 -1 black 4.5 0 0.5 0.5 1 1 1.2 4
В вышеприведенном выводе мы видим, что первые четыре столбца gg$data[[1]]
содержат координаты конечных точек каждого ребра (и они находятся в правильном порядке для ориентированного графа).
Теперь, когда у нас есть конечные точки для каждого ребра, мы можем интерполировать точки между двумя конечными точками, на которых мы будем рисовать сегменты линии со стрелками на конце. Эта функция ниже позаботится об этом. Он берет кадр данных конечных точек для каждого ребра и возвращает список вызовов geom_segment
(по одному для каждого графа графа), который рисует сегменты стрелок n
. Этот список вызовов geom_segment
может быть непосредственно добавлен к нашему первоначальному графику сети.
# Function that interpolates points between each edge in the graph,
# puts those points in a data frame,
# and uses that data frame to return a call to geom_segment to add the arrow heads
add.arrows = function(data, n=10, arrow.length=0.1, col="grey50") {
lapply(1:nrow(data), function(i) {
# Get coordinates of edge end points
x = as.numeric(data[i,1:4])
# Interpolate between the end points and put result in a data frame
# n determines the number of interpolation points
xp=seq(x[1],x[2],length.out=n)
yp=approxfun(x[c(1,2)],x[c(3,4)])(seq(x[1],x[2],length.out=n))
df = data.frame(x=xp[-n], xend=xp[-1], y=yp[-n], yend=yp[-1])
# Create a ggplot2 geom_segment call with n arrow segments along a graph edge
geom_segment(data=df, aes(x=x,xend=xend,y=y,yend=yend), colour=col,
arrow=arrow(length=unit(arrow.length,"inches"), type="closed"))
})
}
Теперь запустите функцию, чтобы добавить головки стрелок к исходному графику сети.
p = p + add.arrows(gg$data[[1]], 15)
И вот как выглядит график: