Googleway

Symbolix presentation at MelbRurn
7 June 2017

chaRades



Guess the book / song / film / quote

2 * b | !(2 * b)

chaRades



Guess the book / song / film / quote

# 2 * b | !(2 * b)
if(!broke){
    fix(FALSE)
}

Melbourne to Sydney

melb

Directions API



GoogleDirections

Polyline

MelbourneSydneyPolyline

googleway is born



get_route() ## now deprecated
decode_pl()
pl <- "jnxeFeaxsZ}u@ngDebEyDa}DjU}|@hkCdDlnBsu@zIy}BrV{dA_}C{VauKynBeZ{yBcn@ssDuSqyAt|@qrAvbEycDtcAeyC_Vg~Fsi@utAcuAqjC_e@mnF_oAeeEgfF{xD|Bg|CoCekCo~B_tA}|@seFyX{bEjKwvFqjBm|B`F}oDyaAewHy`AiiBwlAsnElWapDMexDajBuv@u_AiAckE}{CyqDe}@{yB}jFcyCkrAkuC_xEedHygGapXmrHmmQj]ehFarAa`CgqBqLkhCwmEktDujForCucCi_CknE_pEqxLmtBonJdVcuD}zBodFmXegDnb@ohD_v@mjDcxCysH_jCmjCydBkh@}mA}oGoeDy{Le_@s_GmyAi~Ac}FwbEy~BkgMuhAssCugEquAurBvx@u~Cyi@suSkhOswBm{BenA{_NqOegG{uAi|EkbEyhDc|B_gDihB{zKnOmfFltCo|GhJgvEpE}}Cyx@g|@okCkgBa|EwwG_bDutAcfH{uBcdFrK}m@_sAw@avDxCw}Bsf@aaEgSurDkaAkdFezDwwBy~E_nCwk@qdB_gBepBqlC}zA_fAeeCchEcqC_yEga@k}F_uMsj@cnHslJktLagCg|DuqE_l@_tHcvD_uAoWskCusDorEu~DeaEidDogBclAaqBfI}wCpgBitC_m@qhEg_LsbH{kHosCcvE_eE{cBu^g`GggBo`EaxBkaFyE_iGhH{dCykC}}DcxAmfFo~B}jDmnDci@w{A}wAimImf@}lAgdDggCweBuhB}kBgnDhd@knAskE}aB{dD}jAg~Fc|CivDixBqjByz@keDsCkeKj@wmF}yAy`Jnl@mwPjCcmGreAayC}f@krCa{DouCgy@qvDoZ}yIjIsnFxjFqnLtIkkFlsBm`D~k@qhIy\\meDkaAi}CdG{nDcwE}yN{RqvLrjEw}PbOusHcYegG_\\mqH}v@ikCnW_tDbP{aIa}@q{D{mAe_Ckc@uiEkR_mMyl@auBcrC{bA_pAm{D`OonElm@uvAuAgjHa@eqF{dBgiI_cEgmFemEqvHakAgwBoOkyCaeAkmCqk@k~FkfAwfEooAweBijC_eCksGckDqzF_cEaaD}bBah@oxBcqBwqEkxBc|OiyCq_GiaLsyHebIkhNgpG{uCukI{zIq}BuxBchCiNy{GubDgfDanAueCwuEqyAulAwxC}WuzDiwEyhD_}AmhBqxFjr@emIoi@{iJu@ifLa]mfHnfAq_Da`AkbEy^}lAar@rBc`Fac@s`ChYhQd["

df_line <- decode_pl(pl)
head(df_line)
        lat      lon
1 -37.81366 144.9629
2 -37.80487 144.9359
3 -37.77364 144.9369
4 -37.74323 144.9333
5 -37.73332 144.9108
6 -37.73415 144.8930

chaRades



shouldThrow <- switch(house, "glass" = FALSE, TRUE)

chaRades



# shouldThrow <- switch(house, "glass" = FALSE, TRUE)
tooLate <- function() return(FALSE)

All the APIs



google_directions()   ## get_route()

google_distance()

google_elevation()

google_timezone()

google_geocode()

google_reverse_geocode()

google_places()

google_place_details()

AllThings

google_directions( )



res <- google_directions(origin = "Melbourne, Australia",
                      destination = "Sydney, Australia",
                      key = apiKey)
str(res)

# List of 3
#  $ geocoded_waypoints:'data.frame':   2 obs. of  3 variables:
#   ..$ geocoder_status: chr [1:2] "OK" "OK"
#   ..$ place_id       : chr [1:2] "ChIJ90260rVG1moRkM2MIXVWBAQ" "ChIJP3Sa8ziYEmsRUKgyFmh9AQM"
#
# ...
#
#  $ overview_polyline:'data.frame':    1 obs. of  1 variable:
#   .. ..$ points: chr "jnxeFeaxsZ}u@ngDebEyDa}DjU}|@hkCdDlnBsu@zIy}BrV{dA_}C{VauKynBeZ{yBcn@ssDuSqyAt|@qrAvbEycDtcAeyC_Vg~Fsi@utAcuAqj"| __truncated__
#   ..$ summary          : chr "National Highway M31 and M31"
#  $ status            : chr "OK"

google_elevation( )

elevation <- google_elevation(df_line, key = apiKey)
library(ggplot2)

df_elevation <- elevation$results
ggplot(data = df_elevation, aes(x = row.names(df), y = elevation, group = 1)) +
  geom_line()

google_geocode( )



geocode <- google_geocode(address = "MCG, Melbourne", key = apiKey)
geocode$results$formatted_address

# [1] "Brunton Ave, Richmond VIC 3002, Australia"

geocode$results$geometry$location

#         lat      lng
# 1 -37.81997 144.9834

google_reverse_geocode( )



reverse <- google_reverse_geocode(location = c(-37.81997,144.9834), key = apiKey)
reverse$results$formatted_address

# [1] "120 Brunton Ave, East Melbourne VIC 3002, Australia"
# [2] "East Melbourne VIC 3002, Australia"
# [3] "Melbourne VIC, Australia"
# [4] "East Melbourne VIC 3002, Australia"
# [5] "Melbourne, VIC, Australia"
# [6] "CBD & South Melbourne, Melbourne VIC, Australia"
# [7] "Melbourne Metropolitan Area, VIC, Australia"
# [8] "Victoria, Australia"
# [9] "Australia"

google_places( )



place <- google_places(search_string = "Restaurants, Sydney",
                       key = apiKey)

place$results[1, c('formatted_address', 'name', 'place_id')]

#                         formatted_address                              name
# 1 107 Pitt St, Sydney NSW 2000, Australia Jamie's Italian Australia, Sydney
#                      place_id
# 1 ChIJ283hTECuEmsRHAc-pWx6cUs

google_places_details( )



details <- google_place_details(place_id = place$results[1, 'place_id'], key = apiKey)

details$result$opening_hours$periods
#   close.day close.time open.day open.time
# 1         0       2200        0      1200
# 2         1       2200        1      1130
# 3         2       2200        2      1130
...
lapply(details, names)

# $result
#  [1] "address_components"         "adr_address"                "formatted_address"
#  [4] "formatted_phone_number"     "geometry"                   "icon"
#  [7] "id"                         "international_phone_number" "name"
# [10] "opening_hours"              "photos"                     "place_id"
# [13] "rating"                     "reference"                  "reviews"
# [16] "scope"                      "types"                      "url"
# [19] "utc_offset"                 "vicinity"                   "website"

chaRades



plot(1:5, 1:5, type = "s"); text(5,5,"Heaven")

chaRades



plot(1:5, 1:5, type = "s"); text(5,5,"Heaven")

plot of chunk unnamed-chunk-24

chaRades



load("~/x")
rm(x)
load("~/x")
x
          [,1]      [,2]      [,3]      [,4]       [,5]      [,6]
[1,] 0.6105372 0.9298755 0.2367368 0.0313123 0.68165312 0.4662871
[2,] 0.5116770 0.9684903 0.1151035 0.2768140 0.20134670 0.6105372
[3,] 0.6328304 0.1683396 0.8505320 0.3834281 0.07474697 0.5116770

Plotting the line



library(leaflet)

## using decoded-polyline

leaflet() %>%
  addTiles() %>%
  addPolylines(data = df_line, lng = ~lon,lat = ~lat)

## But, do I have to decode it?

leafletLine

HTMLWidgets

htmlwidgets

Google Map



google_map(key = mapKey)

GoogleMap

Google Map - options



google_map(key = mapKey, search_box = TRUE, styles = map_styles()$silver)
names(googleway::map_styles())
[1] "standard"  "silver"    "retro"     "dark"      "night"     "aubergine"

GoogleMapOptions

Google Map - options



google_map(key = mapKey, zoom = 12, location = c(-37.818, 144.968)) %>%
  add_traffic()

GoogleMapOptions

Google Map - options



google_map(key = mapKey, zoom = 12, location = c(-37.818, 144.968)) %>%
  add_bicycling()

GoogleMapOptions

chaRades



paste0("batman ", paste0(names(googleway::map_styles()[4:5]), collapse = " "))

chaRades



paste0("batman ", paste0(names(googleway::map_styles()[4:5]), collapse = " "))
names(googleway::map_styles()[4:5])
[1] "dark"  "night"

chaRades



paste0("batman ", paste0(names(googleway::map_styles()[4:5]), collapse = " "))
names(googleway::map_styles()[4:5])
[1] "dark"  "night"
paste0("batman ", paste0(names(googleway::map_styles()[4:5]), collapse = " "))
[1] "batman dark night"

Plotting the line



pl <- "jnxeFeaxsZ}u@ngDebEyDa}DjU}|@hkCdDlnBsu@zIy}BrV{dA_}C{VauKynBeZ{yBcn@ssDuSqyAt|@qrAvbEycDtcAeyC_Vg~Fsi@utAcuAqjC_e@mnF_oAeeEgfF{xD|Bg|CoCekCo~B_tA}|@seFyX{bEjKwvFqjBm|B`F}oDyaAewHy`AiiBwlAsnElWapDMexDajBuv@u_AiAckE}{CyqDe}@{yB}jFcyCkrAkuC_xEedHygGapXmrHmmQj]ehFarAa`CgqBqLkhCwmEktDujForCucCi_CknE_pEqxLmtBonJdVcuD}zBodFmXegDnb@ohD_v@mjDcxCysH_jCmjCydBkh@}mA}oGoeDy{Le_@s_GmyAi~Ac}FwbEy~BkgMuhAssCugEquAurBvx@u~Cyi@suSkhOswBm{BenA{_NqOegG{uAi|EkbEyhDc|B_gDihB{zKnOmfFltCo|GhJgvEpE}}Cyx@g|@okCkgBa|EwwG_bDutAcfH{uBcdFrK}m@_sAw@avDxCw}Bsf@aaEgSurDkaAkdFezDwwBy~E_nCwk@qdB_gBepBqlC}zA_fAeeCchEcqC_yEga@k}F_uMsj@cnHslJktLagCg|DuqE_l@_tHcvD_uAoWskCusDorEu~DeaEidDogBclAaqBfI}wCpgBitC_m@qhEg_LsbH{kHosCcvE_eE{cBu^g`GggBo`EaxBkaFyE_iGhH{dCykC}}DcxAmfFo~B}jDmnDci@w{A}wAimImf@}lAgdDggCweBuhB}kBgnDhd@knAskE}aB{dD}jAg~Fc|CivDixBqjByz@keDsCkeKj@wmF}yAy`Jnl@mwPjCcmGreAayC}f@krCa{DouCgy@qvDoZ}yIjIsnFxjFqnLtIkkFlsBm`D~k@qhIy\\meDkaAi}CdG{nDcwE}yN{RqvLrjEw}PbOusHcYegG_\\mqH}v@ikCnW_tDbP{aIa}@q{D{mAe_Ckc@uiEkR_mMyl@auBcrC{bA_pAm{D`OonElm@uvAuAgjHa@eqF{dBgiI_cEgmFemEqvHakAgwBoOkyCaeAkmCqk@k~FkfAwfEooAweBijC_eCksGckDqzF_cEaaD}bBah@oxBcqBwqEkxBc|OiyCq_GiaLsyHebIkhNgpG{uCukI{zIq}BuxBchCiNy{GubDgfDanAueCwuEqyAulAwxC}WuzDiwEyhD_}AmhBqxFjr@emIoi@{iJu@ifLa]mfHnfAq_Da`AkbEy^}lAar@rBc`Fac@s`ChYhQd["

df_line <- decode_pl(pl)

google_map(key = mapKey) %>%
  add_polylines(data = df_line, lat = "lat", lon = "lon")
df_polyline <- data.frame(polyline = pl)

google_map(key = mapKey) %>%
  add_polylines(data = df_polyline, polyline = 'polyline')

GoogleMapOptions

Polyline options



Flight Routes

google_map(key = mapKey, style = style) %>%
  add_polylines(data = flights, polyline = "polyline", mouse_over_group = "airport1",
                stroke_weight = 0.8, stroke_opacity = 0.3, stroke_colour = "#ccffff")

Markers



## ?tram_stops
tram_stops$colour <-ifelse(tram_stops$stop_lat < -37.82, "green", "red")

google_map(data = tram_stops, key = mapKey) %>%
  add_markers(lat = "stop_lat", lon = "stop_lon", colour = "colour")

Markers

Markers



google_map(data = tram_stops, key = mapKey) %>%
  add_markers(lat = "stop_lat", lon = "stop_lon", cluster = T, info_window = "stop_name")

https://stackoverflow.com/a/39339464/5977215

MarkersCluster

Circles



tram_stops$radius <- runif(n = nrow(tram_stops), min = 50, max = 250)

google_map(data = tram_stops, key = mapKey) %>%
  add_circles(lat = "stop_lat", lon = "stop_lon", radius = "radius", colour =)

Circles

Heatmap



google_map(key = mapKey) %>%
  add_heatmap(data = dt_heat[route_type == 0],
              lat = "stop_lat", lon= "stop_lon", weight = "N",
              option_radius = 0.005)

Circles

Heatmap



google_map(key = mapKey, styles = map_styles()$night) %>%
  add_heatmap(data = dt_heat[route_type == 0],
              lat = "stop_lat", lon= "stop_lon", weight = "N",
              option_radius = 0.005,
              option_gradient = c("red", "orange","yellow","whitesmoke"))

Circles

Polygons



google_map(key = mapKey) %>%
  add_polygons(data = df_line, lat = "lat", lon = "lon")
## DEMO

PolygonSimple

chaRades



while (FALSE) print("Never")

chaRades



# while (FALSE) print("Never")



grey(seq(0, 1, length.out=50))

chaRades



# while (FALSE) print("Never")



# grey(seq(0, 1, length.out=50))



while (FALSE) giveUp(you)

Polygons - different IDs



pl_outer <- encode_pl(lat = c(25.774, 18.466,32.321),
      lon = c(-80.190, -66.118, -64.757))

pl_inner <- encode_pl(lat = c(28.745, 29.570, 27.339),
       lon = c(-70.579, -67.514, -66.668))

df <- data.frame(id = c(1, 2),
       polyline = c(pl_outer, pl_inner),
       stringsAsFactors = FALSE)

## note; different IDs
df
##   id                      polyline
## 1  1 o~h|CnbmhN~irk@am{tAw`qsAeyhG
## 2  2    ggmnDt}wmLgc`DesuQvvrLofdD


google_map(key = mapKey) %>%
  add_polygons(data = df, id = "id", polyline = "polyline")

PolygonSimple

Polygons - single ID



df <- data.frame(id = c(1, 1),
       polyline = c(pl_outer, pl_inner),
       stringsAsFactors = FALSE)

## note; same IDs
df
##   id                      polyline
## 1  1 o~h|CnbmhN~irk@am{tAw`qsAeyhG
## 2  1    ggmnDt}wmLgc`DesuQvvrLofdD


google_map(key = mapKey) %>%
  add_polygons(data = df, id = "id", polyline = "polyline")

PolygonSimple

Polygons - Multi-Polygon



pl_other <- encode_pl(lat = c(22, 23, 22),
                      lon = c(-50, -49, -51))

df <- rbind(df, data.frame(id = 1, polyline = pl_other))
df
##   id                      polyline
## 1  1 o~h|CnbmhN~irk@am{tAw`qsAeyhG
## 2  1    ggmnDt}wmLgc`DesuQvvrLofdD
## 3  1    _{geC~rdpH_ibE_ibE~hbE~reK


google_map(key = mapKey) %>%
  add_polygons(data = df, id = "id", polyline = "polyline", mouse_over_group = "id")

PolygonSimple

Polygons - Coordinates



##   myId lineId    lat     lon  colour
## 1    1      1 26.774 -80.190 #00FF0F
## 2    1      1 18.466 -66.118 #00FF0F
## 3    1      1 32.321 -64.757 #00FF0F
## 4    1      2 28.745 -70.579 #00FF0F
## 5    1      2 29.570 -67.514 #00FF0F
## 6    1      2 27.339 -66.668 #00FF0F
## 7    2      1 22.000 -50.000 #FF00FF
## 8    2      1 23.000 -49.000 #FF00FF
## 9    2      1 22.000 -51.000 #FF00FF


google_map(key = mapKey) %>%
  add_polygons(data = dfc, lat = 'lat', lon = 'lon', id = 'myId', pathId = 'lineId',
               fill_colour = 'colour', mouse_over_group = "myId")

PolygonSimple

Polygons - JSON



## [
##   {
##     "id": 1,
##     "polygon": ["o~h|CnbmhN~irk@am{tAw`qsAeyhG", "ggmnDt}wmLgc`DesuQvvrLofdD", "_{geC~rdpH_ibE_ibE~hbE~reK"]
##   }
## ]
##                                                                                                                polygon
## 1 ((25.774 -80.19,18.466 -66.118,32.321 -64.757),(28.745 -70.579,29.57 -67.514,27.339 -66.668),(22 -50,23 -49,22 -51))

Well-Known Text



WellKnownText

WellKnownText

Simple Features



library(sf)
nc.sf <- st_read(system.file("shape/nc.shp", package="sf"))

head(nc.sf[, 11:15])

## Simple feature collection with 6 features and 4 fields
## geometry type:  MULTIPOLYGON
## dimension:      XY
## bbox:           xmin: -81.74107 ymin: 36.07282 xmax: -75.77316 ymax: 36.58965
## epsg (SRID):    4267
## proj4string:    +proj=longlat +datum=NAD27 +no_defs
##   NWBIR74 BIR79 SID79 NWBIR79                       geometry
## 1      10  1364     0      19 MULTIPOLYGON(((-81.47275543...
## 2      10   542     3      12 MULTIPOLYGON(((-81.23989105...
## 3     208  3616     6     260 MULTIPOLYGON(((-80.45634460...
## 4     123   830     2     145 MULTIPOLYGON(((-76.00897216...
## 5    1066  1606     3    1197 MULTIPOLYGON(((-77.21766662...
## 6     954  1838     5    1237 MULTIPOLYGON(((-76.74506378...
plot(nc.sf[1])

sf

Simple Features vs Spatial

nc.sp <- as(nc.sf, "Spatial")
class(nc.sp)
# [1] "SpatialPolygonsDataFrame"


class(nc.sf)
# [1] "sf"    "data.frame"


sapply(mget(c("nc.sf", "nc.sp")), function(x) format(object.size(x), units = "Mb"))

##    nc.sf    nc.sp 
## "0.1 Mb" "0.4 Mb"

spatial.data.table



library(spatial.data.table)

nc.dt <- spToDT(nc.sf)

class(nc.dt)
# [1] "data.table" "data.frame"

nc.dt[, .(id, lineId, coords.V1, coords.V2)]
 #     id lineId coords.V1 coords.V2
 # 1:   1      1 -81.47276  36.23436
 # 2:   1      1 -81.54084  36.27251
 # 3:   1      1 -81.56198  36.27359
 # 4:   1      1 -81.63306  36.34069
 # 5:   1      1 -81.74107  36.39178

sapply(mget(c("nc.sf", "nc.sp", "nc.dt")), function(x) format(object.size(x), units = "Mb"))
#   nc.sf    nc.sp    nc.dt 
# "0.1 Mb" "0.4 Mb" "0.3 Mb"



nc.dtpl <- EncodeSF(nc.sf)

nc.dtpl[1:5, .(.id, polyline)]
#    .id                      polyline
# 1:   1       u_d|EtsgpNmmFphLyEbcCibL
# 2:   2             or}|EhdznNyvA~Ce_D
# 3:   3 }re|EbcajNakAf|BqKbyJo{Bxq@cJb
# 4:   4             mtt|E`o|nMkpBhs@~I
# 5:   4 ~b~Ev``oMJcqDfwAe}OnkLpoAgX|fI
sort(sapply(mget(c("nc.sf", "nc.sp", "nc.dt", "nc.dtpl")), function(x) object.size(x)))

# nc.dtpl   nc.sf   nc.dt   nc.sp 
#   24440  135168  339968  378192

spatial.data.table

library(leaflet)
library(microbenchmark)

## shp_sa2 : shape file of SA2 (statistical area 2) of Victoria, Australia
## dt_pl : data.table with encoded polylines of SA2 of Victoria, Australia

microbenchmark(
  leaf = {
    l <- leaflet() %>%
      addTiles() %>%
      addPolygons(data = shp_sa2)
  },

  goo = {
    g <- google_map(key = mapKey) %>%
        add_polygons(data = dt_pl, polyline = "polyline", id = ".id", pathId = "lineId")
  },
  times = 5
)

# Unit: milliseconds
#  expr       min        lq     mean    median       uq       max neval
#  leaf 1260.8853 1384.9013 1462.266 1394.7890 1489.402 1781.3544     5
#   goo  210.6741  218.5353  240.975  224.5488  228.355  322.7616     5

Distance calculations

Distance calculations



geosphere::distHaversine <- function (p1, p2, r = 6378137) {
    toRad <- pi/180
    p1 <- .pointsToMatrix(p1) * toRad
    p2 <- .pointsToMatrix(p2) * toRad
    p = cbind(p1[, 1], p1[, 2], p2[, 1], p2[, 2], as.vector(r))
    dLat <- p[, 4] - p[, 2]
    dLon <- p[, 3] - p[, 1]
    a <- sin(dLat/2) * sin(dLat/2) + cos(p[, 2]) * cos(p[, 4]) * 
        sin(dLon/2) * sin(dLon/2)
    dist <- 2 * atan2(sqrt(a), sqrt(1 - a)) * p[, 5]
    return(as.vector(dist))
}

dt[, haversine := distHaversine(
    matrix(c(LOC1_LONG_CORD, LOC1_LAT_CORD), ncol = 2), 
    matrix(c(LOC2_LONG_CORD, LOC2_LAT_CORD), ncol = 2)
    )]

rcppDistance

## usage:
dt1[, dist := dtHaversine(lat_orig, long_orig, lat_dest, long_dest)]

Distance calculations



dt1 <- copy(dt)
dt2 <- copy(dt)

microbenchmark(
    sdt = { dt1[, dist := dtHaversine(lat1, lon1, lat2, lon2)]  },
    geo = { dt2[, dist := distHaversine(matrix(c(lon1, lat1), ncol = 2),
                                   matrix(c(lon2, lat2), ncol = 2))]  }
)

# Unit: milliseconds
#  expr      min       lq     mean   median       uq
#   sdt 10.22558 11.13795 12.07124 11.65805 11.98368
#   geo 42.29223 93.21309 96.31312 95.75023 99.91635

Where does this go from here?

## Distance calculations
dtAlongTrackDistance
dtAntipode
dtBearing
dtCosine
dtDestination
dtDist2gc
dtHaversine
dtMidpoint
dtNearestPoints
## spatial operation
PointsInPolygon

chaRades - last round



while (TRUE) story()

theend

chaRades - last round



# while (TRUE) story()
wrong <- 0
right <- 1
wrong * 2 == right
[1] FALSE

theend

Info & Resources