9

I am using the ggmap route function to calculate and visualize hundreds of routes using D.C. Capital Bikeshare data. I am successfully able to do this with one minor problem, the route path doesn't follow roads, particularly curved roads (see screenshot below). Is there a way to tweek my code to all for more detailed paths?

enter image description here

library(tidyverse)
library(ggmap)

# Example dataset
feb_14 <- read.csv('https://raw.githubusercontent.com/smitty1788/Personal-Website/master/dl/CaBi_Feb_2017.csv', stringsAsFactors = FALSE)

# Subset first 300 rows, keep start and end Lat/Long strings
start<-c(feb_14[1:300, 14])
dest<-c(feb_14[1:300, 15])

# df of individual routes
routes <- tibble(
  start,
  dest)

# Function to calculate route
calculationroute <- function(startingpoint, stoppoint) {
  route(from = startingpoint,
        to = stoppoint,
        mode = 'bicycling',
        structure = "route")}

# Calculate route path for all individual trips
calculatedroutes <- mapply(calculationroute,
                           startingpoint = routes$start,
                           stoppoint = routes$dest,
                           SIMPLIFY = FALSE)

# Unlist and merge in single dataframe
do.call(rbind.data.frame, lapply(names(calculatedroutes), function(x) {
  cbind.data.frame(route=x, calculatedroutes[[x]], stringsAsFactors=FALSE)
})) -> long_routes


# create map with routes
basicmap <- get_map(location = 'washingtondc',
                    zoom = 13,
                    maptype = "toner-background",
                    source = "google",
                    color = "bw") 
basicmap <- ggmap(basicmap)


basicmap + geom_path(data=long_routes, 
                     aes(x=lon, y=lat, group=route), color = "red",
                     size=1, alpha = .4, lineend = "round")
Howard Smith
  • 308
  • 2
  • 15
  • try with `output = "all"` inside `route(from = startingpoint, to = stoppoint, mode = 'bicycling', structure = "route", output = "all")` – SymbolixAU Jun 01 '17 at 21:31
  • That causes the do.call(rbind... to throw this error. Error in (function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE, : arguments imply differing number of rows: 1, 0 – Howard Smith Jun 02 '17 at 15:19
  • Mapzen's Valhalla is a web service that can provide routes from point to point, including GeoJSON of the route. https://mapzen.com/blog/valhalla-intro/ . The GeoJSONio package can apparently consume that. – Tony Laidig Jun 05 '17 at 14:28
  • 2
    This question is an exact duplicate of https://stackoverflow.com/questions/30270011/ggmap-route-finding-doesnt-stay-on-roads . The solution provided there will solve your problem. You must indeed use `output="all"`. However, you missed, that the resulting output has a completely different structure and you need to adapt the rest of your program. – AEF Jun 08 '17 at 12:06
  • I keep running into an error with the decodeLine function in that solution. I run into error "Error in while (vindex < vlen) { : argument is of length zero" – Howard Smith Jun 12 '17 at 12:40

1 Answers1

1

The answer was to place the decodeLine function into the do.call to create the long routes dataframe

decodeLine <- function(encoded){
  require(bitops)

  vlen <- nchar(encoded)
  vindex <- 0
  varray <- NULL
  vlat <- 0
  vlng <- 0

  while(vindex < vlen){
    vb <- NULL
    vshift <- 0
    vresult <- 0
    repeat{
      if(vindex + 1 <= vlen){
        vindex <- vindex + 1
        vb <- as.integer(charToRaw(substr(encoded, vindex, vindex))) - 63  
      }

      vresult <- bitOr(vresult, bitShiftL(bitAnd(vb, 31), vshift))
      vshift <- vshift + 5
      if(vb < 32) break
    }

    dlat <- ifelse(
      bitAnd(vresult, 1)
      , -(bitShiftR(vresult, 1)+1)
      , bitShiftR(vresult, 1)
    )
    vlat <- vlat + dlat

    vshift <- 0
    vresult <- 0
    repeat{
      if(vindex + 1 <= vlen) {
        vindex <- vindex+1
        vb <- as.integer(charToRaw(substr(encoded, vindex, vindex))) - 63        

      }

      vresult <- bitOr(vresult, bitShiftL(bitAnd(vb, 31), vshift))
      vshift <- vshift + 5
      if(vb < 32) break
    }

    dlng <- ifelse(
      bitAnd(vresult, 1)
      , -(bitShiftR(vresult, 1)+1)
      , bitShiftR(vresult, 1)
    )
    vlng <- vlng + dlng

    varray <- rbind(varray, c(vlat * 1e-5, vlng * 1e-5))
  }
  coords <- data.frame(varray)
  names(coords) <- c("lat", "lon")
  coords
}

calculatedroutes <- mapply(calculationroute,
                           startingpoint = routes$start,
                           stoppoint = routes$dest,
                           SIMPLIFY = FALSE)

do.call(rbind.data.frame, lapply(names(calculatedroutes), function(x) {
  cbind.data.frame(route = x, decodeLine(calculatedroutes[[x]]$routes[[1]]$overview_polyline$points), stringsAsFactors=FALSE)
})) -> long_routes
Howard Smith
  • 308
  • 2
  • 15