def __init__(self, speclist, xtype='frequency', xarr=None, force=False, **kwargs): if xarr is None: self.xarr = speclist[0].xarr else: self.xarr = xarr self.units = speclist[0].units self.header = speclist[0].header self.parse_header(self.header) for spec in speclist: if not isinstance(spec, Spectrum): raise TypeError( "Must create an ObsBlock with a list of spectra.") if not np.array_equal(spec.xarr, self.xarr): if not force: raise ValueError("Mismatch between X axes in ObsBlock") if spec.units != self.units: raise ValueError("Mismatched units") if force: self.speclist = [ interpolation.interp(spec, self) for spec in speclist ] else: self.speclist = speclist self.nobs = len(self.speclist) # Create a 2-dimensional array of the data self.data = np.array([sp.data for sp in self.speclist]).swapaxes(0, 1).squeeze() self.error = np.array([sp.error for sp in self.speclist]).swapaxes(0, 1).squeeze() self.plotter = plotters.Plotter(self) self._register_fitters() self.specfit = fitters.Specfit(self, Registry=self.Registry) self.baseline = baseline.Baseline(self)
def __init__(self, speclist, xunits='GHz', **kwargs): print "Creating spectra" speclist = list(speclist) for ii, spec in enumerate(speclist): if type(spec) is str: spec = Spectrum(spec) speclist[ii] = spec self.speclist = speclist print "Concatenating data" self.xarr = units.SpectroscopicAxes( [sp.xarr.as_unit(xunits) for sp in speclist]) self.xarr.units = xunits self.xarr.xtype = units.unit_type_dict[xunits] self.data = np.ma.concatenate([sp.data for sp in speclist]) self.error = np.ma.concatenate([sp.error for sp in speclist]) self._sort() self.header = pyfits.Header() for spec in speclist: for key, value in spec.header.items(): try: self.header[key] = value except (ValueError, KeyError): warn("Could not update header KEY=%s to VALUE=%s" % (key, value)) self.plotter = plotters.Plotter(self) self._register_fitters() self.specfit = fitters.Specfit(self, Registry=self.Registry) self.baseline = baseline.Baseline(self) self.units = speclist[0].units for spec in speclist: if spec.units != self.units: raise ValueError("Mismatched units") # Special. This needs to be modified to be more flexible; for now I need it to work for nh3 self.plot_special = None self.plot_special_kwargs = {}
def __init__(self, filename=None, filetype=None, xarr=None, data=None, error=None, header=None, doplot=False, maskdata=True, plotkwargs={}, xarrkwargs={}, **kwargs): """ Create a Spectrum object. Must either pass in a filename or ALL of xarr, data, and header, plus optionally error. kwargs are passed to the file reader Parameters ---------- filename : string The file to read the spectrum from. If data, xarr, and error are specified, leave filename blank. filetype : string Specify the file type (only needed if it cannot be automatically determined from the filename) xarr : `units.SpectroscopicAxis` or `np.ndarray` The X-axis of the data. If it is an np.ndarray, you must pass `xarrkwargs` or a valid header if you want to use any of the unit functionality. data : `np.ndarray` The data array (must have same length as xarr) error : `np.ndarray` The error array (must have same length as the data and xarr arrays) header : `pyfits.Header` or dict The header from which to read unit information. Needs to be a `pyfits.Header` instance or another dictionary-like object with the appropriate information maskdata : boolean turn the array into a masked array with all nan and inf values masked doplot : boolean Plot the spectrum after loading it? plotkwargs : dict keyword arguments to pass to the plotter xarrkwargs : dict keyword arguments to pass to the SpectroscopicAxis initialization (can be used in place of a header) Examples -------- >>> sp = pyspeckit.Spectrum(data=np.random.randn(100), xarr=np.linspace(-50, 50, 100), error=np.ones(100)*0.1, xarrkwargs={'unit':'km/s', 'refX':4.829, 'refX_units':'GHz', 'xtype':'VLSR-RAD'}, header={}) >>> xarr = pyspeckit.units.SpectroscopicAxis(np.linspace(-50,50,100), units='km/s', refX=6562.83, refX_units='angstroms') >>> data = np.random.randn(100)*5 + np.random.rand(100)*100 >>> err = np.sqrt(data/5.)*5. # Poisson noise >>> sp = pyspeckit.Spectrum(data=data, error=err, xarr=xarr, header={}) >>> # if you already have a simple fits file >>> sp = pyspeckit.Spectrum('test.fits') """ if filename: if filetype is None: suffix = filename.rsplit('.', 1)[1] if suffix in readers.suffix_types: # use the default reader for that suffix filetype = readers.suffix_types[suffix][0] reader = readers.readers[filetype] else: raise TypeError("File with suffix %s is not recognized." % suffix) else: if filetype in readers.readers: reader = readers.readers[filetype] else: raise TypeError("Filetype %s not recognized" % filetype) self.data, self.error, self.xarr, self.header = reader( filename, **kwargs) # these should probably be replaced with registerable function s... if filetype in ('fits', 'tspec', 'pyfits', 'sdss'): self.parse_header(self.header) elif filetype is 'txt': self.parse_text_header(self.header) elif filetype in ('hdf5', 'h5'): self.parse_hdf5_header(self.header) if isinstance(filename, str): self.fileprefix = filename.rsplit( '.', 1)[0] # Everything prior to .fits or .txt elif xarr is not None and data is not None: # technically, this is unpythonic. But I don't want to search for all 10 attributes required. if issubclass(type(xarr), units.SpectroscopicAxis): self.xarr = xarr else: self.xarr = units.SpectroscopicAxis(xarr, **xarrkwargs) self.data = data if error is not None: self.error = error else: self.error = data * 0 if hasattr(header, 'get'): self.header = header else: # set as blank warn("WARNING: Blank header.") self.header = pyfits.Header() self.parse_header(self.header) if maskdata: if hasattr(self.data, 'mask'): self.data.mask += np.isnan(self.data) + np.isinf(self.data) self.error.mask += np.isnan(self.data) + np.isinf(self.data) else: self.data = np.ma.masked_where( np.isnan(self.data) + np.isinf(self.data), self.data) self.error = np.ma.masked_where( np.isnan(self.data) + np.isinf(self.data), self.error) self.plotter = plotters.Plotter(self) self._register_fitters() self.specfit = fitters.Specfit(self, Registry=self.Registry) self.baseline = baseline.Baseline(self) self.speclines = speclines self._sort() # Special. This needs to be modified to be more flexible; for now I need it to work for nh3 self.plot_special = None self.plot_special_kwargs = {} if doplot: self.plotter(**plotkwargs)
def slice(self, start=None, stop=None, units='pixel', copy=True, preserve_fits=False): """Slicing the spectrum .. WARNING:: this is the same as cropping right now, but it returns a copy instead of cropping inplace Parameters ---------- start : numpy.float or int start of slice stop : numpy.float or int stop of slice units : str allowed values are any supported physical unit, 'pixel' copy : bool Return a 'view' of the data or a copy? preserve_fits : bool Save the fitted parameters from self.fitter? """ if units in ('pixel', 'pixels'): start_ind = start stop_ind = stop else: x_in_units = self.xarr.as_unit(units) start_ind = x_in_units.x_to_pix(start) stop_ind = x_in_units.x_to_pix(stop) if start_ind > stop_ind: start_ind, stop_ind = stop_ind, start_ind spectrum_slice = slice(start_ind, stop_ind) if copy: sp = self.copy() else: sp = self sp.data = sp.data[spectrum_slice] if sp.error is not None: sp.error = sp.error[spectrum_slice] sp.xarr = sp.xarr[spectrum_slice] if copy: # create new specfit / baseline instances (otherwise they'll be the wrong length) sp._register_fitters() sp.baseline = baseline.Baseline(sp) sp.specfit = fitters.Specfit(sp, Registry=sp.Registry) else: # inplace modification sp.baseline.crop(start_ind, stop_ind) sp.specfit.crop(start_ind, stop_ind) if preserve_fits: sp.specfit.modelpars = self.specfit.modelpars sp.specfit.parinfo = self.specfit.parinfo sp.baseline.baselinepars = self.baseline.baselinepars sp.baseline.order = self.baseline.order return sp