aterhorst
aterhorst

Reputation: 685

Calculating geographic distance of edge in iGraph

I have geographic coordinates for every vertex in an iGraph object. Now I want to calculate distance between existing edges.

library(igraph)
library(ggmap)
library(geosphere)

g <- graph.ring(6)
V(grph)$postcode <- c("Johannesburg 2017", 
                  "Rondebosch 8000",
                  "Durban 4001", 
                  "Pietermaritzburg 3201", 
                  "Jeffreys Bay 6330", 
                  "Pretoria 0001" )

postcode_df <- geocode(V(g)$postcode, sensor = FALSE, 
                       output = "latlon", source = "google")

V(g)$coordinate <- split(postcode_df, 1:nrow(postcode_df))

V(g)$coordinate[1]
[[1]]
       lon       lat
1 28.03837 -26.18825

I want to compute the distance using this general approach:

el <- get.edgelist(g, names=FALSE)
E(g)$distance <- distHaversine(V(g)$coordinate[[el[,1]]],V(g)$coordinate[[el[,2]]])

The problem is that the lon and lat in V(g)$coordinate cannot be referenced this way. I get a recursive indexing failed at level 3. Obviously I cannot nest index of one data frame within another.

str(V(g)$coordinate)
List of 6
 $ :'data.frame':   1 obs. of  2 variables:
  ..$ lon: num 28
  ..$ lat: num -26.2
 $ :'data.frame':   1 obs. of  2 variables:
  ..$ lon: num 28.3
  ..$ lat: num -25.8
 $ :'data.frame':   1 obs. of  2 variables:
  ..$ lon: num 31
  ..$ lat: num -29.8
 $ :'data.frame':   1 obs. of  2 variables:
  ..$ lon: num 30.4
  ..$ lat: num -29.7
 $ :'data.frame':   1 obs. of  2 variables:
  ..$ lon: num 24.9
  ..$ lat: num -34.1
 $ :'data.frame':   1 obs. of  2 variables:
  ..$ lon: num 28.2
  ..$ lat: num -25.7

The general way to compute distance between two points is

distHaversine(p1, p2, r=6378137).

p1 is defined by el[,1] and p2 by el[,2]. el[,1:2] refers to vertex number in g. So I need to extract V(g)$coordinate corresponding to el[,1] and el[,2]. Advice would be appreciated.

Upvotes: 1

Views: 483

Answers (1)

alexwhan
alexwhan

Reputation: 16026

There's a problem here in that the split is returning a dataframe, which we can fix by:

V(g)$coordinate <- lapply(split(postcode_df, 1:nrow(postcode_df)), unlist)

Then you're essentially needing to iterate over two lists, the coordinates of each vertex.

This is easy with map2 from purrr.

library(purrr)
el <- get.edgelist(g, names=FALSE)
E(g)$distance <- unlist(map2(V(g)$coordinate[el[,1]], V(g)$coordinate[el[,2]], distHaversine))

Upvotes: 1

Related Questions