Пользовательский стиль линии для сетевого графика в R

Я надеюсь создать направленный сетевой сюжет с наконечниками стрел (или похожими шевронами) по длине строки...

введите описание изображения здесь

Библиотека igraph, похоже, использует базовую функцию polygon, которая принимает lty для указания типов линий, но они ограничены различными тире.

Есть ли способ сделать настраиваемые символы (или даже использовать треугольники в pch), чтобы сформировать строку в R?

Минимальный код для создания графика:

require(igraph)
gr = graph_from_literal( A -+ B -+ C )
plot(gr,edge.curved=TRUE)

Кстати, мне было бы неплохо использовать другую библиотеку сетевого анализа, если она будет поддерживать это. Я спросил разработчика ggraph, и он сказал, что этого не может сделать.

Ответы

Ответ 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)

И вот как выглядит график:

введите описание изображения здесь

Ответ 2

Cytoscape и RCy3 используются библиотеки для создания сетевых диаграмм.

Установите cytoscape версии 3 и выше отсюда. Затем запустите сеанс cytoscape GUI (графический интерфейс пользователя).

Версии, используемые в этом ответе: cytoscape: 3.4.0 и RCy3: 1.5.2

ОС: Windows-7

# load libraries
library('RCy3')

# create cytoscape connection
cy <- RCy3::CytoscapeConnection()
RCy3::deleteAllWindows(cy)       # delete all windows in cytoscape
hideAllPanels(cy)                # hide all panels

# create node and edge data and create graphNEL object
node.tbl <- data.frame(Node.Name = c('A', 'B', 'C'))
edge.tbl <- data.frame(Gene.1 = c('A', 'B'),
                       Gene.2 = c('B', 'C'))
g <- cyPlot(node.tbl, edge.tbl)
g
# A graphNEL graph with directed edges
# Number of Nodes = 3 
# Number of Edges = 2 

# create cytoscape window and display the graph
window_title <- 'example'
cw <- RCy3::CytoscapeWindow(window_title, graph=g, overwrite=FALSE)
RCy3::displayGraph(cw)

# set visual style and layout algorithm
vis_style <- 'Curved'               # getVisualStyleNames(cw)[7]
RCy3::setVisualStyle(cw, vis_style)       
RCy3::layoutNetwork(obj = cw, layout.name = "circular")
RCy3::layoutNetwork(obj = cw, layout.name = "kamada-kawai")

# get all edges
getAllEdges(cw)
# [1] "A (unspecified) B" "B (unspecified) C"

# get cytoscape supported line types
supported_styles <- getLineStyles (cw)
supported_styles
# [1] "EQUAL_DASH"       "PARALLEL_LINES"   "MARQUEE_DASH"     "MARQUEE_EQUAL"    "SOLID"            "FORWARD_SLASH"    "DASH_DOT"         "MARQUEE_DASH_DOT"
# [9] "SEPARATE_ARROW"   "VERTICAL_SLASH"   "DOT"              "BACKWARD_SLASH"   "SINEWAVE"         "ZIGZAG"           "LONG_DASH"        "CONTIGUOUS_ARROW"

# set edge line type
setEdgeLineStyleDirect(cw, "A (unspecified) B", supported_styles [16])  # "CONTIGUOUS_ARROW"

введите описание изображения здесь

setEdgeLineStyleDirect(cw, "A (unspecified) B", supported_styles [9])   # "SEPARATE_ARROW"

введите описание изображения здесь

# save network as image in the current working directory
fitContent (cw)
setZoom(cw, getZoom(cw) - 1)  # adjust the value from 1 to a desired number to prevent cropping of network diagram
saveImage(obj = cw, 
          file.name = 'example',
          image.type = 'png',
          h = 700)

Для получения дополнительной информации прочитайте ?RCy3::setEdgeLineStyleDirect.

Также для атрибутов края cytoscape см. здесь

Установить RCy3:

# Install RCy3 - Interface between R and Cytoscape (through cyRest app)
library('devtools')

remove.packages("BiocInstaller")
source("https://bioconductor.org/biocLite.R")
biocLite("BiocGenerics")
biocLite("bitops")
install_github("tmuetze/Bioconductor_RCy3_the_new_RCytoscape")