def cut_edges(self, mini, maxi): """Cut the spectrum in wavelength range. Parameters ---------- mini: float Lower limit to cut the spectrum. maxi: float Upper limit to cut the spectrum. Returns ------- out: NirsdustSpectrum object Return a new instance of class NirdustSpectrum cut in wavelength. """ region = su.SpectralRegion(mini * u.AA, maxi * u.AA) cutted_spec1d = sm.extract_region(self.spec1d, region) cutted_freq_axis = cutted_spec1d.spectral_axis.to(u.Hz) new_len = len(cutted_spec1d.flux) kwargs = attr.asdict(self) kwargs.update( spec1d=cutted_spec1d, spectrum_length=new_len, frequency_axis=cutted_freq_axis, ) return NirdustSpectrum(**kwargs)
def frecord(widget): wls_selected = spec_data['wl'][ spec_data.subsets[0].to_index_list()] reg = specutils.SpectralRegion( np.min(wls_selected) * spec.wavelength.unit, np.max(wls_selected) * spec.wavelength.unit) result_text.value = 'Recorded {}: {} to {}'.format( line_selection.value, reg.lower, reg.upper) self.regions[line_selection.value] = reg z_text.value = specutils.analysis.centroid( spec, reg) / rest_lines[line_selection.value] - 1
def measure_EW_simple(waves, fluxes, unc, line, wave_range, feat_type, line_width=[0., 0.], plot=False, file=None, verbose=False, name='Unknown Line', diag_path=None): feat_type = feat_type.lower() #check to see if there's flux if np.all(np.abs(fluxes) <= 2 * unc): print('Warning! No flux in region for {}!'.format(name)) res = 'No Flux' return res, res feature_waves = waves * u.AA feature_flux = fluxes * u.erg / (u.AA * u.s * (u.cm)**2) uncertainties = unc feature_unc = astropy.nddata.StdDevUncertainty(unc * u.erg / (u.AA * u.s * (u.cm)**2)) feature_spec = specutils.Spectrum1D(spectral_axis=feature_waves, flux=feature_flux, uncertainty=feature_unc) continuum_fit = specutils.fitting.fit_generic_continuum(feature_spec)( feature_spec.spectral_axis) #looping to refine the continuum fit #initial mask around the feature mask = np.ones(len(feature_flux), dtype='bool') mask[(feature_waves.value > line_width[0]) & (feature_waves.value < line_width[1])] = False subtr_spec = feature_spec - continuum_fit for i in range(5): masked_spec = specutils.Spectrum1D(spectral_axis=feature_waves[mask], flux=feature_flux[mask], uncertainty=feature_unc[mask]) continuum_model = specutils.fitting.fit_generic_continuum(masked_spec) continuum_fit = continuum_model(feature_spec.spectral_axis) subtr_spec = feature_spec - continuum_fit mask = np.abs(subtr_spec.flux.value) < 3 * uncertainties if verbose: plt.plot(feature_waves, continuum_fit) plt.plot(feature_waves, feature_spec.flux) plt.title('refine {}'.format(i)) plt.show() continuum_fit = continuum_model(feature_spec.spectral_axis) subtr_spec = feature_spec - continuum_fit if plot or (diag_path is not None): plt.figure(figsize=[12, 7]) plt.plot(feature_spec.wavelength, feature_spec.flux) plt.plot(feature_spec.wavelength, continuum_fit) #plt.xlabel('Wavelength') #plt.ylabel('Flux Density') plt.title('Continuum fit of {}'.format(name)) if isinstance(file, str): plt.savefig('kastclassify_EW_continuum_' + file) if diag_path is not None: plt.savefig(diag_path + '{}_EW_continuum_fit.png'.format(name)) if plot: plt.show() plt.close() #finding line center near_line_waves = feature_waves[(feature_waves.value >= (line - 10)) & (feature_waves.value <= (line + 10))] near_line_fluxes = subtr_spec.flux.value[ (feature_waves.value >= (line - 10)) & (feature_waves.value <= (line + 10))] if feat_type == 'absorption': line = near_line_waves.value[near_line_fluxes == np.amin( near_line_fluxes)] elif feat_type == 'emission': line == near_line_waves.value[near_line_fluxes == np.amax( near_line_fluxes)] else: print('WARNING! Feature type {} is unknown'.format(feat_type)) res = 'Unknown Feature Type' return res, res #create continuum normalized spectrum and continuum subtracted spectrum norm_spec = feature_spec / continuum_fit #re-centering using subtracted spectrum #find all features in this spectrum line_info = specutils.fitting.find_lines_threshold(subtr_spec) if len(line_info) == 0: print('Warning! No features detected for {}!'.format(name)) res = 'No Feature Detected' return res, res try: #the actual line center is the closest feature to our expected center nearest = np.argmin( np.abs(line_info[line_info['line_type'] == feat_type] ['line_center'].value - line)) except: print('Warning! No features detected for {}!'.format(name)) res = 'No Feature Detected' return res, res line_center = line_info[line_info['line_type'] == feat_type][nearest]['line_center'].value #if the line width is not defined, calculate it #calculated as 1.5 * FWHM if line_width[0] == 0.: near_line_waves = feature_waves[(feature_waves.value >= (line - 15)) & (feature_waves.value <= (line + 15))].value near_line_fluxes = subtr_spec.flux.value[ (feature_waves.value >= (line - 15)) & (feature_waves.value <= (line + 15))] if feat_type == 'absorption': near_line_fluxes = np.abs(near_line_fluxes) elif feat_type == 'emission': pass else: print('WARNING! Feature type {} is unknown'.format(feat_type)) res = 'Unknown Feature Type' return res, res max_flx = np.amax(near_line_fluxes) half_max = max_flx / 2 outside = near_line_fluxes < half_max try: lower_bound = max(near_line_waves[(near_line_waves < line_center) & outside]) upper_bound = min(near_line_waves[(near_line_waves > line_center) & outside]) except: print('Warning! No features detected for {}!'.format(name)) res = 'No Feature Detected' return res, res FWHM = upper_bound - lower_bound line_width[0] = 1.5 * FWHM line_width[1] = 1.5 * FWHM #pick out the region containing the feature region = specutils.SpectralRegion((line_center - line_width[0]) * u.AA, (line_center + line_width[1]) * u.AA) #calculate the width EW = specutils.analysis.equivalent_width(norm_spec, regions=region) if plot or (diag_path is not None): fig, ax = plt.subplots(1, figsize=[12, 7]) ax.plot(norm_spec.wavelength, norm_spec.flux, label=EW) ax.axvline(line_center - line_width[0]) ax.axvline(line_center + line_width[1]) rect = matplotlib.patches.Rectangle((line_center - EW.value / 2, 0), EW.value, 1, hatch='x', fill=False) ax.add_patch(rect) ax.set_xlabel('Wavelength ({})'.format(u.AA)) ax.set_ylabel('Normalized Flux Density') ax.set_title('Equivalent Width of {}'.format(name)) fig.legend() if isinstance(file, str): fig.savefig('kastclassify_EW_width_' + file) if diag_path is not None: fig.savefig(diag_path + '{}_EW_measurement.png'.format(name)) if plot: fig.show() plt.close(fig) return EW, line_center
def test_cut_edges(NGC4945_continuum): spectrum = NGC4945_continuum region = su.SpectralRegion(20000 * u.AA, 23000 * u.AA) expected = su.manipulation.extract_region(spectrum.spec1d, region) result = spectrum.cut_edges(20000, 23000) np.testing.assert_array_equal(result.spec1d.flux, expected.flux)
def regions(self): wmin, wmax = self.wavelength[[0, -1]] return specutils.SpectralRegion(wmin, wmax)