-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy path4-OfflineMaps-leaflets.Rmd
More file actions
226 lines (163 loc) · 7.68 KB
/
Copy path4-OfflineMaps-leaflets.Rmd
File metadata and controls
226 lines (163 loc) · 7.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
---
title: "Offline Maps with RgoogleMaps and leaflets"
author: "M Loecher"
output:
html_document:
toc: true
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, message=FALSE, warning=FALSE)
library(leaflet)
library(ggmap)
library(RgoogleMaps)
library(tidyverse)
```
## Fetching map tiles
Until version 1.3.0 *RgoogleMaps* only
downloaded static maps as provided by the static maps APIs from e.g. Google, bing and OSM. While there are numerous advantages to this strategy such as full access to the extensive feature list provided by those APIs, the limimtations are also clear:
1. unlikely reusability of previously stored static maps,
2. limits on the maximum size of the map (640,640),
3. and the requirement to be online.
Beginning with [version 1.4.1](https://r-forge.r-project.org/R/?group_id=2178)
, we added the functions *GetMapTiles* and *PlotOnMapTiles* which fetch individual map tiles and store them locally.
For example, if we wanted to fetch 20 tiles (in each direction) at zoom level 16 around Washington Square Park in Manhattan, we would simply run
```{r, eval = FALSE}
library(RgoogleMaps)
(center=getGeoCode("Washington Square Park;NY"))
GetMapTiles(center, zoom=16,nTiles = c(20,20))
```
Note that the default server is taken to be *openstreetmap* and the default local directory $tileDir= "~/mapTiles/OSM/"$.
We could have also passed the location string directly and saved several zoom levels at once (note the constant radius adaptation of the number of tiles):
```{r, eval = FALSE}
for (zoom in 13:15)
GetMapTiles("Washington Square Park;NY", zoom=zoom,nTiles = round(c(20,20)/(17-zoom)))
```
Before requesting new tiles, the function checks if that map tile exists already which avoids redundant downloads.
We can repeat the process with Google map tiles and plot them:
```{r, eval = FALSE}
for (zoom in 13:16)
GetMapTiles("Washington Square Park;NY", zoom=zoom,nTiles = round(c(20,20)/(17-zoom)),
urlBase = "http://mt1.google.com/vt/lyrs=m", tileDir= "~/mapTiles/Google/")
```
```{r, fig.width=8,fig.height=8}
#just get 3x3 tiles:
mt= GetMapTiles("Washington Square Park;NY", zoom=16,nTiles = c(3,3),
urlBase = "http://mt1.google.com/vt/lyrs=m", tileDir= "~/mapTiles/Google/", returnTiles = TRUE)
par(pty="s")
PlotOnMapTiles(mt)
```
## Leaflet
#### Interactive Web Maps with the JavaScript 'Leaflet' Library
As a reminder, the syntax for the leaflet is straightforward once the "pipe" operator %>% is understood. For example, centering a map at Aalborg university:
```{r, echo=TRUE,fig.width=8, fig.height=7}
m = leaflet::leaflet() %>% addTiles()
m = m %>% leaflet::setView(8.638431, 49.866438, zoom = 14)
m
```
While the original motivation of *GetMapTiles* was to enable offline creation of static maps within the package *RgoogleMaps*, combining this feature with the interactivity of the *leaflet* library leads to an effective offline maps version of leaflet!
## Tile Server
We only need to replace the default server specified by the parameter *urlTemplate* by a local server obliging with the file naming scheme zoom_X_Y.png set by *GetMapTiles*
Any simple local Web service will suffice, but a useful recommendation from http://stackoverflow.com/questions/5050851/best-lightweight-web-server-only-static-content-for-windows suggests:
> To use Python as a simple web server just change your working
> directory to the folder with your static content and type
> python -m SimpleHTTPServer 8000, everything in the directory
> will be available at http:/localhost:8000/
So assuming (i) successful execution of the map tileabove and (ii) the correct launch of the server (in the parent dirtectory of *mapTiles/*), the following code will have leaflet dynamically load them (from the local repository) for zooming and panning abilities:
```{r, eval=FALSE }
m = leaflet::leaflet() %>%
addTiles( urlTemplate = "http:/localhost:8000/mapTiles/OSM/{z}_{x}_{y}.png")
m = m %>% leaflet::setView(-73.99733, 40.73082 , zoom = 16)
m = m %>% leaflet::addMarkers(-73.99733, 40.73082 )
m
```
```{r, echo=FALSE }
m = leaflet::leaflet() %>% addTiles()
m = m %>% leaflet::setView(-73.99733, 40.73082 , zoom = 16)
m = m %>% leaflet::addMarkers(-73.99733, 40.73082 )
m
```
And for google map tiles:
```{r, eval=FALSE }
m = leaflet::leaflet() %>%
addTiles( urlTemplate = "http:/localhost:8000/mapTiles/Google/{z}_{x}_{y}.png")
m = m %>% leaflet::setView(-73.99733, 40.73082 , zoom = 16)
m = m %>% leaflet::addMarkers(-73.99733, 40.73082 )
m
```
```{r, echo=FALSE }
m = leaflet::leaflet() %>%
addTiles( urlTemplate = "http://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}")
m = m %>% leaflet::setView(-73.99733, 40.73082 , zoom = 16)
m = m %>% leaflet::addMarkers(-73.99733, 40.73082 )
m
```
## Synchronized Views
```{r}
library(sp)
demo(meuse, ask = FALSE, echo = FALSE) # loads the meuse data sets
library(mapview)
m1 <- mapview(meuse, zcol = "soil", burst = TRUE, legend = TRUE)
m2 <- mapview(meuse, zcol = "lead", legend = TRUE)
m3 <- mapview(meuse, zcol = "landuse", map.types = "Esri.WorldImagery", legend = TRUE)
m4 <- mapview(meuse, zcol = "dist.m", legend = TRUE)
sync(m1, m2, m3, m4) # 4 panels synchronised
```
## Routing
```{r, echo=FALSE}
library(tidyverse)
source('decodeUtils.R')
```
```{r}
p=vector()
p[1] = "Frankfurt train station, Germany"
p[2]= "Frankfurt airport, Germany"
p[3]= "Schoefferstr. 3, 64295 Darmstadt, Germany"
```
```{r, echo=FALSE}
getGeoCode("HWR Berlin, Germany")
# lat lon
#52.48544 13.33785
getGeoCode("Frankfurt, Germany")
# lat lon
# 50.110922 8.682127
getGeoCode("Schoefferstr. 3, 64295 Darmstadt, Germany")
# lat lon
# 49.866438 8.638431
#this function creates a tibble with starting to destinations relationships one per row from your original route p. So this is a wrapper from your original loop, but returns a dataframe instead of a list
connections.from.array <- function(p){
routes <- tibble(start=p,dest=c(p[-1],NA))[1:nrow(cbind(p,c(p[-1],NA)))-1,]
return(routes)
}
routes <- connections.from.array(p) #tibble with a connection per row.
#this function applies route() to start/destinations, output="all" is the most important change
calculationroute <- function(startingpoint, stoppoint) {
route(from = startingpoint,
to = stoppoint,
structure = "route", output="all")}
#mapply the new "route"-replacer function to all the connections in the tibble
calculatedroutes <- mapply(calculationroute,
startingpoint = routes$start,
stoppoint = routes$dest,
SIMPLIFY = FALSE)
# in order to keep the markers on the map working, we still need the list of connections,
#since the structure of the route changes when using output="all", the original code isn`t working anymore
route_df = list()
for (i in 1:(length(p)-1)) {
route_df[[i]] <- route(p[i], p[i+1], structure = "route")
}
myRoute = 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)
}))
```
```{r}
head(myRoute)
```
```{r, fig.width=8, fig.height = 8}
m = leaflet::leaflet() %>% addTiles()
m = m %>% leaflet::setView(myRoute[1,"lon"], myRoute[1,"lat"], zoom = 13)
for (i in 1:(length(p)-1)) {
m = m %>% leaflet::addMarkers(route_df[[i]][1,"lon"], route_df[[i]][1,"lat"])
}
m = m %>% addPolylines(myRoute[,"lon"], myRoute[,"lat"], col="red")
m
```