Imagine you have a zipped folder with a bunch of raster maps containing variables (e.g. the ones you can download from WorldClim or from CliMond), and you need to calculate zonal statistics from each of these rasters. The zonaFromZip function, provided below, automates this process without the need to unzip the folders. It extracts one raster at a time from the .zip, imports it to R, calculates zonal statistics for your zones raster map (the ‘mean’ function is used by default, but you can provide any other argument accepted by the zonal function of the R raster package), and then deletes the unzipped file before unzipping the next one, therefore requiring minimal disk space.
zonalFromZip <- function (zip.file, zones.map, fun, rast.file.ext = ".tif", aux.file.ext = NULL, delete.unzipped = TRUE, verbosity = 2, ...)
# version 2.1 (updated 11/12/2018)
# zip.file: path to the zip containing the raster maps to calculate zonal stats from
# zones.map: map (in your R workspace) containing the spatial units to calculate zonal stats to; must be of class 'raster', 'SpatialPolygons' or 'SpatialPolygonsDataFrame' and have the same CRS (and resolution if raster) of the maps in 'zip.file'
# fun: function to calculate (e.g. mean)
# rast.file.ext: file extension of the raster maps in 'zip.file'
# aux.file.ext: file extension for the auxiliary files (e.g. ".hdr" for .bil raster files, or ".rdc" for Idrisi .rst files)
# ...: additional arguments to pass to the 'raster::zonal' (if 'zones.map' is a raster) or the 'raster::extract' function (if 'zones.map' is a SpatialPolygons* map), such as na.rm = TRUE
{
require(raster)
rast.files <- unzip(zip.file, list = TRUE) $ Name
var.names <- unique(tools::file_path_sans_ext(rast.files))
n.var <- length(var.names)
zonal.stats <- vector("list", length(var.names))
names(zonal.stats) <- var.names
for (i in 1:n.var) {
if (verbosity >= 1) message("Getting variable ", i, " of ", n.var)
if (verbosity >= 2) message(" - unzipping file...")
unzip(zip.file, files = paste0(var.names[i], rast.file.ext))
if (!is.null(aux.file.ext)) unzip(zip.file, files = paste0(var.names[i], aux.file.ext))
var.rast <- raster(paste0(var.names[i], rast.file.ext))
if (!compareRaster(var.rast, zones.map, stopiffalse = FALSE)) {
if (verbosity >= 2) message(" - cropping to zones raster...")
var.rast <- crop(var.rast, zones.map)
}
if (verbosity >= 2) message(" - calculating zonal stats...")
if (class(zones.map) %in% c("raster", "RasterLayer"))
zonal.stats[[i]] <- raster::zonal(var.rast, zones.map, fun = fun, ...)
else if (class(zones.map) %in% c("SpatialPolygons", "SpatialPolygonsDataFrame"))
zonal.stats[[i]] <- raster::extract(var.rast, zones.map, fun = fun, df = TRUE, ...)
else stop("'zones.map' must be of class 'raster', 'RasterLayer', 'SpatialPolygons' or 'SpatialPolygonsDataFrame'")
if (verbosity >= 2) message(" - deleting unzipped file...")
if (delete.unzipped) {
unlink(list.files()[grep(pattern = paste0(var.names[i], rast.file.ext), x = list.files())])
if (!is.null(aux.file.ext)) unlink(list.files()[grep(pattern = paste0(var.names[i], aux.file.ext), x = list.files())])
} # end if delete
} # end for i
if (verbosity >= 1) message("Converting results to data frame...")
zonal.stats <- as.data.frame(zonal.stats)
zonal.stats <- subset(zonal.stats, select = c(1, seq(2, ncol(zonal.stats), 2)))
colnames(zonal.stats)[1] <- "zone"
colnames(zonal.stats)[-1] <- var.names
if (verbosity >= 1) message("Finished!")
return(zonal.stats)
}
Mind that you need the raster R package installed for this, and a raster map of the spatial units (zones) to which you want to extract the raster variables. Usage examples:
LGM.CCSM4.utm10 <- zonalFromZip(zip.file = "LGM/CCSM4.zip", zones.map = utm10, rast.file.ext = ".tif", aux.file.ext = NULL)
head(LGM.CCSM4.utm10)
WClim.utm10 <- zonalFromZip(zip.file = "bio_2-5m_bil.zip", zones.map = utm10, rast.file.ext = ".bil", aux.file.ext = ".hdr")
head(WClim.utm10)
Example for several .zip files within a folder at once (DEPRECATED – see next post’s zonalsFromZips function instead):
for (f in list.files("LGM")) {
# "LGM" is the folder containing the zip files to extract zonal stats from
name <- paste("LGM", tools::file_path_sans_ext(f), "utm10", sep = ".")
zonstat <- zonalFromZip(zip.file = paste("LGM", f, sep = "/"), zones.map = utm10, raster.ext = ".tif", fun = "mean")
assign(name, zonstat)
}