Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Fix from table #24

Merged
merged 7 commits into from

3 participants

@wkerzendorf
Owner

Fixed up from_table-classmethod to add documentation and masks and flags. This should be merged after #23.

@wkerzendorf
Owner

@keflavich @hamogu any comments? if not will merge in 6 hours

@hamogu hamogu commented on the diff
specutils/spectrum1d.py
((44 lines not shown))
flux = table[flux_column]
- disp = table[dispersion_column]
+ dispersion = table[dispersion_column]
if uncertainty_column is not None:
uncertainty = table[uncertainty_column]
@hamogu Collaborator
hamogu added a note

Should we check that flux.units and uncertainty.units are the same? Spectrum1D expects them to be the same (which is a sensible design decision, I think).
I can easility imagine cases, where the input table has e.g. fluxes in 10^-7 erg/s/cm^2 and uncertainities in 10^-9 erg/s/cm. This is not a place to convert the units, but we could issue a warning if they don't match.

@wkerzendorf Owner

@hamogu done! Check it out and if you're happy we can merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
specutils/spectrum1d.py
((47 lines not shown))
if uncertainty_column is not None:
uncertainty = table[uncertainty_column]
+ if uncertainty.unit is not flux.unit:
@keflavich Owner

Is this the right check? i.e., are uncertainty.unit and flux.unit the same object? Usually I'd think == is more appropriate, but not sure.

@hamogu Collaborator
hamogu added a note

+1 to not ... == ... , or more to !=

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
specutils/spectrum1d.py
((53 lines not shown))
else:
uncertainty = None
- return cls.from_array(flux=flux.data, disp=disp.data, uncertainty=uncertainty, dispersion_unit=disp.units, unit=flux.units)
+ if isinstance(flag_columns, basestring):
+ flags = table[flag_columns]
+ elif misc.isiterable(flag_columns):
+ flags = FlagCollection(shape=flux.shape)
+ for flag_column in flag_columns:
+ flags[flag_column] = table[flag_column]
+ else:
+ raise ValueError('flag_columns should either be a string or a list of strings')
@keflavich Owner

a list -> an iterable

@hamogu Collaborator
hamogu added a note

@keflavich While you are certainly right, I kind of like the simpler language of a list. In 90% of the use cases it probably is a list of strings and for a python beginner the term "an iterable" is a hard nut to crack.

@keflavich Owner

@hamogu I generally agree with you. Maybe for precision's sake, we could say a list (or an iterable)? It's a little more verbose, but I think it would be good to know as a user if a tuple or array is acceptable (saves me from doing arr.tolist() thinking that only lists are OK)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
specutils/spectrum1d.py
((53 lines not shown))
else:
uncertainty = None
- return cls.from_array(flux=flux.data, disp=disp.data, uncertainty=uncertainty, dispersion_unit=disp.units, unit=flux.units)
+ if isinstance(flag_columns, basestring):
+ flags = table[flag_columns]
+ elif misc.isiterable(flag_columns):
+ flags = FlagCollection(shape=flux.shape)
+ for flag_column in flag_columns:
+ flags[flag_column] = table[flag_column]
+ else:
+ raise ValueError('flag_columns should either be a string or a list of strings')
+
+ return cls.from_array(flux=flux.data, dispersion=dispersion.data, uncertainty=uncertainty,
+ dispersion_unit=dispersion.units, unit=flux.units, mask=table.mask, flags=flags)
@keflavich Owner

Line wrap? I can't see the end of this line on github, so I assume its >80 chars. (others below too)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@keflavich
Owner

Only a few minor changes needed, then it can be merged.

@wkerzendorf
Owner

@keflavich @hamogu anything else - otherwise will merge in 6 hours.

@wkerzendorf wkerzendorf merged commit d00f357 into from
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
Showing with 58 additions and 20 deletions.
  1. +58 −20 specutils/spectrum1d.py
View
78 specutils/spectrum1d.py
@@ -6,7 +6,9 @@
__all__ = ['Spectrum1D', 'spec_operation']
from astropy import log
-from astropy.nddata import NDData
+from astropy.nddata import NDData, FlagCollection
+
+from astropy.utils import misc
from .wcs import Spectrum1DLookupWCS, Spectrum1DLinearWCS
@@ -22,13 +24,13 @@ class Spectrum1D(NDData):
@classmethod
- def from_array(cls, disp, flux, dispersion_unit=None, uncertainty=None, mask=None, flags=None, meta=None,
+ def from_array(cls, dispersion, flux, dispersion_unit=None, uncertainty=None, mask=None, flags=None, meta=None,
unit=None, copy=True):
"""Initialize `Spectrum1D`-object from two `numpy.ndarray` objects
Parameters:
-----------
- disp : `~numpy.ndarray`
+ dispersion : `~numpy.ndarray`
The dispersion for the Spectrum (i.e. an array of wavelength points).
flux : `~numpy.ndarray`
@@ -67,27 +69,64 @@ def from_array(cls, disp, flux, dispersion_unit=None, uncertainty=None, mask=Non
Raises
------
ValueError
- If the `disp` and `flux` arrays cannot be broadcast (e.g. their shapes
+ If the `dispersion` and `flux` arrays cannot be broadcast (e.g. their shapes
do not match), or the input arrays are not one dimensional.
"""
- if disp.ndim != 1 or disp.shape != flux.shape:
- raise ValueError("disp and flux need to be one-dimensional Numpy arrays with the same shape")
- spec_wcs = Spectrum1DLookupWCS(disp, unit=dispersion_unit)
+ if dispersion.ndim != 1 or dispersion.shape != flux.shape:
+ raise ValueError("dispersion and flux need to be one-dimensional Numpy arrays with the same shape")
+ spec_wcs = Spectrum1DLookupWCS(dispersion, unit=dispersion_unit)
return cls(data=flux, wcs=spec_wcs, unit=unit)
@classmethod
- def from_table(cls, table, mask=None, dispersion_column='disp', flux_column='flux', uncertainty_column=None):
+ def from_table(cls, table, dispersion_column='dispersion', flux_column='flux', uncertainty_column=None,
+ flag_columns=None):
+ """
+ Initializes a `Spectrum1D`-object from an `~astropy.table.Table` object
+
+ Parameters
+ ----------
+
+ table : ~astropy.table.Table object
+
+ dispersion_column : str, optional
+ name of the dispersion column. default is 'dispersion'
+
+ flux_column : str, optional
+ name of the flux column. default is 'flux'
+
+ uncertainty_column : str, optional
+ name of the uncertainty column. If set to None uncertainty is set to None. default is None
+
+ flag_columns : str or list, optional
+ name or names of flag columns. If multiple names are supplied a ~astropy.nddata.FlagCollection will be built.
+ default is None
+ """
+
flux = table[flux_column]
- disp = table[dispersion_column]
+ dispersion = table[dispersion_column]
if uncertainty_column is not None:
uncertainty = table[uncertainty_column]
@hamogu Collaborator
hamogu added a note

Should we check that flux.units and uncertainty.units are the same? Spectrum1D expects them to be the same (which is a sensible design decision, I think).
I can easility imagine cases, where the input table has e.g. fluxes in 10^-7 erg/s/cm^2 and uncertainities in 10^-9 erg/s/cm. This is not a place to convert the units, but we could issue a warning if they don't match.

@wkerzendorf Owner

@hamogu done! Check it out and if you're happy we can merge.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ if uncertainty.unit != flux.unit:
+ log.warning('"uncertainty"-column and "flux"-column do not share the units (%s vs %s) ',
+ uncertainty.unit, flux.unit)
else:
uncertainty = None
- return cls.from_array(flux=flux.data, disp=disp.data, uncertainty=uncertainty, dispersion_unit=disp.units, unit=flux.units)
+ if isinstance(flag_columns, basestring):
+ flags = table[flag_columns]
+ elif misc.isiterable(flag_columns):
+ flags = FlagCollection(shape=flux.shape)
+ for flag_column in flag_columns:
+ flags[flag_column] = table[flag_column]
+ else:
+ raise ValueError('flag_columns should either be a string or a list (or iterable) of strings')
+
+ return cls.from_array(flux=flux.data, dispersion=dispersion.data,
+ uncertainty=uncertainty, dispersion_unit=dispersion.units,
+ unit=flux.units, mask=table.mask, flags=flags)
@@ -102,7 +141,7 @@ def from_ascii(cls, filename, uncertainty=None, mask=None, dtype=np.float, comme
if raw_data.shape[1] != 2:
raise ValueError('data contained in filename must have exactly two columns')
- return cls.from_array(disp=raw_data[:,0], flux=raw_data[:,1], uncertainty=uncertainty, mask=mask)
+ return cls.from_array(dispersion=raw_data[:,0], flux=raw_data[:,1], uncertainty=uncertainty, mask=mask)
@classmethod
def from_fits(cls, filename, uncertainty=None):
@@ -121,7 +160,7 @@ def flux_setter(self, flux):
self.data = flux
@property
- def disp(self):
+ def dispersion(self):
#returning the disp
if not hasattr(self.wcs, 'lookup_table'):
self.wcs.create_lookup_table(np.arange(len(self.flux)))
@@ -137,7 +176,7 @@ def flux_unit(self):
return self.unit
- def interpolate(self, new_disp, kind='linear', bounds_error=True, fill_value=np.nan):
+ def interpolate(self, new_dispersion, kind='linear', bounds_error=True, fill_value=np.nan):
"""Interpolates onto a new wavelength grid and returns a new `Spectrum1D`-object.
Parameters
@@ -183,13 +222,13 @@ def interpolate(self, new_disp, kind='linear', bounds_error=True, fill_value=np.
" interpolate to new dispersion map without this"+
" (need scipy.interpolate.interp1d)")
- spectrum_interp = interpolate.interp1d(self.disp,
+ spectrum_interp = interpolate.interp1d(self.dispersion,
self.flux,
kind=kind,
bounds_error=bounds_error,
fill_value=fill_value)
- new_flux = spectrum_interp(new_disp)
+ new_flux = spectrum_interp(new_dispersion)
# We need to perform error calculation for the new dispersion map
if self.uncertainty is None:
@@ -198,7 +237,7 @@ def interpolate(self, new_disp, kind='linear', bounds_error=True, fill_value=np.
# After having a short think about it, it seems reasonable to me only to
# take the nearest uncertainty for each interpolated dispersion point
- new_uncertainty = interpolate.interp1d(self.disp,
+ new_uncertainty = interpolate.interp1d(self.dispersion,
self.flux,
kind=1, # Nearest
bounds_error=bounds_error,
@@ -208,7 +247,7 @@ def interpolate(self, new_disp, kind='linear', bounds_error=True, fill_value=np.
if self.mask is None:
new_mask = None
else:
- new_mask = interpolate.interp1d(self.disp,
+ new_mask = interpolate.interp1d(self.dispersion,
self.flux,
kind=1, # Nearest
bounds_error=bounds_error,
@@ -217,7 +256,7 @@ def interpolate(self, new_disp, kind='linear', bounds_error=True, fill_value=np.
# As for flags it is not entirely clear to me what the best behaviour is
# In the face of uncertainty, for the time being, I am discarding flags
- return self.__class__.from_array(new_disp,
+ return self.__class__.from_array(new_dispersion,
new_flux,
uncertainty=new_uncertainty,
mask=new_mask,
@@ -296,5 +335,4 @@ def slice_index(self, start=None, stop=None):
# reasonably) assuming that __slice__ will be a NDData base function
# which we will inherit.
raise NotImplemented('Will presumeably implemented in core NDDATA')
- return self.__slice__(start_index, stop_index)
-
+
Something went wrong with that request. Please try again.