Raster Operations
2025-06-27
Calculate a summary for pixels with the same location across layers.
Calculate a summary for pixels with the same location across layers.
In terra you can use some basic functions, such as mean(), sum(), etc.
Calculate a summary for pixels with the same location across layers.
In terra you can use some basic functions, such as mean(), sum(), etc.
For other function, you need to use app().
Global summaries are calculated across all pixels of a layer.
In terra you can use global(<raster>, <function>).
Zonal statistics summarize the values of a raster using categories from another raster or geometry.
In terra, you can use zonal(<x>, <y>), where <x> is the raster with the values to summarize and <y> the raster/geometry specifying the zones.
landcover <- rast("data/landcover_4326-2015.tif")
avg_ndvi <- project(avg_ndvi, landcover) # this will also resample avg_ndvi (see the section Resampling)
zonal(avg_ndvi, landcover, fun = "mean", na.rm = TRUE) category mean
1 Artificial Land 0.3972677
2 Open Soil 0.1917675
3 High Seasonal Vegetation 0.7299292
4 High Perennial Vegetation 0.7495042
5 Low Seasonal Vegetation 0.5193868
6 Low Perennial Vegetation 0.6483166
7 Water -0.2462283
Push it a bit further.
ndvi_landcover <- zonal(avg_ndvi, landcover, fun = "mean", na.rm = TRUE)
ndvi_landcover$sd <- zonal(avg_ndvi, landcover, fun = "sd", na.rm = TRUE)[, 2]
ndvi_landcover category mean sd
1 Artificial Land 0.3972677 0.14956025
2 Open Soil 0.1917675 0.18361272
3 High Seasonal Vegetation 0.7299292 0.04675755
4 High Perennial Vegetation 0.7495042 0.05914027
5 Low Seasonal Vegetation 0.5193868 0.09874814
6 Low Perennial Vegetation 0.6483166 0.09384940
7 Water -0.2462283 0.27004502
Use aggregate(<raster>, <fact>, <fun>) to aggregate rasters.
<fact> is the number of cells in each direction to be aggregated.<fun> is the function used for aggregatation.avg_ndvi_aggr <- aggregate(avg_ndvi, 25, "mean")
par(mfrow = c(1, 2)) # cannot stack rasters with different resolution
plot(avg_ndvi, col = hcl.colors(100, "Fall", rev = TRUE), frame = FALSE, axes = FALSE)
plot(avg_ndvi_aggr, col = hcl.colors(100, "Fall", rev = TRUE), frame = FALSE, axes = FALSE)[1] 25 25
Use disagg(<raster>, <fact>, <method>) to aggregate rasters.
<fact> is the number of cells in each direction to be aggregated.<method> is the method used for disaggregatation.avg_ndvi_disaggr <- disagg(avg_ndvi_aggr, 25, "bilinear")
par(mfrow = c(1, 3)) # cannot stack rasters with different resolution
plot(avg_ndvi, col = hcl.colors(100, "Fall", rev = TRUE), frame = FALSE, axes = FALSE)
plot(avg_ndvi_aggr, col = hcl.colors(100, "Fall", rev = TRUE), frame = FALSE, axes = FALSE)
plot(avg_ndvi_disaggr, col = hcl.colors(100, "Fall", rev = TRUE), frame = FALSE, axes = FALSE)[1] 1 1
Caution
disaggr() and aggregate() are not inverse functions.
Aggregating and disaggregating a raster does not give, in general, the same raster back. Some of the original information is lost during aggregation.
resample(<x>, <y>, <method>) resamples raster <x> to raster <y>.
<method> is used to specify the algorithm used for resampling:
- `near`, for nearest neighbor.
- `bilinear`, for bilinear interpolation.
- `cubic`, for cubic interpolation.
- `cubicspline`, for cubic-spline interpolation.
- `lanczos`, for Lanczos resampling.
ndvi <- rast("data/ndvi-2024.tif")
landcover <- rast("data/landcover_4326-2015.tif")
ndvi <- resample(ndvi, landcover, method = "bilinear")
avg_ndvi <- mean(ndvi)
zonal(avg_ndvi, landcover, fun = "mean", na.rm = TRUE) category mean
1 Artificial Land 0.3972643
2 Open Soil 0.1917675
3 High Seasonal Vegetation 0.7299290
4 High Perennial Vegetation 0.7495042
5 Low Seasonal Vegetation 0.5193560
6 Low Perennial Vegetation 0.6483423
7 Water -0.2462283
project(<x>, <y>) performs an implicit resampling when <y> is a raster and <x> and <y> do not align.
Note
project(<x>, crs(<y>)) projects only the CRS.
project(<x>, <y>) actually resamples <x> to <y>.
In many cases resample(<x>, <y>, <method>) can be avoided by using project(<x>, <y>, <method>).
Explicit is better than implicit.
extract(<x>, <y>) extract the values from raster <x> for the geometries of <y>.
idiv <- vect("data/idiv.shp")
ndvi <- rast("data/ndvi-2024.tif") |> mean()
extract(ndvi, idiv, cells = TRUE, xy = TRUE) ID mean cell x y
1 1 0.2571441 156737 12.39617 51.31837
2 1 0.3292601 157432 12.39617 51.31792
The options cell = TRUE and xy = TRUE return also the cell ID and the coordinates x and y.
crop(<x>, <y>) crop the extent of raster <x> to the extent of <y>.
mask(<x>, <y>) mask the cells of raster <x> to <y>.
mask() does not crop the extent.
If <y> is a geometry, cells outside the geometries are set to NA.
Plot the trend of NDVI during the year for the area within 1 km distance from the iDiv building .
roi <- vect("data/idiv.shp") |> buffer(1e3)
ndvi <- rast("data/ndvi-2024.tif")
trend <- ndvi |>
mask(roi) |>
global("mean", na.rm = TRUE)
trend$month <- rownames(trend)
plot(
seq_along(trend$month),
trend$mean,
xlab = "",
ylab = "NDVI",
type = "b",
axes = FALSE
)
axis(1, seq_along(trend$month), trend$month)
axis(2, seq(-1, 1, by = .025), seq(-1, 1, by = .025))