raster_tools.geo_map_overlap#
- raster_tools.geo_map_overlap(func, *rasters, depth, boundary=None, dtype=None, null_value=None, meta=None, return_mask=False, **kwargs)[source]#
Apply
funcblock-wise with overlap, handing it georeferencedxarray.DataArrayblocks.Same shape and contract as
geo_map_blocks()but adds the overlap machinery frommap_overlap()(depth,boundary, the data/mask boundary correspondence rule). Eachxr.DataArrayblock includes the overlap region, and its coords reflect the overlapped extent (top-left corner shifted outward by the per-side pad).Available both as a module function and as a
Rastermethod:r1.geo_map_overlap(func, r2, depth=1)is equivalent togeo_map_overlap(func, r1, r2, depth=1)– in the method form the calling raster is the first input. References to the “first input” below meanr1in either spelling.Per-block contract
Per-block kwargs (opt-in):
input_masks,input_null_values,block_info,block_id,out_null_value,geo_block_info. Name any of these infunc’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, ornp.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 – passreturn_mask=Trueand havefuncreturn a(data, mask)pair (both overlap-included); seereturn_maskbelow.Always passed positionally:
func(*data_dataarrays, **kwargs)
where
data_dataarraysis a tuple of N georeferencedxarray.DataArrayblocks, one per input raster, in input order. Each block already includes the overlap region; the wrapper trims it after the function returns so the result lands on the first input’s grid.The user can opt in to receive per-block extras by including named parameters in
func’s signature. Same set asgeo_map_blocks():input_masks– tuple of Nxr.DataArray(bool) per-block mask arrays, parallel to and overlap-included with the data DataArrays.input_null_values– tuple of N scalars, each input’snull_value(Noneif unset).block_info– dask’s standard per-block info dict.block_id– dask’s standard per-block index tuple: the block’schunk-location(equivalentlyblock_info[None]["chunk-location"]).Noneduring 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.geo_block_info– the per-chunkGeoBlockInfo, reflecting the overlapped extent:shapematches the data block (including overlap),geoboxextends to cover the overlap region, androw_slice/col_slicemay have negative starts for top/left edge chunks.Noneduring the meta call.
A function whose only kwargs absorber is
**kwargsdoes NOT trigger any of these injections – name the kwargs you want.Reserved kwargs
input_masks,input_null_values,block_info,block_id,out_null_value, andgeo_block_infoare reserved. Passing any of them viageo_map_overlap’s own**kwargsraisesValueError.- Parameters
func (callable) – Per-block function. See “Per-block contract” above. May return either an
xarray.DataArray(its.datais extracted, preserving backend) or any 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 passmeta=.*rasters (Raster or str) – The input rasters. In the method form the calling raster is the first input and
*rastersholds any additional ones; in the function form at least one is required. Path strings are accepted. All inputs must be on the same grid (CRS, affine, shape) within the established sub-pixel tolerance; mismatched inputs raiseValueError. User2.reproject(r1.geobox)to align inputs first if needed. Inputs are then auto-rechunked to the first input’s chunk structure (reprojectdoes not adopt the target’s chunking), so the output stays on the first input’s grid and chunking.depth (int, tuple of int, or dict) – Same semantics as
map_overlap().boundary (optional) – Same semantics as
map_overlap()(None / scalar /"null"/"null_value"/"nodata"/"reflect"/"periodic"/"nearest"/"none").dtype (dtype-like, optional) – Output dtype. When
None(default), dask infers the dtype by callingfuncon 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, a dtype-appropriate default fromraster_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 whenfunccannot tolerate 0-shape DataArray inputs. The wrapper extracts.datafrom any returnedxarray.DataArray, sometadescribes the wrapper’s array output (whatever backend the user’s func produces). WhenNone(default), dask derives a NumPy meta by callingfuncon 0-shape inputs.return_mask (bool, optional) –
If
True,funcmust return a(data, mask)pair instead of a single array/DataArray. The returnedmask– not a sentinel comparison – defines the output Raster’s null cells.maskis a boolean array the same shape asdata(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 isFalse(sentinel-derived mask). Notes:Each element of the pair may be an
xarray.DataArrayor a bare array; the wrapper uses each element’s.data(any coords / CRS are discarded, same as for the data block).The two arrays are carried through dask packed into a single NumPy structured-dtype block, then split apart again – an internal detail;
funcjust returns the plain pair.Passing
dtype=(ormeta=) 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. Composes with
input_masks,geo_block_info, and everyboundarymode.out_null_valueinjection is unnecessary (though harmless) whenreturn_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
Notes
Warning
funcmust not alter the grid. The output Raster lands on the first input’s grid (its CRS / affine / x / y), regardless of any coords / CRS / nodata your func sets on a returned DataArray – the wrapper extracts.dataand discards everything else. Operations that change the grid (reproject, clip, coarsen, sel, manual coord assignment, etc.) will silently produce a Raster whose values were computed on a different grid than the one it claims, with no error at construction time. UseRaster.reproject()/Raster.clip()/ etc. before or after this call instead.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 onraster.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=Trueand return a(data, mask)pair fromfunc(seereturn_mask).The data/mask boundary correspondence rule from
map_overlap()applies ("null"-> mask True; reflect/periodic/nearest -> mask same; constant matching null_value -> mask True; other constants -> mask False). This affects whatfuncsees in the mask block when it opts in toinput_masks=; it does not affect how the output mask is built.Dask invokes
funconce on 0-shape DataArrays (with zero-filled placeholder coords, not real geocoordinates) to derive the output array meta – this happens whether or notdtype=is provided. Passmeta=to skip the call entirely. (Exception: withreturn_mask=True,dtype=is folded into a structuredmeta=and so does skip the 0-shape meta call – seereturn_mask.) During the meta callgeo_block_infoisNoneif the func opts in. Most NumPy / xarray ops handle 0-shape inputs fine. If dask raisesdtype 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; passmeta=instead if your func also can’t tolerate 0-shape inputs (dask silently swallows that crash, but your downstream output meta will be wrong).With
boundary=Noneor"none", edge chunks aren’t padded on the array-boundary side. The per-side overlap split is computed from actual block shape vs base chunk shape and distributed symmetrically; for those edge cases thegeo_block_infoextent may be slightly off-position. For interior chunks and all non-"none"boundaries this is exact.Output null value resolution
When
funcopts in toout_null_value, the wrapper resolves the scalar per-chunk without an extra dtype-inference pass:With
meta=ordtype=set, from that hint (dask leavesblock_info[None]["dtype"]asNonewhenevermeta=is set, which is why the hint is consulted first).Otherwise, from
block_info[None]["dtype"].
During dask’s meta inference call (where
block_infoisNone),out_null_valueis a typed zero of the first input’s dtype so funcs likenp.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 specificout_null_valuescalar, passmeta=to skip dask’s 0-shape meta call entirely;dtype=skips only the additional sample call, not the meta call.Examples
Sum vector-line lengths within a per-cell radius. Pass
meta=so dask skips the 0-shape meta call entirely (nogeo_block_info is Noneguard needed):>>> def length_chunk(xda, *, geo_block_info, gdf, radius): ... xc, yc = geo_block_info.x, geo_block_info.y ... ... ... return out_arr_float32 >>> out = r.geo_map_overlap( ... length_chunk, depth=10, boundary=0, ... meta=np.array((), dtype=np.float32), ... gdf=lines_df, radius=radius, ... )
For dtype-preserving funcs (output dtype equals input dtype), you can skip
meta=and guard on the meta call instead:>>> def smooth(xda, *, geo_block_info=None): ... if geo_block_info is None: ... return xda # safe: same dtype, same shape ... ... # apply per-pixel smoother
See also
raster_tools.geo_map_blocksNo-overlap variant.
raster_tools.map_overlapNon-geo variant; permissive (shape-only check).
raster_tools.Raster.reprojectPer-input alignment to a target grid; pass
r1.geoboxto alignr2tor1.