rr-raster

Problem with the "stackApply" function in R


I have a problem with the "stackApply" function from the raster-package. First I want to stack three raster layers (each layer has one band) - that works. And then I want to create a raster-object that shows in which of the three bands/layers the minimum value occurs (each pixel in the raster layers has a different value). But I get various error messages. Does anyone have an idea how I can solve the problem? Thank you

stacktest<-stack(test,test1,test2)
min_which <- stackApply(stacktest, indices=1, fun=function(x, na.rm=NULL)which.min(x))

Error in setValues(out, v) : values must be a vector
Error in is.infinite(v) : not implemented standard method for type 'list'

Solution

  • Here is a minimal, self-contained, reproducible example:

    Example data from ?stackApply

    library(raster)
    r <- raster(ncol=10, nrow=10)
    values(r) <- 1:ncell(r)
    s <- stack(r,r,r,r,r,r)
    s <- s * 1:6
    

    Now use these data with your function (I removed the na.rm=NULL as it is not used)

    w <- stackApply(s, indices=1, fun=function(x, ...) which.min(x) )
    w
    #class      : RasterLayer 
    #dimensions : 10, 10, 100  (nrow, ncol, ncell)
    #resolution : 36, 18  (x, y)
    #extent     : -180, 180, -90, 90  (xmin, xmax, ymin, ymax)
    #crs        : +proj=longlat +datum=WGS84 +no_defs 
    #source     : memory
    #names      : index_1 
    #values     : 1, 1  (min, max)
    

    Same for which.max

    w <- stackApply(s, indices=1, fun=function(x, na.rm=NULL) which.max(x) )
    w
    # (...)
    #values     : 6, 6  (min, max)
    

    This suggest it works fine. In most cases that means that you probably have cells that are NA

    s[1:10] <- NA
    w <- stackApply(s, indices=1, fun=function(x, ...) which.min(x) )
    # Error in setValues(out, v) : values must be numeric, logical or factor
    

    It is easy to see why this error occurs

    which.min(3:1) 
    #[1] 3
    which.min(c(3:1, NA))
    #[1] 3
    which.min(c(NA, NA, NA))
    #integer(0)
    

    If all values are NA, which.min does not return NA as expected. Instead it returns an empty vector. That can be fixed like this

    which.min(c(NA, NA, NA))[1]
    #[1] NA
    

    And you can do

    w <- stackApply(s, indices=1, fun=function(x, ...) which.min(x)[1] )
    

    However, using stackApply with indices=1 is not a good approach. You should generally use calc to compute cell values across all layers.

    y <- calc(s, function(x) which.min(x)[1])
    

    But in this case you can use the more straightforward

    z <- which.min(s)