Source code for scopesim.effects.data_container
from warnings import warn
from astropy.table import Table
from astropy.io import ascii as ioascii
from astropy.io import fits
from .. import utils
[docs]class DataContainer:
"""
A class to hold data files needed by all Effects objects.
Parameters
----------
filename : str
Path to file containing data.
Accepted formats: ASCII table, FITS table, FITS image
table : astropy.Table
An astropy Table containing data
array_dict : dict
A dictionary out of which an astropy.Table object can be constructed.
kwargs :
addition meta data
Notes
-----
If a table is to be generated from an ``array_dict`` parameter, column
units can be passed as keyword arguments (kwargs) using the following
format::
Datacontainer(... , <column name>_unit="<unit string>")
where unit string is a string recognised by ``astropy.units``.
Any additional table meta-data can also be passed using this format.
Attributes
----------
data : astropy.Table, fits.HDUList
A generic property method which returns the data from the file. Any
function calling this should be prepared to handle both data formats
meta : dict
Contains all meta data read in from the file's header, and/or passed
via kwargs.
table : astropy.Table
If the file has a table format (ASCII of FITS) it is read in
immediately and stored in ``.table``
_file : HDUList pointer
If the file is a FITS image or cube, the data is only read in when
needed in order to save on memory usage. ``._file`` contains a pointer
to the data open FITS file.
"""
def __init__(self, filename=None, table=None, array_dict=None, cmds=None,
**kwargs):
self.cmds = cmds
if filename is None and "file_name" in kwargs:
warn("The 'file_name' kwarg is deprecated and will raise an error "
"in the future, please use 'filename' instead!",
DeprecationWarning, stacklevel=2)
filename = kwargs["file_name"]
if isinstance(filename, str) and filename.startswith("!"):
filename = utils.from_currsys(filename, self.cmds)
filename = utils.find_file(filename)
self.meta = {
"filename": filename,
"description": "",
"history": [],
"name": "<empty>",
}
self.meta.update(kwargs)
self.headers = []
self.table = None
self._file = None
if filename is not None:
if self.is_fits:
self._load_fits()
else:
self._load_ascii()
if table is not None:
self._from_table(table)
if array_dict is not None:
self._from_arrays(array_dict)
def _from_table(self, table):
self.table = table
self.headers += [table.meta]
self.meta.update(table.meta)
self.meta["history"] += ["Table added directly"]
def _from_arrays(self, array_dict):
data = []
colnames = []
for key, val in array_dict.items():
data += [val]
colnames += [key]
self.table = Table(names=colnames, data=data)
self.headers += [None]
self.meta["history"] += ["Table generated from arrays"]
self.table.meta.update(self.meta)
def _load_ascii(self):
self.table = ioascii.read(self.meta["filename"],
format="basic", guess=False)
hdr_dict = utils.convert_table_comments_to_dict(self.table)
if isinstance(hdr_dict, dict):
self.headers += [hdr_dict]
else:
self.headers += [None]
self.meta.update(self.table.meta)
self.meta.update(hdr_dict)
# self.table.meta.update(hdr_dict)
self.table.meta.update(self.meta)
if self.table.meta.get("cmds"):
self.table.meta.pop("cmds")
self.meta["history"] += ["ASCII table read from "
f"{self.meta['filename']}"]
def _load_fits(self):
self._file = fits.open(self.meta["filename"])
for ext in self._file:
self.headers += [ext.header]
self.meta.update(dict(self._file[0].header))
self.meta["history"] += ["Opened handle to FITS file "
f"{self.meta['filename']}"]
[docs] def get_data(self, ext=0, layer=None):
"""
Return either a table or a ImageHDU object.
.. note:: Use this call for reading in individual FITS extensions.
The ``.data`` handle will read in **all** extensions and return an
HDUList object
Parameters
----------
ext : int
layer : int
If the FITS extension is a data cube, layer corresponds to a slice
from this cube of ``<ImageHDU>.data[layer, :, :]``
Returns
-------
data_set : astropy.Table, fits.ImageHDU
"""
data_set = None
if self.is_fits:
if isinstance(self._file[ext], fits.BinTableHDU):
data_set = Table.read(self._file[ext], format="fits")
else:
if self._file[ext].data is not None:
data_dims = len(self._file[ext].data.shape)
if data_dims == 3 and layer is not None:
data_set = self._file[ext].data[layer]
else:
data_set = self._file[ext].data
else:
data_set = self.table
return data_set
@property
def is_fits(self):
flag = False
if isinstance(self._file, fits.HDUList):
flag = True
elif isinstance(self.meta["filename"], str):
flag = utils.is_fits(self.meta["filename"])
return flag
@property
def data(self):
data_set = None
if self.is_fits:
for ii in range(len(self._file)):
data_set = self.get_data(ii)
if data_set is not None:
break
else:
data_set = self.table
return data_set
[docs] def validate(self, etype):
etype_colname = utils.real_colname("ETYPE", self.meta.colnames)
return self.meta[etype_colname] == etype