Search code examples
rterra

Pass custom function with arguments to R terra roll() function


I am trying to use the terra::roll() function to compute a rolling geometric mean. I created another function to calculate the geometric mean, but that function has arguments I would like to pass through. See reprex below, how do I make a function that roll() can call and pass additional args to it?

Thanks

# geomean function with arguments
geomean <- function(v, floor = 0.1, na.rm = TRUE){
  exp(sum(log(v[v > floor]), na.rm=na.rm) / length(v))
}

# outer function for rolling geomean
rollgm <- function(x, N = 30, type = 'to', ...) {
  terra::roll(as.vector(x), N, geomean, type = type, ...)  # ... should be passed to geomean()
}

# example
d <- c(runif(10), NA, NA, runif(10))
rollgm(d, N=5, type = 'to', floor = 0.5)  # error unused argument floor
# how to pass through the floor argument ?

Solution

  • Apparently, roll does not pass the arguments in ... to the function specified in the fun argument (see terra::roll source code). However, you could define geomean inside the outer function using the passed arguments as default values:

    # outer function for rolling geomean
    rollgm <- function(x, N = 30, type = 'to', gm.floor = 0.1, gm.na.rm = TRUE, ...) {
      
      # define inside outer function with specified arguments
      # note that 'floor = floor' would cause an error (recursive default argument reference), 
      # hence the 'gm.' prefix
      geomean <- function(v, floor = gm.floor, na.rm = gm.na.rm){
        exp(sum(log(v[v > floor]), na.rm = na.rm) / length(v))
      }
      
      # help(terra::roll):  ... additional arguments for writing files as in writeRaster
      terra::roll(x = as.vector(x), n = N, fun = geomean, type = type, ...)
    }
    
    # example
    d <- c(runif(10), NA, NA, runif(10))
    rollgm(d, N = 5, type = 'to', gm.floor = 0.5)  # no error
    rollgm(d, N = 5, type = 'to', gm.floor = 0.5, gm.na.rm = FALSE)  # no error