GDAL-RASTER-ZONAL-STATS(1)
π GDAL-RASTER-ZONAL-STATS(1) π
okay bestie, welcome to the GDAL manual, and specifically to the gdal-raster-zonal-stats page. this is a GDAL joint. buckle up, we're computing zonal stats and we're gonna slay while we do it. β¨
πΈ NAME πΈ
gdal-raster-zonal-stats β Compute raster zonal statistics. π
Added in version 3.12.
β¨ SYNOPSIS β¨
Usage: gdal raster zonal-stats [OPTIONS] <INPUT> <OUTPUT>
Calculate raster zonal statistics
Positional arguments:
-i, --input <INPUT> Input raster datasets [required] [not available in pipelines]
-o, --output <OUTPUT> Output vector dataset [required] [not available in pipelines]
Common Options:
-h, --help Display help message and exit
--json-usage Display usage as JSON document and exit
--config <KEY>=<VALUE> Configuration option [may be repeated]
-q, --quiet Quiet mode (no progress bar or warning message) [not available in pipelines]
Options:
-f, --of, --format, --output-format <OUTPUT-FORMAT> Output format ("GDALG" allowed) [not available in pipelines]
--co, --creation-option <KEY>=<VALUE> Creation option [may be repeated] [not available in pipelines]
--lco, --layer-creation-option <KEY>=<VALUE> Layer creation option [may be repeated] [not available in pipelines]
--overwrite Whether overwriting existing output dataset is allowed [not available in pipelines]
--update Whether to open existing dataset in update mode [not available in pipelines]
--overwrite-layer Whether overwriting existing output layer is allowed [not available in pipelines]
--append Whether appending to existing layer is allowed [not available in pipelines]
Mutually exclusive with --upsert
--output-layer <OUTPUT-LAYER> Output layer name [not available in pipelines]
--skip-errors Skip errors when writing features [not available in pipelines]
-b, --band <BAND> Input band(s) (1-based index) [may be repeated]
--zones <ZONES> Dataset containing zone definitions [required]
--zones-band <ZONES-BAND> Band from which zones should be read
Mutually exclusive with --zones-layer
--zones-layer <ZONES-LAYER> Layer from which zones should be read
Mutually exclusive with --zones-band
--weights <WEIGHTS> Weighting raster dataset
--weights-band <WEIGHTS-BAND> Band from which weights should be read (default: 1)
--pixels <PIXELS> Method to determine which pixels are included in stat calculation.. PIXELS=default|fractional|all-touched
--stat <STAT> Statistic(s) to compute for each zone. STAT=center_x|center_y|count|coverage|frac|max|max_center_x|max_center_y|mean|median|min|minority|min_center_x|min_center_y|mode|stdev|sum|unique|values|variance|variety|weighted_mean|weighted_stdev|weighted_sum|weighted_variance|weights [may be repeated] [required]
--include-field <INCLUDE-FIELD> Fields from polygon zones to include in output [may be repeated]
--include-geom Include polygon zone geometry in the output
--strategy <STRATEGY> For polygon zones, whether to iterate over input features or raster chunks. STRATEGY=feature|raster (default: feature)
--chunk-size <CHUNK-SIZE> Maximum size of raster chunks read into memory (default: 5%)
Advanced Options:
--if, --input-format <INPUT-FORMAT> Input formats [may be repeated] [not available in pipelines]
--oo, --open-option <KEY>=<VALUE> Open options [may be repeated] [not available in pipelines]
--output-oo, --output-open-option <KEY>=<VALUE> Output open options [may be repeated] [not available in pipelines]
--upsert Upsert features (implies 'append') [not available in pipelines]
Mutually exclusive with --append
π¦ DESCRIPTION π¦
gdal raster zonal-stats computes raster zonal statistics β which is just a fancy lil way of saying: it summarises the pixel values that live inside zones, where those zones are defined either by polygon features or by a categorical raster. so iconic of it. π
πΌοΈ [image] Mean elevation calculated for each polygon from an elevation raster.
a weighting raster can also be supplied on top of the source raster, bestie, which lets you compute stuff like population-weighted mean weather conditions. obsessed.
all inputs should be handed over in the same spatial reference system. and if the input rasters have different resolutions, they get resampled to a consistent resolution using average resampling. but heads up β no reprojection is performed. none. zero. don't come for me. π
π Pixel inclusion and weighting π
when the zones are defined using polygons, you've got three methods for deciding which pixels make it into the calculation:
- default vibe: the geometries get rasterized using default parameters, and the pixels included in that rasterization are used in the calculation with equal weighting.
--pixels all-touched: all pixels touched by the polygon are used in the calculation, again with equal weighting.--pixels fractional: the fraction of each pixel that is covered by the polygon is computed, and pixels get weighted according to that fraction.
β οΈ ngl this one's a demand: --pixels fractional requires that GDAL be built against version 3.14 or later of the GEOS library. no GEOS 3.14+, no fractional pixels. periodt.
(part 1 done, bestie β more coming, don't go anywhere π)
π Supported stats π
okay bestie so here's the β¨full menuβ¨ of stats you can ask for. each one is a lil computation that runs over the cells touching your polygon, and you pick them by name. let me run through every single one:
center_xβ an array holding the cell center x-coordinate for every cell that intersects the polygon. heads up though: each cell center may or may not actually be inside the polygon πcenter_yβ same vibe, but the cell center y-coordinate for each cell that intersects the polygon. and yeah, each cell center may or may not be inside the polygon π¦countβ the sum of all the cell coverage fractions. that's it, that's the number πcoverageβ an array with the coverage fraction of every cell that intersects the polygon πΈfracβ the fraction of covered cells that are occupied by each distinct raster value, exactly as provided byunique. iykyk β¨maxβ the maximum value of cells that intersect the polygon. and no, it does not take coverage fractions or weighting raster values into account π«Άmax_center_xβ the cell center x-coordinate of the cell that holds the maximum value intersected by the polygon. the center of that cell may or may not be inside the polygon, we don't gatekeep πmax_center_yβ the cell center y-coordinate of the cell holding the maximum value intersected by the polygon. once again, that center may or may not be inside the polygon πmeanβ the mean value of cells that intersect the polygon, weighted by the percent of each cell that is covered. coverage-aware, she's thorough βminβ the minimum value of cells that intersect the polygon, and again no coverage fractions and no weighting raster values in the mix πmin_center_xβ cell center x-coordinate for the cell containing the minimum value intersected by the polygon. that center may or may not be inside the polygon, either way she's valid π§min_center_yβ cell center y-coordinate for the cell containing the minimum value intersected by the polygon. yep, the center may or may not be inside the polygon πminorityβ the raster value occupying the least number of cells, taking cell coverage fractions into account but not weighting raster values πmodeβ the raster value occupying the greatest number of cells, taking cell coverage fractions into account but not weighting raster values. main character value, honestly πstdevβ the population standard deviation of cell values that intersect the polygon, taking the coverage fraction into account πsumβ the sum of values of raster cells that intersect the polygon, with each raster value weighted by its coverage fraction. slay π₯uniqueβ an array of the unique raster values for cells that intersect the polygon β¨valuesβ an array of raster values for each cell that intersects the polygon πvarianceβ the population variance of cell values that intersect the polygon, taking the coverage fraction into account πΈvarietyβ the number of distinct raster values in cells wholly or partially covered by the polygon π¦weighted_fracβ the fraction of covered cells occupied by each distinct raster value, weighted by the value of a second weighting raster. the order corresponds to the values returned byuniqueπweighted_meanβ the mean value of cells thatβ¦
β¦and the table's still going, bestie π we literally got page-broke mid-row. So here's how that chopped-off row lands, plus the rest of the lineup:
- (the stat from just above, whose name the page break absolutely ate π) β β¦intersect the polygon, weighted by the product over the coverage fraction and the weighting raster.
weighted_stdevβ Weighted version ofstdev. πweighted_varianceβ Weighted version ofvariance. β¨weightsβ Array of weight values for each cell that intersects the polygon. π
And yes β this algorithm can be part of a gdal pipeline. π₯
π PROGRAM-SPECIFIC OPTIONS π
okay so these are the ones that are literally just for this tool, the main-character flags π
--band,-b <BAND>β the input band(s) you wanna process. that's it, that's the vibe.--chunk-size <MEMORY>β sets the max size of the raster chunks it reads. you can give it as an amount of memory (500 MB,2 GB, etc.) or as a percentage of your available RAM (like10%). pick your fighter π¦--include-field <INCLUDE-FIELD>β names one or more fields from the zones that get copied over to the output. only works when you're using vector zones, jsyk. and since GDAL 3.13 the special valuesALLandNONEare valid too π--include-geomβ drops the zone geometry into the output feature. vector zones only, bestie.
Added in version 3.13. β
--pixels <PIXELS>β how it decides which pixels actually count for the math:default,all-touched, orfractional.--stat <STAT>β name one or more of the Supported stats and it'll compute them per zone. you can stack these, go off queen π--strategy <STRATEGY>β the processing strategy when vector zones are in play:rasterorfeature. default is--strategy feature, which means GDAL walks over the features in your zone dataset, reads the matching pixels from the raster, and writes stats for that feature. the upside: it never has to load the whole feature dataset into memory at once. the downside: the same pixels can get read more than once if your polygons are big or just not spatially ordered (rude of them, honestly). if you go--strategy rasterinstead, GDAL loops over chunks of the raster, finds the matching polygon zones, and updates their stats. (chunk size is yours to control with--chunk-size.) that guarantees raster pixels are read exactly once β but the same features might get processed multiple times. pick your chaos π--weights <WEIGHTS>β optional path to a dataset you want to use for weighting.--weights-band <WEIGHTS-BAND>β picks which raster band the weights get read from.--zones <ZONES>β path to the dataset that defines your zones. if that dataset has more than 1 raster band or feature layer, you must also pass--zones-bandor--zones-layer.--zones-band <ZONES-BAND>β which raster band the zones get read from.--zones-layer <ZONES-LAYER>β which feature layer the zones get read from.
β¨ STANDARD OPTIONS β¨
the shared besties. every gdal tool gets these π«Ά
--appendβ says whether appending features to existing layer(s) is allowed. it also creates the output dataset for you if it doesn't exist yet. convenient fr.--co,--creation-option <NAME>=<VALUE>β lots of formats have optional dataset creation options that let you control little particulars about the file being created. like, the GeoPackage driver has creation options for controlling the version. π§
May be repeated.
Which creation options exist depends entirely on the format driver, and some simple formats have none at all. you can list what a format supports with the --formats command line option, but the format's own documentation is the definitive source on driver creation options. see the Vector drivers format-specific docs for the legal creation options per format.
heads up: dataset creation options are not the same thing as layer creation options. do not confuse them, bestie π
--if,--input-format <format>β the format/driver name to try when opening the input file(s). you usually don't need it, but it's there to skip automatic driver detection when that detection picks wrong. repeat it as many times as you want to list several candidate drivers. note that it doesn't force those drivers to open the dataset β some drivers have file extension requirements and will simply say no. π«
May be repeated.
--lco,--layer-creation-option <NAME>=<VALUE>β lots of formats have optional layer creation options to control particulars about the layer being created. like, the GeoPackage driver has layer creation options for the feature identifier or geometry column name, setting the identifier or description, that kind of thing. π
May be repeated.
Same deal as creation options: what's available varies by format driver, simple formats might have none, --formats lists what's supported but the format documentation is the definitive source, and you should check the Vector drivers format-specific docs for the legal ones.
and again: layer creation options are not dataset creation options. two different girls, two different energies. π
--oo,--open-option <NAME>=<VALUE>β dataset open option (format specific).
May be repeated.
-f,--of,--format,--output-format <OUTPUT-FORMAT>β which output vector format to use. you can see the allowed values with:
gdal --formats | grep vector | grep rw | sort
--output-layer <NAME>β the name of the layer the features get written to. if you don't specify it, the output layer names just match the input layer names. iconic and lazy, love that for us β¨--output-open-option,--output-oo <NAME>=<VALUE>β dataset open option for the output dataset (format specific).
Added in version 3.12. β
May be repeated.
--overwriteβ lets the program overwrite an existing target file or dataset. without it,gdaljust errors out by default if the target already exists. no consent, no overwrite π--overwrite-layerβ whether overwriting the existing output vector layer is allowed.--skip-errorsβ whether failures to write feature(s) should just be ignored.
Added in version 3.12. β
β οΈ careful bestie: this option sets the transaction unit size to one feature at a time, which can cause severe slowdown when you're inserting into databases. it's giving "technically works, painfully slow" π
--updateβ whether to open an existing output dataset in update mode.--upsertβ a variant of--appendwhere theOGRLayer::UpsertFeature()operation is used to insert or update features, instead of appending withOGRLayer::CreateFeature().
Added in version 3.12. β
right now it's only implemented in a few drivers: GPKG -- GeoPackage vector, Elasticsearch: Geographically Encoded Objects for Elasticsearch, and MongoDBv3 (drivers that implement upsert expose the GDAL_DCAP_UPSERT capability).
the upsert operation uses the FID of the input feature, when it's set (and the FID column name isn't the empty string), as the key for updating existing features. so it is crucial that the FIDs in your source and target layers actually match. seriously. π
for the GPKG driver you can also upsert features whose FID is unset or non-significant (the --unset-fid option of gdal vector edit will make it ignore the FID from the source feature), as long as there's a UNIQUE column that isn't the integer primary key.
π RETURN STATUS CODE π
it returns status code 0 when everything slays, and non-zero when something goes wrong. (non-blocking errors that come out as warnings still count as a successful execution, so don't panic over those π«Ά)
π EXAMPLES π
Example 1: Summarize mean elevation within 200m of points of interest
using a nested pipeline for the zone dataset π¦
gdal pipeline read dem.tif ! \
zonal-stats \
--zones [ read points.geojson ! buffer 200 ] \
--stat mean ! \
write \
--output-format CSV \
--output /vsistdout/
orrr, use the zone vector dataset as the piped dataset with the _PIPE_ placeholder dataset name π
gdal pipeline read points.geojson ! \
buffer 200 ! \
zonal-stats \
--input dem.tif
--zones _PIPE_ \
--stat mean ! \
write \
--output-format CSV \
--output /vsistdout/
Example 2: Create a layer with the highest points in each watershed
gdal pipeline read dem.tif !
zonal-stats \
--zones watersheds.shp \
--stat max_center_x \
--stat max_center_y ! \
make-point \
--x max_center_x \
--y max_center_y \
--output-crs EPSG:4326 ! \
write out.geojson
π AUTHOR π
Dan Baston <dbaston@gmail.com>
π COPYRIGHT π
1998-2026
that's the whole page bestie, you made it to the end π₯Ήβ¨ this was GDAL-RASTER-ZONAL-STATS(1), dated Aug 18, 2026 β go forth and zone your stats, no cap π
π
π¦ where this page comes from
- alpine 3.24: gdal-doc 3.13.3-r0 Β· MIT
- arch rolling: gdal 3.13.3-6 Β· MIT
- ubuntu stonking: gdal-bin 3.13.3+dfsg-1ubuntu4 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms