1

Currently have a data frame of 4 columns, "lon.x," "lat.x," "lon.y," "lat.y." with 581 rows. I would like to find the distance between each pair of coordinates.

I tried:

library(geosphere)
distm(c(coords$lon_x, coords$lat_x),c(coords$lon_y, coords$lat_y), fun = distHaversine())

But got this error

Error in .pointsToMatrix(x) : Wrong length for a vector, should be 2

Is there a different way to do this?

jay.sf
  • 60,139
  • 8
  • 53
  • 110
Angie
  • 183
  • 3
  • 13
  • according to the docs, `distm(cbind(coords$lon_x, coords$lat_x), cbind(coords$lon_y, coords$lat_y), fun = distHaversine())` may work – rawr Jul 17 '20 at 02:09
  • Attempted to do that and got this error unfortunately ```Error in .pointsToMatrix(x) : points should be vectors of length 2, matrices with 2 columns, or inheriting from a SpatialPoints* object``` – Angie Jul 17 '20 at 02:12
  • The error and the documentation say "Can be a vector of two numbers, a matrix of 2 columns (first one is longitude, second is latitude) or a SpatialPoints* object". Your `coords$lon_x` is (I assume, since you didn't provide data) a 581 length vector, so `c(coords$lon_x, coords$lat_x)` is not going to be one of the acceptable input types. You need to call `distm` once for each row instead of trying to call it once for the whole dataframe – Calum You Jul 17 '20 at 02:19
  • alternatively, you could use the `sf` package which provides `st_distance`, with the ability to call it just once for many point pairs – Calum You Jul 17 '20 at 02:20

1 Answers1

0

Using distm(cbind(coords$lon_x, coords$lat_x), cbind(coords$lon_y, coords$lat_y), distHaversine) or distm(coords[, c("lon_x", "lat_x")], coords[, c("lon_y", "lat_y")], distHaversine) works for me, or even more succinct using with:

library(geosphere)
res <- with(coords, distm(cbind(lon_x, lat_x), cbind(lon_y, lat_y), distHaversine))
res
#           [,1]     [,2]     [,3]     [,4]      [,5]
# [1,]  82926.65 102777.0 416520.9 317338.5 229201.72
# [2,] 227148.47 371663.8 472784.4 441059.9  51871.09
# [3,] 131700.50 212885.3 344615.2 270580.8 166672.80
# [4,] 170629.69 314137.0 566038.0 506409.5 114399.77
# [5,] 125941.89 208759.0 350108.9 275223.3 164881.02

You just want the diag, though.

diag(res)
# [1]  82926.65 371663.76 344615.24 506409.47 164881.02

Check:

with(coords, distm(cbind(lon_x, lat_x)[1,], cbind(lon_y, lat_y)[1,], distHaversine))
#          [,1]
# [1,] 82926.65
with(coords, distm(cbind(lon_x, lat_x)[2,], cbind(lon_y, lat_y)[2,], distHaversine))
#          [,1]
# [1,] 371663.8
with(coords, distm(cbind(lon_x, lat_x)[3,], cbind(lon_y, lat_y)[3,], distHaversine))
#          [,1]
# [1,] 344615.2

Toy data:

n <- 5
set.seed(42)
coords <- data.frame(id=seq(n), 
                     lon_x=rnorm(n, 47.364842), lat_x=rnorm(n, 8.573026),
                     lon_y=rnorm(n, 47.364842), lat_y=rnorm(n, 8.573026),
                     sth_else=rnorm(n))
jay.sf
  • 60,139
  • 8
  • 53
  • 110