Source code for specutils.spectra.spectral_axis
import astropy.units as u
from astropy.utils.decorators import lazyproperty
from astropy.coordinates import SpectralCoord
import numpy as np
__all__ = ['SpectralAxis']
# We don't want to run doctests in the docstrings we inherit from Quantity
__doctest_skip__ = ['SpectralAxis.*']
[docs]
class SpectralAxis(SpectralCoord):
"""
Coordinate object representing spectral values corresponding to a specific
spectrum. Overloads SpectralCoord with additional information (currently
only bin edges).
Parameters
----------
bin_specification: str, optional
Must be "edges" or "centers". Determines whether specified axis values
are interpreted as bin edges or bin centers. Defaults to "centers".
"""
_equivalent_unit = SpectralCoord._equivalent_unit + (u.pixel,)
def __new__(cls, value, *args, bin_specification="centers", **kwargs):
# Enforce pixel axes are ascending
if ((type(value) is u.quantity.Quantity) and
(value.size > 1) and
(value.unit is u.pix) and
(value[-1] <= value[0])):
raise ValueError("u.pix spectral axes should always be ascending")
# Convert to bin centers if bin edges were given, since SpectralCoord
# only accepts centers
if bin_specification == "edges":
bin_edges = value
value = SpectralAxis._centers_from_edges(value)
obj = super().__new__(cls, value, *args, **kwargs)
if bin_specification == "edges":
obj._bin_edges = bin_edges
return obj
@staticmethod
def _edges_from_centers(centers, unit):
"""
Calculates interior bin edges based on the average of each pair of
centers, with the two outer edges based on extrapolated centers added
to the beginning and end of the spectral axis.
"""
a = np.insert(centers, 0, 2*centers[0] - centers[1])
b = np.append(centers, 2*centers[-1] - centers[-2])
edges = (a + b) / 2
return edges*unit
@staticmethod
def _centers_from_edges(edges):
"""
Calculates the bin centers as the average of each pair of edges
"""
return (edges[1:] + edges[:-1]) / 2
@lazyproperty
def bin_edges(self):
"""
Calculates bin edges if the spectral axis was created with centers
specified.
"""
if hasattr(self, '_bin_edges'):
return self._bin_edges
else:
return self._edges_from_centers(self.value, self.unit)
[docs]
def with_observer_stationary_relative_to(self, frame,
velocity=None,
preserve_observer_frame=False):
if self.unit is u.pixel:
raise u.UnitsError("Cannot transform spectral coordinates in pixel units")
return super().with_observer_stationary_relative_to(frame,
velocity=velocity,
preserve_observer_frame=preserve_observer_frame)
[docs]
def with_radial_velocity_shift(self, target_shift=None, observer_shift=None):
if self.unit is u.pixel:
raise u.UnitsError("Cannot transform spectral coordinates in pixel units")
return super().with_radial_velocity_shift(target_shift=target_shift,
observer_shift=observer_shift)