Skip to content

Instantly share code, notes, and snippets.

@h-a-graham
Last active February 16, 2025 07:21
Show Gist options
  • Save h-a-graham/11977fc9a934e20e7b466fe83cb28383 to your computer and use it in GitHub Desktop.
Save h-a-graham/11977fc9a934e20e7b466fe83cb28383 to your computer and use it in GitHub Desktop.
create a composite raster using gdal's VRT and warp via {gdalraster}
#' Create a composite raster with a VRT pixel function
#' @param src_files a character vector with the paths to the source rasters.
#' @param outfile a character path to the output raster.
#' @param fun a character with the pixel function to apply.
#' @param t_srs a character with the target SRS. If empty string "", the spatial
#' reference of src_files[1] will be used.
#' @param vrt_options a character vector with additional options to pass to the
#' gdalbuildVRT command.
#' @param warp_options a character vector with additional options to pass to the
#' gdalwarp command.
#' @param config_options a named character vector with additional GDAL configuration
#' options.
#' @param quiet a logical indicating whether to suppress progress bar.
#' @return a character path to the output raster.
vrt_composite <- function(
src_files,
outfile,
fun = c("median", "mean"),
t_srs = "",
vrt_options = NULL,
warp_options = c(
"-multi",
"-overwrite",
"-co", "COMPRESS=DEFLATE",
"-co", "PREDICTOR=2",
"-co", "NUM_THREADS=ALL_CPUS"
),
config_options = c(
GDAL_VRT_ENABLE_PYTHON = "YES",
VSI_CACHE = "TRUE",
GDAL_CACHEMAX = "30%",
VSI_CACHE_SIZE = "10000000",
GDAL_HTTP_MULTIPLEX = "YES",
GDAL_INGESTED_BYTES_AT_OPEN = "32000",
GDAL_DISABLE_READDIR_ON_OPEN = "EMPTY_DIR",
GDAL_HTTP_VERSION = "2",
GDAL_HTTP_MERGE_CONSECUTIVE_RANGES = "YES",
GDAL_NUM_THREADS = "ALL_CPUS"
),
quiet = FALSE) {
fun <- rlang::arg_match(fun)
purrr::iwalk(
config_options,
~ gdalraster::set_config_option(.y, .x)
)
init_vrt_path <- tempfile(fileext = ".vrt")
init_vrt <- gdalraster::buildVRT(
init_vrt_path,
src_files,
cl_arg = vrt_options,
quiet = TRUE
)
tvrt <- xml2::read_xml(init_vrt_path)
bands <- xml2::xml_find_all(tvrt, "//VRTRasterBand")
purrr::walk(bands, function(x) {
xml2::xml_set_attr(x, "subClass", "VRTDerivedRasterBand")
# Add pixel function elements
xml2::xml_add_child(x, "PixelFunctionType", "median")
xml2::xml_add_child(x, "PixelFunctionLanguage", "Python")
xml2::xml_add_child(x, "PixelFunctionCode", glue::glue("
import numpy as np
def median(in_ar, out_ar, xoff, yoff, xsize, ysize, raster_xsize, raster_ysize, buf_radius, gt, **kwargs):
out_ar[:] = np.nan{fun}(in_ar, axis=0)
"))
})
# Write modified VRT
med_vrt <- tempfile(fileext = ".vrt")
xml2::write_xml(tvrt, med_vrt)
gdalraster::warp(
med_vrt,
outfile,
t_srs = t_srs,
cl_arg = warp_options,
quiet = quiet
)
return(outfile)
}
@h-a-graham
Copy link
Author

h-a-graham commented Feb 16, 2025

Thanks so much for all of this will dig into this more asap!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment