Reputation: 1
I have a stack of five maps showing average NDVI values, and I want to calculate the Hurst exponent for each pixel in the stack using the "hurstexp" function from the "pracma" package. My stacked maps have some missing values (NAs) represented as -Inf when extracted, and I want to return an output raster with the calculated Hurst exponent values. Can you please help me with this, including how to handle the NAs in the process?
library(sp)
library(raster)
library(pracma)
modis_list <- list.files(path = "path",
pattern = "*.tif$", full.names = TRUE)
modis_raster <- stack(modis_list)
# i try this but not working
modis_hurst <- raster::calc(modis_raster, function(x) {
spec <- hurstexp(x, d = 50, display = TRUE)
return(spec$H)
})
writeRaster(modis_hurst, filename = "path/to/output/file.tif", format = "GTiff")
Error:Error in .calcTest(x[1:5], fun, na.rm, forcefun, forceapply) :
cannot use this function
#### I also tried this
calculate_hurst <- function(x) {
tryCatch({
spec <- hurstexp(x, d = 50, display = FALSE) # Use display = FALSE to suppress plot
return(as.numeric(spec$H)) # Ensure the result is numeric
}, error = function(e) {
return(NA) # Handle NA values or errors during calculation
})
}
# Calculate the Hurst exponent for each layer using calc
modis_hurst <- raster::calc(modis_raster, calculate_hurst)
# Write the result to a new raster file
writeRaster(modis_hurst, filename = "path/to/output/file.tif", format = "GTiff")
Error in setValues(out, x) : values must be numeric, logical or factor
Upvotes: 0
Views: 204
Reputation: 2584
You can use the function app
in the terra
package (i.e., the new raster
package). Since I don't know the function hurstexp
and its results meaning, I suppose that whenever a pixel in your time series is NA, the results should be NA (but this is up to you). In any case, hurstexp
cannot handle NA, so you have to get rid of them.
library(terra)
library(pracma)
f <- system.file("ex/elev.tif", package="terra")
r <- rast(f)
#create raster stack
rr <- c(r,r*2,r/2,r^2,log(r))
plot(rr)
spec <- terra::app(rr,function(x){
x <- as.numeric(x)
x <- x[!is.na(x)]
if(length(x)==0)return(NA)
spec <- hurstexp(x,display = F)
Hs <- as.numeric(spec$Hs)
return(Hs)
},cores=1)
plot(spec)
If you (likely) have more than 1 core in your machine you can change the cores
argument of app
to speed up the computation by running the function in parallel.
EDIT
The problem with returning more than one parameter in hutstexp
is that app
cannot return a raster stack. So, one solution could be to loop over the desired parameters with e.g. lapply
.
res <- lapply(list("Hs","He"),function(par){
spec <- terra::app(rr,function(x){
x <- as.numeric(x)
x <- x[!is.na(x)]
if(length(x)==0)return(NA)
spec <- hurstexp(x,display = F)
res <- spec[[par]]
return(res)
},cores=1)
})
res <- do.call(c,res)
plot(res)
Maybe there are better ways, but an advantage of this approach is that you can parallelize both the function in app
with the argument cores
and the outer lapply
loop, with e.g., foreach
or snowfall
(but all other parallelization mechanisms should work fine)
Upvotes: 0