| Title: | Create GDAL Multidimensional VRTs from 2D Raster Collections |
|---|---|
| Description: | Stack 2D rasters (COGs, GeoTIFFs, etc.) along a new dimension, producing GDAL Multidimensional VRT files. This enables treating a collection of 2D rasters as a single multidimensional array, readable by GDAL's multidim API, xarray backends (gdx, xgdal), and other tools. Supports regular axes (start + increment), explicit values, and automatic extraction of dimension values from filenames using regex patterns with optional date/time parsing. |
| Authors: | Michael Sumner [aut, cre] (ORCID: <https://orcid.org/0000-0002-2471-7511>) |
| Maintainer: | Michael Sumner <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.0.9001 |
| Built: | 2026-10-15 00:46:18 UTC |
| Source: | https://github.com/hypertidy/vrtstack |
Stack 2D rasters along a new dimension, producing a GDAL Multidimensional VRT. This enables treating a collection of 2D rasters (COGs, GeoTIFFs, etc.) as a single multidimensional array, readable by GDAL's multidim API and xarray backends.
gdal_mdim_stack( files, dim_name, dim_values = NULL, dim_start = NULL, dim_increment = NULL, dim_type = NULL, dim_direction = NULL, dim_unit = NULL, time_origin = NULL, time_unit = "days", parse_format = NULL, array_name = NULL, output = NULL )gdal_mdim_stack( files, dim_name, dim_values = NULL, dim_start = NULL, dim_increment = NULL, dim_type = NULL, dim_direction = NULL, dim_unit = NULL, time_origin = NULL, time_unit = "days", parse_format = NULL, array_name = NULL, output = NULL )
files |
Character vector of file paths (COGs, GeoTIFFs, /vsicurl/ URIs, etc.) |
dim_name |
Name for the new dimension (e.g., "time", "depth", "level") |
dim_values |
Dimension values. One of:
|
dim_start, dim_increment
|
For regular axes, specify start and increment instead of explicit values. Files are assumed to be in the correct order. |
dim_type |
Optional dimension type: |
dim_direction |
Optional direction: |
dim_unit |
Unit string for the dimension (e.g., |
time_origin |
For temporal dimensions, origin date as |
time_unit |
For temporal dimensions: |
parse_format |
For date/time extraction, a |
array_name |
Name for the data array in the VRT. Default: derived from
common filename prefix, or |
output |
Output VRT path. If NULL, returns XML string without writing. |
The function generates a GDAL Multidimensional VRT that virtually stacks 2D rasters along a new dimension. Key features:
Regular axes: When dimension values are evenly spaced (or specified via
dim_start/dim_increment), the VRT uses <RegularlySpacedValues> for
compact representation.
Auto-detection: Even with explicit dim_values, regular spacing is
detected automatically and converted to the compact form.
Filename parsing: Extract dimension values from filenames using regex,
with optional date/time parsing. Useful for time series like
"temperature_20230101.tif".
Cloud-native: Supports /vsicurl/ URIs for remote files. HTTP(S) URLs
are automatically prefixed with /vsicurl/.
The resulting VRT can be read by:
GDAL's multidim API: gdalmdiminfo, gdalmdimtranslate
Python xarray backends: gdx, xgdal
Any tool supporting GDAL multidimensional rasters
Path to VRT file (invisibly), or XML string if output is NULL.
## Not run: # Stack soil layers by depth gdal_mdim_stack( files = c("soil_0cm.tif", "soil_30cm.tif", "soil_100cm.tif"), dim_name = "depth", dim_values = c(0, 30, 100), dim_type = "VERTICAL", dim_direction = "DOWN", dim_unit = "cm", output = "soil_stack.vrt" ) # Time series with regex extraction gdal_mdim_stack( files = list.files(pattern = "temp_\\d{8}\\.tif$"), dim_name = "time", dim_values = "(\\d{8})", parse_format = "%Y%m%d", dim_type = "TEMPORAL", time_origin = "1970-01-01", time_unit = "days", output = "temperature.vrt" ) # Regular axis - monthly data gdal_mdim_stack( files = sprintf("precip_%02d.tif", 1:12), dim_name = "month", dim_start = 1, dim_increment = 1, output = "monthly.vrt" ) # Cloud-hosted COGs gdal_mdim_stack( files = paste0( "https://storage.googleapis.com/solus100pub/claytotal_", c(0, 5, 15, 30, 60, 100, 150), "_cm_p.tif" ), dim_name = "depth", dim_values = c(0, 5, 15, 30, 60, 100, 150), dim_type = "VERTICAL", dim_unit = "cm", array_name = "claytotal", output = "solus_clay.vrt" ) ## End(Not run)## Not run: # Stack soil layers by depth gdal_mdim_stack( files = c("soil_0cm.tif", "soil_30cm.tif", "soil_100cm.tif"), dim_name = "depth", dim_values = c(0, 30, 100), dim_type = "VERTICAL", dim_direction = "DOWN", dim_unit = "cm", output = "soil_stack.vrt" ) # Time series with regex extraction gdal_mdim_stack( files = list.files(pattern = "temp_\\d{8}\\.tif$"), dim_name = "time", dim_values = "(\\d{8})", parse_format = "%Y%m%d", dim_type = "TEMPORAL", time_origin = "1970-01-01", time_unit = "days", output = "temperature.vrt" ) # Regular axis - monthly data gdal_mdim_stack( files = sprintf("precip_%02d.tif", 1:12), dim_name = "month", dim_start = 1, dim_increment = 1, output = "monthly.vrt" ) # Cloud-hosted COGs gdal_mdim_stack( files = paste0( "https://storage.googleapis.com/solus100pub/claytotal_", c(0, 5, 15, 30, 60, 100, 150), "_cm_p.tif" ), dim_name = "depth", dim_values = c(0, 5, 15, 30, 60, 100, 150), dim_type = "VERTICAL", dim_unit = "cm", array_name = "claytotal", output = "solus_clay.vrt" ) ## End(Not run)
Pure XML-tree rewrite (no GDAL needed). Sets the concat dimension size,
rewrites the concat coordinate array's values, and regenerates the
<Source> list of every data array (an <Array> that owns a <Source>).
Per-array SourceArray path and slab geometry are read from the array's
first source, never assumed from the array name.
mdim_template_extend(xml, files, concat_values = NULL, concat_dim = "time")mdim_template_extend(xml, files, concat_values = NULL, concat_dim = "time")
xml |
Template VRT as an XML string (or anything |
files |
Full character vector of sources. |
concat_values |
Values for the concat coordinate array, or |
concat_dim |
Concat dimension name (default |
An xml_document (serialise with as.character() / xml2::write_xml()).
A convenience wrapper for gdal_mdim_stack() for vertical profile data
(soil layers, atmospheric levels, ocean depths, etc.)
vrt_depth_stack( files, values, direction = "DOWN", unit = NULL, dim_name = NULL, array_name = NULL, output = NULL )vrt_depth_stack( files, values, direction = "DOWN", unit = NULL, dim_name = NULL, array_name = NULL, output = NULL )
files |
Character vector of file paths |
values |
Numeric vector of depth/level values, or regex pattern to extract |
direction |
Vertical direction: |
unit |
Unit string (e.g., |
dim_name |
Dimension name. Default: |
array_name |
Name for the data array |
output |
Output VRT path |
Path to VRT file (invisibly), or XML string if output is NULL.
## Not run: # Soil layers at specific depths vrt_depth_stack( files = c("soil_0cm.tif", "soil_30cm.tif", "soil_100cm.tif"), values = c(0, 30, 100), unit = "cm", output = "soil_profile.vrt" ) # Extract depth from filename vrt_depth_stack( files = list.files(pattern = "temp_\\d+m\\.tif$"), values = "(\\d+)m", # extracts "50" from "temp_50m.tif" unit = "m", output = "ocean_profile.vrt" ) ## End(Not run)## Not run: # Soil layers at specific depths vrt_depth_stack( files = c("soil_0cm.tif", "soil_30cm.tif", "soil_100cm.tif"), values = c(0, 30, 100), unit = "cm", output = "soil_profile.vrt" ) # Extract depth from filename vrt_depth_stack( files = list.files(pattern = "temp_\\d+m\\.tif$"), values = "(\\d+)m", # extracts "50" from "temp_50m.tif" unit = "m", output = "ocean_profile.vrt" ) ## End(Not run)
A convenience wrapper for gdal_mdim_stack() when files represent regularly
spaced values (e.g., monthly data, hourly snapshots, uniform vertical levels).
vrt_regular_stack( files, dim_name, start, increment, unit = NULL, array_name = NULL, output = NULL )vrt_regular_stack( files, dim_name, start, increment, unit = NULL, array_name = NULL, output = NULL )
files |
Character vector of file paths, in order |
dim_name |
Name for the new dimension |
start |
Starting value |
increment |
Spacing between values |
unit |
Unit string |
array_name |
Name for the data array |
output |
Output VRT path |
Path to VRT file (invisibly), or XML string if output is NULL.
## Not run: # 12 monthly files vrt_regular_stack( files = sprintf("precip_%02d.tif", 1:12), dim_name = "month", start = 1, increment = 1, output = "monthly_precip.vrt" ) # Pressure levels at 50 hPa intervals vrt_regular_stack( files = level_files, dim_name = "pressure", start = 1000, increment = -50, unit = "hPa", output = "pressure_levels.vrt" ) ## End(Not run)## Not run: # 12 monthly files vrt_regular_stack( files = sprintf("precip_%02d.tif", 1:12), dim_name = "month", start = 1, increment = 1, output = "monthly_precip.vrt" ) # Pressure levels at 50 hPa intervals vrt_regular_stack( files = level_files, dim_name = "pressure", start = 1000, increment = -50, unit = "hPa", output = "pressure_levels.vrt" ) ## End(Not run)
A convenience wrapper for gdal_mdim_stack() tailored for time series data.
Extracts dates from filenames and encodes them as numeric offsets from an origin.
vrt_time_stack( files, pattern = "(\\d{8})", format = "%Y%m%d", origin = "1970-01-01", unit = "days", array_name = NULL, output = NULL )vrt_time_stack( files, pattern = "(\\d{8})", format = "%Y%m%d", origin = "1970-01-01", unit = "days", array_name = NULL, output = NULL )
files |
Character vector of file paths |
pattern |
Regex pattern with one capturing group for the date portion.
Default: |
format |
strptime format for parsing. Default: |
origin |
Time origin as |
unit |
Time unit: |
array_name |
Name for the data array |
output |
Output VRT path |
Path to VRT file (invisibly), or XML string if output is NULL.
## Not run: # Daily temperature files: temp_20230101.tif, temp_20230102.tif, ... vrt_time_stack( files = list.files(pattern = "temp_\\d{8}\\.tif$"), output = "temperature_timeseries.vrt" ) # Custom pattern for ISO dates: data_2023-01-15.tif vrt_time_stack( files = my_files, pattern = "(\\d{4}-\\d{2}-\\d{2})", format = "%Y-%m-%d", output = "timeseries.vrt" ) ## End(Not run)## Not run: # Daily temperature files: temp_20230101.tif, temp_20230102.tif, ... vrt_time_stack( files = list.files(pattern = "temp_\\d{8}\\.tif$"), output = "temperature_timeseries.vrt" ) # Custom pattern for ISO dates: data_2023-01-15.tif vrt_time_stack( files = my_files, pattern = "(\\d{4}-\\d{2}-\\d{2})", format = "%Y-%m-%d", output = "timeseries.vrt" ) ## End(Not run)
vrtstack() builds a GDAL multidimensional VRT that concatenates a set of
sources along one axis. Two construction paths share a single concat-axis
resolver:
vrtstack( files, concat = NULL, template = NULL, concat_dim = "time", n_template = 10, parse_format = NULL, origin = NULL, unit = "days", output = NULL, ... )vrtstack( files, concat = NULL, template = NULL, concat_dim = "time", n_template = 10, parse_format = NULL, origin = NULL, unit = "days", output = NULL, ... )
files |
Character vector of source paths/URIs (full set). |
concat |
Concat-axis spec, resolved by |
template |
One of: |
concat_dim |
Name of the concatenation dimension. Default |
n_template |
Files used to build the auto-generated recipe when
|
parse_format, origin, unit
|
Passed to |
output |
Output VRT path, or |
... |
Passed to the from-scratch builder ( |
from-scratch (template = NULL) — the original GeoTIFF/COG path. Each
2D source contributes one slab of a single new 3D array. Sources use the
classic <SourceBand> + <SourceTranspose> form.
template-extend (template = <vrt> or template = TRUE) — for
mdim-recognised sources (NetCDF/Zarr/HDF5) that may carry several arrays
(OISST: anom/err/ice/sst). A small "first-n" mdim VRT is taken as the
recipe, and the full file set is fleshed out by re-parameterising only the
concat dimension and the per-array <Source> lists. Everything else
(coordinate arrays, slab geometry, scale/offset/unit/attributes) is carried
verbatim from the template.
The template is the GDAL-native analogue of the "recipe-not-payload"
principle: GDAL's own gdal mdim mosaic writes the recipe for the first n
files; we only template the axis that varies with the file set.
Path to the VRT (invisibly) or the XML string if output is NULL.
#vrt <- vrtstack(<files>, concat = "(\d{8})", parse_format = "%Y%m%d", #origin = "1978-01-01", unit = "days", # must match the template #template = TRUE, concat_dim = "time")#vrt <- vrtstack(<files>, concat = "(\d{8})", parse_format = "%Y%m%d", #origin = "1978-01-01", unit = "days", # must match the template #template = TRUE, concat_dim = "time")