Skip to content

rslearn.dataset.compositing

compositing

Built-in and abstract compositing methods for raster materialization.

BandSetCompositeRequest dataclass

All inputs needed to composite one materialized band set.

Source code in rslearn/dataset/compositing.py
@dataclass(frozen=True)
class BandSetCompositeRequest:
    """All inputs needed to composite one materialized band set."""

    nodata_val: int | float | None
    bands: list[str]
    bounds: PixelBounds
    band_dtype: npt.DTypeLike
    projection: Projection
    resampling_method: Resampling
    remapper: Remapper | None

Compositor

Bases: ABC

Abstract base for compositing methods.

All built-in compositing methods and custom (jsonargparse-injectable) ones share this interface.

Source code in rslearn/dataset/compositing.py
class Compositor(ABC):
    """Abstract base for compositing methods.

    All built-in compositing methods and custom (jsonargparse-injectable) ones
    share this interface.
    """

    def build_composites(
        self,
        group: list[ItemType],
        requests: list[BandSetCompositeRequest],
        tile_store: TileStoreWithLayer,
        window: Window | None = None,
        request_time_range: tuple[datetime, datetime] | None = None,
    ) -> Iterator[RasterArray]:
        """Yield composites for multiple band sets in a window.

        The default implementation preserves the existing per-band-set behavior by
        iterating over ``requests`` and delegating to ``build_composite``. Custom
        compositors can override this to enforce consistency across band sets or
        to share expensive preprocessing work.
        """
        for request in requests:
            yield self.build_composite(
                group=group,
                nodata_val=request.nodata_val,
                bands=request.bands,
                bounds=request.bounds,
                band_dtype=request.band_dtype,
                tile_store=tile_store,
                projection=request.projection,
                resampling_method=request.resampling_method,
                remapper=request.remapper,
                request_time_range=request_time_range,
            )

    @abstractmethod
    def build_composite(
        self,
        group: list[ItemType],
        nodata_val: int | float | None,
        bands: list[str],
        bounds: PixelBounds,
        band_dtype: npt.DTypeLike,
        tile_store: TileStoreWithLayer,
        projection: Projection,
        resampling_method: Resampling,
        remapper: Remapper | None,
        request_time_range: tuple[datetime, datetime] | None = None,
    ) -> RasterArray:
        """Build a composite from items in the group.

        Args:
            group: list of items to composite together.
            nodata_val: scalar nodata value for the band set, or None.
            bands: band names to include in the composite.
            bounds: pixel bounds for the spatial extent.
            band_dtype: numpy dtype for the output.
            tile_store: tile store for reading raster data.
            projection: target spatial projection.
            resampling_method: rasterio resampling enum.
            remapper: optional pixel-value remapper.
            request_time_range: optional time range for the request.

        Returns:
            A RasterArray produced by this compositing method.
        """
        ...

build_composites

build_composites(group: list[ItemType], requests: list[BandSetCompositeRequest], tile_store: TileStoreWithLayer, window: Window | None = None, request_time_range: tuple[datetime, datetime] | None = None) -> Iterator[RasterArray]

Yield composites for multiple band sets in a window.

The default implementation preserves the existing per-band-set behavior by iterating over requests and delegating to build_composite. Custom compositors can override this to enforce consistency across band sets or to share expensive preprocessing work.

Source code in rslearn/dataset/compositing.py
def build_composites(
    self,
    group: list[ItemType],
    requests: list[BandSetCompositeRequest],
    tile_store: TileStoreWithLayer,
    window: Window | None = None,
    request_time_range: tuple[datetime, datetime] | None = None,
) -> Iterator[RasterArray]:
    """Yield composites for multiple band sets in a window.

    The default implementation preserves the existing per-band-set behavior by
    iterating over ``requests`` and delegating to ``build_composite``. Custom
    compositors can override this to enforce consistency across band sets or
    to share expensive preprocessing work.
    """
    for request in requests:
        yield self.build_composite(
            group=group,
            nodata_val=request.nodata_val,
            bands=request.bands,
            bounds=request.bounds,
            band_dtype=request.band_dtype,
            tile_store=tile_store,
            projection=request.projection,
            resampling_method=request.resampling_method,
            remapper=request.remapper,
            request_time_range=request_time_range,
        )

build_composite abstractmethod

build_composite(group: list[ItemType], nodata_val: int | float | None, bands: list[str], bounds: PixelBounds, band_dtype: DTypeLike, tile_store: TileStoreWithLayer, projection: Projection, resampling_method: Resampling, remapper: Remapper | None, request_time_range: tuple[datetime, datetime] | None = None) -> RasterArray

Build a composite from items in the group.

Parameters:

Name Type Description Default
group list[ItemType]

list of items to composite together.

required
nodata_val int | float | None

scalar nodata value for the band set, or None.

required
bands list[str]

band names to include in the composite.

required
bounds PixelBounds

pixel bounds for the spatial extent.

required
band_dtype DTypeLike

numpy dtype for the output.

required
tile_store TileStoreWithLayer

tile store for reading raster data.

required
projection Projection

target spatial projection.

required
resampling_method Resampling

rasterio resampling enum.

required
remapper Remapper | None

optional pixel-value remapper.

required
request_time_range tuple[datetime, datetime] | None

optional time range for the request.

None

Returns:

Type Description
RasterArray

A RasterArray produced by this compositing method.

Source code in rslearn/dataset/compositing.py
@abstractmethod
def build_composite(
    self,
    group: list[ItemType],
    nodata_val: int | float | None,
    bands: list[str],
    bounds: PixelBounds,
    band_dtype: npt.DTypeLike,
    tile_store: TileStoreWithLayer,
    projection: Projection,
    resampling_method: Resampling,
    remapper: Remapper | None,
    request_time_range: tuple[datetime, datetime] | None = None,
) -> RasterArray:
    """Build a composite from items in the group.

    Args:
        group: list of items to composite together.
        nodata_val: scalar nodata value for the band set, or None.
        bands: band names to include in the composite.
        bounds: pixel bounds for the spatial extent.
        band_dtype: numpy dtype for the output.
        tile_store: tile store for reading raster data.
        projection: target spatial projection.
        resampling_method: rasterio resampling enum.
        remapper: optional pixel-value remapper.
        request_time_range: optional time range for the request.

    Returns:
        A RasterArray produced by this compositing method.
    """
    ...

FirstValidCompositor

Bases: Compositor

Select the first valid (non-nodata) pixel across items in order.

Source code in rslearn/dataset/compositing.py
class FirstValidCompositor(Compositor):
    """Select the first valid (non-nodata) pixel across items in order."""

    def build_composite(
        self,
        group: list[ItemType],
        nodata_val: int | float | None,
        bands: list[str],
        bounds: PixelBounds,
        band_dtype: npt.DTypeLike,
        tile_store: TileStoreWithLayer,
        projection: Projection,
        resampling_method: Resampling,
        remapper: Remapper | None,
        request_time_range: tuple[datetime, datetime] | None = None,
    ) -> RasterArray:
        """Build a first-valid composite."""
        # When the source has no declared nodata, fall back to 0 for the
        # first-valid merge logic.  The output metadata will still reflect
        # the *original* nodata_val (None -> no nodata tag on the file).
        effective_nodata = nodata_val
        if effective_nodata is None:
            logger.warning(
                "No nodata value available for FIRST_VALID compositing; "
                "defaulting to 0 for merge logic. Set nodata_value in "
                "BandSetConfig or use a data source with nodata metadata "
                "to avoid this warning."
            )
            effective_nodata = 0

        dst: RasterArray | None = None
        for item in group:
            dst = read_raster_window_from_tiles(
                tile_store=tile_store,
                item=item,
                bands=bands,
                projection=projection,
                bounds=bounds,
                nodata_val=effective_nodata,
                band_dtype=band_dtype,
                remapper=remapper,
                resampling=resampling_method,
                dst=dst,
            )

        if dst is None:
            height = bounds[3] - bounds[1]
            width = bounds[2] - bounds[0]
            arr = np.full(
                (len(bands), 1, height, width), effective_nodata, dtype=band_dtype
            )
            dst = RasterArray(array=arr)

        dst.metadata.nodata_value = nodata_val
        return dst

build_composite

build_composite(group: list[ItemType], nodata_val: int | float | None, bands: list[str], bounds: PixelBounds, band_dtype: DTypeLike, tile_store: TileStoreWithLayer, projection: Projection, resampling_method: Resampling, remapper: Remapper | None, request_time_range: tuple[datetime, datetime] | None = None) -> RasterArray

Build a first-valid composite.

Source code in rslearn/dataset/compositing.py
def build_composite(
    self,
    group: list[ItemType],
    nodata_val: int | float | None,
    bands: list[str],
    bounds: PixelBounds,
    band_dtype: npt.DTypeLike,
    tile_store: TileStoreWithLayer,
    projection: Projection,
    resampling_method: Resampling,
    remapper: Remapper | None,
    request_time_range: tuple[datetime, datetime] | None = None,
) -> RasterArray:
    """Build a first-valid composite."""
    # When the source has no declared nodata, fall back to 0 for the
    # first-valid merge logic.  The output metadata will still reflect
    # the *original* nodata_val (None -> no nodata tag on the file).
    effective_nodata = nodata_val
    if effective_nodata is None:
        logger.warning(
            "No nodata value available for FIRST_VALID compositing; "
            "defaulting to 0 for merge logic. Set nodata_value in "
            "BandSetConfig or use a data source with nodata metadata "
            "to avoid this warning."
        )
        effective_nodata = 0

    dst: RasterArray | None = None
    for item in group:
        dst = read_raster_window_from_tiles(
            tile_store=tile_store,
            item=item,
            bands=bands,
            projection=projection,
            bounds=bounds,
            nodata_val=effective_nodata,
            band_dtype=band_dtype,
            remapper=remapper,
            resampling=resampling_method,
            dst=dst,
        )

    if dst is None:
        height = bounds[3] - bounds[1]
        width = bounds[2] - bounds[0]
        arr = np.full(
            (len(bands), 1, height, width), effective_nodata, dtype=band_dtype
        )
        dst = RasterArray(array=arr)

    dst.metadata.nodata_value = nodata_val
    return dst

MeanCompositor

Bases: Compositor

Per-pixel mean of valid (non-nodata) values across items.

Source code in rslearn/dataset/compositing.py
class MeanCompositor(Compositor):
    """Per-pixel mean of valid (non-nodata) values across items."""

    def build_composite(
        self,
        group: list[ItemType],
        nodata_val: int | float | None,
        bands: list[str],
        bounds: PixelBounds,
        band_dtype: npt.DTypeLike,
        tile_store: TileStoreWithLayer,
        projection: Projection,
        resampling_method: Resampling,
        remapper: Remapper | None,
        request_time_range: tuple[datetime, datetime] | None = None,
    ) -> RasterArray:
        """Build a mean composite."""
        if nodata_val is None:
            raise ValueError(_NODATA_REQUIRED_MSG.format(name="MEAN"))
        rasters = read_raster_windows(
            group=group,
            bands=bands,
            tile_store=tile_store,
            projection=projection,
            bounds=bounds,
            nodata_val=nodata_val,
            band_dtype=band_dtype,
            remapper=remapper,
            resampling_method=resampling_method,
        )

        num_timesteps = rasters[0].array.shape[1]
        for raster in rasters[1:]:
            if raster.array.shape[1] != num_timesteps:
                raise ValueError(
                    f"All items must have the same number of timesteps, "
                    f"got T={num_timesteps} and T={raster.array.shape[1]}"
                )

        stacked_arrays = np.stack([r.array for r in rasters], axis=0)
        masked_data = mask_stacked_rasters(stacked_arrays, nodata_val)
        mean_result = np.ma.mean(masked_data, axis=0)

        cthw = np.ma.filled(mean_result, fill_value=nodata_val).astype(band_dtype)
        metadata = RasterMetadata(nodata_value=nodata_val)
        return RasterArray(
            array=cthw, timestamps=rasters[0].timestamps, metadata=metadata
        )

build_composite

build_composite(group: list[ItemType], nodata_val: int | float | None, bands: list[str], bounds: PixelBounds, band_dtype: DTypeLike, tile_store: TileStoreWithLayer, projection: Projection, resampling_method: Resampling, remapper: Remapper | None, request_time_range: tuple[datetime, datetime] | None = None) -> RasterArray

Build a mean composite.

Source code in rslearn/dataset/compositing.py
def build_composite(
    self,
    group: list[ItemType],
    nodata_val: int | float | None,
    bands: list[str],
    bounds: PixelBounds,
    band_dtype: npt.DTypeLike,
    tile_store: TileStoreWithLayer,
    projection: Projection,
    resampling_method: Resampling,
    remapper: Remapper | None,
    request_time_range: tuple[datetime, datetime] | None = None,
) -> RasterArray:
    """Build a mean composite."""
    if nodata_val is None:
        raise ValueError(_NODATA_REQUIRED_MSG.format(name="MEAN"))
    rasters = read_raster_windows(
        group=group,
        bands=bands,
        tile_store=tile_store,
        projection=projection,
        bounds=bounds,
        nodata_val=nodata_val,
        band_dtype=band_dtype,
        remapper=remapper,
        resampling_method=resampling_method,
    )

    num_timesteps = rasters[0].array.shape[1]
    for raster in rasters[1:]:
        if raster.array.shape[1] != num_timesteps:
            raise ValueError(
                f"All items must have the same number of timesteps, "
                f"got T={num_timesteps} and T={raster.array.shape[1]}"
            )

    stacked_arrays = np.stack([r.array for r in rasters], axis=0)
    masked_data = mask_stacked_rasters(stacked_arrays, nodata_val)
    mean_result = np.ma.mean(masked_data, axis=0)

    cthw = np.ma.filled(mean_result, fill_value=nodata_val).astype(band_dtype)
    metadata = RasterMetadata(nodata_value=nodata_val)
    return RasterArray(
        array=cthw, timestamps=rasters[0].timestamps, metadata=metadata
    )

MedianCompositor

Bases: Compositor

Per-pixel median of valid (non-nodata) values across items.

Source code in rslearn/dataset/compositing.py
class MedianCompositor(Compositor):
    """Per-pixel median of valid (non-nodata) values across items."""

    def build_composite(
        self,
        group: list[ItemType],
        nodata_val: int | float | None,
        bands: list[str],
        bounds: PixelBounds,
        band_dtype: npt.DTypeLike,
        tile_store: TileStoreWithLayer,
        projection: Projection,
        resampling_method: Resampling,
        remapper: Remapper | None,
        request_time_range: tuple[datetime, datetime] | None = None,
    ) -> RasterArray:
        """Build a median composite."""
        if nodata_val is None:
            raise ValueError(_NODATA_REQUIRED_MSG.format(name="MEDIAN"))
        rasters = read_raster_windows(
            group=group,
            bands=bands,
            tile_store=tile_store,
            projection=projection,
            bounds=bounds,
            nodata_val=nodata_val,
            band_dtype=band_dtype,
            remapper=remapper,
            resampling_method=resampling_method,
        )

        num_timesteps = rasters[0].array.shape[1]
        for raster in rasters[1:]:
            if raster.array.shape[1] != num_timesteps:
                raise ValueError(
                    f"All items must have the same number of timesteps, "
                    f"got T={num_timesteps} and T={raster.array.shape[1]}"
                )

        stacked_arrays = np.stack([r.array for r in rasters], axis=0)
        masked_data = mask_stacked_rasters(stacked_arrays, nodata_val)
        median_result = np.ma.median(masked_data, axis=0)

        cthw = np.ma.filled(median_result, fill_value=nodata_val).astype(band_dtype)
        metadata = RasterMetadata(nodata_value=nodata_val)
        return RasterArray(
            array=cthw, timestamps=rasters[0].timestamps, metadata=metadata
        )

build_composite

build_composite(group: list[ItemType], nodata_val: int | float | None, bands: list[str], bounds: PixelBounds, band_dtype: DTypeLike, tile_store: TileStoreWithLayer, projection: Projection, resampling_method: Resampling, remapper: Remapper | None, request_time_range: tuple[datetime, datetime] | None = None) -> RasterArray

Build a median composite.

Source code in rslearn/dataset/compositing.py
def build_composite(
    self,
    group: list[ItemType],
    nodata_val: int | float | None,
    bands: list[str],
    bounds: PixelBounds,
    band_dtype: npt.DTypeLike,
    tile_store: TileStoreWithLayer,
    projection: Projection,
    resampling_method: Resampling,
    remapper: Remapper | None,
    request_time_range: tuple[datetime, datetime] | None = None,
) -> RasterArray:
    """Build a median composite."""
    if nodata_val is None:
        raise ValueError(_NODATA_REQUIRED_MSG.format(name="MEDIAN"))
    rasters = read_raster_windows(
        group=group,
        bands=bands,
        tile_store=tile_store,
        projection=projection,
        bounds=bounds,
        nodata_val=nodata_val,
        band_dtype=band_dtype,
        remapper=remapper,
        resampling_method=resampling_method,
    )

    num_timesteps = rasters[0].array.shape[1]
    for raster in rasters[1:]:
        if raster.array.shape[1] != num_timesteps:
            raise ValueError(
                f"All items must have the same number of timesteps, "
                f"got T={num_timesteps} and T={raster.array.shape[1]}"
            )

    stacked_arrays = np.stack([r.array for r in rasters], axis=0)
    masked_data = mask_stacked_rasters(stacked_arrays, nodata_val)
    median_result = np.ma.median(masked_data, axis=0)

    cthw = np.ma.filled(median_result, fill_value=nodata_val).astype(band_dtype)
    metadata = RasterMetadata(nodata_value=nodata_val)
    return RasterArray(
        array=cthw, timestamps=rasters[0].timestamps, metadata=metadata
    )

SpatialMosaicTemporalStackCompositor

Bases: Compositor

Spatial first-valid compositing per timestep, stacked along T.

Source code in rslearn/dataset/compositing.py
class SpatialMosaicTemporalStackCompositor(Compositor):
    """Spatial first-valid compositing per timestep, stacked along T."""

    def build_composite(
        self,
        group: list[ItemType],
        nodata_val: int | float | None,
        bands: list[str],
        bounds: PixelBounds,
        band_dtype: npt.DTypeLike,
        tile_store: TileStoreWithLayer,
        projection: Projection,
        resampling_method: Resampling,
        remapper: Remapper | None,
        request_time_range: tuple[datetime, datetime] | None = None,
    ) -> RasterArray:
        """Build a spatial-mosaic temporal-stack composite."""
        if nodata_val is None:
            raise ValueError(
                _NODATA_REQUIRED_MSG.format(name="SPATIAL_MOSAIC_TEMPORAL_STACK")
            )
        height = bounds[3] - bounds[1]
        width = bounds[2] - bounds[0]

        rasters = read_raster_windows(
            group=group,
            bands=bands,
            tile_store=tile_store,
            projection=projection,
            bounds=bounds,
            nodata_val=nodata_val,
            band_dtype=band_dtype,
            remapper=remapper,
            resampling_method=resampling_method,
        )

        if not rasters:
            raise ValueError("No valid items found for temporal stack")

        # Clip timestamps to request time range.
        if request_time_range is not None:
            w_start, w_end = request_time_range
            clipped: list[RasterArray] = []
            for raster in rasters:
                if raster.timestamps is None:
                    raise ValueError(
                        "SPATIAL_MOSAIC_TEMPORAL_STACK requires items to have timestamps"
                    )
                keep = [
                    i
                    for i, (ts_s, ts_e) in enumerate(raster.timestamps)
                    if ts_s < w_end and ts_e > w_start
                ]
                if not keep:
                    continue
                clipped.append(
                    RasterArray(
                        array=raster.array[:, keep, :, :],
                        timestamps=[raster.timestamps[i] for i in keep],
                        metadata=RasterMetadata(nodata_value=nodata_val),
                    )
                )
            rasters = clipped

        if not rasters:
            raise ValueError("No valid timesteps after clipping to request time range")

        # Union of timestamps across all items.
        all_timestamps: set[tuple[datetime, datetime]] = set()
        for raster in rasters:
            if raster.timestamps is None:
                raise ValueError(
                    "SPATIAL_MOSAIC_TEMPORAL_STACK requires items to have timestamps"
                )
            all_timestamps.update(raster.timestamps)

        sorted_timestamps = sorted(all_timestamps)
        ts_to_idx = {tr: idx for idx, tr in enumerate(sorted_timestamps)}
        num_timesteps = len(sorted_timestamps)

        output = np.full(
            (len(bands), num_timesteps, height, width), nodata_val, dtype=band_dtype
        )

        for raster in rasters:
            assert raster.timestamps is not None
            out_idxs = [ts_to_idx[tr] for tr in raster.timestamps]
            dst_slice = output[:, out_idxs, :, :]
            src_slice = raster.array

            mask = nodata_eq(dst_slice, nodata_val).min(axis=0)
            output[:, out_idxs, :, :] = np.where(mask[np.newaxis], src_slice, dst_slice)

        metadata = RasterMetadata(nodata_value=nodata_val)
        return RasterArray(
            array=output, timestamps=sorted_timestamps, metadata=metadata
        )

build_composite

build_composite(group: list[ItemType], nodata_val: int | float | None, bands: list[str], bounds: PixelBounds, band_dtype: DTypeLike, tile_store: TileStoreWithLayer, projection: Projection, resampling_method: Resampling, remapper: Remapper | None, request_time_range: tuple[datetime, datetime] | None = None) -> RasterArray

Build a spatial-mosaic temporal-stack composite.

Source code in rslearn/dataset/compositing.py
def build_composite(
    self,
    group: list[ItemType],
    nodata_val: int | float | None,
    bands: list[str],
    bounds: PixelBounds,
    band_dtype: npt.DTypeLike,
    tile_store: TileStoreWithLayer,
    projection: Projection,
    resampling_method: Resampling,
    remapper: Remapper | None,
    request_time_range: tuple[datetime, datetime] | None = None,
) -> RasterArray:
    """Build a spatial-mosaic temporal-stack composite."""
    if nodata_val is None:
        raise ValueError(
            _NODATA_REQUIRED_MSG.format(name="SPATIAL_MOSAIC_TEMPORAL_STACK")
        )
    height = bounds[3] - bounds[1]
    width = bounds[2] - bounds[0]

    rasters = read_raster_windows(
        group=group,
        bands=bands,
        tile_store=tile_store,
        projection=projection,
        bounds=bounds,
        nodata_val=nodata_val,
        band_dtype=band_dtype,
        remapper=remapper,
        resampling_method=resampling_method,
    )

    if not rasters:
        raise ValueError("No valid items found for temporal stack")

    # Clip timestamps to request time range.
    if request_time_range is not None:
        w_start, w_end = request_time_range
        clipped: list[RasterArray] = []
        for raster in rasters:
            if raster.timestamps is None:
                raise ValueError(
                    "SPATIAL_MOSAIC_TEMPORAL_STACK requires items to have timestamps"
                )
            keep = [
                i
                for i, (ts_s, ts_e) in enumerate(raster.timestamps)
                if ts_s < w_end and ts_e > w_start
            ]
            if not keep:
                continue
            clipped.append(
                RasterArray(
                    array=raster.array[:, keep, :, :],
                    timestamps=[raster.timestamps[i] for i in keep],
                    metadata=RasterMetadata(nodata_value=nodata_val),
                )
            )
        rasters = clipped

    if not rasters:
        raise ValueError("No valid timesteps after clipping to request time range")

    # Union of timestamps across all items.
    all_timestamps: set[tuple[datetime, datetime]] = set()
    for raster in rasters:
        if raster.timestamps is None:
            raise ValueError(
                "SPATIAL_MOSAIC_TEMPORAL_STACK requires items to have timestamps"
            )
        all_timestamps.update(raster.timestamps)

    sorted_timestamps = sorted(all_timestamps)
    ts_to_idx = {tr: idx for idx, tr in enumerate(sorted_timestamps)}
    num_timesteps = len(sorted_timestamps)

    output = np.full(
        (len(bands), num_timesteps, height, width), nodata_val, dtype=band_dtype
    )

    for raster in rasters:
        assert raster.timestamps is not None
        out_idxs = [ts_to_idx[tr] for tr in raster.timestamps]
        dst_slice = output[:, out_idxs, :, :]
        src_slice = raster.array

        mask = nodata_eq(dst_slice, nodata_val).min(axis=0)
        output[:, out_idxs, :, :] = np.where(mask[np.newaxis], src_slice, dst_slice)

    metadata = RasterMetadata(nodata_value=nodata_val)
    return RasterArray(
        array=output, timestamps=sorted_timestamps, metadata=metadata
    )

TemporalMeanCompositor

Bases: _TemporalReducerCompositor

Reduce a multi-temporal raster stack to one timestep via temporal mean.

Source code in rslearn/dataset/compositing.py
class TemporalMeanCompositor(_TemporalReducerCompositor):
    """Reduce a multi-temporal raster stack to one timestep via temporal mean."""

    def reduce(self, masked_data: np.ma.MaskedArray) -> np.ma.MaskedArray:
        """Reduce along T via mean."""
        return np.ma.mean(masked_data, axis=1)

reduce

reduce(masked_data: MaskedArray) -> MaskedArray

Reduce along T via mean.

Source code in rslearn/dataset/compositing.py
def reduce(self, masked_data: np.ma.MaskedArray) -> np.ma.MaskedArray:
    """Reduce along T via mean."""
    return np.ma.mean(masked_data, axis=1)

TemporalMaxCompositor

Bases: _TemporalReducerCompositor

Reduce a multi-temporal raster stack to one timestep via temporal max.

Source code in rslearn/dataset/compositing.py
class TemporalMaxCompositor(_TemporalReducerCompositor):
    """Reduce a multi-temporal raster stack to one timestep via temporal max."""

    def reduce(self, masked_data: np.ma.MaskedArray) -> np.ma.MaskedArray:
        """Reduce along T via max."""
        return np.ma.max(masked_data, axis=1)

reduce

reduce(masked_data: MaskedArray) -> MaskedArray

Reduce along T via max.

Source code in rslearn/dataset/compositing.py
def reduce(self, masked_data: np.ma.MaskedArray) -> np.ma.MaskedArray:
    """Reduce along T via max."""
    return np.ma.max(masked_data, axis=1)

TemporalMinCompositor

Bases: _TemporalReducerCompositor

Reduce a multi-temporal raster stack to one timestep via temporal min.

Source code in rslearn/dataset/compositing.py
class TemporalMinCompositor(_TemporalReducerCompositor):
    """Reduce a multi-temporal raster stack to one timestep via temporal min."""

    def reduce(self, masked_data: np.ma.MaskedArray) -> np.ma.MaskedArray:
        """Reduce along T via min."""
        return np.ma.min(masked_data, axis=1)

reduce

reduce(masked_data: MaskedArray) -> MaskedArray

Reduce along T via min.

Source code in rslearn/dataset/compositing.py
def reduce(self, masked_data: np.ma.MaskedArray) -> np.ma.MaskedArray:
    """Reduce along T via min."""
    return np.ma.min(masked_data, axis=1)