Source code for pyckles.spectral_library

# -*- coding: utf-8 -*-
"""Main module."""

from astropy.table import Table
from astropy import units as u

from .utils import load_catalog


[docs] class SpectralLibrary: """ A container for a library of spectra. Holds and returns spectra from various catalogues in various "python-friendly" formats, such as: ``synphot.SourceSpectrum``, ``astropy.Quantity``, ``numpy.ndarray``, and ``fits.BinTableHDU`` Spectra can be accessed by using the attribute syntax:: >>> spec_lib = pyckles.SpectralLibrary("pickles") >>> spec_lib.A0V or using the item syntax:: >>> spec_lib["A0V"] The returned spectrum is formatted according to ``meta["return_style"]`` parameter:: >>> spec_lib.meta["return_style"] = 'fits' >>> type(spec_lib.A0V) astropy.io.fits.hdu.table.BinTableHDU Parameters ---------- catalog_name : str The name of the spectral catalogue. See ``pyckles.catalogs`` Keyword arguments ----------------- return_style : str - "fits": Returns the original FITS BinTableHDU object - "synphot": Returns a ``synphot.SourceSpectrum`` object - "quantity": Returns wavelength and flux as ``astropy.Quantity`` - "array": Returns wavelength and flux as ``numpy.ndarray`` Examples -------- List the available spectra:: >>> import pyckles >>> spec_lib = pyckles.SpectralLibrary("pickles", return_style="quantity") >>> spec_lib.available_spectra <Column name='name' dtype='str5' length=131> A0I A0III A0IV ... K2III K3III K4III Get an A0V spectrum:: >>> vega = spec_lib.A0V >>> vega [<Quantity [ 1150., 1155., 1160., ..., 24990., 24995., 25000.] Angstrom>, <Quantity [0.181751, 0.203323, 0.142062, ..., 0.00699 , 0.006986, 0.006983] erg / (Angstrom cm2 s)>] Return synphot.SourceSpectrum objects instead of a list of Quantity arrays:: >>> spec_lib.meta["return_style"] = "synphot" >>> spec_lib.A0V <synphot.spectrum.SourceSpectrum at 0x251800272e8> """ def __init__(self, catalog_name=None, **kwargs): self.catalog_name = catalog_name self.catalog = None self.table = None self.meta = {"return_style": "fits"} | kwargs self.load(catalog_name)
[docs] def load(self, catalog_name): """Load the catalogue for a valid string ``catalog_name``.""" if catalog_name is None: return # TODO: is this really wise? self.catalog = load_catalog(catalog_name) # pylint: disable=maybe-no-member self.table = Table(self.catalog[1].data) self.table["name"] = [name.strip() for name in self.table["name"]] self.table.add_index("name", unique=True)
@property def available_spectra(self): """Return table column containing all spectra name in the library.""" return self.table["name"] def __getattr__(self, item): """Look for `item` in the 'name' column of `self.table`.""" try: ext = int(self.table.loc[item]["ext"]) except KeyError as err: raise ValueError(f"No spectrum found for name '{item}'") from err spec = spectrum_from_hdu(self.catalog[ext], self.meta["return_style"]) return spec def __getitem__(self, item): """Forward to __getattr__.""" return self.__getattr__(item)
[docs] def spectrum_from_hdu(hdu, return_type="fits"): """ Convert a ``BinTableHDU`` into the required `return_type` format. Parameters ---------- hdu : BinTableHDU A BinTableHDU spectrum with column names: ``wavelength``, ``flux`` return_type : str The format of the returned spectra - See SpectralLibrary docs Returns ------- spec : various See above See Also -------- SpectralLibrary """ wave = hdu.data["wavelength"] flux = hdu.data["flux"] wave_unit = u.Unit(hdu.header["TUNIT1"]) flux_unit = u.Unit(hdu.header["TUNIT2"]) if return_type.lower() == "quantity": return wave << wave_unit, flux << flux_unit if return_type.lower() == "array": return wave, flux if return_type.lower() == "synphot": # Import here because synphot is an extra (optional) dependency from synphot import Empirical1D, SourceSpectrum spec = SourceSpectrum( Empirical1D, points=(wave << wave_unit), lookup_table=(flux << flux_unit) ) else: spec = hdu return spec