-
Notifications
You must be signed in to change notification settings - Fork 13
/
spatial.Rmd
261 lines (218 loc) · 8.93 KB
/
spatial.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
---
title: "Spatial data"
description: >
Examples and conversation starters for spatial data.
output:
rmarkdown::html_vignette:
self_contained: false
vignette: >
%\VignetteIndexEntry{Spatial data}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
```
For forms with spatial types, such as geopoint, geotrace, or geoshape,
`ruODK` gives two options to access the captured spatial data.
Firstly, to make spatial data as simple and accessible as possible,
`ruODK` extracts the lat/lon/alt/acc from geopoints, as well as from
the first coordinate of geotraces and geoshapes into separate columns.
This works for both GeoJSON and WKT.
The extracted columns are named as the original geofield appended with
`_latitude`, `_longitude`, `_altitude`, and `_accuracy`, respectively.
Secondly, this vignette demonstrates how to turn the spatial data types returned
from ODK Central into spatially enabled objects.
To do so, we have to address two challenges.
The first challenge is to select which of the potentially many spatial fields
which an ODK form can capture shall be used as the primary geometry of a native
spatial object, such as an `sf` SimpleFeature class.
If several spatial fields are captured, it is up to the user to choose which
field to use as primary geometry.
The second challenge is that the parsed data from ODK Central is a plain table
(`tbl_df`) in which some columns contain spatial data. Well Know Text (WKT) is
parsed as text columns, whereas GeoJSON (nested JSON) is parsed as list columns.
Most spatial packages require either atomic coordinates in separate columns,
which works well for points (latitude, longitude, altitude), or the data to be
spatially enabled.
This vignette shows how to transform a `tbl_df` with a column containing (point,
line, or polygon) WKT into a spatially enabled `sf` object.
```{r, message=FALSE, warning=FALSE}
library(ruODK)
# Visualisation
library(leaflet)
library(ggplot2)
library(lattice)
# library(tmap) # Suggested but not included here yet
# Spatial
can_run <- require(sf) && require(leafem) && require(mapview) && require(terra)
# Fix https://github.com/r-spatial/mapview/issues/313
# See also https://github.com/r-spatial/mapview/issues/312
# option 'fgb' requires GDAL >= 3.1.0
if (require(mapview)) {
mapview::mapviewOptions(
fgb = FALSE,
basemaps = c(
"Esri.WorldImagery",
"Esri.WorldShadedRelief",
"OpenTopoMap",
"OpenStreetMap"
),
layers.control.pos = "topright"
)
}
```
## Data
The original data shown in this vignette are hosted on a ODK Central server which
is used for the `ruODK` package tests. The form we show here contains every
spatial widget supported by ODK Build for every supported spatial field type.
With working credentials to the ODK Central test server we could download the data directly.
```{r dl_submissions, eval=FALSE}
# Set ruODK defaults to an ODK Central form, choose tz and verbosity
ruODK::ru_setup(
url = get_test_url(),
pid = get_test_pid(),
fid = get_test_fid_wkt(),
un = get_test_un(),
pw = get_test_pw(),
odkc_version = "2023.5.1",
tz = "Australia/Perth",
verbose = TRUE
)
data_wkt <- ruODK::odata_submission_get(wkt = TRUE)
data_gj <- ruODK::odata_submission_get(wkt = FALSE)
```
To allow users to build this vignette without credentials to the ODK Central
test server, `ruODK` provides above form data also as package data.
```{r}
data("geo_wkt", package = "ruODK")
data("geo_gj", package = "ruODK")
```
## Map geopoints
We can turn data with a text column containing WKT into an `sf` (SimpleFeatures)
object.
In addition, we can leave the `tbl_df` as non-spatial object, and instead
use the separately extracted latitude, longitude, altitude, and accuracy
individually e.g. to plot a Leaflet map.
```{r, fig.width=9, fig.height=7, eval=can_run}
geo_sf_point <- geo_wkt %>% sf::st_as_sf(wkt = "point_location_point_gps")
# ODK Collect captures WGS84 (EPSG:4326)
sf::st_crs(geo_sf_point) <- 4326
```
### Mapview using sf
See also further information under heading "Outlook".
```{r, eval=can_run}
mapview::mapview(geo_sf_point, col.regions = sf::sf.colors(10))
```
### GGplot using sf
```{r, eval=can_run}
ggplot2::ggplot() +
ggplot2::geom_sf(data = geo_sf_point, ggplot2::aes(fill = device_id))
```
### Leaflet using sf
```{r, eval=can_run}
leaflet::leaflet(data = geo_sf_point) %>%
leaflet::addTiles() %>%
leaflet::addMarkers(label = ~device_id, popup = ~device_id)
```
### Leaflet using extracted coordinate components in tbl_df
```{r, eval=can_run}
leaflet::leaflet(data = geo_wkt) %>%
leaflet::addTiles() %>%
leaflet::addMarkers(
lng = ~point_location_point_gps_longitude,
lat = ~point_location_point_gps_latitude,
label = ~device_id,
popup = ~device_id
)
```
## Map geotraces (lines)
We use `sf::st_as_sf` on a text column containing a WKT geotrace.
```{r, fig.width=9, fig.height=7, eval=can_run}
geo_sf_line <- geo_wkt %>% sf::st_as_sf(wkt = "path_location_path_gps")
# ODK Collect captures WGS84 (EPSG:4326)
sf::st_crs(geo_sf_line) <- 4326
```
### Mapview using sf
```{r, eval=can_run}
mapview::mapview(geo_sf_line, col.regions = sf::sf.colors(10))
```
### GGplot using sf
```{r, eval=can_run}
ggplot2::ggplot() +
ggplot2::geom_sf(data = geo_sf_line, ggplot2::aes(fill = device_id))
```
### Leaflet using sf and extracted coordinates
You can show either first extracted coordinate components from plain `tbl_df`
or show the full polygons using `{leafem}`.
See the mapview article on [extra functionality](https://r-spatial.github.io/mapview/articles/articles/mapview_06-add.html).
```{r, eval=can_run}
leaflet::leaflet(data = geo_wkt) %>%
leaflet::addTiles() %>%
leaflet::addMarkers(
lng = ~path_location_path_gps_longitude,
lat = ~path_location_path_gps_latitude,
label = ~device_id,
popup = ~device_id
) %>%
leafem::addFeatures(geo_sf_line, label = ~device_id, popup = ~device_id)
```
## Map geoshapes (polygons)
Again, we'll use `sf::st_as_sf` but select a WKT geoshape column.
```{r, fig.width=9, fig.height=7, eval=can_run}
geo_sf_poly <- geo_wkt %>% sf::st_as_sf(wkt = "shape_location_shape_gps")
# ODK Collect captures WGS84 (EPSG:4326)
sf::st_crs(geo_sf_poly) <- 4326
```
### Mapview using sf
```{r, eval=can_run}
mapview::mapview(geo_sf_poly, col.regions = sf::sf.colors(10))
```
### GGplot using sf
```{r, eval=can_run}
ggplot2::ggplot() +
ggplot2::geom_sf(data = geo_sf_poly, ggplot2::aes(fill = device_id))
```
### Leaflet using sf and extracted coordinates
You can show either first extracted coordinate components from plain `tbl_df`
or show the full polygons using `{leafem}`.
See the mapview article on [extra functionality](https://r-spatial.github.io/mapview/articles/articles/mapview_06-add.html).
```{r, eval=can_run}
leaflet::leaflet(data = geo_wkt) %>%
leaflet::addTiles() %>%
leaflet::addMarkers(
lng = ~shape_location_shape_gps_longitude,
lat = ~shape_location_shape_gps_latitude,
label = ~device_id,
popup = ~device_id
) %>%
leafem::addFeatures(geo_sf_poly, label = ~device_id, popup = ~device_id)
```
# Outlook
The above examples show how to turn spatial data into an `sf` object, and give
very rudimentary visualisation examples to bridge the gap between
spatial data coming from ODK and creating maps and further spatial analyses in R.
See the [sf homepage](https://r-spatial.github.io/sf/) for more context and examples.
The [sf cheatsheet](https://github.com/rstudio/cheatsheets/blob/master/sf.pdf)
deserves a spatial mention.
Review the options for
[mapview popups](https://r-spatial.github.io/mapview/articles/articles/mapview_04-popups.html)
and the whole [mapview](https://r-spatial.github.io/mapview/index.html) homepage for a
comprehensive overview of mapview.
The powerful visualisation package [`tmap`](https://cran.r-project.org/package=tmap)
supports `sf` objects and produces both printable and static maps as well as interactive `leaflet` maps.
See the [vignette "Get started"](https://cran.r-project.org/web/packages/tmap/vignettes/tmap-getstarted.html).
There are several other good entry points for all things R and spatial,
including but not limited to:
* The [R Spatial CRAN Task View](https://cran.r-project.org/view=Spatial)
* The [RSpatial](https://rspatial.org/) website
* [Geospatial data in R and beyond](https://www.maths.lancs.ac.uk/~rowlings/Teaching/UseR2012/)
by [Barry Rowlingson](http://barry.rowlingson.com/)
* [GIS with R](https://www.jessesadler.com/post/gis-with-r-intro/)
by [Jesse Sadler](https://www.jessesadler.com/page/cv/)
* GIS and mapping by [Olivier Gimenez](https://oliviergimenez.github.io/):
[Slides](https://oliviergimenez.github.io/intro_spatialR/) and
[code](https://github.com/oliviergimenez/intro_spatialR)
The above list of examples and resources is far from comprehensive.
Feel free to [contribute or suggest](https://github.com/ropensci/ruODK/issues)
other working examples for turning data from `ruODK` into spatial formats.