rgis

Replacing NA cells in specific layers of a raster based on several conditions


I have a raster with three layers: A, B, and C. In each layer, there are several cells with NAs. I would like to replace certain cells with NA, for which I have retrieved the ID number in each layer, with a value of -999.

In my reproducible example below, the ID numbers of the NA cells that should be replaced by -999 are defined by the "test" variable and correspond to 8, 4, and 20.

But when I do: r[c(8, 4, 20)] <- -250, cells 8 in layers A, B, and C, cells 4 in layers A, B, and C, and cells 20 in layers A, B, and C are all replaced by -999. I only want cell 8 in layer A, cell 4 in layer B, and cell 20 in layer C to be replaced by -999 (see the cells with a red circle in the figure below).

I think two conditions should be applied: 1) the cells 8, 4, and 20, and 2) those that have NAs. But, I don't know how to select cells based on both conditions.

## Build the raster
df <-  data.frame(x = c(1, 2, 3, 4, 5, 6, 7, 8, 9),   
  y = c(1, 2, 3, 4, 5, 6, 7, 8, 9),     
  var1 = c(1, 9, 5, 9, 4, 2, 2, 7, 6),
  var2 = c(3, 3, 7, 8, 9, 5, 6, 7, 3),
  var3 = c(1, 1, 8, 8, 4, 4, 4, 1, 2))

r <- tidyterra::as_spatraster(df, xycols = c(1, 2), crs = "EPSG:4326")
terra::plot(r)

m1 <- matrix(1:25, nrow=5, ncol=5)
m1[2, 3] <- NA
m1[4, 3] <- NA
m1[1, 1] <- NA 
r1 <- terra::rast(m1)

m2 <- matrix(1:25, nrow=5, ncol=5)
m2[1, 4] <- NA 
m2[4, 1] <- NA
r2 <- terra::rast(m2)

m3 <- matrix(1:25, nrow=5, ncol=5)
m3[4, 5] <- NA
m3[4, 3] <- NA 
r3 <- terra::rast(m3)

r <- c(r1, r2, r3)
names(r) <- c("A", "B", "C")
terra::plot(r)

## ID numbers of the NA cells
test <- c(8, 4, 20)

## Test
r[c(8, 4, 20)] <- -250
terra::plot(r)

enter image description here

EDIT

Sorry for the confusion. I had written: I would like to replace certain cells with NA, for which I have retrieved the ID number in each layer, with a value of -999. [...] I think two conditions should be applied: 1) the cells 8, 4, and 20, and 2) those that have NAs.

I added NA cells in my code that I do not want to modify the value of.


Solution

  • A simple way to do this could be

    x <- r
    # replace the values in all layers
    x[test] <- -999
    # only keep the replaced values if they were NA
    y <- cover(r, x)
    

    Alternatively with your example data

    x <- r
    a <- apply(is.na(r[test]), 1, which)
    i <- cbind(rowColFromCell(x, test), 1:3)
    x[i] <- -99
    

    And more generally (there can be multiple layers with a NA for a cell)

    x <- r
    b <- as.list(apply(is.na(r[test]), 1, which))
    rc <- rowColFromCell(x, test)
    i <- do.call(rbind, lapply(1:length(test), \(i) cbind(rc[i,,drop=FALSE], b[[i]])))
    x[i] <- -99