-
Notifications
You must be signed in to change notification settings - Fork 5
/
Geomed19_I.Rmd
684 lines (474 loc) · 26.1 KB
/
Geomed19_I.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
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
---
title: "R and GIS, or R as GIS: handling spatial data: Representation and visualisation of spatial data"
author: "Roger Bivand"
date: "Tuesday, 27 August 2019, 09:00-10:40; Wolfson Medical School building Gannochy room"
output:
html_document:
toc: true
toc_float:
collapsed: false
smooth_scroll: false
toc_depth: 2
theme: united
bibliography: Geomed19.bib
link-citations: yes
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = FALSE)
```
### Copyright
All the material presented here, to the extent it is original, is available under [CC-BY-SA](https://creativecommons.org/licenses/by-sa/4.0/). Parts build on joint tutorials with Edzer Pebesma.
### Required current contributed CRAN packages:
I am running R 3.6.1, with recent `update.packages()`.
```{r, echo=TRUE}
needed <- c("sf", "mapview", "sp", "spdep", "elevatr", "raster", "stars", "classInt",
"RColorBrewer", "tmap", "tmaptools", "cartography", "ggplot2", "colorspace")
```
### Script
Script and data at https://github.com/rsbivand/geomed19-workshop/raw/master/Geomed19_I.zip. Download to suitable location, unzip and use as basis.
## Session I
- 09:00-09:30 (20+10) Vector representation: **sf** replaces **sp**, **rgeos** and **rgdal**: vector
- 09:30-10:00 (20+10) Raster representation: **stars**/**sf** replace **sp** and **rgdal**: **raster** remains for now
- 10:00-10:40 (20+20) Visualization: **tmap**, **cartography**, **ggplot2** and **mapview**
## Outline
- Spatial and spatio-temporal data are characterised by structures that distinguish them from typical tabular data
- The geometric structures also have spatial reference system information, and can adhere to standards, which may ease geometrical operations
- Satellite data and numerical model output data typically have regular grid structures, but these are often domain-specific
- Computationally intensive tasks include interpolation, upsampling, focal operations, change of support and handling vector data with very detailed boundaries, as well as modelling using Bayesian inference
## A short history of handling spatial data in R
- pre-2003: several people doing spatial statistics or map manipulation with S-Plus (1996 SpatialStats module), and later R (e.g. spatial in MASS; spatstat, maptools, geoR, splancs, gstat, ...)
- 2003: workshop at [DSC](https://www.r-project.org/conferences/DSC-2003/), concensus that a package with base classes should be useful; this ended up being a multiplicator
- 2003: start of [r-sig-geo](https://stat.ethz.ch/mailman/listinfo/r-sig-geo)
- 2003: [rgdal](https://cran.r-project.org/package=rgdal) released on CRAN (with GDAL and PROJ support)
- 2005: [sp](https://cran.r-project.org/package=sp) released on CRAN; **sp** support in **rgdal**
- 2008: [Applied Spatial Data Analysis with R](https://www.asdar-book.org/)
- 2011: [rgeos](https://cran.r-project.org/package=rgeos) released on CRAN (with GEOS support for **sp** class objects)
- 2013: second edition of [Applied Spatial Data Analysis with R](https://www.asdar-book.org/) [@asdar]
- 2015 [JSS special issue](https://www.jstatsoft.org/index.php/jss/issue/view/v063)
- 2016-7: **sf** [simple features for R](https://cran.r-project.org/package=sf), R consortium support (combines GDAL, GEOS and PROJ support and S3 classes)
- 2017-9: **stars** [spatiotemporal tidy arrays for R](https://cran.r-project.org/package=stars), R consortium support (considered pretty much "finished"; uses **sf** to interface GDAL)
- 2019 [Geocomputation with R](https://geocompr.robinlovelace.net/) [@geocompr]
- 2020 [Spatial Data Science; uses cases in R](https://r-spatial.org/book) [@sdsr]
## Spatial data
Spatial data typically combine position data in 2D (or 3D), attribute data and metadata related to the position data. Much spatial data could be called map data or GIS data. We collect and handle much more position data since global navigation satellite system (GNSS) like GPS came on stream 20 years ago, earth observation satellites have been providing data for longer.
Lapa et al. [-@LAPA2001] (Leprosy surveillance in Olinda, Brazil, using spatial analysis techniques) made available the underlying data set of Olinda census tracts (setor) in the Corrego Alegre 1970-72 / UTM zone 25S projection (EPSG:22525). Marilia Sá Carvalho and I wrote a [tutorial](https://rsbivand.github.io/geomed19-workshop/olinda.pdf) in 2003/4 based on this data set; there is more information in the tutorial.
```{r, echo = TRUE}
library(sf)
```
```{r, echo = TRUE, cache=TRUE}
olinda <- st_read("data/olinda.gpkg")
st_crs(olinda) <- 22525
```
```{r, echo = TRUE}
library(mapview)
mapview(olinda)
```
## Vector data
Spatial vector data is based on points, from which other geometries are constructed. Vector data is often also termed object-based spatial data. The light rail tracks are 2D vector data. The points themselves are stored as double precision floating point numbers, typically without recorded measures of accuracy (GNSS provides a measure of accuracy). Here, lines are constructed from points.
```{r, echo = TRUE}
all(st_is(olinda, "XY"))
str(st_coordinates(st_geometry(olinda)[[1]]))
```
### Representing spatial vector data in R (**sp**)
The **sp** package was a child of its time, using S4 formal classes, and the best compromise we then had of positional representation (not arc-node, but hard to handle holes in polygons). If we coerse `byb` to the **sp** representation, we see the formal class structure. Input/output used OGR/GDAL vector drivers in the **rgdal** package, and topological operations used GEOS in the **rgeos** package.
```{r, echo = TRUE, mysize=TRUE, size='\\tiny'}
library(sp)
str(slot(as(st_geometry(olinda), "Spatial"), "polygons")[[1]])
```
### Representing spatial vector data in R (**sf**)
The recent **sf** package bundles GDAL and GEOS (**sp** just defined the classes and methods, leaving I/O and computational geometry to other packages). **sf** used `data.frame` objects with one (or more) geometry column for vector data. The representation follows ISO 19125 (*Simple Features*), and has WKT (text) and WKB (binary) representations (used by GDAL and GEOS internally). The drivers include PostGIS and other database constructions permitting selection, and WFS for server APIs (**rgdal** does too, but requires more from the user).
```{r, echo = TRUE, mysize=TRUE, size='\\tiny'}
strwrap(st_as_text(st_geometry(olinda)[[1]]))
```
### Simple feature access in R: package `sf`
- Simple feature access is an [ISO standard](http://www.opengeospatial.org/standards/sfa) that is widely adopted. It is used in spatial databases, GIS, open source libraries, GeoJSON, GeoSPARQL, etc.
**sf** uses the OSGEO stack of software:
```{r, echo=TRUE}
sf_extSoftVersion()
```
Internal (R) and system dependencies look like this:
```{r echo=FALSE}
knitr::include_graphics('sf_deps.png')
```
Package **sf** provides handling of feature data, where feature
geometries are points, lines, polygons or combinations of those.
It implements the full set of geometric functions described in the
_simple feature access_ standard, and some. The basic storage is
very simple, and uses only base R types (list, matrix).
* feature sets are held as records (rows) in `"sf"` objects, inheriting from `"data.frame"`
* `"sf"` objects have at least one simple feature geometry list-column of class `"sfc"`
* geometry list-columns are *sticky*, that is they stay stuck to the object when subsetting columns, for example using `[`
* `"sfc"` geometry list-columns have a bounding box and a coordinate reference system as attribute, and a class attribute pointing out the common type (or `"GEOMETRY"` in case of a mix)
* a single simple feature geometry is of class `"sfg"`, and further classes pointing out dimension and type
Storage of simple feature geometry:
* `"POINT"` is a numeric vector
* `"LINESTRING"` and `"MULTIPOINT"` are numeric matrix, points/vertices in rows
* `"POLYGON"` and `"MULTILINESTRING"` are lists of matrices
* `"MULTIPOLYGON"` is a lists of those
* `"GEOMETRYCOLLECTION"` is a list of typed geometries
To build from scratch:
```{r, echo=TRUE}
p1 = st_point(c(3,5))
class(p1)
p2 = st_point(c(4,6))
p3 = st_point(c(4,4))
pts = st_sfc(p1, p2, p3)
class(pts)
sf = st_sf(a = c(3,2.5,4), b = c(1,2,4), geom = pts)
class(sf)
sf
```
**lwgeom** is useful for fixing geometry probems and other tasks.
### Input/output
```{r, echo=TRUE}
library(osmdata)
```
```{r, echo=TRUE, cache=TRUE}
bbox <- opq(bbox = 'olinda brazil')
(osm_water <- osmdata_sf(add_osm_feature(bbox, key = 'natural', value = 'water'))$osm_points)
```
We write in EPSG:31985, SIRGAS 2000 UTM zone 25S projected coordinates, rather than WGS84 geographical coordinates.
```{r, echo=TRUE}
if (!dir.exists("output")) dir.create("output")
tf <- "output/water-pts.gpkg"
st_write(st_transform(osm_water, 31985), dsn=tf, layer="water-pts", driver="GPKG", layer_options="OVERWRITE=YES")
```
```{r, echo=TRUE}
st_layers(tf)
```
```{r, echo=TRUE}
water_pts <- st_read(tf)
```
Here we transformed to SIRGAS 2000 UTM zone 25S (EPSG:31985), to match Landsat raster dat to be used later.
```{r, echo=TRUE}
olinda_sirgas2000 <- st_transform(olinda, 31985)
st_crs(olinda_sirgas2000)
if (!dir.exists("output")) dir.create("output")
st_write(olinda_sirgas2000, dsn="output/olinda_sirgas2000.gpkg", driver="GPKG", layer_options="OVERWRITE=YES")
```
## Exercise + review
Try doing this in pairs or small groups and discuss what is going on.
Look at the [North Carolina SIDS data vignette](https://r-spatial.github.io/spdep/articles/sids.html) for background:
```{r, echo=TRUE}
library(sf)
nc <- st_read(system.file("shapes/sids.shp", package="spData")[1], quiet=TRUE)
st_crs(nc) <- "+proj=longlat +datum=NAD27"
row.names(nc) <- as.character(nc$FIPSNO)
head(nc)
```
The variables are largely count data, `L_id` and `M_id` are grouping variables. We can also read the original neighbour object:
```{r, echo=TRUE, warning=FALSE}
library(spdep)
gal_file <- system.file("weights/ncCR85.gal", package="spData")[1]
ncCR85 <- read.gal(gal_file, region.id=nc$FIPSNO)
ncCR85
```
```{r, echo=TRUE, warning=TRUE, out.width='90%', fig.align='center', width=7, height=4}
plot(st_geometry(nc), border="grey")
plot(ncCR85, st_centroid(st_geometry(nc), of_largest_polygon), add=TRUE, col="blue")
```
Now generate a random variable. Here I've set the seed - maybe choose your own, and compare outcomes with the people around you. With many people in the room, about 5 in 100 may get a draw that is autocorrelated when tested with Moran's $I$ (why?).
```{r, echo=TRUE}
set.seed(1)
nc$rand <- rnorm(nrow(nc))
lw <- nb2listw(ncCR85, style="B")
moran.test(nc$rand, listw=lw, alternative="two.sided")
```
Now we'll create a trend (maybe try plotting `LM` to see the trend pattern). Do we get different test outcomes by varying beta and sigma (alpha is constant).
```{r, echo=TRUE}
nc$LM <- as.numeric(interaction(nc$L_id, nc$M_id))
alpha <- 1
beta <- 0.5
sigma <- 2
nc$trend <- alpha + beta*nc$LM + sigma*nc$rand
moran.test(nc$trend, listw=lw, alternative="two.sided")
```
To get back to reality, include the trend in a linear model, and test again.
```{r, echo=TRUE}
lm.morantest(lm(trend ~ LM, nc), listw=lw, alternative="two.sided")
```
So we can manipulate a missing variable mis-specification to look like spatial autocorrelation. Is this informative?
#### Extra problem (own time after we're done if you like):
Sometimes we only have data on a covariate for aggregates of our units of observation. What happens when we "copy out" these aggregate values to the less aggregated observations? First we'll aggregate `nc` by `LM`, then make a neighbour object for the aggregate units
```{r, echo=TRUE}
aggLM <- aggregate(nc[,"LM"], list(nc$LM), head, n=1)
(aggnb <- poly2nb(aggLM))
```
```{r, echo=TRUE}
plot(st_geometry(aggLM))
```
Next, draw a random sample for the aggregated units:
```{r, echo=TRUE}
set.seed(1)
LMrand <- rnorm(nrow(aggLM))
```
Check that it does not show any spatial autocorrelation:
```{r, echo=TRUE}
moran.test(LMrand, nb2listw(aggnb, style="B"))
```
Copy it out to the full data set, indexing on values of LM; the pattern now looks pretty autocorrelated
```{r, echo=TRUE}
nc$LMrand <- LMrand[match(nc$LM, aggLM$LM)]
plot(nc[,"LMrand"])
```
which it is:
```{r, echo=TRUE}
moran.test(nc$LMrand, listw=lw, alternative="two.sided")
```
We've manipulated ourselves into a situation with abundant spatial autocorrelation at the level of the counties, but only by copying out from a more aggregated level. What is going on?
## Raster data
Spatial raster data is observed using rectangular (often square) cells, within which attribute data are observed. Raster data are very rarely object-based, very often they are field-based and could have been observed everywhere. We probably do not know where within the raster cell the observed value is correct; all we know is that at the chosen resolution, this is the value representing the whole cell area.
```{r, echo = TRUE}
library(elevatr)
```
```{r, echo = TRUE, cache=TRUE}
elevation <- get_elev_raster(as(olinda_sirgas2000, "Spatial"), z = 14)
elevation[elevation$layer < 1] <- NA
```
```{r, echo = TRUE}
mapview(elevation, col=terrain.colors)
```
### Representing spatial raster data in R (**sp** and **raster**)
The **raster** package S4 representation builds on the **sp** representation, using a `GridTopology` S4 object to specify the grid, and a data frame to hold the data. **raster** defines `RasterLayer`, and combinations of layers as stacks (may be different storage classes) or bricks (same storage class - array). Adding time remains an issue; **raster** can avoid reading data into memory using **rgdal** mechanisms.
```{r, echo = TRUE}
elevation
```
```{r, echo = TRUE}
sp::gridparameters(as(elevation, "SpatialGrid"))
```
```{r, echo = TRUE}
library(stars)
e1 <- st_as_stars(elevation)
e1
if (!dir.exists("output")) dir.create("output")
write_stars(e1, "output/elevation.tif")
```
### Analysing raster data
Package [`raster`](https://rspatial.org/raster/index.html) has
been around for a long time, is robust, well tested, versatile,
and works for large rasters. We will not discuss it here.
The more recent [`stars`](https://r-spatial.github.io/stars/)
package has a different take on raster data, and will be used here.
The following example loads 6 bands from a (section of a) Landsat
7 image, and plots it:
```{r, echo = TRUE}
fn <- system.file("tif/L7_ETMs.tif", package = "stars")
system.time(L7 <- read_stars(fn))
L7
```
```{r, echo = TRUE}
plot(L7)
```
The irregular color breaks come from the default of using "type =
quantile" to `classInt::classIntervals()`, which causes [histogram
stretching](https://en.wikipedia.org/wiki/Histogram_equalization);
this is done over all 6 bands.
We can compute an index like [ndvi](https://en.wikipedia.org/wiki/Normalized_difference_vegetation_index), and plot it:
```{r, echo=TRUE}
ndvi <- function(x) (x[4] - x[3])/(x[4] + x[3])
(s2.ndvi <- st_apply(L7, c("x", "y"), ndvi))
if (!dir.exists("output")) dir.create("output")
write_stars(s2.ndvi, "output/L7_ndvi.tif")
system.time(plot(s2.ndvi))
```
### stars: out-of-memory
As we can see, the proxy object contains no data, but only a pointer to the data. Plotting takes less time, because only pixels that can be seen are read:
```{r, echo = TRUE}
system.time(L7 <- read_stars(fn, proxy=TRUE))
L7
```
In calculating the NDVI, lazy evaluation is used: `s2.ndvi` still contains no pixels,
but only `plot` calls for them, and instructs `st_apply` to only work on the resolution called for, and so optimizes plotting time too.
```{r, echo=TRUE}
(s2.ndvi = st_apply(L7, c("x", "y"), ndvi))
system.time(plot(s2.ndvi))
```
### openeo
[OpenEO](http://openeo.org/about/) proposes proof-of-concept client-server API approaches. The sample data sets are from the southern Alps, and the project is under development.
```{r, echo=TRUE}
if (!dir.exists("output")) dir.create("output")
```
```{r, echo = TRUE, message=FALSE, warning=FALSE, cache=TRUE}
library(openeo) # v 0.3.1
euracHost = "http://saocompute.eurac.edu/openEO_0_3_0/openeo/"
eurac = connect(host = euracHost,disable_auth = TRUE)
pgb = eurac %>% pgb()
bb <- list(west=10.98,east=11.25,south=46.58,north=46.76)
tt <- c("2017-01-01T00:00:00Z","2017-01-31T00:00:00Z")
pgb$collection$S2_L2A_T32TPS_20M %>%
pgb$filter_bbox(extent=bb) %>%
pgb$filter_daterange(extent=tt) %>%
pgb$NDVI(red="B04",nir="B8A") %>%
pgb$min_time() -> task
tf <- "output/preview.tif"
preview <- preview(eurac, task=task, format="GTiff",
output_file=tf)
```
```{r, echo = TRUE}
plot(read_stars(preview))
```
### gdalcubes
Earth Observation Data Cubes from Satellite Image Collections - extension of the **stars** proxy mechansim and the **raster** out-of-memory approach: (https://github.com/appelmar/gdalcubes_R).
Processing collections of Earth observation images as on-demand multispectral, multitemporal data cubes. Users define cubes by spatiotemporal extent, resolution, and spatial reference system and let 'gdalcubes' automatically apply cropping, reprojection, and resampling using the 'Geospatial Data Abstraction Library' ('GDAL').
Implemented functions on data cubes include reduction over space and time, applying arithmetic expressions on pixel band values, moving window aggregates over time, filtering by space, time, bands, and predicates on pixel values, materializing data cubes as 'netCDF' files, and plotting. User-defined 'R' functions can be applied over chunks of data cubes. The package implements lazy evaluation and multithreading. See also [a one month old blog post](https://www.r-spatial.org//r/2019/07/18/gdalcubes1.html).
## Exercise + review
1. Start R, install package **stars** (if not already present), and load it
```{r, echo=TRUE}
library(stars)
```
2. load the Landsat image test set, as above
```{r, echo=TRUE}
tif <- system.file("tif/L7_ETMs.tif", package = "stars")
x <- read_stars(tif)
```
```{r, echo=TRUE}
str(x)
```
3. Create an RGB composite plot using argument `rgb = c(3,2,1)` for RGB, and `rgb = c(4,3,2)` for false color.
```{r, echo=TRUE}
plot(x, rgb = c(3, 2, 1))
```
```{r, echo=TRUE}
plot(x, rgb = c(4, 3, 2))
```
4. Use `x6 <- split(x, "band")` to create a 2-dimensional raster with 6 attributes
```{r, echo=TRUE}
(x6 <- split(x, "band"))
```
5. Plot `x6`. What has changed?
```{r, echo=TRUE}
plot(x6)
```
```{r, echo=TRUE}
str(x6)
```
6. Compute the mean of all six bands by adding all six attributes and dividing by 6, and assigning the resulting matrix as a new attribute in `x6`
```{r, echo=TRUE}
x6$mean <- (x6[[1]] + x6[[2]] + x6[[3]] + x6[[4]] + x6[[5]] + x6[[6]])/6
```
7. As an alternative, compute the mean of all six bands by applying function `mean` over the `x` and `y` dimensions (essentially reducing "band"), by using `st_apply`; compare the results of the two approaches
```{r, echo=TRUE}
xm <- st_apply(x, c("x", "y"), mean)
all.equal(xm[[1]], x6$mean)
```
```{r, echo=TRUE}
str(xm)
```
## Visualization
We have already seen some plot methods for `"sf"`, `"sfc"` and `"nb"` objects in several packages for static plots, and **mapview** for interactive visualization. Let's run through available packages, functions and methods quickly.
### Thematic mapping
**classInt** provides the key class interval determination for thematic mapping of continuous variables. The `classIntervals()` function takes a numeric vector (now also of classes POSIXt or units), a target number of intervals, and a style of class interval. Other arguments control the closure and precision of the intervals found.
```{r, echo=TRUE}
library(classInt)
args(classIntervals)
```
We'll find 7 intervals using Fisher natural breaks for the deprivation variable:
```{r, echo=TRUE}
(cI <- classIntervals(olinda_sirgas2000$DEPRIV, n=7, style="fisher"))
```
We also need to assign a palette of graphical values, most often colours, to use to fill the intervals, and can inspect the intervals and fill colours with a plot method:
The **RColorBrewer** package gives by permission access to the ColorBrewer palettes accesible from the [ColorBrewer](http://colorbrewer2.org)
website. Note that ColorBrewer limits the number of classes tightly, only 3--9 sequential classes
```{r, echo=TRUE}
library(RColorBrewer)
pal <- RColorBrewer::brewer.pal((length(cI$brks)-1), "Reds")
plot(cI, pal)
```
We can also display all the ColorBrewer palettes:
```{r, echo=TRUE}
display.brewer.all()
```
### Package-specific plot and image methods
The **sp** package provided base graphics plot and image methods. **sf** provides plot methods using base graphics; the method for `"sf"` objects re-arranges the plot window to provide a colour key, so extra steps are needed if overplotting is needed:
```{r, echo=TRUE}
plot(olinda_sirgas2000[,"DEPRIV"], breaks=cI$brks, pal=pal)
```
(returns current `par()` settings); the method also supports direct use of **classInt**:
```{r, echo=TRUE}
plot(olinda_sirgas2000[,"DEPRIV"], nbreaks=7, breaks="fisher", pal=pal)
```
Earlier we used the plot method for `"sfc"` objects which does not manipulate the graphics device, and is easier for overplotting.
### The mapview package
**mapview**: Quickly and conveniently create interactive visualisations of spatial data with or without background maps. Attributes of displayed features are fully queryable via pop-up windows. Additional functionality includes methods to visualise true- and false-color raster images, bounding boxes, small multiples and 3D raster data cubes. It uses **leaflet** and other HTML packages.
```{r, echo=TRUE}
mapview(olinda_sirgas2000, zcol="DEPRIV", col.regions=pal, at=cI$brks)
```
### The tmap package
**tmap**: Thematic maps show spatial distributions. The theme refers to the phenomena that is shown, which is often demographical, social, cultural, or economic. The best known thematic map type is the choropleth, in which regions are colored according to the distribution of a data variable. The R package tmap offers a coherent plotting system for thematic maps that is based on the layered grammar of graphics. Thematic maps are created by stacking layers, where per layer, data can be mapped to one or more aesthetics. It is also possible to generate small multiples. Thematic maps can be further embellished by configuring the map layout and by adding map attributes, such as a scale bar and a compass. Besides plotting thematic maps on the graphics device, they can also be made interactive as an HTML widget. In addition, the R package **tmaptools** contains several convenient functions for reading and processing spatial data. See [@JSSv084i06] and Chapter 8 in [@geocompr].
The **tmap** package provides cartographically informed, grammar of graphics (gg) based functionality now, like **ggplot2** using **grid** graphics. John McIntosh tried with [ggplot2](http://johnmackintosh.com/2017-08-22-simply-mapping/), with quite nice results. I suggested he look at **tmap**, and things got [better](http://johnmackintosh.com/2017-09-01-easy-maps-with-tmap/), because **tmap** can switch between interactive and static viewing. **tmap** also provides direct access to **classInt** class intervals.
```{r, echo=TRUE}
library(tmap)
tmap_mode("plot")
o <- tm_shape(olinda_sirgas2000) + tm_fill("DEPRIV", style="fisher", n=7, palette="Reds")
class(o)
```
returns a `"tmap"` object, a **grid** GROB (graphics object), with print methods.
```{r, echo=TRUE}
o
```
Since the objects are GROBs, they can be updated, as in **lattice** with **latticeExtra** or **ggplot2**:
```{r, echo=TRUE}
o + tm_borders(alpha=0.5, lwd=0.5)
```
Using `tmap_mode()`, we can switch between presentation (`"plot"`) and interactive (`"view"`) plotting:
```{r, echo=TRUE}
tmap_mode("view")
```
```{r, echo=TRUE}
o + tm_borders(alpha=0.5, lwd=0.5)
```
```{r, echo=TRUE}
tmap_mode("plot")
```
There is also a Shiny tool for exploring palettes:
```{r, echo=TRUE, eval=FALSE}
tmaptools::palette_explorer()
```
### The cartography package
**cartography** helps to design cartographic representations such as proportional symbols, choropleth, typology, flows or discontinuities maps. It also offers several features that improve the graphic presentation of maps, for instance, map palettes, layout elements (scale, north arrow, title...), labels or legends. [@giraud+lambert16; @giraud+lambert17], http://riatelab.github.io/cartography/vignettes/cheatsheet/cartography_cheatsheet.pdf. The package is associated with **rosm**: Download and plot Open Street Map <http://www.openstreetmap.org/>, Bing Maps <http://www.bing.com/maps> and other tiled map sources. Use to create basemaps quickly and add hillshade to vector-based maps. https://cran.r-project.org/web/packages/rosm/vignettes/rosm.html
The package organizes extra palettes:
```{r, echo=TRUE}
library(cartography)
display.carto.all()
```
The plotting functions (mot methods) use base graphics:
```{r, echo=TRUE}
choroLayer(olinda_sirgas2000, var="DEPRIV", method="fisher-jenks", nclass=7, col=pal, legend.values.rnd=3)
```
(returns NULL)
### The ggplot2 package
The **ggplot2** package provides the `geom_sf()` facility for mapping:
```{r, echo=TRUE}
library(ggplot2)
```
```{r, echo=TRUE}
g <- ggplot(olinda_sirgas2000) + geom_sf(aes(fill=DEPRIV))
g
```
It is possible to set a theme that drops the arguably unnecessary graticule:
```{r, echo=TRUE}
g + theme_void()
```
```{r, echo=TRUE}
g + theme_void() + scale_fill_distiller(palette="Reds", direction=1)
```
but there is a lot of jumping through hoops to get a simple map. To get proper class intervals involves even more work, because **ggplot2** takes specific, not general, positions on how graphics are observed. ColorBrewer eschews continuous colour scales based on cognitive research, but ggplot2 enforces them for continuous variables (similarly for graticules, which may make sense for data plots but not for maps).
## Exercise + review
Since the break is close, try exploring alternative class interval definitions and palettes, maybe also visiting http://hclwizard.org/ and its `hclwizard()` Shiny app, returning a palette generating function on clicking the "Return to R" button:
```{r, echo=TRUE}
library(colorspace)
hcl_palettes("sequential (single-hue)", n = 7, plot = TRUE)
```
```{r, echo=TRUE, eval=FALSE}
pal <- hclwizard()
pal(6)
```
The end of rainbow discussion is informative:
```{r, echo=TRUE}
wheel <- function(col, radius = 1, ...)
pie(rep(1, length(col)), col = col, radius = radius, ...)
opar <- par(mfrow=c(1,2))
wheel(rainbow_hcl(12))
wheel(rainbow(12))
par(opar)
```