2

I have a series of locations (Points_B) and would like to find the closest point to them from a different set of points (Points_A) and the distance between them in kms. I can do this as the crow flies but cannot work out how to do the same along a road network (the 'Roads' object in the code). The code I have so far is a follows:

library(sp)
library(rgdal)
library(rgeos)

download.file("https://dl.dropboxusercontent.com/u/27869346/Road_Shp.zip", "Road_Shp.zip")
#2.9mb 
unzip("Road_Shp.zip")
Roads <- readOGR(".", "Subset_Roads_WGS")

Points_A <- data.frame(ID = c("A","B","C","D","E","F","G","H","I","J","K","L"), ID_Lat  = c(50.91487, 50.92848, 50.94560, 50.94069, 50.92275, 50.94109, 50.92288, 50.92994, 50.92076, 50.90496, 50.89203, 50.88757), ID_Lon  = c(-1.405821, -1.423619, -1.383509, -1.396910, -1.441801, -1.459088, -1.466626, -1.369458, -1.340104, -1.360153, -1.344662, -1.355842))
rownames(Points_A) <- Points_A$ID

Points_B <- data.frame(Code = 1:30, Code_Lat  = c(50.92658, 50.92373, 50.93785, 50.92274, 50.91056, 50.88747, 50.90940, 50.91328, 50.91887, 50.92129, 50.91326, 50.91961, 50.91653, 50.90910, 50.91432, 50.93742, 50.91848, 50.93196, 50.94209, 50.92080, 50.92127, 50.92538, 50.88418, 50.91648, 50.91224, 50.92216, 50.90526, 50.91580, 50.91203, 50.91774), Code_Lon  = c(-1.417311, -1.457155, -1.400106, -1.374250, -1.335896, -1.362710, -1.360263, -1.430976, -1.461693, -1.417107, -1.426709, -1.439435, -1.429997, -1.413220, -1.415046, -1.440672, -1.392502, -1.459934, -1.432446, -1.357745, -1.374369, -1.458929, -1.365000, -1.426285, -1.403963, -1.344068, -1.340864, -1.399607, -1.407266, -1.386722))
rownames(Points_B) <- Points_B$Code

Points_A_SP <- SpatialPoints(Points_A[,2:3])
Points_B_SP <- SpatialPoints(Points_B[,2:3])
Distances <- (gDistance(Points_A_SP, Points_B_SP, byid=TRUE))*100

Points_B$Nearest_Points_A_CF <- colnames(Distances)[apply(Distances,1,which.min)]
Points_B$Distance_Points_A_CF <- apply(Distances,1,min)

The output I am after would be two additional columns in 'Points_B' with 1) having the nearest Point A object ID along the road network and 2) having the distance along the network in km. Any help would be appreciated. Thanks.

Chris
  • 1,197
  • 9
  • 28

2 Answers2

1

The packages igraph, osmr and walkalytics all seem to provide this functionality these days. Mode-specific routing networks exist (in various degrees of functionality).

Mox
  • 511
  • 5
  • 15
0

I've been working on this kind of problem all day. Try mapdist() in the ggmap package and see if this works:

library(dplyr)
library(ggmap)
#Your data
   Points_A <- data.frame(ID = c("A","B","C","D","E","F","G","H","I","J","K","L"), ID_Lat  = c(50.91487, 50.92848, 50.94560, 50.94069, 50.92275, 50.94109, 50.92288, 50.92994, 50.92076, 50.90496, 50.89203, 50.88757), ID_Lon  = c(-1.405821, -1.423619, -1.383509, -1.396910, -1.441801, -1.459088, -1.466626, -1.369458, -1.340104, -1.360153, -1.344662, -1.355842))
   Points_B <- data.frame(Code = 1:30, Code_Lat  = c(50.92658, 50.92373, 50.93785, 50.92274, 50.91056, 50.88747, 50.90940, 50.91328, 50.91887, 50.92129, 50.91326, 50.91961, 50.91653, 50.90910, 50.91432, 50.93742, 50.91848, 50.93196, 50.94209, 50.92080, 50.92127, 50.92538, 50.88418, 50.91648, 50.91224, 50.92216, 50.90526, 50.91580, 50.91203, 50.91774), Code_Lon  = c(-1.417311, -1.457155, -1.400106, -1.374250, -1.335896, -1.362710, -1.360263, -1.430976, -1.461693, -1.417107, -1.426709, -1.439435, -1.429997, -1.413220, -1.415046, -1.440672, -1.392502, -1.459934, -1.432446, -1.357745, -1.374369, -1.458929, -1.365000, -1.426285, -1.403963, -1.344068, -1.340864, -1.399607, -1.407266, -1.386722))

#Combine coords into one field (mapdist was doing something funny with the commas so I had to specify "%2C" here)
   Points_A$COORD <- paste(ID_Lat, ID_Lon, sep="%2C")
   Points_B$COORD <- paste(Code_Lat, Code_Lon, sep="%2C")

#use expand grid to generate all combos
   get_directions <- expand.grid(Start = Points_A$COORD,
                                 End = Points_B$COORD,
                                 stringsAsFactors = F,
                                 KEEP.OUT.ATTRS = F) %>%
                     left_join(select(Points_A, COORD, ID), by = c("Start" = "COORD")) %>%
                     left_join(select(Points_B, COORD, Code), by = c("End" = "COORD"))

#make a base dataframe
   route_df <- mapdist(from = get_directions$Start[1], 
                       to = get_directions$End[1], 
                       mode = "driving") %>% 
               mutate(Point_A = get_directions$ID[1],
                      Point_B = get_directions$Code[1])

#get the rest in a for-loop
  start <- Sys.time()
    for(i in 2:nrow(get_directions)){
      get_route <- mapdist(from = get_directions$Start[i], 
                           to = get_directions$End[i], 
                           mode = "driving") %>% 
                  mutate(Point_A = get_directions$ID[i],
                         Point_B = get_directions$Code[i])

      route_df <<- rbind(route_df, get_route) #add to your original file

      Sys.sleep(time = 1) #so google doesn't get mad at you for speed

      end <- Sys.time()

      print(paste(i, "of", nrow(get_directions), 
                  round(i/nrow(get_directions),4)*100, "%", sep=" "))
      print(end-start)
  }

#save if you want   
write.csv(route_df, "route_df.csv", row.names = F)    

#Route Evaluation
   closest_point <-route_df %>% 
                     group_by(Point_A) %>%
                     filter(km == min(km)) %>%
                     ungroup()

I'm still kind of new at this so there may be a better way to do the data wrangling. Hope this helps & good luck

yake84
  • 3,004
  • 2
  • 19
  • 35
  • Thank you for your answer, the end result is just what I am after. I was however trying to avoid Google and the 2,500 limit so I could potentially scale up the number of distances calculated at one time. – Chris Jun 24 '16 at 23:46
  • 1
    I would like to find something free and open source that isn't Google as well. These forums have some leads: http://gis.stackexchange.com/questions/6803/alternatives-to-network-analyst http://stackoverflow.com/questions/21961849/creating-road-network-datasets-in-r. Let us know what you come up with. – yake84 Jun 25 '16 at 11:26
  • @ yake84: great answer! do you think you can please take a look at this question if you have time https://stackoverflow.com/questions/76508074/how-to-use-tbl-graphs thank you so much! – stats_noob Jun 20 '23 at 03:20