Problems using lat/long data for a layout in ggraph
Asked Answered
S

1

6

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.

Scald answered 16/10, 2017 at 23:35 Comment(0)
R
5

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.

Rockery answered 17/10, 2017 at 0:41 Comment(4)
Thank you! Can you see anyway that you can apply a projection to this? I turned it into an sf object but ggraph wouldn't plot it.Scald
not off the top of my head, it might be easier to just build polygons or lines via a spatial plotting package instead of ggraphRockery
Yep this is sort of the approach I took. Process the node coordinates before the layout step using the same projection as the polygon then plot the polygon using geom_polygon. Worked well.Scald
this approach can be used to convert any non-ggraph layout to a ggraph layout, so very useful (I used it to get the layout_as_star(), which gives more control over the star-layout than the one in ggraph, into gggraph.)Preferable

© 2022 - 2024 — McMap. All rights reserved.