Search code examples
rrasterr-rasterterra

Replace NA's by numeric values in RasterStack (raster) or multi-layer SpatRaster (terra)


I seek to replace NA's by numeric values (-9999) in a multi-layer raster object. My question is a direct extension of this question, extended to multi-layered raster objects.

First, let's construct reproducible data from Josh O'Brien's post adapted to the terra package.

m <- terra::rast(ncol=100, nrow=100)
n <- terra::rast(ncol=100, nrow=100)
m[] <- runif(ncell(m))
n[] <- runif(ncell(n))
m[m < 0.2] <- NA
n[n < 0.2] <- NA
sr <- c(m,n) # SpatRaster (terra)
rs <- raster::stack(sr) # transform to RasterStack (raster)

My approach is to apply a for loop and replace NA's with values for each raster layer individually with the codes proposed by Robert Hijmans. I have tried both for a multi-layered SpatRaster object (terra package) and for a RasterStack object (raster package).

# Replace NA's with numeric values (raster package)
rs.na_fill <- for (i in 1:nlayers(rs)) {
  raster::reclassify(rs[[i]], cbind(NA, -9999))
}

# Replace NA's with numeric values (terra package)
sr.na_fill <- for (i in 1:nlayers(rs)) {
  terra::classify(sr[[i]], cbind(NA, -9999))

}

Both times, the loops run through don't throw an error but the final results (sr.na_fill & rs.na_fill, respectively) remain NULL.

My question is thus: How can I replace NA's with numeric values in multi-layered raster objects?


Solution

  • Example SpatRaster

    library(terra)
    x <- terra::rast(ncol=10, nrow=10, nlyr=3, vals=runif(300))
    x <- clamp(x, 0.2, Inf, FALSE)
    

    Solution

    y <- subst(x, NA, -9999)
    

    (Less efficient) alternative solutions

    a1 <- classify(x, cbind(NA, -9999))
    

    And

    a2 <- ifel(is.na(x), -9999, x)
    

    Most R functions are "vectorized". That is, you generally do not need to loop over the elements of an object. In this case, you do not need to loop over the layers of a SpatRaster. It is possible, but what you do does not work because you do not assign the output of classify to anything, and what you computed is immediately lost again. You need to make the assignments inside the for-loop. The loop itself does not return anything.

    In the rare case that you do need a loop, you can use sapp:

    s <- sapp(x, \(r) subst(r, NA, -9999))