raster_tools.map_overlap#

raster_tools.map_overlap(func, *rasters, depth, boundary=None, dtype=None, null_value=None, meta=None, return_mask=False, **kwargs)[source]#

Apply func block-wise with overlap across one or more rasters.

Thin wrapper over dask.array.overlap.map_overlap(). Each call to func receives one block from each input raster, in input order, with depth extra cells of overlap on each side. dask trims the overlap from the result before it’s wrapped back into a Raster on the first input’s grid, so the user function returns same-shape (overlap-included) blocks and doesn’t need to trim itself.

Available both as a module function and as a Raster method: r1.map_overlap(func, r2, depth=1) is equivalent to map_overlap(func, r1, r2, depth=1) – in the method form the calling raster is the first input. References to the “first input” below mean r1 in either spelling.

Per-block contract

Per-block kwargs (opt-in): input_masks, input_null_values, block_info, block_id, out_null_value. Name any of these in func’s signature to receive them per chunk; see below.

By default the output Raster’s mask is rebuilt from the output data and the resolved output null value (out_data == null_value, or np.isnan(out_data) for NaN nulls) – write the sentinel only at cells you want masked. Cells your func happens to leave equal to the sentinel will appear masked even if you didn’t intend them to; cells you wanted masked but didn’t write the sentinel to will not. This is true regardless of the input rasters’ masks: input masks do not carry through unchanged. To set the output mask explicitly instead – decoupling nullness from the data values – pass return_mask=True and have func return a (data, mask) pair (both overlap-included); see return_mask below.

Always passed positionally:

func(*input_data, **kwargs)

where input_data is a tuple of N NumPy blocks, one per input raster, in input order. Each block already includes the overlap region.

The user can also opt in to receive per-block extras by including named parameters in func’s signature. Detection mirrors dask’s own block_info= / block_id= mechanism and uses inspect.signature() (via dask.utils.has_keyword()). Recognized names (same set as map_blocks()):

  • input_masks – tuple of N np.ndarray (bool) per-block mask arrays, parallel to input_data and overlap-included.

  • input_null_values – tuple of N scalars, each input raster’s null_value (None if unset).

  • block_info – dask’s standard per-block info dict.

  • block_id – dask’s standard per-block index tuple: the block’s chunk-location (equivalently block_info[None]["chunk-location"]). None during the meta inference call.

  • out_null_value – scalar; the resolved output null value the wrapper will use to derive the output mask. Write this sentinel at cells you want masked. See “Output null value resolution” in Notes below.

A function whose only kwargs absorber is **kwargs does NOT trigger any of these injections – name the kwargs you want.

Reserved kwargs

input_masks, input_null_values, block_info, block_id, and out_null_value are reserved. Passing any of them via map_overlap’s own **kwargs raises ValueError.

Parameters
  • func (callable) – Per-block function. See “Per-block contract” above. Must return an array-like that dask can ingest (NumPy ndarray, cupy ndarray, sparse array, etc.) with the same shape as a single (overlap-included) data block. For non-numpy backends, also pass meta=.

  • *rasters (Raster or str) – The input rasters. In the method form the calling raster is the first input and *rasters holds any additional ones; in the function form at least one is required. Path strings are accepted. Only the 3D shape is validated; CRS and affine are not checked. The caller is responsible for aligning inputs – typically via r2.reproject(r1.geobox). Inputs are auto-rechunked to the first input’s chunk structure, so same-shape inputs with differing chunking are handled. For a geo-aware variant that strictly requires matching grids, see geo_map_overlap().

  • depth (int, tuple of int, or dict) – Number of overlap cells per spatial axis. int applies to both y and x (band axis fixed at 0). (dy, dx) sets per-spatial-axis depth. dict maps axis index to depth (or to a (top, bottom) / (left, right) tuple for asymmetric depths). Asymmetric depths require boundary=None or boundary="none" per dask’s restriction.

  • boundary (optional) –

    How to fill cells outside the array’s edges. Choices:

    • None (default): no padding (matches dask).

    • "null" / "null_value" / "nodata" (case-insensitive, so "NODATA" / "NoData" also work): fill with the input raster’s null value (or get_default_null_value(dtype) if unset). The corresponding mask cells are set to True.

    • a numeric scalar: fill with that value. If the value matches the raster’s null value, mask cells are set to True; otherwise they’re set to False.

    • "reflect" / "periodic" / "nearest": dask’s standard padding modes. The mask is padded the same way so reflected/wrapped/copied data and mask stay in sync at the source cell.

    • "none": explicit no-padding (same as None).

    For multi-input, each raster’s null value is consulted independently.

    The boundary -> mask rule only affects what the user’s function sees in the mask block when it opts in to input_masks=. The output Raster’s mask is built independently from the output data (see Returns / Notes below); padded cells are trimmed off before the user sees them.

  • dtype (dtype-like, optional) – Output dtype. When None (default), dask infers the dtype by calling func on tiny meta samples.

  • null_value (scalar, optional) –

    Output null value.

    • None (default): if there is exactly one input raster and the output dtype matches its dtype, the output inherits that input’s null value. Otherwise, the value is a dtype-appropriate default from raster_tools.masking.get_default_null_value().

    • scalar: used as-is.

  • meta (array-like, optional) – Empty array with the desired output array type. Forwarded to dask.array.overlap.map_overlap(). When provided, dask uses this as the output meta and skips the 0-shape sample call it would otherwise make to derive one – useful when func cannot tolerate 0-shape input. When None (default), dask derives a NumPy meta by calling func on 0-shape inputs.

  • return_mask (bool, optional) –

    If True, func must return a (data, mask) pair instead of a single array. The returned mask – not a sentinel comparison – defines the output Raster’s null cells. mask is a boolean array the same shape as data (both overlap-included; dask trims them together). Masked cells are set to the resolved output null value (burned in). Use this to decouple which cells are null from what value they hold, avoiding the sentinel-collision pitfalls described above. The default is False (sentinel-derived mask). Notes:

    • The two arrays are carried through dask packed into a single NumPy structured-dtype block, then split apart again – an internal detail; func just returns the plain pair.

    • Passing dtype= (or meta=) describing the data dtype is recommended: it lets dask skip its 0-shape probe. Without a hint the func must tolerate that probe.

    • Requires NumPy-backed blocks (the structured-dtype carrier is a NumPy concept). Composes with input_masks and every boundary mode.

    • out_null_value injection is unnecessary (though harmless) when return_mask=True.

  • **kwargs – Extra keyword arguments forwarded per-block to func. The reserved names listed above are not allowed here.

Returns

A new lazy Raster on the first input’s grid.

Return type

Raster

Notes

The wrapper always trims overlap before returning so the result matches the input grid. If you need un-trimmed output, call dask.array.overlap.map_overlap() directly on raster.data.

The output mask is all-False if no null value is set (see the per-block contract above for how the mask is built when one is). To write the output mask directly, pass return_mask=True and return a (data, mask) pair from func (see return_mask).

Asymmetric per-side depths are only supported with no padding (boundary=None or "none").

Dask invokes func once on 0-shape inputs to derive the output array meta – this happens whether or not dtype= is provided. Pass meta= to skip the call entirely; dtype= only skips the additional sample call dask would otherwise make to infer the output dtype, not the 0-shape meta call. (Exception: with return_mask=True, dtype= is folded into a structured meta= and so does skip the 0-shape meta call – see return_mask.) Most NumPy ops handle 0-shape inputs fine. If dask raises dtype inference failed in map_blocks. Please specify the dtype explicitly using the dtype kwarg, that’s the sample call (dask routes overlap through its inner map_blocks, so the message says map_blocks even from this function) – dtype= per dask’s hint is usually enough; pass meta= instead if your func also can’t tolerate 0-shape inputs (dask silently swallows that crash, but your downstream output meta will be wrong).

Output null value resolution

When func opts in to out_null_value, the wrapper resolves the scalar per-chunk without an extra dtype-inference pass:

  • With meta= or dtype= set, from that hint (dask leaves block_info[None]["dtype"] as None whenever meta= is set, which is why the hint is consulted first).

  • Otherwise, from block_info[None]["dtype"].

During dask’s meta inference call (where block_info is None), out_null_value is a typed zero of the first input’s dtype so funcs like np.where(m, out_null_value, d) infer the same dtype as their input rather than collapsing to object. If your func’s output dtype depends on the specific out_null_value scalar, pass meta= to skip dask’s 0-shape meta call entirely; dtype= skips only the additional sample call, not the meta call.

Examples

3x3 mean with reflected edges:

>>> def mean_3x3(d):                                
...     pad = d[0]
...     out = np.zeros_like(pad, dtype=np.float32)
...     ... # convolve and write to out[1:-1, 1:-1]
...     return out[None]
>>> smoothed = r.map_overlap(
...     mean_3x3, depth=1, boundary="reflect",
... )                                                

See also

raster_tools.map_blocks

Block-wise without overlap; same per-block contract.

raster_tools.geo_map_overlap

Geo-aware variant that hands func georeferenced xr.DataArray blocks.