import pandas as pd
import numpy as np
from astropy.table import Table
from astropy.coordinates import SkyCoord
import astropy.units as u
from .fileformats import DAO
# Subclassing pandas:
# http://pandas.pydata.org/pandas-docs/stable/internals.html#subclassing-pandas-data-structures
[docs]class StarList(pd.DataFrame):
#
# StarList properties extending pd.DataFrame
_metadata = ['_DAO_hdr', '_DAO_type']
_DAO_hdr = None
_DAO_type = None
[docs] @staticmethod
def new():
"""Returns empty StarList instance with columns id,x,y"""
idx = pd.Series(name='id', dtype='int64')
id = pd.Series(dtype='int64')
x = pd.Series(dtype='float64')
y = pd.Series(dtype='float64')
return StarList({'id': id, 'x': x, 'y': y}, index=idx)
@property
def _constructor(self):
return StarList
@property
def DAO_hdr(self):
"""DAO file header dict if any"""
return self._DAO_hdr
@DAO_hdr.setter
def DAO_hdr(self, hdr):
self._DAO_hdr = hdr
@property
def DAO_type(self):
"""DAO file header dict if any"""
return self._DAO_type
@DAO_type.setter
def DAO_type(self, typ):
self._DAO_type = typ
[docs] def stars_number(self):
"""returns number of stars in list"""
return self.shape[0]
[docs] def renumber(self, start=1):
"""Renumbers starlist (in place), updating `id` column and index to range start.. start+stars_number"""
self['id'] = range(start, self.stars_number() + start)
self.index = self.id
[docs] def refresh_id(self):
"""Cheks for id column existence and renumber if needed then recreate index basin on id
If `id` column exist but cannot be casted to `int` (by `pandas.Series.to_numeric`),
`ValueError` exception is raised
"""
try:
if self['id'].dtype != int:
self['id'] = pd.to_numeric(self['id'], downcast='integer', errors='raise')
except KeyError:
self.renumber()
self.index = self['id']
[docs] def to_table(self):
"""
Return a :class:`astropy.table.Table` instance
"""
t = Table.from_pandas(self)
if self.DAO_hdr is not None:
t.meta.update(self.DAO_hdr)
if self.DAO_type is not None:
t.meta['DAO_type'] = self.DAO_type
return t
[docs] @classmethod
def from_table(cls, table):
"""
Create a `StarList` from a :class:`astropy.table.Table` instance
Parameters
----------
table : :class:`astropy.table.Table`
The astropy :class:`astropy.table.Table` instance
Returns
-------
sl : `StarList`
A `StarList`instance
"""
from .file_helpers import as_starlist
return as_starlist(table)
[docs] @classmethod
def from_skycoord(cls, coo):
"""
Create a `StarList` from a :class:`astropy.coordinates.SkyCoord` instance
Parameters
----------
coo : :class:`astropy.coordinates.SkyCoord`
Source
Returns
-------
sl : `StarList`
A `StarList`instance
"""
sl = StarList(
np.array([coo.ra.to_string(sep=':', unit=u.hourangle, pad=True),
coo.dec.to_string(sep=':', unit=u.deg, pad=True, alwayssign=True)]).T,
columns=['ra', 'dec'])
sl.DAO_type = DAO.RADEC_FILE
sl.renumber()
return sl
def radec_hmsdms_from_skycoord(self, coo):
self['ra'] = coo.ra.to_string(sep=':', unit=u.hourangle, pad=True)
self['dec'] = coo.dec.to_string(sep=':', unit=u.deg, pad=True, alwayssign=True)
def radec_deg_from_hmsdms(self):
sky = SkyCoord(self.ra, self.dec, unit=(u.hourangle, u.deg))
self['ra_deg'] = sky.ra.deg
self['dec_deg'] = sky.dec.deg
def radec_hmsdms_from_deg(self):
sky = SkyCoord(self.ra_deg, self.dec_deg, unit=u.deg)
self['ra'] = sky.ra.to_string(sep=':', pad=True, unit=u.hourangle)
self['dec'] = sky.dec.to_string(sep=':',pad=True, alwayssign=True)
def to_skycoords(self):
try:
sky = SkyCoord(self.ra, self.dec, unit=(u.hourangle, u.deg))
except:
sky = SkyCoord(self.ra_deg, self.dec_deg, unit=u.deg)
return sky
def xy_from_radec(self, fitsimage):
from astwro.coord import skyradec2xy
try:
x,y = skyradec2xy(self.ra_deg, self.dec_deg, unit='deg', transformer=fitsimage)
except:
x,y = skyradec2xy(self.ra, self.dec, unit=(u.hourangle, u.deg), transformer=fitsimage)
self['x'] = x
self['y'] = y