Cela_101
Cela_101

Reputation: 31

ggraph network plot: specify node coordinates

Trying to plot a network with the ggraph package and specify the coordinates of each node. While I can implement this with the igraph package - I cannot do this with the ggraph package.

# reproducible example to generate a random graph
library(igraph)
g1 <- erdos.renyi.game(20, 1/2)
plot(g1)

# function to produce coordinates for each node in order of the node
# degree (number of links per node)
coord <- function(g){   
    n.nod <- length(V(g))
    mat.c <- matrix(0, nrow = n.nod, ncol = 2)
    deg <- degree(g)
    uniq.deg <- unique(deg)
    min.d <- min(deg); max.d<- max(deg)
    spa <- 10/(max.d - min.d) # how much to increment 0 to 10 space along y-axis

    divi.y.1 <- seq(from = min.d, to=max.d, by = 1)
    divi.y.2 <- seq(from = 0, to=10, by = spa)  # both have same length

    ind.x <- c(); ind.x[1] = 0
    for(x in 2:n.nod){
      ind.x[x] <- ind.x[x-1] + 0.1
      if(ind.x[x] >= 10){
        ind.x[x] = ind.x[x-1] - 0.1
      }  
    } 
 d1 <- data.frame(divi.y.1, divi.y.2)

 # plotting space of grid is (0,0), (0, 10), (10, 10), (10, 0)
 for(i in 1:n.nod){
    # y-axis in order
    inD <-  which(d1$divi.y.1 == deg[i])
    mat.c[i, 2] <- d1[inD,2]
 } 
 mat.c[, 1] <- ind.x
 return(data.frame(mat.c))
}

Here is the "old fashioned" way of plotting the igraph object:

# plot igraph object - the old fashion way
x11()
plot(g1, layout = coord(g1), rescale = T, frame=T,
 vertex.frame.color = "black", edge.color = "lightsteelblue",
 edge.width = 1, vertex.label.cex = 1,
 vertex.label.color = "black", 
 main = "Nodes in order of degree: top have more links, bottom fewer links")

Link to ggraph documentation is here. Please also see GitHub repository for ggraph for package installation instructions (need >R.3.3 version). Below is the ggraph plot that works (but I haven't specified the coordinates for each node):

library(ggraph)
V(g1)$NaMe <- seq(1:20)

x11()
   ggraph(g1, 'igraph', algorithm = 'kk') +  
   geom_edge_link(colour = "black", alpha = 0.8, show.legend = F) + 
   geom_node_label(aes(label = NaMe)) + ggtitle("ggraph plot: How to allocate coordinate for each node?") + 
   ggforce::theme_no_axes()

Here is my attempt to make the ggraph plot with specified coordinates for each node. Following similar examples and earlier attempts in ggraph() where coordinates of the nodes are passed onto the plot, I tried the following:

g <- make_ring(10) + make_full_graph(5)
coords <- layout_(g, as_star())
plot(g, layout = coords)
# try to replicate this example:
coords2 <- add_layout_(g1, coord(g1))

Also tried using this function. It is difficult because there is not an example in the documentation.

Lay <- layout_igraph_manual(g1, coord(g1))
Lay <- layout_igraph_igraph(g1, coord(g1))

x11()
ggraph(g1, 'igraph', algorithm = 'kk' ) + add_layout_(Lay) +
# layout_igraph_circlepack() + 
geom_edge_link(colour = "black", alpha = 0.8, show.legend = F) + 
geom_node_label(aes(label = NaMe)) + ggtitle("ggraph plot: Cannot allocate    coordinate for each node") + 
ggforce::theme_no_axes()

Upvotes: 2

Views: 2888

Answers (3)

MilesMcBain
MilesMcBain

Reputation: 1205

I don't believe it is the author's intention that you call layout_igraph_manual directly. If you name the layout as "manual" you can pass in the arguments you need to layout the vertices manually. This got me what you are after, if I understand it correctly:

coords <- coord(g1)
names(coords) <- c("x","y")
coords <- as.data.frame(coords)

ggraph(g1, layout = "manual", circular = FALSE, node.positions = coords)+
  geom_edge_link(colour = "black", alpha = 0.8, show.legend = F) + 
  geom_node_label(aes(label = NaMe)) + ggtitle("ggraph plot: How to allocate coordinate for each node?") + 
  ggforce::theme_no_axes()

According to the documentation it is important that your manual layout is a dataframe and contains the columns x and y. I have done this to the output of your coord() function. You probably just want to update it to return the data in that form.

Upvotes: 3

Cela_101
Cela_101

Reputation: 31

Thanks @ThomasP85 (wow! the developer for ggraph). In this instance I wanted to specify the coordinates for each of the nodes. I've tried layout_igraph_manual, layout_, add_layout_ and many others and did not seem to work.

What did work was this

co2<- data.frame(coord(g1))  # my mistake above, the output of coord() should be a matrix
colnames(co2)<- c("x", "y")
Lay<- createLayout(g1, layout = "nicely") # try any layout
Lay$x<- co2$x  # <== now overwrite their coordinates
Lay$y<- co2$y


x11()  # <==== this is ggraph version of the igraph plot above 
ggraph(graph=g1, data=Lay) + 
geom_edge_link(colour = "black", alpha = 0.5, show.legend = F) + 
geom_node_label(aes(label = NaMe)) + ggtitle("Nodes with higher degree at top, lower degree nodes at the bottom") + 
ggforce::theme_no_axes()

@ThomasP85 if you can provide a working example with the code above using layout_igraph_manual, it would be much appreciated.

Upvotes: 1

ThomasP85
ThomasP85

Reputation: 1712

You generally don't have to think about node coordinates when using ggraph - they are supplied automatically based on the chosen layout. If you want to calculate the layout yourself beforehand, just use the manual layout - check the documentation for layout_igraph_manual

Upvotes: 1

Related Questions