Running examples from the ?terra::mask
revealed that there is a small but notable difference in the way the touches
argument works in terra::mask
and terra::crop
. With touches=FALSE
the raster stats are identical, however with touches=TRUE
there is a small difference. See reprex below.
My questions are: 1) why there is a difference, and 2) which algorithm is more reliable?
library(terra)
#> terra 1.8.50
f <- system.file("ex/elev.tif", package = "terra")
r <- terra::rast(f)
f <- system.file("ex/lux.shp", package = "terra")
v <- terra::vect(f)[1, ]
# With touches=FALSE
bench::mark(
mask = terra::mask(r, v, touches = FALSE) |>
terra::global("sum", na.rm = TRUE),
crop = terra::crop(r, v, mask = TRUE, touches = FALSE) |>
terra::global("sum", na.rm = TRUE),
check = TRUE
)
#> # A tibble: 2 × 6
#> expression min median `itr/sec` mem_alloc `gc/sec`
#> <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl>
#> 1 mask 2.48ms 2.53ms 393. 143KB 18.4
#> 2 crop 2.43ms 2.49ms 399. 773KB 22.6
# With touchhes=TRUE
bench::mark(
mask = terra::mask(r, v, touches = TRUE) |>
terra::global("sum", na.rm = TRUE),
crop = terra::crop(r, v, mask = TRUE, touches = TRUE) |>
terra::global("sum", na.rm = TRUE),
check = TRUE
)
#> Error: Each result must equal the first result:
#> `mask` does not equal `crop`
The difference is caused by some additional cells being dropped by the cropping process. If a raster cell sits (mainly) outside of the rectangular spatial extent of the vector you are using to crop with then it will not be included in the result. This does not happen with mask
We can draw the outputs to demonstrate. If we start with mask
, and draw in the bounding box of the extent of v
, we will see that there are three cells on the Southern tip that touch the polygon but whose centres are not within the bounding box:
plot(v)
plot(terra::mask(r, v, touches = TRUE), add = TRUE)
plot(v, add = TRUE)
plot(ext(v), add = TRUE)
If we do the same with crop
, then we will lose those three cells:
plot(v)
plot(terra::crop(r, v, mask = TRUE, touches = TRUE), add = TRUE)
plot(v, add = TRUE)
plot(ext(v), add = TRUE)
This is not an issue when touches = FALSE
because those cells are not included either way.
As for which is most reliable, there is a strong argument to say that are both equally reliable, since they are algorithmic. Which one is most suitable for your use case depends on what you are trying to do, but if you want the cells around the edges of the polygon treated equally whether or not they are close to the bounding box of the polygon, then mask
would seem more appropriate.