Source code for ess.reduce.live.roi

# SPDX-License-Identifier: BSD-3-Clause
# Copyright (c) 2025 Scipp contributors (https://github.com/scipp)
"""Utilities for region of interest (ROI) selection."""

from __future__ import annotations

from typing import TypeVar

import numpy as np
import scipp as sc


[docs] def select_indices_in_intervals( intervals: sc.DataGroup[tuple[int, int] | tuple[sc.Variable, sc.Variable]], indices: sc.Variable | sc.DataArray, ) -> sc.Variable: """ Return subset of indices that fall within the intervals. Parameters ---------- intervals: DataGroup with dimension names as keys and tuples of low and high values. This can be used to define a band or a rectangle to selected. When low and high are scipp.Variable, the selection is done using label-based indexing. In this case `indices` must be a DataArray with corresponding coordinates. indices: Variable or DataArray with indices to select from. If binned data the selected indices will be returned concatenated into a dense array. """ out_dim = 'index' for dim, bounds in intervals.items(): low, high = sorted(bounds) indices = indices[dim, low:high] indices = indices.flatten(to=out_dim) if indices.bins is None: return indices indices = indices.bins.concat().value return indices.rename_dims({indices.dim: out_dim})
T = TypeVar('T', sc.DataArray, sc.Variable)
[docs] def apply_selection( data: T, *, selection: sc.Variable, norm: float = 1.0 ) -> tuple[T, sc.Variable]: """ Apply selection to data. Parameters ---------- data: Data to filter. selection: Variable with indices to select. norm: Normalization factor to apply to the selected data. This is used for cases where indices may be selected multiple times. Returns ------- : Filtered data and scale factor. """ indices, counts = np.unique(selection.values, return_counts=True) if data.ndim != 1: data = data.flatten(to='detector_number') scale = sc.array(dims=[data.dim], values=counts) / norm return data[indices], scale
[docs] class ROIFilter: """Filter for selecting a region of interest (ROI)."""
[docs] def __init__(self, indices: sc.Variable | sc.DataArray, norm: float = 1.0) -> None: """ Create a new ROI filter. Parameters ---------- indices: Variable with indices to filter. The indices facilitate selecting a 2-D ROI in a projection of a 3-D dataset. Typically the indices are given by a 2-D array. Each element in the array may correspond to a single index (when there is no projection) or a list of indices that were projected into an output pixel. """ self._indices = indices self._selection = sc.array(dims=['index'], values=[]) self._norm = norm
[docs] def set_roi_from_intervals(self, intervals: sc.DataGroup) -> None: """Set the ROI from (typically 1 or 2) intervals.""" self._selection = select_indices_in_intervals(intervals, self._indices)
[docs] def apply(self, data: T) -> tuple[T, sc.Variable]: """ Apply the ROI filter to data. The returned scale factor can be used to handle filtering via a projection, to take into account that fractions of source data point contribute to a data point in the projection. Parameters ---------- data: Data to filter. Returns ------- : Filtered data and scale factor. """ return apply_selection(data, selection=self._selection, norm=self._norm)