Source code for gwcs.coordinate_frames._composite

from collections.abc import Generator

import numpy as np
from astropy import units as u

from ._axis import AxisType
from ._base import (
    WorldAxisObjectClass,
    WorldAxisObjectClassConverter,
    WorldAxisObjectClasses,
    WorldAxisObjectComponent,
)
from ._core import CoordinateFrame

__all__ = ["CompositeFrame"]


[docs] class CompositeFrame(CoordinateFrame): """ Represents one or more frames. Parameters ---------- frames : list List of constituient frames. name : str Name for this frame. """ def __init__(self, frames: list[CoordinateFrame], name: str | None = None) -> None: self._frames = frames[:] naxes = sum([frame._naxes for frame in self._frames]) axes_order: list[int] = [] axes_type: list[AxisType | str] = [] axes_names: list[str] = [] unit: list[u.Unit] = [] ph_type: list[str | None] = [] for frame in frames: axes_order.extend(frame.axes_order) # Stack the raw (not-native) ordered properties for frame in frames: axes_type += list(frame._prop.axes_type) axes_names += list(frame._prop.axes_names) unit += list(frame._prop.unit) ph_type += list(frame._prop.axis_physical_types) if len(np.unique(axes_order)) != len(axes_order): msg = ( "Incorrect numbering of axes, " "axes_order should contain unique numbers, " f"got {axes_order}." ) raise ValueError(msg) super().__init__( naxes, axes_type=tuple(axes_type), axes_order=tuple(axes_order), unit=tuple(unit), axes_names=tuple(axes_names), axis_physical_types=tuple(ph_type), name=name, ) # Reset after the super init which may have messed this up self._axis_physical_types = tuple(ph_type) @property def frames(self) -> list[CoordinateFrame]: """ The constituient frames that comprise this `CompositeFrame`. """ return self._frames def __repr__(self) -> str: return repr(self.frames) @property def _wao_classes_rename_map(self) -> dict[CoordinateFrame, dict[str, str]]: mapper: dict[CoordinateFrame, dict[str, str]] = {} seen_names: list[str] = [] for frame in self.frames: if frame not in mapper: mapper[frame] = {} for key in frame.world_axis_object_classes: if key in seen_names: new_key = f"{key}{seen_names.count(key)}" mapper[frame][key] = new_key seen_names.append(key) return mapper @property def _wao_renamed_components_iter( self, ) -> Generator[tuple[CoordinateFrame, list[WorldAxisObjectComponent]], None, None]: mapper = self._wao_classes_rename_map for frame in self.frames: yield ( frame, [ WorldAxisObjectComponent( mapper[frame].get(component[0], component[0]), component[1], component[2], ) for component in frame._native_world_axis_object_components ], ) @property def _wao_renamed_classes_iter( self, ) -> Generator[ tuple[str, WorldAxisObjectClass | WorldAxisObjectClassConverter], None, None ]: mapper = self._wao_classes_rename_map for frame in self.frames: for key, value in frame.world_axis_object_classes.items(): yield mapper[frame].get(key, key), value @property def world_axis_object_components(self) -> list[WorldAxisObjectComponent]: out_dict: dict[int, WorldAxisObjectComponent] = {} for frame, components in self._wao_renamed_components_iter: for i, ao in enumerate(frame.axes_order): out_dict[ao] = components[i] if len(out_dict) != self.naxes: msg = "axes_order leads to incomplete world_axis_object_components" raise ValueError(msg) return [out_dict[i] for i in range(self.naxes)] @property def world_axis_object_classes(self) -> WorldAxisObjectClasses: return dict(self._wao_renamed_classes_iter)