Source code for qblox_scheduler.analysis.helpers

# Repository: https://gitlab.com/qblox/packages/software/qblox-scheduler
# Licensed according to the LICENSE file on the main branch
#
# Copyright 2020-2025, Quantify Consortium
# Copyright 2025, Qblox B.V.
"""Helper functions for analysis."""

from collections.abc import Hashable, Iterable
from typing import overload

import xarray


@overload
[docs] def acq_coords_to_dims( data: xarray.Dataset, coords: list[Hashable], acq_channels: Iterable[Hashable] | None = None, ) -> xarray.Dataset: ...
@overload def acq_coords_to_dims( data: xarray.DataArray, coords: list[Hashable], acq_channels: Iterable[Hashable] | None = None, ) -> xarray.DataArray: ... def acq_coords_to_dims( data: xarray.Dataset | xarray.DataArray, coords: list[Hashable], acq_channels: Iterable[Hashable] | None = None, ): """ Reshapes the acquisitions dataset or dataarray so that the given coords become dimensions. It can also reshape from a 1 dimensional data to a multi-dimensional data along the given coords. If a dataset is given, all acquisition channels are reshaped, unless acq_channels are given. Parameters ---------- data The data to be converted to multi-dimensions. Can be a Dataset or a DataArray. coords The coords keys that needs to be converted to dimensions. acq_channels In case of a Dataset, these acquisition channels need to be converted. Returns ------- A DataArray or Dataset that has multi-dimensional dimensions along the specified coords. Raises ------ ValueError If there are no coords or if the data does not contain the acquisition index dimension name. """ if len(coords) == 0: raise ValueError( "Attempting to convert acquisition data to multidimensional, 'coords' cannot be empty." ) if isinstance(data, xarray.DataArray): if (acq_index_dim_name := data.attrs.get("acq_index_dim_name")) is None: raise ValueError( "Attempting to convert acquisition data to multidimensional, " "acq_index dimension not found." ) if len(coords) == 1: # 1 dimensional case. # Swap the old dimension with the new one. data = data.swap_dims({acq_index_dim_name: coords[0]}) # After swapping, we drop the old dimension. return data.drop_vars(acq_index_dim_name) else: # Multidimensional case. # set_index and unstack here. return data.set_index({acq_index_dim_name: coords}).unstack(acq_index_dim_name) else: def convert_conditionally(acq_channel: Hashable) -> xarray.DataArray: if (acq_channels is None) or (acq_channel in acq_channels): return acq_coords_to_dims(data[acq_channel], coords) else: return data[acq_channel] return xarray.Dataset( {acq_channel: convert_conditionally(acq_channel) for acq_channel in data.data_vars}, attrs=data.attrs, )