Source code for ndcube.utils.misc

import inspect
from functools import wraps

import astropy.units as u
from astropy.wcs.wcsapi import BaseHighLevelWCS

__all__ = ['sanitise_wcs', 'unique_sorted']


[docs]def unique_sorted(iterable): """ Return unique values in the order they are first encountered in the iterable. """ lookup = set() # a temporary lookup set return [ele for ele in iterable if ele not in lookup and lookup.add(ele) is None]
[docs]def sanitise_wcs(func): """ A wrapper for NDCube methods to sanitise the wcs argument. This decorator is only designed to be used on methods of NDCube. It will find the wcs argument, keyword or positional and if it is None, set it to `self.wcs`. It will then verify that the WCS has a matching number of pixel dimensions to the dimensionality of the array. It will finally verify that the object passed is a HighLevelWCS object, or an ExtraCoords object. """ # This needs to be here to prevent a circular import from ndcube.extra_coords import ExtraCoords @wraps(func) def wcs_wrapper(*args, **kwargs): sig = inspect.signature(func) params = sig.bind(*args, **kwargs) wcs = params.arguments.get('wcs', None) self = params.arguments['self'] if wcs is None: wcs = self.wcs if not isinstance(wcs, ExtraCoords): if not wcs.pixel_n_dim == self.data.ndim: raise ValueError("The supplied WCS must have the same number of " "pixel dimensions as the NDCube object. " "If you specified `cube.extra_coords.wcs` " "please just pass `cube.extra_coords`.") if not isinstance(wcs, (BaseHighLevelWCS, ExtraCoords)): raise TypeError("wcs argument must be a High Level WCS or an ExtraCoords object.") params.arguments['wcs'] = wcs return func(*params.args, **params.kwargs) return wcs_wrapper
def sanitize_corners(*corners): """Sanitize corner inputs to NDCube crop methods.""" corners = [list(corner) if isinstance(corner, (tuple, list)) else [corner] for corner in corners] n_coords = [len(corner) for corner in corners] if len(set(n_coords)) != 1: raise ValueError("All corner inputs must have same number of coordinate objects. " f"Lengths of corner objects: {n_coords}") return corners def convert_quantities_to_units(coords, units): """Converts a sequence of Quantities to units used in the WCS. Non-Quantity types in the sequence are allowed and ignored. Parameters ---------- coords: iterable of `astropy.units.Quantity` or `None` The coordinates to be converted. units: iterable of `astropy.units.Unit` or `str` The units to which the coordinates should be converted. Returns ------- converted_coords: iterable of `astropy.units.Quantity` or `None` The coordinates converted to the units. Non-quantity types remain. """ return [coord.to(unit) if isinstance(coord, u.Quantity) else coord for coord, unit in zip(coords, units)]