Skip to content

API reference

earthcarekit.utils.np_array_utils

earthcarekit.utils.np_array_utils

Utilities based on numpy.


all_same

all_same(a: ArrayLike) -> bool

Check if all elements in the input array are the same.

Parameters:

Name Type Description Default
a ArrayLike

Input array or array-like object to check.

required

Returns:

Name Type Description
bool bool

True if all elements in the array are the same, False otherwise.

Source code in earthcarekit/utils/np_array_utils/_check.py
def all_same(a: ArrayLike) -> bool:
    """
    Check if all elements in the input array are the same.

    Args:
        a (ArrayLike): Input array or array-like object to check.

    Returns:
        bool: True if all elements in the array are the same, False otherwise.
    """
    a = np.asarray(a)
    return bool(np.all(a == a[0]))

bins_to_centers

bins_to_centers(bins: ArrayLike) -> NDArray

Converts bin edges to bin centers.

Parameters:

Name Type Description Default
bins ArrayLike

Array of N+1 bin edges.

required

Returns:

Name Type Description
NDArray NDArray

Array of N bin centers.

Source code in earthcarekit/utils/np_array_utils/_bin.py
def bins_to_centers(bins: ArrayLike) -> NDArray:
    """
    Converts bin edges to bin centers.

    Args:
        bins (ArrayLike): Array of N+1 bin edges.

    Returns:
        NDArray: Array of N bin centers.
    """
    bins = np.asarray(bins)
    return bins[0:-1] + np.diff(bins) * 0.5

centers_to_bins

centers_to_bins(centers: ArrayLike) -> NDArray

Estimates bin edges from bin centers, assuming edges lie halfway between centers.

Parameters:

Name Type Description Default
centers ArrayLike

Array of N bin centers.

required

Returns:

Name Type Description
NDArray NDArray

Array of N+1 bin edges.

Source code in earthcarekit/utils/np_array_utils/_bin.py
def centers_to_bins(centers: ArrayLike) -> NDArray:
    """
    Estimates bin edges from bin centers, assuming edges lie halfway between centers.

    Args:
        centers (ArrayLike): Array of N bin centers.

    Returns:
        NDArray: Array of N+1 bin edges.
    """
    centers = np.asarray(centers)

    d1 = np.diff(centers)
    d2 = np.append(d1[0], d1)
    d3 = np.append(d1, d1[-1])

    bins1 = centers - d2 / 2
    bins2 = centers + d3 / 2

    return np.append(bins1, bins2[-1])

circular_nanmean

circular_nanmean(degrees: ArrayLike, axis: int | None = None) -> float

Compute the circular mean of angles in degrees, ignoring NaNs.

Source code in earthcarekit/utils/np_array_utils/_circular.py
def circular_nanmean(degrees: ArrayLike, axis: int | None = None) -> float:
    """Compute the circular mean of angles in degrees, ignoring NaNs."""
    radians = np.deg2rad(degrees)
    sin_sum = np.nanmean(np.sin(radians), axis=axis)
    cos_sum = np.nanmean(np.cos(radians), axis=axis)
    mean_angle = np.arctan2(sin_sum, cos_sum)
    return np.rad2deg(mean_angle)

clamp

clamp(a: ArrayLike, min: float, max: float) -> NDArray

Limits given values to a range between a minimum and maximum value.

Parameters:

Name Type Description Default
a ArrayLike

Input array or array-like object to be clamped.

required
min float

Minimum limit.

required
max float

Maximum limit.

required

Returns:

Name Type Description
NDArray NDArray

Clampled array.

Source code in earthcarekit/utils/np_array_utils/_clamp.py
def clamp(a: ArrayLike, min: float, max: float) -> NDArray:
    """
    Limits given values to a range between a minimum and maximum value.

    Args:
        a (ArrayLike): Input array or array-like object to be clamped.
        min (float): Minimum limit.
        max (float): Maximum limit.

    Returns:
        NDArray: Clampled array.
    """
    if np.isnan(max):
        max = np.nanmax(a)
    if np.isnan(min):
        min = np.nanmin(a)
    return np.maximum(np.minimum(np.asarray(a), max), min)

coarsen_mean

coarsen_mean(a: ArrayLike, n: int, axis: int = 0, is_bin: bool = False) -> NDArray

Downsamples a array by averaging every n adjacient elements together, discarding residual elements at the end.

Parameters:

Name Type Description Default
a ArrayLike

Input array or array-like object to downsample.

required
n int

Number of elements to be averaged together.

required
axis int

The axis along which the array a will be downsampled.

0

Returns:

Type Description
NDArray

np.ndarray: The downsampled array.

Source code in earthcarekit/utils/np_array_utils/_coarsen_mean.py
def coarsen_mean(
    a: ArrayLike,
    n: int,
    axis: int = 0,
    is_bin: bool = False,
) -> NDArray:
    """
    Downsamples a array by averaging every n adjacient elements together, discarding residual elements at the end.

    Args:
        a (ArrayLike): Input array or array-like object to downsample.
        n (int): Number of elements to be averaged together.
        axis (int): The axis along which the array `a` will be downsampled.

    Returns:
        np.ndarray: The downsampled array.
    """
    a = np.asarray(a)
    a = np.moveaxis(a, axis, 0)

    # Discard residual data points
    trimmed_len = (a.shape[0] // n) * n
    trimmed = a[:trimmed_len]
    reshaped = trimmed.reshape(-1, n, *a.shape[1:])

    # Average
    is_datetime = np.issubdtype(a.dtype, np.datetime64)
    averaged: NDArray
    if is_datetime:
        averaged = reshaped.astype("datetime64[ns]").astype("int64").mean(axis=1)
        averaged = averaged.astype("datetime64[ns]")
    elif is_bin:
        if len(a.shape) == 1:
            averaged = np.apply_along_axis(get_most_freq_int, 0, reshaped)
        elif len(a.shape) == 2:
            averaged = np.array([np.apply_along_axis(get_most_freq_int, 0, x) for x in reshaped])
    else:
        with warnings.catch_warnings():
            warnings.simplefilter("ignore", category=RuntimeWarning)
            averaged = np.nanmean(reshaped, axis=1)

    return np.moveaxis(averaged, 0, axis)

flatten_array

flatten_array(sequence: ArrayLike) -> NDArray

Flatten a nested sequence of array-likes into a 1D numpy.array.

Parameters:

Name Type Description Default
sequence ArrayLike

Sequence of array-like objects (may contain lists, tuples, arrays, or non-iterable elements).

required

Returns:

Type Description
NDArray

np.ndarray: Flattened 1D array.

Source code in earthcarekit/utils/np_array_utils/_flatten.py
def flatten_array(sequence: ArrayLike) -> NDArray:
    """
    Flatten a nested sequence of array-likes into a 1D numpy.array.

    Args:
        sequence (ArrayLike): Sequence of array-like objects (may contain lists, tuples, arrays, or non-iterable elements).

    Returns:
        np.ndarray: Flattened 1D array.
    """
    if isinstance(sequence, np.ndarray):
        return sequence.flatten()

    flattened_sequence = []

    def _ensure_list(x):
        if isinstance(x, list):
            return x.copy()
        return [x].copy()

    stack = _ensure_list(sequence)  # type: ignore

    while stack:
        item = stack.pop(0)
        if isinstance(item, (list, tuple, np.ndarray)):
            stack = list(item) + stack
        else:
            flattened_sequence.append(item)

    return np.array(flattened_sequence)

get_number_range

get_number_range(
    start: float, end: float, freq: float | None = None, periods: int | None = None
) -> NDArray[floating | integer]

Generates a sequence of numbers based on frequency or number of periods.

Parameters:

Name Type Description Default
freq float

A number defining the frequency of sampled values in the sequence.

None
periods int

A number of defining the number of evenly spaced values to sample.

None

Returns:

Name Type Description
number_range ndarray[floating | integer]

A sequence of numbers, either sampled by frequency or evenly spaced n times.

Source code in earthcarekit/utils/np_array_utils/_misc.py
def get_number_range(
    start: float, end: float, freq: float | None = None, periods: int | None = None
) -> NDArray[np.floating | np.integer]:
    """
    Generates a sequence of numbers based on frequency or number of periods.

    Args:
        freq (float, optional): A number defining the frequency of sampled values in the sequence.
        periods (int, optional): A number of defining the number of evenly spaced values to sample.

    Returns:
        number_range (np.ndarray[np.floating | np.integer]): A sequence of numbers,
            either sampled by frequency or evenly spaced n times.
    """
    if freq is None and periods is None:
        raise TypeError(
            f"{get_number_range.__name__}() missing 1 required argument: 'freq' or 'periods'"
        )
    elif isinstance(freq, float) and isinstance(periods, int):
        raise TypeError(
            f"{get_number_range.__name__}() expected 1 out of the 2 required arguments 'freq' and 'periods' but got both"
        )
    elif isinstance(freq, float):
        mod = start % freq
        s = start - mod
        if mod != 0.0:
            s += freq
        mod = end % freq
        e = end - mod
        result = np.arange(s, e + freq, freq)
        return np.array(result)
    elif isinstance(periods, int):
        result = np.linspace(start, end, periods)
        return np.array(result)
    else:
        raise RuntimeError(f"{get_number_range.__name__}() implementation error")

isascending

isascending(a: ArrayLike, raise_error: bool = False, result_constant: bool = True) -> bool

Check whether a sequence is initially ascending.

Parameters:

Name Type Description Default
lats ArrayLike

Input sequence (e.g., list, numpy.array, etc.).

required
raise_error bool

If True, raises ValueError if the sequence is too short (< 2). Defaults to False.

False
result_constant bool

If True, a constant sequence counts as acending. Defaults to True.

True

Returns:

Name Type Description
is_ascending bool

True if the sequence is ascending, False otherwise.

Raises:

Type Description
ValueError

If given mode is invalid.

Source code in earthcarekit/utils/np_array_utils/_check.py
def isascending(
    a: ArrayLike,
    raise_error: bool = False,
    result_constant: bool = True,
) -> bool:
    """
    Check whether a sequence is initially ascending.

    Args:
        lats (ArrayLike): Input sequence (e.g., `list`, `numpy.array`, etc.).
        raise_error (bool, optional): If True, raises ValueError if the sequence is too short (< 2). Defaults to False.
        result_constant (bool, optional): If True, a constant sequence counts as acending. Defaults to True.

    Returns:
        is_ascending (bool): True if the sequence is ascending, False otherwise.

    Raises:
        ValueError: If given `mode` is invalid.
    """
    _a: NDArray = np.array(a)
    _a = _a[~np.isnan(_a)]

    if len(_a) < 2:
        if raise_error:
            raise ValueError(f"too few latitude values ({len(_a)}) but at least 2 are needed.")
        return False
    diff = np.diff(_a)
    for d in diff:
        if d > 0:
            return True
        elif d < 0:
            return False
    return result_constant

ismonotonic

ismonotonic(
    a: ArrayLike,
    strict: bool = False,
    mode: Literal["any", "increasing", "decreasing"] = "any",
    raise_error: bool = False,
    ignore_nans: bool = True,
)

Check whether a sequence is monotonic.

Parameters:

Name Type Description Default
a ArrayLike

Input sequence (e.g., list, numpy.array, etc.).

required
strict bool

If True, checks for strictly increasing or decreasing sequences. If False, allows equal adjacent elements. Defaults to False.

False
mode Literal['any', 'increasing', 'decreasing']

Direction of monotonicity to check. Defaults to 'any'. - 'any': Checks if the sequence is either increasing or decreasing, depending on the initial difference of the first two elements. - 'increasing': Checks only for increasing order. - 'decreasing': Checks only for decreasing order.

'any'
raise_error bool

If True, raises ValueError if the sequence is not monotonic.

False

Returns:

Name Type Description
is_monotonic bool

True if the sequence is monotonic according to the specified parameters, False otherwise.

Raises:

Type Description
ValueError

If given mode is invalid.

Source code in earthcarekit/utils/np_array_utils/_check.py
def ismonotonic(
    a: ArrayLike,
    strict: bool = False,
    mode: Literal["any", "increasing", "decreasing"] = "any",
    raise_error: bool = False,
    ignore_nans: bool = True,
):
    """
    Check whether a sequence is monotonic.

    Args:
        a (ArrayLike): Input sequence (e.g., `list`, `numpy.array`, etc.).
        strict (bool, optional): If True, checks for strictly increasing or decreasing sequences.
            If False, allows equal adjacent elements. Defaults to False.
        mode (Literal['any', 'increasing', 'decreasing'], optional): Direction of monotonicity to check. Defaults to 'any'.
            - 'any': Checks if the sequence is either increasing or decreasing,
                     depending on the initial difference of the first two elements.
            - 'increasing': Checks only for increasing order.
            - 'decreasing': Checks only for decreasing order.
        raise_error (bool): If True, raises ValueError if the sequence is not monotonic.

    Returns:
        is_monotonic (bool): True if the sequence is monotonic according to the specified parameters, False otherwise.

    Raises:
        ValueError: If given `mode` is invalid.
    """
    a = np.asarray(a)
    if ignore_nans:
        a = a[~np.isnan(a)]

    signs = np.sign(np.diff(a))

    correct_signs = []

    if not strict:
        correct_signs.append(0)

    if mode == "any":
        i: int = 0
        while i < len(signs) - 1 and signs[i] == 0:
            i = i + 1

        if signs[i] != 0:
            correct_signs.append(signs[i])
    elif mode == "increasing":
        correct_signs.append(1)
    elif mode == "decreasing":
        correct_signs.append(-1)
    else:
        raise ValueError(
            f"invalid `mode` ('{mode}') given, but expecting 'any', 'increasing' or 'decreasing'"
        )

    is_monotonic = all([s in correct_signs for s in signs])

    if raise_error and not is_monotonic:
        raise TypeError(
            f"sequence must be monotonic but it is not (strict={strict}, mode='{mode}')"
        )

    return is_monotonic

isndarray

isndarray(input: Any, dtype: DTypeLike | None = None, raise_error: bool = False)

Returns True if input has type numpy.ndarray and also checks if dtype is lower/equal in type hierarchy if given (i.e. returns True if input.dtype is subtype of dtype).

Source code in earthcarekit/utils/np_array_utils/_check.py
def isndarray(input: Any, dtype: DTypeLike | None = None, raise_error: bool = False):
    """
    Returns True if `input` has type `numpy.ndarray` and also checks if `dtype` is lower/equal
    in type hierarchy if given (i.e. returns True if `input.dtype` is subtype of `dtype`).
    """
    if dtype is None:
        is_ndarray = isinstance(input, np.ndarray)
    else:
        is_ndarray = isinstance(input, np.ndarray) and np.issubdtype(input.dtype, dtype)

    if raise_error and not is_ndarray:
        dtype_str = "Any" if dtype is None else str(dtype)
        raise TypeError(
            f"expected type ndarray[{dtype_str}] for `input` but got {type(input).__name__}[{type(input[0]).__name__}]"
        )

    return is_ndarray

lookup_value_by_number

lookup_value_by_number(n: float, numbers: ArrayLike, values: ArrayLike) -> Any

Returns the value corresponding to the number closest to a given number, using interpolation.

Parameters:

Name Type Description Default
n float

A single number to look up.

required
numbers NDArray

A series of of monotonically increasing numbers.

required
values NDArray[Any]

A series of values corresponding to each number in numbers.

required

Returns:

Name Type Description
v Any

The value from values that corresponds to the closest number in numbers to n.

Raises:

Type Description
ValueError

If numbers and values have different lengths.

Source code in earthcarekit/utils/np_array_utils/_misc.py
def lookup_value_by_number(n: float, numbers: ArrayLike, values: ArrayLike) -> Any:
    """
    Returns the value corresponding to the number closest to a given number, using interpolation.

    Args:
        n (float): A single number to look up.
        numbers (NDArray): A series of of monotonically increasing numbers.
        values (NDArray[Any]): A series of values corresponding to each number in `numbers`.

    Returns:
        v (Any): The value from `values` that corresponds to the closest number in `numbers` to `n`.

    Raises:
        ValueError: If `numbers` and `values` have different lengths.
    """
    if n is None:
        raise ValueError(f"{lookup_value_by_number.__name__}() missing `n`")
    if numbers is None:
        raise ValueError(f"{lookup_value_by_number.__name__}() missing `numbers`")
    if values is None:
        raise ValueError(f"{lookup_value_by_number.__name__}() missing `values`")

    n = float(n)
    numbers = np.asarray(numbers)
    values = np.asarray(values)

    if numbers.shape[0] == 0:
        raise ValueError(
            f"{lookup_value_by_number.__name__}() `numbers` is empty but needs at least on element"
        )
    if values.shape[0] != numbers.shape[0]:
        raise ValueError(
            f"{lookup_value_by_number.__name__}() First shapes must be the same for `values` ({values.shape[0]}) and `numbers` ({numbers.shape[0]})"
        )

    idx0 = int(np.searchsorted(numbers, n).astype(int) - 1)
    idx1 = int(np.searchsorted(numbers, n).astype(int))

    idx0 = int(np.min([len(numbers) - 1, np.max([0, idx0])]))
    idx1 = int(np.min([len(numbers) - 1, np.max([0, idx1])]))

    if numbers[idx0] > n:
        idx0 = idx1

    total_diff = numbers[idx1] - numbers[idx0]

    diff = n - numbers[idx0]

    if total_diff == 0:
        frac = 0
    else:
        frac = diff / total_diff

    total_amount = values[idx1] - values[idx0]
    v = values[idx0] + total_amount * frac

    return v

normalize

normalize(values: ArrayLike, vmin: float = 0, vmax: float = 1) -> NDArray

Normalizes a list or array of numbers to a specified range [vmin, vmax], preserving NaNs.

The input is linearly scaled such that the minimum non-NaN value maps to vmin and the maximum to vmax. NaN values are preserved in their original positions.

Parameters:

Name Type Description Default
values ArrayLike

A sequence of numeric values, possibly containing NaNs.

required
vmin float

The minimum value of the normalized output range. Defaults to 0.

0
vmax float

The maximum value of the normalized output range. Defaults to 1.

1

Returns:

Type Description
NDArray

A numpy.ndarray of the same shape as values, with values scaled to [vmin, vmax]

NDArray

and NaNs preserved.

Raises:

Type Description
ValueError

If vmin is equal (i.e. zero output range) or greater than vmax.

Source code in earthcarekit/utils/np_array_utils/_normalize.py
def normalize(
    values: ArrayLike,
    vmin: float = 0,
    vmax: float = 1,
) -> NDArray:
    """
    Normalizes a list or array of numbers to a specified range [vmin, vmax], preserving NaNs.

    The input is linearly scaled such that the minimum non-NaN value maps to `vmin`
    and the maximum to `vmax`. NaN values are preserved in their original positions.

    Args:
        values (ArrayLike): A sequence of numeric values, possibly containing NaNs.
        vmin (float): The minimum value of the normalized output range. Defaults to 0.
        vmax (float): The maximum value of the normalized output range. Defaults to 1.

    Returns:
        A `numpy.ndarray` of the same shape as `values`, with values scaled to [vmin, vmax]
        and NaNs preserved.

    Raises:
        ValueError: If `vmin` is equal (i.e. zero output range) or greater than `vmax`.
    """
    if vmin >= vmax:
        raise ValueError(f"vmin ({vmin}) must be smaller than vmax ({vmax})")

    a_old = np.asarray(values, dtype=float)
    vmin_old = np.nanmin(a_old)
    vmax_old = np.nanmax(a_old)

    if np.isnan(vmin_old) or vmin_old == vmax_old:
        a_new = np.full_like(a_old, np.nan)
    else:
        a_new = (a_old - vmin_old) / (vmax_old - vmin_old)

    # Scale
    a_new = a_new * (vmax - vmin)

    # Shift
    a_new = a_new + vmin

    return a_new

pad_true_sequence

pad_true_sequence(a: NDArray[bool_], n: int) -> NDArray[bool_]

Pads all sequences of True values occuring in an array with n True values before and after the sequence (while keeping the original size).

Source code in earthcarekit/utils/np_array_utils/_true_sequence.py
def pad_true_sequence(
    a: NDArray[np.bool_],
    n: int,
) -> NDArray[np.bool_]:
    """Pads all sequences of True values occuring in an array with n True values before and after the sequence (while keeping the original size)."""
    idx = np.flatnonzero(a)
    if idx.size == 0:
        return a.copy()
    mask: NDArray[np.bool_] = np.full(a.shape, False, dtype=bool)
    start = max(0, idx[0] - n)
    end = min(len(a), idx[-1] + n + 1)
    mask[start:end] = True
    return mask

pad_true_sequence_2d

pad_true_sequence_2d(a: NDArray[bool_], n: int, axis: int = 1) -> NDArray[bool_]

Pads all sequences of True values occuring along one axis in an 2d array with n True values before and after the sequence (while keeping the original size).

Source code in earthcarekit/utils/np_array_utils/_true_sequence.py
def pad_true_sequence_2d(
    a: NDArray[np.bool_],
    n: int,
    axis: int = 1,
) -> NDArray[np.bool_]:
    """Pads all sequences of True values occuring along one axis in an 2d array with n True values before and after the sequence (while keeping the original size)."""

    if axis not in [0, 1]:
        raise ValueError(f"invalid axis ({axis}), expected 0 or 1")

    if axis == 0:
        a = a.T

    ncols = a.shape[1]
    idx = np.arange(ncols)

    any_true = np.asarray(a.any(axis=1))

    first_true = np.argmax(a, axis=1)
    first_true = np.where(any_true, first_true, ncols)

    last_true = ncols - 1 - np.argmax(a[:, ::-1], axis=1)
    last_true = np.where(any_true, last_true, -1)

    start = np.clip(first_true - n, 0, ncols)
    end = np.clip(last_true + n + 1, 0, ncols)

    mask = (idx >= start[:, np.newaxis]) & (idx < end[:, np.newaxis])
    mask &= any_true[:, np.newaxis]

    if axis == 0:
        mask = mask.T

    return mask

rebin_lerp

rebin_lerp(
    v: ArrayLike,
    axis0_coords: ArrayLike,
    rebin_index: ArrayLike | None = None,
    bin_edges: ArrayLike | None = None,
    bin_centers: ArrayLike | None = None,
) -> NDArray

Rebin 1D or 2D arrays along the first axis (0) by linearly interpolating the two samples around a bin center.

Parameters:

Name Type Description Default
v ArrayLike

1D or 2D array to be rebinned.

required
axis0_coords ArrayLike

Array of reference monotonic values.

required
rebin_index ArrayLike | None

Array of non-decreasing indecies mapping values in v to target bins. Defaults to None.

None
bin_edges ArrayLike | None

Array of N+1 bin edges. Defaults to None.

None
bin_centers ArrayLike | None

Array of N bin centers. Defaults to None.

None
ignore_nans bool

If True, NaNs are ignored during interpolation. If False, bins containing NaN return NaN. Defaults to True.

required

Returns:

Name Type Description
NDArray NDArray

Along axis 0 rebinned version of original array v.

Source code in earthcarekit/utils/np_array_utils/_rebin_lerp.py
def rebin_lerp(
    v: ArrayLike,
    axis0_coords: ArrayLike,
    rebin_index: ArrayLike | None = None,
    bin_edges: ArrayLike | None = None,
    bin_centers: ArrayLike | None = None,
) -> NDArray:
    """
    Rebin 1D or 2D arrays along the first axis (0) by linearly interpolating the two samples around a bin center.

    Args:
        v (ArrayLike): 1D or 2D array to be rebinned.
        axis0_coords (ArrayLike): Array of reference monotonic values.
        rebin_index (ArrayLike | None, optional): Array of non-decreasing indecies mapping values in `v` to target bins. Defaults to None.
        bin_edges (ArrayLike | None, optional): Array of N+1 bin edges. Defaults to None.
        bin_centers (ArrayLike | None, optional): Array of N bin centers. Defaults to None.
        ignore_nans (bool, optional): If True, NaNs are ignored during interpolation. If False, bins containing NaN return NaN. Defaults to True.

    Returns:
        NDArray: Along axis 0 rebinned version of original array `v`.
    """
    v = np.asarray(v)
    axis0_coords = np.asarray(axis0_coords)

    if bin_centers is not None:
        bin_centers = np.asarray(bin_centers)
    elif bin_edges is not None:
        bin_centers = bins_to_centers(bin_edges)
    elif rebin_index is not None:
        rebin_index = np.asarray(rebin_index)
        bin_centers = bins_to_centers(
            axis0_coords[np.append(np.unique(rebin_index, return_index=True)[1], len(rebin_index))]
        )
    else:
        raise ValueError("requires either 'bin_centers', 'bin_edges' or 'rebin_index'")

    idx, w = _get_lerp_params(axis0_coords, bin_centers)
    if v.ndim == 2:
        return _rebin_lerp_2d(idx, w, v)
    elif v.ndim == 1:
        return _rebin_lerp_1d(idx, w, v)
    else:
        raise ValueError(f"{v.ndim}d array not supported: requires 1d or 2d")

rebin_mean

rebin_mean(
    v: ArrayLike,
    rebin_index: ArrayLike | None = None,
    axis0_coords: ArrayLike | None = None,
    bin_edges: ArrayLike | None = None,
    bin_centers: ArrayLike | None = None,
    ignore_nans: bool = True,
) -> NDArray

Rebin 1D or 2D arrays along the first axis (0) by averaging all samples that fall within a bin.

Parameters:

Name Type Description Default
v ArrayLike

1D or 2D array to be rebinned.

required
rebin_index ArrayLike | None

Array of non-decreasing indecies mapping values in v to target bins. Defaults to None.

None
axis0_coords ArrayLike | None

Array of reference monotonic values used to derive rebin_index if it is not given (for this, additional input of bin_edges or bin_centers is also required). Defaults to None.

None
bin_edges ArrayLike | None

Array of N+1 bin edges. Ignored if rebin_index is given, otherwise axis0_coords is also required. Defaults to None.

None
bin_centers ArrayLike | None

Array of N bin centers. Ignored if rebin_index is given, otherwise axis0_coords is also required. Defaults to None.

None
ignore_nans bool

If True, NaNs are ignored during averaging. If False, bins containing NaN return NaN. Defaults to True.

True

Returns:

Name Type Description
NDArray NDArray

Along axis 0 rebinned version of original array v.

Source code in earthcarekit/utils/np_array_utils/_rebin_mean.py
def rebin_mean(
    v: ArrayLike,
    rebin_index: ArrayLike | None = None,
    axis0_coords: ArrayLike | None = None,
    bin_edges: ArrayLike | None = None,
    bin_centers: ArrayLike | None = None,
    ignore_nans: bool = True,
) -> NDArray:
    """
    Rebin 1D or 2D arrays along the first axis (0) by averaging all samples that fall within a bin.

    Args:
        v (ArrayLike): 1D or 2D array to be rebinned.
        rebin_index (ArrayLike | None, optional): Array of non-decreasing indecies mapping values in `v` to target bins. Defaults to None.
        axis0_coords (ArrayLike | None, optional): Array of reference monotonic values used to derive `rebin_index` if it is not given (for this, additional input of `bin_edges` or `bin_centers` is also required). Defaults to None.
        bin_edges (ArrayLike | None, optional): Array of N+1 bin edges. Ignored if `rebin_index` is given, otherwise `axis0_coords` is also required. Defaults to None.
        bin_centers (ArrayLike | None, optional): Array of N bin centers. Ignored if `rebin_index` is given, otherwise `axis0_coords` is also required. Defaults to None.
        ignore_nans (bool, optional): If True, NaNs are ignored during averaging. If False, bins containing NaN return NaN. Defaults to True.

    Returns:
        NDArray: Along axis 0 rebinned version of original array `v`.
    """
    return _rebin(
        func1d=_rebin_mean_1d,
        func2d=_rebin_mean_2d,
        v=v,
        rebin_index=rebin_index,
        axis0_coords=axis0_coords,
        bin_edges=bin_edges,
        bin_centers=bin_centers,
        ignore_nans=ignore_nans,
    )

rebin_median

rebin_median(
    v: ArrayLike,
    rebin_index: ArrayLike | None = None,
    axis0_coords: ArrayLike | None = None,
    bin_edges: ArrayLike | None = None,
    bin_centers: ArrayLike | None = None,
    ignore_nans: bool = True,
) -> NDArray

Rebin 1D or 2D arrays along the first axis (0) by finding the median out of samples falling within a bin.

Parameters:

Name Type Description Default
v ArrayLike

1D or 2D array to be rebinned.

required
rebin_index ArrayLike | None

Array of non-decreasing indecies mapping values in v to target bins. Defaults to None.

None
axis0_coords ArrayLike | None

Array of reference monotonic values used to derive rebin_index if it is not given (for this, additional input of bin_edges or bin_centers is also required). Defaults to None.

None
bin_edges ArrayLike | None

Array of N+1 bin edges. Ignored if rebin_index is given, otherwise axis0_coords is also required. Defaults to None.

None
bin_centers ArrayLike | None

Array of N bin centers. Ignored if rebin_index is given, otherwise axis0_coords is also required. Defaults to None.

None
ignore_nans bool

If True, NaNs are ignored during median search. If False, bins containing NaN return NaN. Defaults to True.

True

Returns:

Name Type Description
NDArray NDArray

Along axis 0 rebinned version of original array v.

Source code in earthcarekit/utils/np_array_utils/_rebin_median.py
def rebin_median(
    v: ArrayLike,
    rebin_index: ArrayLike | None = None,
    axis0_coords: ArrayLike | None = None,
    bin_edges: ArrayLike | None = None,
    bin_centers: ArrayLike | None = None,
    ignore_nans: bool = True,
) -> NDArray:
    """
    Rebin 1D or 2D arrays along the first axis (0) by finding the median out of samples falling within a bin.

    Args:
        v (ArrayLike): 1D or 2D array to be rebinned.
        rebin_index (ArrayLike | None, optional): Array of non-decreasing indecies mapping values in `v` to target bins. Defaults to None.
        axis0_coords (ArrayLike | None, optional): Array of reference monotonic values used to derive `rebin_index` if it is not given (for this, additional input of `bin_edges` or `bin_centers` is also required). Defaults to None.
        bin_edges (ArrayLike | None, optional): Array of N+1 bin edges. Ignored if `rebin_index` is given, otherwise `axis0_coords` is also required. Defaults to None.
        bin_centers (ArrayLike | None, optional): Array of N bin centers. Ignored if `rebin_index` is given, otherwise `axis0_coords` is also required. Defaults to None.
        ignore_nans (bool, optional): If True, NaNs are ignored during median search. If False, bins containing NaN return NaN. Defaults to True.

    Returns:
        NDArray: Along axis 0 rebinned version of original array `v`.
    """
    return _rebin(
        func1d=_rebin_median_1d,
        func2d=_rebin_median_2d,
        v=v,
        rebin_index=rebin_index,
        axis0_coords=axis0_coords,
        bin_edges=bin_edges,
        bin_centers=bin_centers,
        ignore_nans=ignore_nans,
    )

shift_true_sequence

shift_true_sequence(a: NDArray[bool_], n: int) -> NDArray[bool_]

Offsets all sequences of True values occuring in an array (while keeping the original size).

Source code in earthcarekit/utils/np_array_utils/_true_sequence.py
def shift_true_sequence(
    a: NDArray[np.bool_],
    n: int,
) -> NDArray[np.bool_]:
    """Offsets all sequences of True values occuring in an array (while keeping the original size)."""
    if n == 0:
        return a

    a = np.roll(a, n)
    if n > 0:
        a[:n] = False
    elif n < 0:
        a[n:] = False

    return a

wrap_to_interval

wrap_to_interval(a: ArrayLike, min: float, max: float) -> NDArray

Wrap values in a to the interval [min, max).

Source code in earthcarekit/utils/np_array_utils/_circular.py
def wrap_to_interval(a: ArrayLike, min: float, max: float) -> NDArray:
    """Wrap values in `a` to the interval [`min`, `max`)."""
    a = np.array(a)
    interval = max - min
    return (a - min) % interval + min