2017-01-19 70 views
14

mam nadzieję dokonać w reżyserii wykres sieciowy ze strzałek (lub podobny) szewrony wzdłuż długości linii ...styl linii na wykresie klienta sieciowego w R

enter image description here

Biblioteka igraph wydaje użyj funkcji bazy polygon, która akceptuje lty, aby określić typy linii, ale są one ograniczone do różnych kresek.

Czy istnieje sposób na wykonanie spersonalizowanych symboli (lub nawet użycie trójkątów w pch) w celu utworzenia linii w R?

Minimal kod do wykresu:

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

BTW, byłbym grzywny za pomocą innej biblioteki analizy sieci, jeśli byłoby to wspierać. Zapytałem programistę ggraph i powiedział, że nie można tego zrobić.

+0

w podobnym duchu do eipi miło odpowiedź, można użyć Rgraphviz zapisać wykres, który umożliwia łatwe wydobycie pozycje krzywej węzła i beziera, zamień na ggplot (patrz [tutaj] (http://stackoverflow.com/questions/40668022/plott-a-dag-in-a-dot-layout-using-ggnet/41204088#41204088)) a następnie dodaj strzałki, jak w odpowiedzi eipi. – user20650

Odpowiedz

7

Aby to zrobić, używając igraph, myślę, że musisz przekopać się w funkcję plot.igraph, dowiedzieć się, gdzie generuje ona krzywe Beziera dla zakrzywionych krawędzi między wierzchołkami, a następnie użyć interpolacji, aby uzyskać punkty wzdłuż tych krawędzi. Dzięki tej informacji możesz rysować segmenty strzałek wzdłuż krawędzi wykresu.

Oto inne podejście, które nie jest dokładnie tym, o co prosiłeś, ale mam nadzieję, że spełni twoje oczekiwania. Zamiast igraph, zamierzam użyć ggplot2 wraz z funkcją ggnet2 z pakietu GGally.

Podstawowym podejściem jest uzyskanie współrzędnych punktów końcowych każdej krawędzi wykresu, a następnie interpolacja punktów wzdłuż każdej krawędzi, na której narysujemy segmenty strzałek. Zwróć uwagę, że krawędzie są liniami prostymi, ponieważ ggnet2 nie obsługuje zakrzywionych krawędzi.

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) 

Oto co na wykresie wygląda następująco:

enter image description here

Teraz chcemy dodać strzały wzdłuż każdej krawędzi. Aby to zrobić, musimy najpierw ustalić współrzędne punktów końcowych każdej krawędzi. Możemy dostać to od samego obiektu wykresu za pomocą ggplot_build:

gg = ggplot_build(p) 

Dane wykres jest przechowywane w 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 

W wyjściu powyżej, widzimy, że pierwsze cztery kolumny gg$data[[1]] zawierają współrzędne punktów końcowych każdej krawędzi (i są one we właściwej kolejności dla skierowanego wykresu).

Teraz, gdy mamy punkty końcowe dla każdej krawędzi, możemy interpolować punkty między dwoma punktami końcowymi, w których narysujemy odcinki linii ze strzałkami na końcu. Poniższa funkcja się tym zajmuje. Pobiera ramkę danych punktów końcowych dla każdej krawędzi i zwraca listę połączeń do geom_segment (po jednym dla każdej krawędzi wykresu), która rysuje segmenty strzałek n.Listę połączeń geom_segment można następnie dodać bezpośrednio do naszego oryginalnego wykresu sieciowego.

# 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")) 
    }) 
} 

Teraz uruchomić funkcję, aby dodać głowice strzałek do oryginalnego grafu sieci

p = p + add.arrows(gg$data[[1]], 15) 

A oto co na wykresie wygląda następująco:

enter image description here

9

Cytoscape i RCy3 bibliotek są używane do tworzenia diagramów sieci.

Zainstalować cytoscape w wersji 3 i powyżej from here. Następnie uruchom sesję graficznego interfejsu użytkownika (grafical user interface).

Wersje stosowane w tej odpowiedzi są cytoscape:3.4.0 i RCy3:1.5.2

OS: 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" 

enter image description here

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

enter image description here

# 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) 

Aby uzyskać więcej informacji, przeczytaj ?RCy3::setEdgeLineStyleDirect.

również dla atrybutów krawędziowych cytoscape patrz here

Install 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") 
+0

Bardzo twórczy, chociaż nie jestem pewien, czy użyłbym Cytoscape do tego celu. – beroe