Interpolation¶
Value resampling between grids and point clouds: regrid, coarsen / refine,
gap-fill, bin scattered observations onto a grid, smooth, and sample a grid
at arbitrary points (e.g. along a satellite track). Grid, SpaceTimeGrid,
and Period are the lightweight target-grid carriers.
Regridding & resolution¶
Three ways to move a field between grids, by what they preserve:
RegridLike—xr.interponto another grid's coordinates. Smooth point values; does not preserve integrals.Coarsen(conservative=True)— integer-factor block averaging with cosine-latitude weights.RegridConservative— first-order conservative regrid onto an arbitrary rectilinear grid (mode="mean"for intensive fields such as concentrations,mode="sum"for extensive per-cell totals such as emissions). Cell bounds are inferred from the centres (midpoints, end cells symmetric) unless CFboundsare present; on the default spherical geometry longitude is periodic with period 360°, so a 0–360 source regrids onto a −180–180 target directly. For an aligned integer factor it reproducesCoarsen(conservative=True).
import numpy as np
from xrops.interpolate import RegridConservative
# 0.1° inventory -> analysis grid; basin totals are preserved.
regrid = RegridConservative(
{"lat": np.arange(40.05, 45.0, 0.1), "lon": np.arange(-5.95, 0.0, 0.1)},
mode="sum",
)
prior = regrid(inventory)
RegridLike
¶
RegridLike(target: Dataset | DataArray, *, dims: tuple[str, ...] = ('lat', 'lon'), method: str = 'linear')
Bases: Operator
Wrap :func:xrops.interpolate.regrid_like — bilinear resample
of the input onto another Dataset's coordinate grid along dims.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
RegridConservative
¶
RegridConservative(target: GridLike, *, dims: tuple[str, str] = ('lat', 'lon'), geometry: Geometry = 'spherical', target_bounds: Mapping[str, BoundsLike] | None = None, mode: RegridMode = 'mean', normalize: Normalize = 'fracarea', skipna: bool = True)
Bases: Operator
Wrap :func:xrops.interpolate.regrid_conservative — first-order
conservative (area-weighted) regrid onto another rectilinear grid.
mode="mean" preserves the area integral of intensive fields;
mode="sum" preserves the total of extensive per-cell fields. See
the primitive for the bounds inference, longitude wrap and NaN rules.
The effective target cell bounds are resolved at construction
(explicit target_bounds > CF bounds attribute > midpoints
between centres) and serialised by :meth:get_config as
{dim: [[lo, hi], ...]}, so an operator rebuilt from its config
regrids onto exactly the same cells.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target
|
GridLike
|
Target grid — a dataset / data array whose coordinates
include |
required |
dims
|
tuple[str, str]
|
The two dims to regrid, |
('lat', 'lon')
|
geometry
|
Geometry
|
|
'spherical'
|
target_bounds
|
Mapping[str, BoundsLike] | None
|
Explicit target cell bounds per dim, as |
None
|
mode
|
RegridMode
|
|
'mean'
|
normalize
|
Normalize
|
|
'fracarea'
|
skipna
|
bool
|
Whether NaN source cells are skipped. |
True
|
Example
>>> import numpy as np, xarray as xr
>>> from xrops.interpolate import RegridConservative
>>> lat, lon = np.arange(-9.5, 10.0, 1.0), np.arange(0.5, 20.0, 1.0)
>>> ds = xr.Dataset(
... {"flux": (("lat", "lon"), np.ones((lat.size, lon.size)))},
... coords={"lat": lat, "lon": lon},
... )
>>> target = {"lat": np.arange(-8.0, 10.0, 4.0), "lon": [5.0, 15.0]}
>>> op = RegridConservative(target)
>>> op(ds)["flux"].shape
(5, 2)
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
Coarsen
¶
Coarsen(factor: dict[str, int], method: str = 'mean', boundary: str = 'trim', conservative: bool = False, lat: str = 'lat')
Bases: Operator
Wrap :func:xrops.interpolate.coarsen.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
Refine
¶
Refine(factor: dict[str, int | float], method: str = 'linear', *, order: int | None = None, lat: str = 'lat', lon: str = 'lon', anti_aliasing: bool | None = None, mode: ResizeMode = 'reflect', cval: float = 0.0)
Bases: Operator
Wrap :func:xrops.interpolate.refine.
If order is set, dispatches to the scikit-image-backed 2-D resize
path and requires factor to include both lat and lon.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
factor
|
dict[str, int | float]
|
Per-dimension refinement factors. |
required |
method
|
str
|
Interpolation method for the default |
'linear'
|
order
|
int | None
|
Optional scikit-image spline order (0..5). When set, uses the 2-D resize path. |
None
|
lat
|
str
|
Latitude-like dimension name for the 2-D resize path. |
'lat'
|
lon
|
str
|
Longitude-like dimension name for the 2-D resize path. |
'lon'
|
anti_aliasing
|
bool | None
|
Anti-aliasing setting passed to scikit-image. |
None
|
mode
|
ResizeMode
|
Boundary mode for scikit-image ( |
'reflect'
|
cval
|
float
|
Fill value used when |
0.0
|
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
ResampleTime
¶
ResampleTime(freq: str = '1D', method: str = 'mean', time: str = 'time', interp_method: Literal['linear', 'nearest', 'cubic'] = 'linear')
Bases: Operator
Wrap :func:xrops.interpolate.resample_time.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
freq
|
str
|
Pandas-style frequency string (e.g. |
'1D'
|
method
|
str
|
Zero-argument aggregation method ( |
'mean'
|
time
|
str
|
Name of the time dimension. |
'time'
|
interp_method
|
Literal['linear', 'nearest', 'cubic']
|
Interpolation method forwarded to xarray when
|
'linear'
|
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
Gap-filling¶
FillNaNSpatial
¶
Bases: Operator
Wrap :func:xrops.interpolate.fillnan_spatial.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
method
|
str
|
|
'linear'
|
lon
|
str
|
Name of the longitude coordinate. |
'lon'
|
lat
|
str
|
Name of the latitude coordinate. |
'lat'
|
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
FillNaNTemporal
¶
Bases: Operator
Wrap :func:xrops.interpolate.fillnan_temporal.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
method
|
str
|
Any method accepted by xarray's |
'linear'
|
time
|
str
|
Name of the time dimension. |
'time'
|
max_gap
|
Any
|
Maximum time delta to interpolate across; gaps wider than this stay NaN. |
None
|
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
FillNaNLaplacian
¶
FillNaNLaplacian(*, max_iter: int = 1000, tol: float = 0.0001, relaxation: float = 1.0, boundary: str = 'reflect', lon: str = 'lon', lat: str = 'lat')
Bases: Operator
Wrap :func:xrops.interpolate.fillnan_laplacian.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
max_iter
|
int
|
Maximum red/black Gauss-Seidel sweeps. |
1000
|
tol
|
float
|
Absolute convergence tolerance for missing-cell updates. |
0.0001
|
relaxation
|
float
|
SOR relaxation factor. |
1.0
|
boundary
|
str
|
|
'reflect'
|
lon
|
str
|
Name of the longitude dimension. |
'lon'
|
lat
|
str
|
Name of the latitude dimension. |
'lat'
|
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
FillNaNBiharmonic
¶
Bases: Operator
Wrap :func:xrops.interpolate.fillnan_biharmonic.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lon
|
str
|
Name of the longitude dimension. |
'lon'
|
lat
|
str
|
Name of the latitude dimension. |
'lat'
|
split_into_regions
|
bool
|
Forwarded to scikit-image. When |
True
|
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
FillNaNRBF
¶
FillNaNRBF(kernel: str = 'thin_plate_spline', neighbors: int | None = 32, lon: str = 'lon', lat: str = 'lat')
Bases: Operator
Wrap :func:xrops.interpolate.fillnan_rbf.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
kernel
|
str
|
RBF kernel passed to
:class: |
'thin_plate_spline'
|
neighbors
|
int | None
|
Number of nearest neighbors used per query point;
|
32
|
lon
|
str
|
Name of the longitude coordinate. |
'lon'
|
lat
|
str
|
Name of the latitude coordinate. |
'lat'
|
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
FillNaNIDW
¶
FillNaNIDW(*, lon: str = 'lon', lat: str = 'lat', k: int = 8, power: float = 2.0, metric: Metric = 'euclidean', max_distance: float | None = None, eps: float = 1e-12)
Bases: Operator
Wrap :func:xrops.interpolate.fillnan_idw.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lon
|
str
|
Name of the longitude coordinate and dimension. |
'lon'
|
lat
|
str
|
Name of the latitude coordinate and dimension. |
'lat'
|
k
|
int
|
Number of nearest finite neighbours to use. |
8
|
power
|
float
|
Inverse-distance exponent. |
2.0
|
metric
|
Metric
|
|
'euclidean'
|
max_distance
|
float | None
|
Optional neighbour cutoff (radians for
|
None
|
eps
|
float
|
Small non-negative offset for non-exact distance weights. |
1e-12
|
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
FillNaNClimatology
¶
FillNaNClimatology(*, time: str = 'time', group: Literal['month', 'dayofyear', 'season'] = 'month', residual: Literal['zero', 'linear'] = 'linear', min_count: int = 1)
Bases: Operator
Wrap :func:xrops.interpolate.fillnan_climatology.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
time
|
str
|
Name of the time dimension. |
'time'
|
group
|
Literal['month', 'dayofyear', 'season']
|
Calendar grouping used to compute the climatology. |
'month'
|
residual
|
Literal['zero', 'linear']
|
|
'linear'
|
min_count
|
int
|
Minimum finite observations required for each climatology group. |
1
|
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
Binning & gridding scattered data¶
Bin2D
¶
Bin2D(grid: Grid, statistic: str = 'mean', lon: str = 'lon', lat: str = 'lat')
Bases: Operator
Wrap :func:xrops.interpolate.bin_2d.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
KDEToGrid
¶
KDEToGrid(grid: Grid, *, bandwidth: float | str = 'scott', kernel: str = 'gaussian', metric: str = 'euclidean', algorithm: str = 'auto', output: str = 'density', rtol: float = 0.0001)
Bases: Operator
Wrap :func:xrops.interpolate.kde_to_grid.
Expects (lons, lats) or (lons, lats, weights) as input.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
PointsToGrid
¶
PointsToGrid(grid: Grid, statistic: str = 'mean')
Bases: Operator
Wrap :func:xrops.interpolate.points_to_grid.
Expects a 3-tuple (lons, lats, values) as input.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
IDWToGrid
¶
IDWToGrid(grid: Grid, *, k: int = 8, power: float = 2.0, metric: Metric = 'euclidean', max_distance: float | None = None, eps: float = 1e-12)
Bases: Operator
Wrap :func:xrops.interpolate.idw_to_grid.
Expects a 3-tuple (lons, lats, values) as input.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
IDWToPoints
¶
IDWToPoints(dst_lons: ndarray, dst_lats: ndarray, *, k: int = 8, power: float = 2.0, metric: Metric = 'euclidean', max_distance: float | None = None, eps: float = 1e-12)
Bases: Operator
Wrap :func:xrops.interpolate.idw_to_points.
Expects source (lons, lats, values) as input.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
Smoothing & filtering¶
GaussianSmooth
¶
Bases: Operator
Wrap :func:xrops.interpolate._src.smooth.gaussian_smooth.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
GaussianSmoothMasked
¶
GaussianSmoothMasked(*, dim: str | Sequence[str], sigma: float | Mapping[str, float], truncate: float = 4.0, mode: str = 'reflect', nan_aware: bool = True, min_weight: float = 1e-06)
Bases: Operator
Wrap :func:xrops.interpolate._src.smooth.gaussian_smooth_masked.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
MovingAverage
¶
Bases: Operator
Wrap :func:xrops.interpolate._src.smooth.moving_average.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
LowpassFilter
¶
Bases: Operator
Wrap :func:xrops.interpolate._src.smooth.lowpass_filter.
For btype in {"low", "high", "lowpass", "highpass"} cutoff
is a scalar in (0, 1). For btype in
{"bandpass", "bandstop"} it is a length-2 sequence. Validation
is delegated to the private kernel.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
Mask cleanup¶
CleanMask
¶
CleanMask(*, fill_holes_area: int | None = 4, drop_objects_area: int | None = None, closing_footprint: Footprint | None = None, opening_footprint: Footprint | None = None, lon: str = 'lon', lat: str = 'lat')
Bases: Operator
Convenience operator for the common mask-cleanup pipeline.
The fixed order is remove small holes, remove small objects, binary closing, then binary opening; each step is opt-in through its keyword.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fill_holes_area
|
int | None
|
Optional hole area threshold. |
4
|
drop_objects_area
|
int | None
|
Optional object area threshold. |
None
|
closing_footprint
|
Footprint | None
|
Optional binary-closing footprint. |
None
|
opening_footprint
|
Footprint | None
|
Optional binary-opening footprint. |
None
|
lon
|
str
|
Longitude dimension name. |
'lon'
|
lat
|
str
|
Latitude dimension name. |
'lat'
|
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
MaskBinaryOpening
¶
Bases: Operator
Operator wrapper for binary opening inside Sequential pipelines.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
footprint
|
Footprint
|
Structuring element specification. |
1
|
lon
|
str
|
Longitude dimension name. |
'lon'
|
lat
|
str
|
Latitude dimension name. |
'lat'
|
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
MaskBinaryClosing
¶
Bases: Operator
Operator wrapper for binary closing inside Sequential pipelines.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
footprint
|
Footprint
|
Structuring element specification. |
1
|
lon
|
str
|
Longitude dimension name. |
'lon'
|
lat
|
str
|
Latitude dimension name. |
'lat'
|
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
MaskRemoveSmallHoles
¶
Bases: Operator
Operator wrapper for filling small unmasked holes in mask pipelines.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
area
|
int
|
False regions smaller than this pixel count are filled. |
4
|
lon
|
str
|
Longitude dimension name. |
'lon'
|
lat
|
str
|
Latitude dimension name. |
'lat'
|
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
MaskRemoveSmallObjects
¶
Bases: Operator
Operator wrapper for dropping small masked specks in mask pipelines.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
area
|
int
|
True regions smaller than this pixel count are dropped. |
4
|
lon
|
str
|
Longitude dimension name. |
'lon'
|
lat
|
str
|
Latitude dimension name. |
'lat'
|
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
Point sampling¶
SampleAtPoints
¶
SampleAtPoints(points: Dataset, *, coords: tuple[str, ...] = ('lat', 'lon'), method: Method = 'linear', fill_value: float | None = nan, bounds_error: bool = False, point_dim: str = 'points')
Bases: Operator
Wrap :func:xrops.interpolate.sample_at_points.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
AlongTrack
¶
AlongTrack(track: Dataset, *, coords: tuple[str, ...] = ('time', 'lat', 'lon'), method: Method = 'linear', fill_value: float | None = nan, point_dim: str = 'points')
Bases: Operator
Wrap :func:xrops.interpolate.along_track.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
Vertical & axis remapping¶
RemapAxis replaces one dimension of every numeric variable by a new
axis of target values; the vertical presets pin conventional source /
target names. Two options cover terrain-following (WRF η) and hybrid
(ERA5 model-level) grids, whose source levels vary per column:
source_coords=names a coordinate on the input — e.g.z_agl(time, level, y, x)— that supplies the source axis values for every column. Each column must be strictly monotone along the source dim (ascending or descending, and the orientation may differ between columns).extrapolate="nearest"holds each column's end value beyond its own range instead of the default"nan". An analysis level that sits below the lowest model level of a column thus gets the lowest-level value.
import numpy as np
from xrops.interpolate import ToHeight
# ds: (time, level, y, x) model-level fields plus a 4-D ``z_agl`` coordinate.
to_height = ToHeight(
np.array([10.0, 50.0, 100.0, 250.0]),
source_coords="z_agl",
extrapolate="nearest",
)
out = to_height(ds) # ``level`` -> ``height``; variables without ``level`` pass through
Chunked inputs stay lazy along every dim except the source dim, which must
sit in a single chunk. With a 1-D dimension coordinate and the default
extrapolate="nan" the operator is unchanged from earlier releases.
RemapAxis
¶
RemapAxis(source_axis: str, target_axis: DataArray | ndarray | list, *, target_name: str | None = None, method: str = 'linear', source_coords: str | None = None, extrapolate: Extrapolate = 'nan')
Bases: Operator
Generic axis remapping (D12).
Replaces the source_axis dimension in the input Dataset with a
new dimension whose coordinate values are target_axis. Every
numeric variable that carries source_axis is interpolated onto
the target axis.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source_axis
|
str
|
Name of the existing dimension to remap. |
required |
target_axis
|
DataArray | ndarray | list
|
Target coordinate values. If an :class: |
required |
target_name
|
str | None
|
Optional explicit new dim name. |
None
|
method
|
str
|
|
'linear'
|
source_coords
|
str | None
|
Name of a coordinate on the input supplying
per-column source axis values (e.g. |
None
|
extrapolate
|
Extrapolate
|
|
'nan'
|
Example
Model-level temperature with a 4-D height-above-ground coordinate onto fixed heights, holding the end values beyond each column:
>>> import numpy as np, xarray as xr
>>> from xrops.interpolate import ToHeight
>>> level = np.arange(4)[None, :, None, None]
>>> z_agl = 20.0 * (level + 1) + np.zeros((2, 4, 3, 3))
>>> ds = xr.Dataset(
... {"t": (("time", "level", "y", "x"), 300.0 - 0.01 * z_agl)},
... coords={"z_agl": (("time", "level", "y", "x"), z_agl)},
... )
>>> heights = np.array([10.0, 50.0, 90.0])
>>> op = ToHeight(heights, source_coords="z_agl", extrapolate="nearest")
>>> op(ds)["t"].dims
('time', 'height', 'y', 'x')
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
ToHeight
¶
ToHeight(target_axis: DataArray | ndarray | list, *, source_axis: str | None = None, target_name: str | None = None, method: str = 'linear', source_coords: str | None = None, extrapolate: Extrapolate = 'nan')
Bases: _VerticalPreset
Remap a pressure or hybrid axis to geometric height.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
ToPressureLevels
¶
ToPressureLevels(target_axis: DataArray | ndarray | list, *, source_axis: str | None = None, target_name: str | None = None, method: str = 'linear', source_coords: str | None = None, extrapolate: Extrapolate = 'nan')
Bases: _VerticalPreset
Remap a height/depth axis to standard pressure levels.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
ToSigma
¶
ToSigma(target_axis: DataArray | ndarray | list, *, source_axis: str | None = None, target_name: str | None = None, method: str = 'linear', source_coords: str | None = None, extrapolate: Extrapolate = 'nan')
Bases: _VerticalPreset
Remap a depth axis to terrain-following sigma values.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
FromSigma
¶
FromSigma(target_axis: DataArray | ndarray | list, *, source_axis: str | None = None, target_name: str | None = None, method: str = 'linear', source_coords: str | None = None, extrapolate: Extrapolate = 'nan')
Bases: _VerticalPreset
Remap a sigma axis back to a fixed depth grid.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
ToIsopycnal
¶
ToIsopycnal(target_axis: DataArray | ndarray | list, *, source_axis: str | None = None, target_name: str | None = None, method: str = 'linear', source_coords: str | None = None, extrapolate: Extrapolate = 'nan')
Bases: _VerticalPreset
Remap a depth axis to potential-density (isopycnal) levels.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
ToPhase
¶
Bases: Operator
Fold a time axis onto a phase axis by binning + averaging.
Phase is computed as ((t - epoch) / period) mod 1 and binned
into n_bins evenly-spaced bins on [0, 1).
Parameters¶
time_dim Name of the time dimension. period Length of one cycle, in the same units as the time coordinate. n_bins Number of phase bins. epoch Reference time at which phase = 0.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/operators.py
Functional primitives (Layer 0)¶
These pure functions back the operators above; each takes xr.DataArray/xr.Dataset and a dim: argument.
regrid_like
¶
regrid_like(ds: Dataset | DataArray, target: Dataset | DataArray, *, dims: Iterable[str] = ('lat', 'lon'), method: str = 'linear') -> Dataset | DataArray
Resample ds onto target's coordinates along dims.
Thin :meth:xr.Dataset.interp wrapper for the common
"regrid model output to observation grid" step. Coordinates listed
in dims must exist on both ds and target; values along
other dims pass through.
Assumes ds and target share a coordinate space — if they are
in different CRSs, use :func:xrops.geom.reproject_match instead,
which is CRS-aware and matches target's pixel grid exactly.
Interpolation does not preserve integrals; for fluxes, inventories
and other fields whose area integral must survive the regrid use
:func:regrid_conservative.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/grid_to_grid.py
regrid_conservative
¶
regrid_conservative(ds: Dataset | DataArray, target: GridLike, *, dims: tuple[str, str] = ('lat', 'lon'), geometry: Geometry = 'spherical', bounds: Mapping[str, BoundsLike] | None = None, target_bounds: Mapping[str, BoundsLike] | None = None, mode: RegridMode = 'mean', normalize: Normalize = 'fracarea', skipna: bool = True) -> Dataset | DataArray
First-order conservative regrid along two rectilinear dims.
Source cells \(i\) (area \(a_i\), value \(f_i\)) and target cells \(j\) overlap
on areas \(w_{ij} = |c_i \cap c_j|\). Because both grids are rectilinear
the overlap factorises into one 1-D weight matrix per axis
(:func:overlap_weights_1d), so the whole regrid is two matrix
products per field:
mode="mean" preserves intensive fields (concentration, mixing
ratio, flux density). With normalize="destarea" the area integral
\(\sum_j A_j \bar f_j = \sum_i a_i f_i\) is conserved whenever the target
covers the source; with normalize="fracarea" (default) it is
conserved only over target cells that are fully covered by unmasked
source cells — a partially covered or partially masked target cell
holds the mean of its valid part, which over-counts that cell's
contribution to the integral. mode="sum" preserves extensive
per-cell fields (mass, emission per cell): each source cell's value
is split among the target cells in proportion to the overlapped
fraction, so \(\sum_j F_j = \sum_i f_i\).
On a "spherical" geometry dims[0] is latitude and dims[1]
longitude, both in degrees, and cell areas are \(R^2 \Delta\lambda
(\sin\varphi_+ - \sin\varphi_-)\) (\(R\) cancels). Longitude is periodic
with period 360 degrees: the target bounds are unwrapped into the
source's range, so a source on 0–360 regrids onto a target on
−180–180 (and vice versa) without pre-rolling. On a "planar"
geometry areas are \(\Delta x\,\Delta y\) in coordinate units and nothing
is periodic.
Cell bounds default to the midpoints between centres, with the end
cells extrapolated symmetrically. A CF bounds attribute on a
coordinate (naming an (n, 2) variable) is honoured, and bounds
/ target_bounds override both, as (n + 1,) edges or CF
(n, 2) bounds per dim. CF bounds need not be contiguous: cells
may leave gaps (or overlap), and only the overlap with each cell's
own (lo, hi) interval counts.
Missing values: with skipna=True (default) NaN source cells carry
no weight. normalize="fracarea" divides by the valid overlap, so
a partially masked (or partially covered) target cell keeps the mean
of its valid part; "destarea" divides by the full target cell area
(ESMF / xESMF naming), scaling the mean down by the valid fraction.
A target cell with no valid overlap is NaN in every mode. With
skipna=False any NaN source cell that touches a target cell makes
it NaN. Complex fields are regridded component-wise (a cell is valid
when both parts are finite) and stay complex.
Extra dims (time, level) broadcast; dask inputs stay lazy
along them, while the two regridded dims must each sit in a single
chunk. Datasets are regridded per variable: variables without either
dim pass through, CF bounds variables of the source grid are dropped
(those of the target grid, when it is a dataset / data array carrying
them, are attached), and a variable carrying only one of the two dims
raises. A data array output has no room for a bounds variable, so its
coordinates carry no dangling bounds attribute.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ds
|
Dataset | DataArray
|
Source dataset or data array with 1-D, strictly monotone
coordinates for both |
required |
target
|
GridLike
|
Target grid — a dataset / data array whose coordinates
include |
required |
dims
|
tuple[str, str]
|
The two dims to regrid, |
('lat', 'lon')
|
geometry
|
Geometry
|
|
'spherical'
|
bounds
|
Mapping[str, BoundsLike] | None
|
Explicit source cell bounds per dim. |
None
|
target_bounds
|
Mapping[str, BoundsLike] | None
|
Explicit target cell bounds per dim. |
None
|
mode
|
RegridMode
|
|
'mean'
|
normalize
|
Normalize
|
|
'fracarea'
|
skipna
|
bool
|
Whether NaN source cells are skipped (default) or propagate. |
True
|
Returns:
| Type | Description |
|---|---|
Dataset | DataArray
|
|
Dataset | DataArray
|
along |
Dataset | DataArray
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If an option is unknown, a dim or its coordinate is missing, a coordinate is not strictly monotone, bounds have the wrong shape, longitude bounds span more than one period, a dask input is chunked along a regridded dim, or a Dataset variable carries only one of the two dims. |
Example
Move a 1-degree per-cell emission inventory (0–360 longitudes) onto a 2-degree grid on −180–180; the global total is preserved to round-off:
>>> import numpy as np, xarray as xr
>>> from xrops.interpolate import regrid_conservative
>>> lat, lon = np.arange(-89.5, 90.0, 1.0), np.arange(0.5, 360.0, 1.0)
>>> rng = np.random.default_rng(0)
>>> emis = xr.DataArray(
... rng.uniform(0.0, 1.0, size=(lat.size, lon.size)),
... dims=("lat", "lon"),
... coords={"lat": lat, "lon": lon},
... )
>>> target = {
... "lat": np.arange(-89.0, 90.0, 2.0),
... "lon": np.arange(-179.0, 180.0, 2.0),
... }
>>> out = regrid_conservative(emis, target, mode="sum")
>>> out.sizes
Frozen({'lat': 90, 'lon': 180})
>>> bool(np.isclose(float(out.sum()), float(emis.sum()), rtol=1e-12))
True
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/grid_to_grid.py
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 | |
overlap_weights_1d
¶
overlap_weights_1d(src_bounds: Float[ndarray, 'n+1'], tgt_bounds: Float[ndarray, 'm+1']) -> Float[ndarray, 'm n']
Overlap length of each source interval with each target interval.
Entry (j, i) is max(0, min(hi_i, hi_j) - max(lo_i, lo_j)) for
source interval i and target interval j. Bounds may be
ascending or descending (each interval is normalised to lo < hi),
and in any unit — pass sin(lat) bounds to obtain spherical
latitude weights.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
src_bounds
|
Float[ndarray, 'n+1']
|
|
required |
tgt_bounds
|
Float[ndarray, 'm+1']
|
|
required |
Returns:
| Type | Description |
|---|---|
Float[ndarray, 'm n']
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If either bounds array is not 1-D with at least two edges. |
Example
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/grid_to_grid.py
coarsen
¶
coarsen(ds: Dataset | DataArray, factor: dict[str, int], method: str = 'mean', boundary: str = 'trim') -> Dataset | DataArray
Coarsen ds along one or more dimensions by integer factors.
Thin wrapper around xr.Dataset.coarsen.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/grid_to_grid.py
coarsen_conservative
¶
coarsen_conservative(ds: Dataset | DataArray, factor: Mapping[str, int], *, lat: str = 'lat', boundary: Literal['trim', 'exact', 'pad'] = 'trim') -> Dataset | DataArray
Area-weighted coarsen using cosine-of-latitude weights.
This preserves cosine-latitude-weighted integrals for aligned, integer
coarsening of regular latitude/longitude grids. Non-latitude dimensions
use uniform weights, and missing values are skipped with weights
renormalized within each block. For non-integer factors or an
arbitrary rectilinear target grid use :func:regrid_conservative,
which reduces to this function for aligned integer factors.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ds
|
Dataset | DataArray
|
Dataset or data array to coarsen. |
required |
factor
|
Mapping[str, int]
|
Mapping from dimension name to integer coarsen factor. |
required |
lat
|
str
|
Latitude dimension name. Values are expected to be cell centers in degrees within the usual [-90, 90] latitude range. |
'lat'
|
boundary
|
Literal['trim', 'exact', 'pad']
|
Boundary mode forwarded to :meth: |
'trim'
|
Returns:
| Type | Description |
|---|---|
Dataset | DataArray
|
Coarsened dataset or data array with the same dimension names. |
Examples:
>>> coarsen_conservative(da, {"lat": 4, "lon": 4})
>>> coarsen_conservative(ds, {"latitude": 2}, lat="latitude")
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/grid_to_grid.py
refine
¶
refine(ds: Dataset | DataArray, factor: dict[str, int], method: str = 'linear') -> Dataset | DataArray
Refine ds along one or more dimensions by integer factors.
Produces a factor[dim]-times-denser grid along each dimension
via :meth:xr.Dataset.interp.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/grid_to_grid.py
resample_time
¶
resample_time(da: DataArray, freq: str = '1D', method: str = 'mean', time: str = 'time', *, interp_method: Literal['linear', 'nearest', 'cubic'] = 'linear') -> DataArray
Resample a DataArray along the time axis via xarray's built-in resampler.
Per the PR β primitive-flip, this primitive is DataArray-only.
The Layer-1 ResampleTime operator handles ds.map-style
dispatch when a Dataset is supplied.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
da
|
DataArray
|
Input DataArray. |
required |
freq
|
str
|
Pandas-style frequency string (e.g. |
'1D'
|
method
|
str
|
Zero-argument aggregation method; one of |
'mean'
|
time
|
str
|
Name of the time dimension. |
'time'
|
interp_method
|
Literal['linear', 'nearest', 'cubic']
|
Interpolation method forwarded to xarray when
|
'linear'
|
Returns:
| Type | Description |
|---|---|
DataArray
|
Resampled DataArray. |
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/resample.py
fillnan_spatial
¶
fillnan_spatial(da: DataArray, method: str = 'linear', lon: str = 'lon', lat: str = 'lat') -> DataArray
Fill NaNs in a 2-D lon/lat field by scattered interpolation.
Operates slice-by-slice along any leading dimensions. Uses
:func:scipy.interpolate.griddata over the non-NaN support.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
da
|
DataArray
|
Input DataArray with at least |
required |
method
|
str
|
|
'linear'
|
lon
|
str
|
Name of the longitude coordinate. |
'lon'
|
lat
|
str
|
Name of the latitude coordinate. |
'lat'
|
Returns:
| Type | Description |
|---|---|
DataArray
|
Same-shaped DataArray with NaNs filled where interpolation is |
DataArray
|
possible; points outside the convex hull of non-NaN samples stay |
DataArray
|
NaN (except for |
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/gap_fill.py
fillnan_temporal
¶
fillnan_temporal(ds: Dataset | DataArray, method: str = 'linear', time: str = 'time', max_gap: Any = None) -> Dataset | DataArray
Interpolate NaNs along the time dimension.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ds
|
Dataset | DataArray
|
Input Dataset or DataArray. |
required |
method
|
str
|
Any method accepted by xarray's |
'linear'
|
time
|
str
|
Name of the time dimension. |
'time'
|
max_gap
|
Any
|
Maximum time delta to interpolate across; gaps wider than this stay NaN. |
None
|
Returns:
| Type | Description |
|---|---|
Dataset | DataArray
|
Same-shaped container with temporal NaNs interpolated. |
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/gap_fill.py
fillnan_laplacian
¶
fillnan_laplacian(da: DataArray, *, max_iter: int = 1000, tol: float = 0.0001, relaxation: float = 1.0, boundary: str = 'reflect', lon: str = 'lon', lat: str = 'lat') -> DataArray
Fill NaN cells via iterative harmonic relaxation.
Solves ∇²u = 0 on the masked region with Dirichlet boundary values
from finite cells. Iteration stops when the maximum absolute update
over missing cells is below tol or after max_iter iterations.
All-NaN and all-finite slices pass through unchanged.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
da
|
DataArray
|
Input DataArray with at least |
required |
max_iter
|
int
|
Maximum red/black Gauss-Seidel sweeps. |
1000
|
tol
|
float
|
Absolute convergence tolerance for missing-cell updates. |
0.0001
|
relaxation
|
float
|
SOR relaxation factor. |
1.0
|
boundary
|
str
|
|
'reflect'
|
lon
|
str
|
Name of the longitude dimension. |
'lon'
|
lat
|
str
|
Name of the latitude dimension. |
'lat'
|
Returns:
| Type | Description |
|---|---|
DataArray
|
Same-shaped DataArray with NaNs filled slice-by-slice along any |
DataArray
|
leading dimensions. |
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/gap_fill.py
fillnan_biharmonic
¶
fillnan_biharmonic(da: DataArray, *, lon: str = 'lon', lat: str = 'lat', mask: DataArray | None = None, split_into_regions: bool = True) -> DataArray
Fill NaNs in a 2-D lon/lat field by biharmonic inpainting.
Operates slice-by-slice along any leading dimensions and wraps
:func:skimage.restoration.inpaint_biharmonic. The optional mask
follows scikit-image semantics: True marks pixels to fill.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
da
|
DataArray
|
Input DataArray with at least |
required |
lon
|
str
|
Name of the longitude dimension. |
'lon'
|
lat
|
str
|
Name of the latitude dimension. |
'lat'
|
mask
|
DataArray | None
|
Optional explicit boolean mask. If |
None
|
split_into_regions
|
bool
|
Forwarded to scikit-image. When |
True
|
Returns:
| Type | Description |
|---|---|
DataArray
|
Same-shaped DataArray with masked pixels inpainted. Fully masked |
DataArray
|
slices pass through unchanged. |
Raises:
| Type | Description |
|---|---|
ImportError
|
If scikit-image is not installed. |
ValueError
|
If |
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/gap_fill.py
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 | |
fillnan_rbf
¶
fillnan_rbf(da: DataArray, kernel: str = 'thin_plate_spline', neighbors: int | None = 32, lon: str = 'lon', lat: str = 'lat') -> DataArray
Fill NaNs using a radial-basis-function interpolator.
Uses :class:scipy.interpolate.RBFInterpolator. More expensive than
fillnan_spatial but extrapolates smoothly and respects the
global shape of the signal.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/gap_fill.py
fillnan_idw
¶
fillnan_idw(da: DataArray, *, lon: str = 'lon', lat: str = 'lat', k: int = 8, power: float = 2.0, metric: Metric = 'euclidean', max_distance: float | None = None, eps: float = 1e-12) -> DataArray
Fill NaNs in a 2-D lon/lat field by IDW from finite neighbours.
Operates slice-by-slice along any leading dimensions. For
metric="haversine", coordinate values are interpreted as lon/lat
degrees and converted to radians internally; max_distance is in
radians. For metric="euclidean", distances are measured in array-index
space (column/row positions), not coordinate-value space.
This differs from :func:idw_to_points and :func:idw_to_grid, whose
Euclidean mode uses source and target lon/lat coordinate values directly.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
da
|
DataArray
|
Input DataArray with |
required |
lon
|
str
|
Name of the longitude coordinate and dimension. |
'lon'
|
lat
|
str
|
Name of the latitude coordinate and dimension. |
'lat'
|
k
|
int
|
Number of nearest finite neighbours to use. |
8
|
power
|
float
|
Inverse-distance exponent. |
2.0
|
metric
|
Metric
|
|
'euclidean'
|
max_distance
|
float | None
|
Optional neighbour cutoff. For |
None
|
eps
|
float
|
Small non-negative offset for non-exact distance weights. |
1e-12
|
Returns:
| Type | Description |
|---|---|
DataArray
|
Same-shaped DataArray with NaNs filled where finite neighbours are |
DataArray
|
available. |
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/knn.py
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 | |
fillnan_climatology
¶
fillnan_climatology(da: DataArray, *, time: str = 'time', group: Literal['month', 'dayofyear', 'season'] = 'month', residual: Literal['zero', 'linear'] = 'linear', min_count: int = 1) -> DataArray
Fill temporal NaNs from a climatological mean.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
da
|
DataArray
|
Input DataArray with a datetime-like time dimension. |
required |
time
|
str
|
Name of the time dimension. |
'time'
|
group
|
Literal['month', 'dayofyear', 'season']
|
Calendar grouping used to compute the climatology. |
'month'
|
residual
|
Literal['zero', 'linear']
|
|
'linear'
|
min_count
|
int
|
Minimum finite observations required for each climatology group. |
1
|
Returns:
| Type | Description |
|---|---|
DataArray
|
Same-shaped DataArray with fillable temporal NaNs replaced. |
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/gap_fill.py
bin_2d
¶
bin_2d(da: DataArray, grid: Grid, statistic: str = 'mean', lon: str = 'lon', lat: str = 'lat') -> DataArray
Bin a scattered DataArray onto a regular lon/lat grid.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
da
|
DataArray
|
Input DataArray whose non-NaN samples will be binned. Must
carry 1-D |
required |
grid
|
Grid
|
Target :class: |
required |
statistic
|
str
|
|
'mean'
|
lon
|
str
|
Name of the longitude coordinate on |
'lon'
|
lat
|
str
|
Name of the latitude coordinate on |
'lat'
|
Returns:
| Type | Description |
|---|---|
DataArray
|
DataArray on the grid with |
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/binning.py
histogram_2d
¶
histogram_2d(da: DataArray, grid: Grid, lon: str = 'lon', lat: str = 'lat') -> DataArray
2-D histogram count on grid.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/binning.py
kde_to_grid
¶
kde_to_grid(lons: Float[ndarray, 'n'], lats: Float[ndarray, 'n'], grid: Grid, *, weights: Float[ndarray, 'n'] | None = None, bandwidth: float | BandwidthRule = 'scott', kernel: KernelName = 'gaussian', metric: MetricName = 'euclidean', algorithm: AlgorithmName = 'auto', output: OutputMode = 'density', rtol: float = 0.0001) -> DataArray
Evaluate a KDE of scattered lon/lat points on grid.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lons
|
Float[ndarray, 'n']
|
1-D point longitudes. Non-finite entries are dropped. |
required |
lats
|
Float[ndarray, 'n']
|
1-D point latitudes. Non-finite entries are dropped. |
required |
grid
|
Grid
|
Target :class: |
required |
weights
|
Float[ndarray, 'n'] | None
|
Optional per-point weights passed to
:class: |
None
|
bandwidth
|
float | BandwidthRule
|
Positive float, or |
'scott'
|
kernel
|
KernelName
|
sklearn KDE kernel name. |
'gaussian'
|
metric
|
MetricName
|
|
'euclidean'
|
algorithm
|
AlgorithmName
|
sklearn tree backend. |
'auto'
|
output
|
OutputMode
|
Output normalization. See semantics below. |
'density'
|
rtol
|
float
|
Relative tolerance for sklearn tree pruning. |
0.0001
|
Output modes
"density" is a probability density that integrates to 1 over the
grid (per unit area). For metric="haversine" the output is
renormalized to integrate to 1 on the sphere using
cos(lat) * dlat * dlon (steradian) cell areas, since sklearn's
KernelDensity only normalizes correctly for the Euclidean metric.
"counts_per_area" is the expected per-unit-area count
(density * n_eff). Integrating over the grid recovers the input
point count (or weight sum). Comparable across grids of different
resolutions.
"counts" is the expected per-cell count
(density * n_eff * cell_area). Summing over the grid recovers
the input point count (or weight sum). Scales with cell size, so it
is only comparable across grids of identical resolution.
Returns:
| Type | Description |
|---|---|
DataArray
|
DataArray on |
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/points_to_grid.py
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 | |
points_to_grid
¶
points_to_grid(lons: Float[ndarray, 'n'], lats: Float[ndarray, 'n'], values: Float[ndarray, 'n'], grid: Grid, statistic: str = 'mean') -> DataArray
Bin raw (lon, lat, value) tuples onto grid.
Thin wrapper around :func:scipy.stats.binned_statistic_2d that
doesn't require constructing a scattered DataArray first.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/points_to_grid.py
idw_to_grid
¶
idw_to_grid(lons: Float[ndarray, '...'], lats: Float[ndarray, '...'], values: Float[ndarray, '...'], grid: Grid, *, k: int = 8, power: float = 2.0, metric: Metric = 'euclidean', max_distance: float | None = None, eps: float = 1e-12) -> DataArray
Inverse-distance interpolate scattered points onto grid.
For metric="haversine", max_distance is interpreted in radians
(for example, 50 / 6371 for approximately 50 km).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lons
|
Float[ndarray, '...']
|
Source longitudes. |
required |
lats
|
Float[ndarray, '...']
|
Source latitudes. |
required |
values
|
Float[ndarray, '...']
|
Source values. |
required |
grid
|
Grid
|
Target regular lon/lat grid. |
required |
k
|
int
|
Number of nearest finite source neighbours to use. |
8
|
power
|
float
|
Inverse-distance exponent. |
2.0
|
metric
|
Metric
|
|
'euclidean'
|
max_distance
|
float | None
|
Optional neighbour cutoff. For |
None
|
eps
|
float
|
Small non-negative offset for non-exact distance weights. |
1e-12
|
Returns:
| Type | Description |
|---|---|
DataArray
|
DataArray with |
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/knn.py
idw_to_points
¶
idw_to_points(src_lons: Float[ndarray, '...'], src_lats: Float[ndarray, '...'], src_values: Float[ndarray, '...'], dst_lons: Float[ndarray, '...'], dst_lats: Float[ndarray, '...'], *, k: int = 8, power: float = 2.0, metric: Metric = 'euclidean', max_distance: float | None = None, eps: float = 1e-12) -> Float[ndarray, '...']
Inverse-distance interpolate scattered samples onto target points.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
src_lons
|
Float[ndarray, '...']
|
Source longitudes. |
required |
src_lats
|
Float[ndarray, '...']
|
Source latitudes. |
required |
src_values
|
Float[ndarray, '...']
|
Source values. |
required |
dst_lons
|
Float[ndarray, '...']
|
Target longitudes. |
required |
dst_lats
|
Float[ndarray, '...']
|
Target latitudes. |
required |
k
|
int
|
Number of nearest finite source neighbours to use. |
8
|
power
|
float
|
Inverse-distance exponent. |
2.0
|
metric
|
Metric
|
|
'euclidean'
|
max_distance
|
float | None
|
Optional neighbour cutoff. For |
None
|
eps
|
float
|
Small non-negative offset for non-exact distance weights. |
1e-12
|
Returns:
| Type | Description |
|---|---|
Float[ndarray, '...']
|
NumPy array matching the broadcast shape of |
Float[ndarray, '...']
|
|
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/knn.py
gaussian_smooth
¶
Gaussian smoothing along dim with standard deviation sigma.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/smooth.py
gaussian_smooth_masked
¶
gaussian_smooth_masked(da: DataArray, *, dim: str | Sequence[str], sigma: float | Mapping[str, float], truncate: float = 4.0, mode: str = 'reflect', nan_aware: bool = True, min_weight: float = 1e-06) -> DataArray
NaN-aware N-D Gaussian smoothing along one or more dimensions.
Operates on a single :class:xr.DataArray. The Layer-1
GaussianSmoothMasked operator handles the Dataset loop.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/smooth.py
moving_average
¶
moving_average(da: DataArray, *, dim: str, window: int, center: bool = True, min_periods: int | None = None) -> DataArray
Sliding-window mean along dim.
Computes a centred (center=True) or trailing sliding-window mean
of length window along dim. min_periods controls the
minimum number of valid (non-NaN) samples required inside the window
for the output to be non-NaN; if unset it defaults to window.
Inputs with fewer than min_periods valid samples in a window
produce NaN at that position.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/smooth.py
lowpass_filter
¶
lowpass_filter(da: DataArray, *, dim: str, cutoff: float | tuple[float, float] | list[float] | ndarray, order: int = 4, btype: str = 'low') -> DataArray
Zero-phase Butterworth filter along dim.
cutoff is the normalized critical frequency (fraction of the
Nyquist rate). For btype in {"bandpass", "bandstop"} pass a
length-2 (low, high) sequence. The filter is applied with
scipy.signal.sosfiltfilt (forward-backward) for zero phase
distortion; order is the per-direction order of the SOS sections.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/smooth.py
fir_filter
¶
fir_filter(da: DataArray, *, dim: str, cutoff: float | tuple[float, float] | list[float] | ndarray, method: str = 'lanczos', btype: str = 'low', num_taps: int | None = None, attenuation_db: float | None = None) -> DataArray
Zero-phase FIR filter along dim.
cutoff is the normalized critical frequency (fraction of the
Nyquist rate); for btype in {"bandpass", "bandstop"} pass a
length-2 (low, high) sequence. method selects the window
family used to taper the ideal sinc response — "lanczos" or
"kaiser". num_taps is an odd FIR tap count; if omitted, a
conservative default is chosen (Lanczos picks from cutoff;
Kaiser estimates from attenuation_db). attenuation_db is the
Kaiser stop-band attenuation target in decibels (default 60.0)
and is ignored when method="lanczos". The filter is applied with
scipy.signal.filtfilt for zero phase.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/smooth.py
sample_at_points
¶
sample_at_points(da: DataArray, points: Dataset | Mapping[str, object], *, coords: tuple[str, ...] = ('lat', 'lon'), method: Method = 'linear', fill_value: float | None = nan, bounds_error: bool = False, point_dim: str = 'points') -> DataArray
Sample a gridded field at scattered target points using RGI.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
da
|
DataArray
|
Source data with 1-D, strictly monotone coordinates for every
interpolation dimension in |
required |
points
|
Dataset | Mapping[str, object]
|
Target locations as a dataset or mapping. Each coordinate in
|
required |
coords
|
tuple[str, ...]
|
Source/target coordinate names to interpolate over. |
('lat', 'lon')
|
method
|
Method
|
Interpolation method supported by
:class: |
'linear'
|
fill_value
|
float | None
|
Value used for finite out-of-bounds points when
|
nan
|
bounds_error
|
bool
|
Whether finite out-of-bounds points raise an error. |
False
|
point_dim
|
str
|
Name of the target-point dimension. |
'points'
|
Returns:
| Type | Description |
|---|---|
DataArray
|
Values sampled at |
DataArray
|
dimensions retained and |
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/grid_to_points.py
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 | |
along_track
¶
along_track(da: DataArray, track: Dataset, *, coords: tuple[str, ...] = ('time', 'lat', 'lon'), method: Method = 'linear', fill_value: float | None = nan, point_dim: str = 'points') -> DataArray
Collocate a gridded field onto an observation track.
This is a convenience wrapper around :func:sample_at_points for
time-collocated tracks such as satellite altimetry, drifters, or buoys.
It validates that datetime-like coordinates are datetime-like in both the
source and target before delegating to the generic sampler.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
da
|
DataArray
|
Source gridded field with 1-D coordinates for every name in
|
required |
track
|
Dataset
|
Track dataset containing each coordinate in |
required |
coords
|
tuple[str, ...]
|
Coordinate names to interpolate over. Defaults to
|
('time', 'lat', 'lon')
|
method
|
Method
|
Interpolation method supported by
:class: |
'linear'
|
fill_value
|
float | None
|
Value used for finite out-of-bounds track points. |
nan
|
point_dim
|
str
|
Name of the target-track dimension. |
'points'
|
Returns:
| Type | Description |
|---|---|
DataArray
|
Values from |
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/grid_to_points.py
remap_axis
¶
remap_axis(da: DataArray, *, source_dim: str, target_coords: DataArray | ndarray, target_name: str | None = None, method: str = 'linear', source_coords: str | DataArray | None = None, extrapolate: Extrapolate = 'nan') -> DataArray
Remap da along source_dim onto target_coords.
If target_coords is a :class:xr.DataArray and target_name
is None, the new dim name is taken from target_coords.name;
otherwise target_name (or source_dim) is used.
Every coordinate that depends on source_dim is dropped from the
output; the new target coordinate is attached under the new name.
The Layer-1 RemapAxis operator handles Dataset selection /
per-variable looping.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
da
|
DataArray
|
Numeric DataArray carrying |
required |
source_dim
|
str
|
Name of the dimension being replaced. |
required |
target_coords
|
DataArray | ndarray
|
1-D target axis values. |
required |
target_name
|
str | None
|
Explicit name for the new dimension. |
None
|
method
|
str
|
|
'linear'
|
source_coords
|
str | DataArray | None
|
Source axis values. |
None
|
extrapolate
|
Extrapolate
|
|
'nan'
|
Returns:
| Type | Description |
|---|---|
DataArray
|
|
DataArray
|
|
DataArray
|
long as |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
TypeError
|
If |
Example
Remap a model-level field with a 4-D height-above-ground coordinate onto fixed heights, holding the lowest / highest model level beyond each column's range:
>>> import numpy as np, xarray as xr
>>> from xrops.transforms import remap_axis
>>> level = np.arange(4)
>>> z_agl = 20.0 * (level[None, :, None, None] + 1) + np.zeros((2, 4, 3, 3))
>>> z_agl[..., 0, 0] += 15.0 # one column starts higher up
>>> t = xr.DataArray(
... 300.0 - 0.01 * z_agl,
... dims=("time", "level", "y", "x"),
... coords={"z_agl": (("time", "level", "y", "x"), z_agl)},
... )
>>> out = remap_axis(
... t,
... source_dim="level",
... target_coords=np.array([10.0, 50.0, 90.0]),
... target_name="height",
... source_coords="z_agl",
... extrapolate="nearest",
... )
>>> out.dims, out.sizes["height"]
(('time', 'height', 'y', 'x'), 3)
>>> float(out.isel(time=0, height=1, y=1, x=1)) # in range: linear
299.5
Source code in packages/xrtoolz-ops/src/xrops/transforms/_src/coord_remap.py
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | |
to_phase
¶
to_phase(da: DataArray, *, time_dim: str, period: float, n_bins: int, epoch: float = 0.0) -> DataArray
Fold time_dim onto a phase axis by binning + averaging.
The time coordinate must be numeric in the same units as period.
Phase is computed as ((t - epoch) / period) mod 1 and binned
into n_bins evenly-spaced bins on [0, 1). Output carries
a "phase" dim with coordinate values at bin centers.
The Layer-1 ToPhase operator handles Dataset selection /
per-variable looping.
Source code in packages/xrtoolz-ops/src/xrops/transforms/_src/coord_remap.py
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | |
Grid carriers¶
Grid
dataclass
¶
Regular lon/lat grid defined by 1-D coordinate arrays.
from_bounds
classmethod
¶
from_bounds(lon_bnds: tuple[float, float], lat_bnds: tuple[float, float], resolution: float) -> Grid
Build a grid whose cells have width resolution degrees.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/binning.py
bin_edges
¶
Return (lon_edges, lat_edges) for use by np.histogram2d.
Source code in packages/xrtoolz-ops/src/xrops/interpolate/_src/binning.py
SpaceTimeGrid
dataclass
¶
SpaceTimeGrid(lon: Float[ndarray, 'lon'], lat: Float[ndarray, 'lat'], time: DatetimeIndex = (lambda: DatetimeIndex([]))())
Lon/lat/time grid. Use :meth:from_bounds for the common case.
Period
dataclass
¶
A pandas-compatible time window.