-
Notifications
You must be signed in to change notification settings - Fork 231
/
README.Rmd
276 lines (214 loc) · 10.5 KB
/
README.Rmd
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
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
---
output:
md_document:
variant: markdown_github
---
<!-- README.md is generated from README.Rmd. Please edit that file -->
```{r setup, echo = FALSE}
knitr::opts_chunk$set(
collapse = TRUE, cache = FALSE,
comment = "# ",
fig.path = "tools/README-",
dpi = 300 # 60 on CRAN; 300 on github
)
```
<!-- badges: start -->
[![CRAN status](https://www.r-pkg.org/badges/version/ggmap)](https://cran.r-project.org/package=ggmap)
[![AppVeyor build status](https://ci.appveyor.com/api/projects/status/github/dkahle/ggmap?branch=master&svg=true)](https://ci.appveyor.com/project/dkahle/ggmap)
<!-- badges: end -->
<hr>
# ggmap
__ggmap__ is an R package that makes it easy to retrieve raster map tiles from
popular online mapping services like [Google
Maps](https://developers.google.com/maps/documentation/maps-static?hl=en),
[Stadia Maps](https://stadiamaps.com/), and
[OpenStreetMap](https://www.openstreetmap.org/), and plot them using the
[__ggplot2__](https://github.com/tidyverse/ggplot2) framework.
## Stadia Maps
Stadia Maps offers map tiles in several styles, including updated [tiles from
Stamen Design](https://stadiamaps.com/stamen/). An API key is required, but no
credit card is necessary to [sign up](https://client.stadiamaps.com/signup) and
there is a free tier for non-commercial use. Once you have your API key, invoke
the registration function: `register_stadiamaps("YOUR-API-KEY", write =
FALSE)`{.R}. Note that setting `write = TRUE`{.R} will update your `~/.Renviron`
file by replacing/adding the relevant line. If you use the former, know that
you'll need to re-do it every time you reset R.
Your API key is _private_ and unique to you, so be careful not to share it
online, for example in a GitHub issue or saving it in a shared R script file. If
you share it inadvertently, just go to client.stadiamaps.com, delete your API
key, and create a new one.
```{r maptypes, fig.height=4, fig.width=7}
library("ggmap")
us <- c(left = -125, bottom = 25.75, right = -67, top = 49)
get_stadiamap(us, zoom = 5, maptype = "alidade_smooth") |> ggmap()
```
Use `qmplot()`{.R} in the same way you'd use `qplot()`{.R}, but with a map
automatically added in the background:
```{r qmplot, fig.height=5, fig.width=5}
library("dplyr", warn.conflicts = FALSE)
library("forcats")
# define helper
`%notin%` <- function(lhs, rhs) !(lhs %in% rhs)
# reduce crime to violent crimes in downtown houston
violent_crimes <- crime |>
filter(
offense %notin% c("auto theft", "theft", "burglary"),
between(lon, -95.39681, -95.34188),
between(lat, 29.73631, 29.78400)
) |>
mutate(
offense = fct_drop(offense),
offense = fct_relevel(offense, c("robbery", "aggravated assault", "rape", "murder"))
)
# use qmplot to make a scatterplot on a map
qmplot(lon, lat, data = violent_crimes, maptype = "stamen_toner_lite", color = I("red"))
```
Often `qmplot()`{.R} is easiest because it automatically computes a nice
bounding box for you without having to pre-compute it for yourself, get a map,
and then use `ggmap(map)`{.R} in place of where you would ordinarily (in a
**ggplot2** formulation) use `ggplot()`{.R}. Nevertheless, doing it yourself is
more efficient. In that workflow you get the map first (and you can visualize it
with `ggmap()`{.R}):
```{r ggmap, fig.height=5, fig.width=5}
bbox <- make_bbox(lon, lat, data = violent_crimes)
map <- get_stadiamap( bbox = bbox, maptype = "stamen_toner_lite", zoom = 14 )
ggmap(map)
```
And then you layer on geoms/stats as you would with **ggplot2**. The only difference is that (1) you need to specify the `data` arguments in the layers and (2) the spatial aesthetics `x` and `y` are set to `lon` and `lat`, respectively. (If they're named something different in your dataset, just put `mapping = aes(x = longitude, y = latitude))`, for example.)
```{r ggmap-layers, fig.height=5, fig.width=5}
ggmap(map) +
geom_point(data = violent_crimes, color = "red")
```
With **ggmap** you're working with **ggplot2**, so you can add in other kinds of layers, use [**patchwork**](https://patchwork.data-imaginist.com), etc.
All the __ggplot2__ geom's are available. For example, you can make a contour
plot with `geom = "density2d"`{.R}:
```{r ggmap-patchwork, warning=FALSE, fig.height=4, fig.width=8}
library("patchwork")
library("ggdensity")
robberies <- violent_crimes |> filter(offense == "robbery")
points_map <- ggmap(map) + geom_point(data = robberies, color = "red")
# warnings disabled
hdr_map <- ggmap(map) +
geom_hdr(
aes(lon, lat, fill = after_stat(probs)), data = robberies,
alpha = .5
) +
geomtextpath::geom_labeldensity2d(
aes(lon, lat, level = after_stat(probs)),
data = robberies, stat = "hdr_lines", size = 3, boxcolour = NA
) +
scale_fill_brewer(palette = "YlOrRd") +
theme(legend.position = "none")
(points_map + hdr_map) &
theme(axis.title = element_blank(), axis.text = element_blank(), axis.ticks = element_blank())
```
Faceting works, too:
```{r faceting, fig.height=2.5, fig.width=8}
ggmap(map, darken = .3) +
geom_point(
aes(lon, lat), data = violent_crimes,
shape = 21, color = "gray25", fill = "yellow"
) +
facet_wrap(~ offense, nrow = 1) +
theme(axis.title = element_blank(), axis.text = element_blank(), axis.ticks = element_blank())
```
## Google Maps
[Google Maps](https://cloud.google.com/maps-platform/terms/) can be used just as
easily. However, since Google Maps use a center/zoom specification, their input
is a bit different:
```{r google_maps, fig.height=5, fig.width=5}
(map <- get_googlemap("waco texas", zoom = 12))
ggmap(map)
```
Moreover, you can get various different styles of Google Maps with __ggmap__
(just like Stadia Maps):
```{r google_styles, eval=FALSE}
get_googlemap("waco texas", zoom = 12, maptype = "satellite") |> ggmap()
get_googlemap("waco texas", zoom = 12, maptype = "hybrid") |> ggmap()
get_googlemap("waco texas", zoom = 12, maptype = "roadmap") |> ggmap()
```
Google's geocoding and reverse geocoding API's are available through `geocode()`{.R}
and `revgeocode()`{.R}, respectively:
```{r geocode}
geocode("1301 S University Parks Dr, Waco, TX 76798")
revgeocode(c(lon = -97.1161, lat = 31.55098))
```
_Note: `geocode()` uses Google's Geocoding API to geocode addresses. Please take care not to disclose sensitive information. [Rundle, Bader, and Moody (2022)](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC8972108/) have considered this issue and suggest various alternative options for such data._
There is also a `mutate_geocode()`{.R} that works similarly to
[__dplyr__](https://github.com/tidyverse/dplyr/)'s `mutate()`{.R} function:
```{r mutate_geocode}
tibble(address = c("white house", "", "waco texas")) |>
mutate_geocode(address)
```
Treks use Google's routing API to give you routes (`route()`{.R} and
`trek()`{.R} give slightly different results; the latter hugs roads):
```{r route_trek, fig.height=5, fig.width=5}
trek_df <- trek("houson, texas", "waco, texas", structure = "route")
qmap("college station, texas", zoom = 8) +
geom_path(
aes(x = lon, y = lat), colour = "blue",
size = 1.5, alpha = .5,
data = trek_df, lineend = "round"
)
```
(They also provide information on how long it takes to get from point A to point
B.)
Map distances, in both length and anticipated time, can be computed with
`mapdist()`{.R}). Moreover the function is vectorized:
```{r mapdist}
mapdist(c("houston, texas", "dallas"), "waco, texas")
```
## Google Maps API key
A few years ago Google has [changed its API
requirements](https://developers.google.com/maps/documentation/geocoding/usage-and-billing),
and __ggmap__ users are now required to register with Google. From a user's
perspective, there are essentially three ramifications of this:
1. Users must register with Google. You can do this at
https://mapsplatform.google.com. While it will require a valid credit card
(sorry!), there seems to be a fair bit of free use before you incur charges, and
even then the charges are modest for light use.
2. Users must enable the APIs they intend to use. What may appear to __ggmap__
users as one overarching "Google Maps" product, Google in fact has several
services that it provides as geo-related solutions. For example, the [Maps
Static
API](https://developers.google.com/maps/documentation/maps-static/overview)
provides map images, while the [Geocoding
API](https://developers.google.com/maps/documentation/geocoding/overview)
provides geocoding and reverse geocoding services. Apart from the relevant
Terms of Service, generally __ggmap__ users don't need to think about the
different services. For example, you just need to remember that
`get_googlemap()`{.R} gets maps, `geocode()`{.R} geocodes (with Google, DSK is
done), etc., and __ggmap__ handles the queries for you. _However_, you do need
to enable the APIs before you use them. You'll only need to do that once, and
then they'll be ready for you to use. Enabling the APIs just means clicking a
few radio buttons on the Google Maps Platform web interface listed above, so
it's easy.
3. Inside R, after loading the new version of __ggmap__, you'll need provide
__ggmap__ with your API key, a [hash
value](https://en.wikipedia.org/wiki/Hash_function) (think string of jibberish)
that authenticates you to Google's servers. This can be done on a temporary
basis with `register_google(key = "[your key]")`{.R} or permanently using
`register_google(key = "[your key]", write = TRUE)`{.R} (note: this will
overwrite your `~/.Renviron` file by replacing/adding the relevant line). If you
use the former, know that you'll need to re-do it every time you reset R.
Your API key is _private_ and unique to you, so be careful not to share it
online, for example in a GitHub issue or saving it in a shared R script file. If
you share it inadvertantly, just get on Google's website and regenerate your key
- this will retire the old one. Keeping your key private is made a bit easier by
__ggmap__ scrubbing the key out of queries by default, so when URLs are shown in
your console, they'll look something like `key=xxx`{.R}. (Read the details
section of the `register_google()`{.R} documentation for a bit more info on this
point.)
The new version of __ggmap__ is now on CRAN soon, but you can install the latest
version, including an important bug fix in `mapdist()`{.R}, here with:
```{r attn, eval=FALSE}
if(!requireNamespace("devtools")) install.packages("devtools")
devtools::install_github("dkahle/ggmap")
```
## Installation
* From CRAN: `install.packages("ggmap")`{.R}
* From Github:
```{r, eval=FALSE}
if (!requireNamespace("remotes")) install.packages("remotes")
remotes::install_github("dkahle/ggmap")
```