Drawing Journey Path Using Leaflet in R

Drawing journey path using leaflet in R

You can use my googleway package to both get the directions/routes, and plot it on a Google map

To use Google's API you need a valid key for each API you want to use. In this case you'll want a directions key, and for plotting the map you'll want a maps javascript key

(You can generate one key and enable it for both APIs if you wish)

To call the Directions API and plot it in R, you can do

library(googleway)

api_key <- "your_directions_api_key"
map_key <- "your_maps_api_key"

## set up a data.frame of locations
## can also use 'lat/lon' coordinates as the origin/destination
df_locations <- data.frame(
origin = c("Melbourne, Australia", "Sydney, Australia")
, destination = c("Sydney, Australia", "Brisbane, Australia")
, stringsAsFactors = F
)

## loop over each pair of locations, and extract the polyline from the result
lst_directions <- apply(df_locations, 1, function(x){
res <- google_directions(
key = api_key
, origin = x[['origin']]
, destination = x[['destination']]
)

df_result <- data.frame(
origin = x[['origin']]
, destination = x[['destination']]
, route = res$routes$overview_polyline$points
)
return(df_result)
})

## convert the results to a data.frame
df_directions <- do.call(rbind, lst_directions)

## plot the map
google_map(key = map_key ) %>%
add_polylines(data = df_directions, polyline = "route")

Sample Image


And similarly in a Shiny app

library(shiny)
library(shinydashboard)
library(googleway)

ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
textInput(inputId = "origin", label = "Origin"),
textInput(inputId = "destination", label = "Destination"),
actionButton(inputId = "getRoute", label = "Get Rotue"),
google_mapOutput("myMap")
)
)

server <- function(input, output){

api_key <- "your_directions_api_key"
map_key <- "your_maps_api_key"

df_route <- eventReactive(input$getRoute,{

print("getting route")

o <- input$origin
d <- input$destination

return(data.frame(origin = o, destination = d, stringsAsFactors = F))
})

output$myMap <- renderGoogle_map({

df <- df_route()
print(df)
if(df$origin == "" | df$destination == "")
return()

res <- google_directions(
key = api_key
, origin = df$origin
, destination = df$destination
)

df_route <- data.frame(route = res$routes$overview_polyline$points)

google_map(key = map_key ) %>%
add_polylines(data = df_route, polyline = "route")
})
}

shinyApp(ui, server)

Sample Image

Drawing driving routes in R

For what it's worth, I just ran your code without any issues. So as @Dave2e suspects they may be something wrong with your API calls, either timing-out or google not returning a result for some reason. So you'll have to keep debugging / printing the results to see if this is the case.

df_locations<-structure(list(origin = c("WARWICK", "EAST PROVIDENCE", "WARREN", 
"CENTERDALE", "CENTRAL FALLS", "DAVISVILLE", "NORTH PROVIDENCE",
"EAST PROVIDENCE", "PROVIDENCE", "CHEPACHET"), destination = c("CENTERDALE", "EAST PROVIDENCE", "BRISTOL", "JOHNSTON", "CRANSTON", "WARWICK","NORTH PROVIDENCE", "EAST PROVIDENCE", "WARREN", "CHEPACHET")), class = "data.frame", row.names = c(NA, -10L))

library(googleway)

set_key("MYKEY")

## loop over each pair of locations, and extract the polyline from the result
lst_directions <- apply(df_locations, 1, function(x){
res <- google_directions(
origin = x[['origin']]
, destination = x[['destination']]
)

df_result <- data.frame(
origin = x[['origin']]
, destination = x[['destination']]
, route = res$routes$overview_polyline$points
)
return(df_result)
})

df_directions <- do.call(rbind, lst_directions)

## plot the map
google_map() %>%
add_polylines(data = df_directions, polyline = "route")

Sample Image

Is it possible to use rMaps to draw a route on a map in R?

In Order to add a poligon (such as a circle) you should:

  1. Go to the location of the html page of the actual map (you should see the location in the browser) and open it, with right click, preferable with notepad ++
  2. look for :

    var map = L.map(spec.dom, {
    fullscreenControl: true
    }).setView(spec.center, spec.zoom);

    if (spec.provider){
    L.tileLayer.provider(spec.provider).addTo(map)
    } else {
    L.tileLayer(spec.urlTemplate, spec.layerOpts).addTo(map)
    }

and right after that you can add a nice circle with the following code, (dont forget to save the file):

L.circle([29.7601927,-95.3693896],7200,{color:'red'}).addTo(map).bindPopup('some thing').addTo(map)

for more info, just see the leaflet API in http://leafletjs.com/reference.html

btw, rmaps is just an interface for R and leaflet, if you want to create real crazy stuff, you should get used to open the html file and add java script code from the leaflet API, people created amazing plugins, much more that just adding polygons, for cool examples see:

http://leafletjs.com/plugins.html

i also really like this one:

http://threatwiki.thesentinelproject.org/iranvisualization

Just to add some additional info of how rMaps works(that's also true for rCharts)

  1. All that rMaps does, is to create the javascript code, the build of the map is done by your web browsr, which means that if you will go to the library that rmaps is installed and copy it to another computer without R, the html file will run perfectly, so that means you can create a rMap, and then add any other elements from the leaflet API that are not supported by rMaps, manually, in the html file, just as i explained (i showed how to do it for "circle").

  2. For shiny apps, you cant add thing manually, so you'll have to make sure that the elements from the API are supported in rmaps. in order to know which elements of the API are supported, first create a map:

    map <- Leaflet$new()

and then look in all of the elements of "map", and compare it to the leaflet API.
for instance the marker creation command that you can find in the API:

http://leafletjs.com/reference.html#marker (from the leaflet API), which is created by:

L.marker([51.5, -0.09]).bindPopup('Hi. I am a popup').addTo(map);

has an equivalent in rMaps:

map$marker(
c(51.5, -0.09),
bindPopup = 'Hi. I am a popup'
)

Just go step by step for each element in leaflet API you are interested in, if it doesn't exist, then you can ask ramnath in Github to add it https://github.com/ramnathv/rMaps/pulls ,
or create by your own a function that does that in the R code.

Calculate, decode and plot routes on map using leaflet and R

What you have to do:

  • Import the points
  • Calculate all routes between the points (I use OSRM)
  • Extract the route geometry from the routes (Appreciate the reference and have a look there for the speed updates!). Thanks to @SymbolixAU: You can also use googleway::decode_pl() or gepaf::decodePolyline()
  • Display everything on a map (I use leaflet)

My approach is not optimized for anything, but it should do the job...
(It is script in RStudio, therefore the print() statements after leaflet.)

library(leaflet)
library(stringr)
library(bitops)

df <- structure(list(
lat = c(-33.9409444, -33.9335713, -33.9333906, -33.9297826),
lng = c(18.5001774, 18.5033218, 18.518719, 18.5209372)),
.Names = c("lat", "lng"),
row.names = c(NA, 4L), class = "data.frame")
nn <- nrow(df)

# Functions
# =========
viaroute <- function(lat1, lng1, lat2, lng2) {
R.utils::evalWithTimeout({
repeat {
res <- try(
route <- rjson::fromJSON(
file = paste("http://router.project-osrm.org/route/v1/driving/",
lng1, ",", lat1, ";", lng2, ",", lat2,
"?overview=full", sep = "", NULL)))
if (class(res) != "try-error") {
if (!is.null(res)) {
break
}
}
}
}, timeout = 1, onTimeout = "warning")
return(res)
}

decode_geom <- function(encoded) {
scale <- 1e-5
len = str_length(encoded)
encoded <- strsplit(encoded, NULL)[[1]]
index = 1
N <- 100000
df.index <- 1
array = matrix(nrow = N, ncol = 2)
lat <- dlat <- lng <- dlnt <- b <- shift <- result <- 0

while (index <= len) {
# if (index == 80) browser()
shift <- result <- 0
repeat {
b = as.integer(charToRaw(encoded[index])) - 63
index <- index + 1
result = bitOr(result, bitShiftL(bitAnd(b, 0x1f), shift))
shift = shift + 5
if (b < 0x20) break
}
dlat = ifelse(bitAnd(result, 1),
-(result - (bitShiftR(result, 1))),
bitShiftR(result, 1))
lat = lat + dlat;

shift <- result <- b <- 0
repeat {
b = as.integer(charToRaw(encoded[index])) - 63
index <- index + 1
result = bitOr(result, bitShiftL(bitAnd(b, 0x1f), shift))
shift = shift + 5
if (b < 0x20) break
}
dlng = ifelse(bitAnd(result, 1),
-(result - (bitShiftR(result, 1))),
bitShiftR(result, 1))
lng = lng + dlng

array[df.index,] <- c(lat = lat * scale, lng = lng * scale)
df.index <- df.index + 1
}

geometry <- data.frame(array[1:df.index - 1,])
names(geometry) <- c("lat", "lng")
return(geometry)
}

map <- function() {
m <- leaflet() %>%
addTiles(group = "OSM") %>%
addProviderTiles("Stamen.TonerLite") %>%
addLayersControl(
baseGroups = c("OSM", "Stamen.TonerLite")
)
return(m)
}

map_route <- function(df, my_list) {
m <- map()
m <- addCircleMarkers(map = m,
lat = df$lat,
lng = df$lng,
color = "blue",
stroke = FALSE,
radius = 6,
fillOpacity = 0.8) %>%
addLayersControl(baseGroups = c("OSM", "Stamen.TonerLite")) %>%
{
for (i in 1:length(my_list)) {
. <- addPolylines(., lat = my_list[[i]]$lat, lng = my_list[[i]]$lng, color = "red", weight = 4)
}
return(.)
}
return(m)
}

# Main
# ======
m <- map()
m <- m %>% addCircleMarkers(lat = df$lat,
lng = df$lng,
color = "red",
stroke = FALSE,
radius = 10,
fillOpacity = 0.8)
print(m)

my_list <- list()
r <- 1
for (i in 1:(nn-1)) {
for (j in ((i+1):nn)) {
my_route <- viaroute(df$lat[i], df$lng[i],df$lat[j], df$lng[j])
geom <- decode_geom(my_route$routes[[1]]$geometry)
my_list[[r]] <- geom
r <- r + 1
}
}

print(map_route(df, my_list))

Result:

Points with routes

In the end, you have to put all that in your shiny server...

I hope that helps!

Adding Curved Flight path using R's Leaflet Package

following up on mrub, just pass the object you get from gcIntermediate to leaflet. something like this:

library(leaflet)
library(geosphere)
gcIntermediate(c(5,52), c(-120,37),
n=100,
addStartEnd=TRUE,
sp=TRUE) %>%
leaflet() %>%
addTiles() %>%
addPolylines()

Sample Image

How to draw a path between two nodes using Leaflet

It was my mistake, Polyline works properly. I had an array of latlng that were not in an order. Putting an ordered latlng points helped me plot the route correctly between source and destination.



Related Topics



Leave a reply



Submit