% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/spatial.R
\name{zonal}
\alias{zonal}
\title{Summarise raster values within zones}
\usage{
zonal(
  raster,
  zones,
  fun = "mean",
  band = 1L,
  zone_band = 1L,
  zone_field = NULL,
  na.rm = TRUE
)
}
\arguments{
\item{raster}{A \code{vectra_raster} (from \code{\link[=vec_open_raster]{vec_open_raster()}}) or a path to a
\code{.vec} raster holding the values to summarise.}

\item{zones}{The zones to summarise within: a \code{vectra_raster} / \code{.vec} path
aligned to \code{raster} (zone id per pixel), or an \code{sf}/\code{sfc} polygon layer.}

\item{fun}{One or more of \code{"mean"}, \code{"sum"}, \code{"count"}, \code{"min"}, \code{"max"},
\code{"sd"}. Each becomes a column in the result. Default \code{"mean"}.}

\item{band}{Band of the value \code{raster} to summarise (1-based). Default 1.}

\item{zone_band}{Band of a raster \code{zones} holding the zone ids. Default 1.}

\item{zone_field}{For an \code{sf} \code{zones} layer, the column giving each polygon's
zone id. Default \code{NULL} uses the polygon row index \code{1:n}.}

\item{na.rm}{If \code{TRUE} (default) skip nodata pixels; if \code{FALSE} let a nodata
pixel propagate \code{NA} to its zone's statistics.}
}
\value{
A data.frame with a \code{zone} column (sorted) followed by one column per
\code{fun}, one row per zone.
}
\description{
Reduces a raster to one summary row per zone, streaming the raster one
tile-row strip at a time so the whole grid never has to be resident. Zones
come either from a second raster aligned to the value grid (each pixel's zone
is that raster's value, the \code{terra::zonal} pattern) or from an \pkg{sf}
polygon layer (each pixel is assigned the polygon its centre falls in). The
per-zone running moments (count, sum, sum of squares, min, max) are folded in
memory as strips arrive, so peak memory is one strip plus the small per-zone
table regardless of raster size. This is the \emph{monoid fold} tier of the
spatial toolbox: bounded memory, a single streaming pass, no spill.
}
\details{
\code{sd} is derived from the streamed moments
(\code{sqrt((sum2 - sum^2 / n) / (n - 1))}), so it needs no second pass. With
\code{na.rm = TRUE} (the default) nodata pixels are skipped; with \code{na.rm = FALSE}
any nodata pixel in a zone makes that zone's \code{sum}/\code{mean}/\code{min}/\code{max}/\code{sd}
\code{NA}, matching the resident behaviour. \code{count} always reports the number of
non-nodata cells in the zone.

Polygon zones assign each pixel centre to a polygon natively on the GEOS C
API (the polygons parsed once into a spatial index, every strip's centres
located in C), so \pkg{sf} is touched only to read the polygons in; geographic
polygons with spherical geometry on (\code{sf::sf_use_s2()}) keep the \pkg{sf}
point-in-polygon path. Raster zones are fully \pkg{sf}-free. The zone raster
must share the value raster's dimensions and geotransform.
}
\examples{
# A value raster and an aligned 2x2-block zone raster on a 4x4 grid.
vals <- matrix(1:16, 4, 4, byrow = TRUE)
zone <- matrix(c(1, 1, 2, 2, 1, 1, 2, 2,
                 3, 3, 4, 4, 3, 3, 4, 4), 4, 4, byrow = TRUE)
fv <- tempfile(fileext = ".vec"); fz <- tempfile(fileext = ".vec")
vec_write_raster(vals, fv, dtype = "f64", extent = c(0, 0, 4, 4))
vec_write_raster(zone, fz, dtype = "f64", extent = c(0, 0, 4, 4))

zonal(fv, fz, fun = c("mean", "sum", "count"))
unlink(c(fv, fz))

}
\seealso{
\code{\link[=rasterize]{rasterize()}} to build a value raster from streamed points,
\code{\link[=vec_open_raster]{vec_open_raster()}} to open the inputs.
}
