Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problems using lat/long data for a layout in ggraph

Tags:

r

igraph

ggraph

I am trying to figure how to use a lat/long layout in ggraph but can't seem to work my way through the syntax. Consider this reprex with some data modified from the iris dataset:

data <- structure(list(Sepal.Length = c(5.1, 4.9, 4.7, 4.6, 5, 5.4, 4.6, 
5, 4.4, 4.9, 5.4, 4.8), Sepal.Width = c(3.5, 3, 3.2, 3.1, 3.6, 
3.9, 3.4, 3.4, 2.9, 3.1, 3.7, 3.4), Lon = c(-122.683, -122.688, 
-122.686, -122.683, -122.678, -122.675, -122.674, -122.673, -122.676, 
-122.674, -122.677, -122.68), Lat = c(45.523, 45.52, 45.514, 
45.515, 45.513, 45.514, 45.517, 45.519, 45.519, 45.522, 45.524, 
45.521)), class = "data.frame", .Names = c("Sepal.Length", "Sepal.Width", 
"Lon", "Lat"), row.names = c(NA, -12L))

library(ggplot2)
library(igraph)
library(ggraph)

A simple plot of the positions of the coordinates looks like this:

ggplot(data, aes(x = Lon, y = Lat)) +
  geom_point(size = 6)

enter image description here

layout accepts a matrix so I'll extract here the coordinates and turn it into a matrix:

spatial_layout <- layout.norm(as.matrix(data[,c(3,4)]))

and then turn data into a igraph object:

igraph_data <- graph_from_data_frame(data)

If I plot with the basic plot.igraph the layout is as expected; the spatial coordinates of each point:

plot.igraph(igraph_data, layout = spatial_layout)

enter image description here

Now here is where I run into problems. I would rather use ggraph to take advantage of the power of ggplot2. However I am not sure how to get it to accept a spatial layout. This doesn't work:

ggraph(igraph_data, spatial_layout) +
  geom_edge_link() +
  geom_node_point(color = "black", size = 9, pch = 1) +
  geom_node_text(aes(label = name))

Error in create_layout.igraph(graph, layout, ...) : Unknown layout

Nor does trying to create a custom layout:

create_layout(data, layout = "spatial_layout")

Error in create_layout.default(data, layout = "spatial_layout") :
No layout function defined for objects of class data.frame

Manually adding the lat/long data to the igraph object doesn't seem to do the trick either:

igraph_data$layout=cbind(E(igraph_data)$Lon,E(igraph_data)$Lat)
ggraph(igraph_data) +
  geom_edge_link() +
  geom_node_point(color = "black", size = 9, pch = 1) +
  geom_node_text(aes(label = name))

Using nicely as default layout Error in data.frame(..., check.names = FALSE) : arguments imply differing number of rows: 12, 17

So ultimately my question is how do I add spatial data to a ggraph layout? Obviously I am missing something here but I can't seem to figure out the right approach.

like image 341
boshek Avatar asked Oct 16 '17 23:10

boshek


1 Answers

We can make the equivalent manual layout with ggraph::create_layout. But first, we need to make the number of spatial coordinates match the number of vertexes in the graph we are passing. Looks like plot.igraph was recycling your original layout silently.

# must have columns named x and y
data2 <-  data.frame(x = rep(spatial_layout[,1], length.out = 17),
                     y = rep(spatial_layout[,2], length.out = 17))

Then use the help page for ?layout_igraph_manual as a guide for subsequent argument names.

manual_layout <- create_layout(graph = igraph_data,
              layout = "manual", node.positions = data2)

Note: I raise the warning Error: 'layout_igraph_manual' is not an exported object from 'namespace:ggraph' when I call the function directly.

Then we can plug it into the original:

ggraph(manual_layout) + 
    geom_edge_link() +
    geom_node_point(color = "black", size = 9, pch = 1) +
    geom_node_text(aes(label = name))

enter image description here

The axis limits are not the same by default, but that's a small + xlim(-2.5,2.5)#ish tweak.

like image 95
Nate Avatar answered Oct 04 '22 22:10

Nate