@@ -22,8 +22,7 @@ source("setup.R")
22
22
::::::::::::::::::::::::::::::::::::::::::::::::::
23
23
24
24
``` {r load-libraries, echo=FALSE, results="hide", message=FALSE, warning=FALSE}
25
- library(raster)
26
- library(rgdal)
25
+ library(terra)
27
26
library(ggplot2)
28
27
library(dplyr)
29
28
```
@@ -33,16 +32,17 @@ library(dplyr)
33
32
## Things You'll Need To Complete This Episode
34
33
35
34
See the [ lesson homepage] ( . ) for detailed information about the software,
36
- data, and other prerequisites you will need to work through the examples in this episode.
35
+ data, and other prerequisites you will need to work through the examples in
36
+ this episode.
37
37
38
38
39
39
::::::::::::::::::::::::::::::::::::::::::::::::::
40
40
41
41
Sometimes we encounter raster datasets that do not "line up" when plotted or
42
42
analyzed. Rasters that don't line up are most often in different Coordinate
43
- Reference Systems (CRS). This episode explains how to deal with rasters in different, known CRSs. It
44
- will walk though reprojecting rasters in R using the ` projectRaster() `
45
- function in the ` raster ` package.
43
+ Reference Systems (CRS). This episode explains how to deal with rasters in
44
+ different, known CRSs. It will walk though reprojecting rasters in R using
45
+ the ` project() ` function in the ` terra ` package.
46
46
47
47
## Raster Projection in R
48
48
@@ -57,21 +57,23 @@ far in that the digital surface model (DSM) includes the tops of trees, while
57
57
the digital terrain model (DTM) shows the ground level.
58
58
59
59
We'll be looking at another model (the canopy height model) in
60
- [ a later episode] ( 04-raster-calculations-in-r/ ) and will see how to calculate the CHM from the
61
- DSM and DTM. Here, we will create a map of the Harvard Forest Digital
62
- Terrain Model
63
- (` DTM_HARV ` ) draped or layered on top of the hillshade ( ` DTM_hill_HARV ` ).
64
- The hillshade layer maps the terrain using light and shadow to create a 3D-looking image,
65
- based on a hypothetical illumination of the ground level.
60
+ [ a later episode] ( 04-raster-calculations-in-r/ ) and will see how to calculate
61
+ the CHM from the DSM and DTM. Here, we will create a map of the Harvard Forest
62
+ Digital Terrain Model ( ` DTM_HARV ` ) draped or layered on top of the hillshade
63
+ (` DTM_hill_HARV ` ).
64
+ The hillshade layer maps the terrain using light and shadow to create a
65
+ 3D-looking image, based on a hypothetical illumination of the ground level.
66
66
67
67
![ ] ( fig/dc-spatial-raster/lidarTree-height.png ) {alt='Source: National Ecological Observatory Network (NEON).'}
68
68
69
69
First, we need to import the DTM and DTM hillshade data.
70
70
71
71
``` {r import-DTM-hillshade}
72
- DTM_HARV <- raster("data/NEON-DS-Airborne-Remote-Sensing/HARV/DTM/HARV_dtmCrop.tif")
72
+ DTM_HARV <-
73
+ rast("data/NEON-DS-Airborne-Remote-Sensing/HARV/DTM/HARV_dtmCrop.tif")
73
74
74
- DTM_hill_HARV <- raster("data/NEON-DS-Airborne-Remote-Sensing/HARV/DTM/HARV_DTMhill_WGS84.tif")
75
+ DTM_hill_HARV <-
76
+ rast("data/NEON-DS-Airborne-Remote-Sensing/HARV/DTM/HARV_DTMhill_WGS84.tif")
75
77
```
76
78
77
79
Next, we will convert each of these datasets to a dataframe for
@@ -99,13 +101,13 @@ ggplot() +
99
101
100
102
Our results are curious - neither the Digital Terrain Model (` DTM_HARV_df ` )
101
103
nor the DTM Hillshade (` DTM_hill_HARV_df ` ) plotted.
102
- Let's try to
103
- plot the DTM on its own to make sure there are data there.
104
+ Let's try to plot the DTM on its own to make sure there are data there.
104
105
105
106
``` {r plot-DTM}
106
107
ggplot() +
107
108
geom_raster(data = DTM_HARV_df,
108
- aes(x = x, y = y, fill = HARV_dtmCrop)) +
109
+ aes(x = x, y = y,
110
+ fill = HARV_dtmCrop)) +
109
111
scale_fill_gradientn(name = "Elevation", colors = terrain.colors(10)) +
110
112
coord_quickmap()
111
113
```
@@ -122,10 +124,12 @@ geom_raster(data = DTM_hill_HARV_df,
122
124
coord_quickmap()
123
125
```
124
126
125
- If we look at the axes, we can see that the projections of the two rasters are different.
126
- When this is the case, ` ggplot ` won't render the image. It won't even
127
- throw an error message to tell you something has gone wrong. We can look at Coordinate Reference Systems (CRSs) of the DTM and
128
- the hillshade data to see how they differ.
127
+ If we look at the axes, we can see that the projections of the two rasters are
128
+ different.
129
+ When this is the case, ` ggplot ` won't render the image. It won't even throw an
130
+ error message to tell you something has gone wrong. We can look at Coordinate
131
+ Reference Systems (CRSs) of the DTM and the hillshade data to see how they
132
+ differ.
129
133
130
134
::::::::::::::::::::::::::::::::::::::: challenge
131
135
@@ -140,10 +144,10 @@ does each use?
140
144
141
145
``` {r explore-crs}
142
146
# view crs for DTM
143
- crs(DTM_HARV)
147
+ crs(DTM_HARV, parse = TRUE )
144
148
145
149
# view crs for hillshade
146
- crs(DTM_hill_HARV)
150
+ crs(DTM_hill_HARV, parse = TRUE )
147
151
```
148
152
149
153
` DTM_HARV ` is in the UTM projection, with units of meters.
@@ -157,12 +161,12 @@ crs(DTM_hill_HARV)
157
161
::::::::::::::::::::::::::::::::::::::::::::::::::
158
162
159
163
Because the two rasters are in different CRSs, they don't line up when plotted
160
- in R. We need to reproject (or change the projection of) ` DTM_hill_HARV ` into the UTM CRS. Alternatively,
161
- we could reproject ` DTM_HARV ` into WGS84.
164
+ in R. We need to reproject (or change the projection of) ` DTM_hill_HARV ` into
165
+ the UTM CRS. Alternatively, we could reproject ` DTM_HARV ` into WGS84.
162
166
163
167
## Reproject Rasters
164
168
165
- We can use the ` projectRaster ()` function to reproject a raster into a new CRS.
169
+ We can use the ` project ()` function to reproject a raster into a new CRS.
166
170
Keep in mind that reprojection only works when you first have a defined CRS
167
171
for the raster object that you want to reproject. It cannot be used if no
168
172
CRS is defined. Lucky for us, the ` DTM_hill_HARV ` has a defined CRS.
@@ -171,46 +175,46 @@ CRS is defined. Lucky for us, the `DTM_hill_HARV` has a defined CRS.
171
175
172
176
## Data Tip
173
177
174
- When we reproject a raster, we
175
- move it from one "grid" to another. Thus, we are modifying the data! Keep this
176
- in mind as we work with raster data.
178
+ When we reproject a raster, we move it from one "grid" to another. Thus, we are
179
+ modifying the data! Keep this in mind as we work with raster data.
177
180
178
181
179
182
::::::::::::::::::::::::::::::::::::::::::::::::::
180
183
181
- To use the ` projectRaster ()` function, we need to define two things:
184
+ To use the ` project ()` function, we need to define two things:
182
185
183
186
1 . the object we want to reproject and
184
187
2 . the CRS that we want to reproject it to.
185
188
186
- The syntax is ` projectRaster (RasterObject, crs = CRSToReprojectTo )`
189
+ The syntax is ` project (RasterObject, crs)`
187
190
188
191
We want the CRS of our hillshade to match the ` DTM_HARV ` raster. We can thus
189
- assign the CRS of our ` DTM_HARV ` to our hillshade within the ` projectRaster ()`
190
- function as follows: ` crs = crs (DTM_HARV) ` .
191
- Note that we are using the ` projectRaster ()` function on the raster object,
192
+ assign the CRS of our ` DTM_HARV ` to our hillshade within the ` project ()`
193
+ function as follows: ` crs(DTM_HARV) ` .
194
+ Note that we are using the ` project ()` function on the raster object,
192
195
not the ` data.frame() ` we use for plotting with ` ggplot ` .
193
196
194
- First we will reproject our ` DTM_hill_HARV ` raster data to match the ` DTM_HARV ` raster CRS:
197
+ First we will reproject our ` DTM_hill_HARV ` raster data to match the ` DTM_HARV `
198
+ raster CRS:
195
199
196
200
``` {r reproject-raster}
197
- DTM_hill_UTMZ18N_HARV <- projectRaster (DTM_hill_HARV,
198
- crs = crs(DTM_HARV))
201
+ DTM_hill_UTMZ18N_HARV <- project (DTM_hill_HARV,
202
+ crs(DTM_HARV))
199
203
```
200
204
201
- Now we can compare the CRS of our original DTM hillshade
202
- and our new DTM hillshade, to see how they are different.
205
+ Now we can compare the CRS of our original DTM hillshade and our new DTM
206
+ hillshade, to see how they are different.
203
207
204
208
``` {r}
205
- crs(DTM_hill_UTMZ18N_HARV)
206
- crs(DTM_hill_HARV)
209
+ crs(DTM_hill_UTMZ18N_HARV, parse = TRUE )
210
+ crs(DTM_hill_HARV, parse = TRUE )
207
211
```
208
212
209
213
We can also compare the extent of the two objects.
210
214
211
215
``` {r}
212
- extent (DTM_hill_UTMZ18N_HARV)
213
- extent (DTM_hill_HARV)
216
+ ext (DTM_hill_UTMZ18N_HARV)
217
+ ext (DTM_hill_HARV)
214
218
```
215
219
216
220
Notice in the output above that the ` crs() ` of ` DTM_hill_UTMZ18N_HARV ` is now
@@ -227,8 +231,9 @@ Why do you think the two extents differ?
227
231
228
232
## Answers
229
233
230
- The extent for DTM\_ hill\_ UTMZ18N\_ HARV is in UTMs so the extent is in meters. The extent for DTM\_ hill\_ HARV is in lat/long so the extent is expressed
231
- in decimal degrees.
234
+ The extent for DTM\_ hill\_ UTMZ18N\_ HARV is in UTMs so the extent is in meters.
235
+ The extent for DTM\_ hill\_ HARV is in lat/long so the extent is expressed in
236
+ decimal degrees.
232
237
233
238
234
239
@@ -238,31 +243,36 @@ in decimal degrees.
238
243
239
244
## Deal with Raster Resolution
240
245
241
- Let's next have a look at the resolution of our reprojected hillshade versus our original data.
246
+ Let's next have a look at the resolution of our reprojected hillshade versus
247
+ our original data.
242
248
243
249
``` {r view-resolution}
244
250
res(DTM_hill_UTMZ18N_HARV)
245
251
res(DTM_HARV)
246
252
```
247
253
248
- These two resolutions are different, but they're representing the same data. We can tell R to force our
249
- newly reprojected raster to be 1m x 1m resolution by adding a line of code
250
- ` res=1 ` within the ` projectRaster() ` function. In the example below, we ensure a resolution match by using ` res(DTM_HARV) ` as a variable.
254
+ These two resolutions are different, but they're representing the same data. We
255
+ can tell R to force our newly reprojected raster to be 1m x 1m resolution by
256
+ adding a line of code ` res=1 ` within the ` project() ` function. In the
257
+ example below, we ensure a resolution match by using ` res(DTM_HARV) ` as a
258
+ variable.
251
259
252
260
``` {r reproject-assign-resolution}
253
- DTM_hill_UTMZ18N_HARV <- projectRaster (DTM_hill_HARV,
254
- crs = crs (DTM_HARV),
255
- res = res(DTM_HARV))
261
+ DTM_hill_UTMZ18N_HARV <- project (DTM_hill_HARV,
262
+ crs(DTM_HARV),
263
+ res = res(DTM_HARV))
256
264
```
257
265
258
- Now both our resolutions and our CRSs match, so we can plot these two data sets together. Let's double-check our resolution to be sure:
266
+ Now both our resolutions and our CRSs match, so we can plot these two data sets
267
+ together. Let's double-check our resolution to be sure:
259
268
260
269
``` {r}
261
270
res(DTM_hill_UTMZ18N_HARV)
262
271
res(DTM_HARV)
263
272
```
264
273
265
- For plotting with ` ggplot() ` , we will need to create a dataframe from our newly reprojected raster.
274
+ For plotting with ` ggplot() ` , we will need to create a dataframe from our newly
275
+ reprojected raster.
266
276
267
277
``` {r make-df-projected-raster}
268
278
DTM_hill_HARV_2_df <- as.data.frame(DTM_hill_UTMZ18N_HARV, xy = TRUE)
@@ -301,15 +311,16 @@ Reproject the data as necessary to make things line up!
301
311
302
312
``` {r challenge-code-reprojection, echo=TRUE}
303
313
# import DSM
304
- DSM_SJER <- raster("data/NEON-DS-Airborne-Remote-Sensing/SJER/DSM/SJER_dsmCrop.tif")
314
+ DSM_SJER <-
315
+ rast("data/NEON-DS-Airborne-Remote-Sensing/SJER/DSM/SJER_dsmCrop.tif")
305
316
# import DSM hillshade
306
317
DSM_hill_SJER_WGS <-
307
- raster ("data/NEON-DS-Airborne-Remote-Sensing/SJER/DSM/SJER_DSMhill_WGS84.tif")
318
+ rast ("data/NEON-DS-Airborne-Remote-Sensing/SJER/DSM/SJER_DSMhill_WGS84.tif")
308
319
309
320
# reproject raster
310
- DTM_hill_UTMZ18N_SJER <- projectRaster (DSM_hill_SJER_WGS,
311
- crs = crs(DSM_SJER),
312
- res = 1)
321
+ DTM_hill_UTMZ18N_SJER <- project (DSM_hill_SJER_WGS,
322
+ crs(DSM_SJER),
323
+ res = 1)
313
324
314
325
# convert to data.frames
315
326
DSM_SJER_df <- as.data.frame(DSM_SJER, xy = TRUE)
@@ -354,7 +365,7 @@ is this one was reprojected from WGS84 to UTM prior to plotting.
354
365
:::::::::::::::::::::::::::::::::::::::: keypoints
355
366
356
367
- In order to plot two raster data sets together, they must be in the same CRS.
357
- - Use the ` projectRaster ()` function to convert between CRSs.
368
+ - Use the ` project ()` function to convert between CRSs.
358
369
359
370
::::::::::::::::::::::::::::::::::::::::::::::::::
360
371
0 commit comments