Compute Raster Statistics per Polygon in QGIS (Zonal Statistics)

QGIStutorialzonal statisticsNDVIdrone mappingPython

Zonal statistics let you summarise a raster (like NDVI or elevation) within each polygon in a vector layer. Instead of manually clipping rasters to each zone, this script handles the entire operation — including CRS alignment — and writes the result directly to the attribute table.

What it does

The zonal_statistics.py script computes a summary statistic (mean, median, min, or max) of a raster’s pixel values within each polygon in a vector layer, then writes the result as a new attribute column. The attribute name is {data_type}_{aggregation} (e.g. ndvi_mean, height_max).

If the vector and raster are in different CRS, the vector is automatically reprojected to the raster CRS before sampling.

Output: {raster_name}_{data_type}_{aggregation}.geojson saved in the vector layer’s directory with the new statistics column, loaded into the QGIS project.

What you need

  • QGIS 3.28 or newer
  • QGIS processing framework (bundled)
  • First checked vector layer — polygon zones (plot boundaries, field parcels, etc.)
  • First checked raster layer — any single-band raster (NDVI, CHM, elevation)
  • The zonal_statistics.py script from the Vegetation & Field Analysis Pack

Steps

  1. Load your polygon vector layer and check (tick) it in the Layers panel — it must be first.
  2. Load your raster layer and check (tick) it in the Layers panel — it must be second.
  3. Open Plugins → Python Console → Show Editor.
  4. Paste the script. At the bottom, set:
    • data_type — label for the column prefix (e.g. 'ndvi', 'height', 'osavi')
    • aggregation'mean', 'median', 'min', or 'max'
  5. Click Run.

Configurable parameters

ParameterExample valuesWhat it controls
data_type'ndvi', 'height', 'elev'Prefix for the output column name
aggregation'mean', 'median', 'min', 'max'How pixel values are summarised per polygon

When to use zonal statistics vs canopy NDVI

Zonal statistics (this script) samples all pixels inside a polygon — including bare soil. The canopy_ndvi_median_calc.py script samples only canopy pixels by applying a mask first.

Use this script for:

  • CHM height statistics per plot
  • Elevation summary per zone
  • Any raster where bare-ground pixels are meaningful

Use canopy_ndvi_median_calc.py for NDVI where bare soil within the polygon would bias the result.

Get the script

zonal_statistics.py is part of the Vegetation & Field Analysis Pack — six vegetation analysis scripts for QGIS at $40 USD.