def test_get_fitdata(): data_path = pkg_resources.resource_filename("measure_extinction", "data/") # read in the observed data of the stars redstar = StarData("hd229238.dat", path=data_path) compstar = StarData("hd204172.dat", path=data_path) # calculate the extinction curve ext = ExtData() ext.calc_elx(redstar, compstar) # once wavelenth units saved, update FITS file and use this line instead # of the 4 lines above # ext = ExtData(filename=data_path + "hd283809_hd064802_ext.fits") wave, y, unc = ext.get_fitdata( ["BAND", "IUE"], remove_uvwind_region=True, remove_lya_region=True ) # fitting routines often cannot handle units, make sure none are present for cursrc in ext.waves.keys(): assert isinstance(wave, u.Quantity) assert not isinstance(y, u.Quantity) assert not isinstance(unc, u.Quantity)
def SED_to_StarData(self, sed): """ Convert the model created SED into a StarData object. Needed to plug into generating an ExtData object. Parameters ---------- sed : object SED of each component """ sd = StarData(None) for cspec in sed.keys(): if cspec == "BAND": # populate the BAND info sd.data["BAND"] = BandData("BAND") for k, cband in enumerate(self.band_names): sd.data["BAND"].band_fluxes[cband] = (sed["BAND"][k], 0.0) sd.data["BAND"].get_band_mags_from_fluxes() else: # populate the spectral info sd.data[cspec] = SpecData(cspec) sd.data[cspec].waves = self.waves[cspec] sd.data[cspec].n_waves = len(sd.data[cspec].waves) sd.data[cspec].fluxes = sed[cspec] * ( u.erg / ((u.cm ** 2) * u.s * u.angstrom) ) sd.data[cspec].uncs = 0.0 * sd.data[cspec].fluxes sd.data[cspec].npts = np.full((sd.data[cspec].n_waves), 1.0) print(sd.data[cspec].fluxes) return sd
def SNR_final_spec(data_path, plot_path, stars, plot=False): """ - Calculate the median SNR of the final used spectra after the 1% noise addition and after "merging" (in merge_obsspec.py), in certain wavelength regions - Plot the SNR of the final used spectra if requested Parameters ---------- data_path : string Path to the data files plot_path : string Path to save the plots stars : list of strings List of stars for which to calculate (and plot) the SNR plot : boolean [default=False] Whether or not to plot the SNR vs. wavelength for every star Returns ------- - Median SNRs in certain wavelength regions - Plots of the SNR vs. wavelength (if requested) """ meds = np.zeros((3, len(stars))) for j, star in enumerate(stars): # obtain the flux values and uncertainties starobs = StarData( "%s.dat" % star.lower(), path=data_path, use_corfac=True, ) waves, fluxes, uncs = starobs.get_flat_data_arrays(["SpeX_SXD", "SpeX_LXD"]) # calculate the median SNR in certain wavelength regions ranges = [ (0.79, 2.54), (2.85, 4.05), (4.55, 5.5), ] SNR = fluxes / uncs for i, range in enumerate(ranges): mask = (waves > range[0]) & (waves < range[1]) meds[i][j] = np.median(SNR[mask]) # plot SNR vs. wavelength if requested if plot: fig, ax = plt.subplots() ax.scatter(waves, fluxes / uncs, s=1) plt.savefig(plot_path + star + "_SNR.pdf") print(ranges[0], np.nanmin(meds[0]), np.nanmax(meds[0])) print(ranges[1], np.nanmin(meds[1]), np.nanmax(meds[1])) print(ranges[2], np.nanmin(meds[2]), np.nanmax(meds[2]))
def calc_extinction(redstarname, compstarname, path): # read in the observed data for both stars redstarobs = StarData("%s.dat" % redstarname.lower(), path=path) compstarobs = StarData("%s.dat" % compstarname.lower(), path=path) # calculate the extinction curve extdata = ExtData() extdata.calc_elx(redstarobs, compstarobs) extdata.save(path + "%s_%s_ext.fits" % (redstarname.lower(), compstarname.lower()))
def calc_save_corfac_spex(starname, path): # read in the data file (do not use the correction factors at this point) star_data = StarData("%s.dat" % starname.lower(), path=path, use_corfac=False) star_phot = star_data.data["BAND"] # if the LXD scaling factor has been set manually, warn the user and do not recalculate the scaling factors. if star_data.LXD_man: print( "The LXD scaling factor has been set manually and the scaling factors (SXD and LXD) will not be recalculated!" ) return # check which spectra are available, # and calculate the correction factors for the spectra (if they have not been set manually) if "SpeX_SXD" in star_data.data.keys(): star_spec_SXD = star_data.data["SpeX_SXD"] corfac_SXD = calc_corfac(star_phot, star_spec_SXD, ["J", "H", "K"]) else: corfac_SXD = None if "SpeX_LXD" in star_data.data.keys(): star_spec_LXD = star_data.data["SpeX_LXD"] corfac_LXD = calc_corfac( star_phot, star_spec_LXD, ["IRAC1", "IRAC2", "WISE1", "WISE2", "L", "M"]) else: corfac_LXD = None # add the correction factors to the data file if not already in there, # otherwise overwrite the existing correction factors if "SpeX_SXD" in star_data.corfac.keys(): datafile = open(path + "%s.dat" % starname.lower(), "w") for ln, line in enumerate(star_data.datfile_lines): if "corfac_spex_SXD" in line: star_data.datfile_lines[ln] = ("corfac_spex_SXD = " + str(corfac_SXD) + "\n") datafile.write(star_data.datfile_lines[ln]) datafile.close() else: with open(path + "%s.dat" % starname.lower(), "a") as datafile: datafile.write("corfac_spex_SXD = " + str(corfac_SXD) + "\n") if "SpeX_LXD" in star_data.corfac.keys(): datafile = open(path + "%s.dat" % starname.lower(), "w") for ln, line in enumerate(star_data.datfile_lines): if "corfac_spex_LXD" in line: star_data.datfile_lines[ln] = ("corfac_spex_LXD = " + str(corfac_LXD) + "\n") datafile.write(star_data.datfile_lines[ln]) datafile.close() else: with open(path + "%s.dat" % starname.lower(), "a") as datafile: datafile.write("corfac_spex_LXD = " + str(corfac_LXD) + "\n")
def measure_SNR(spex_path, data_path, plot_path, star, ranges): """ Measure the SNR of a spectrum, by fitting straight lines to pieces of the spectrum """ # plot the spectrum to define regions without spectral lines fig, ax = plot_spectrum(star, data_path, range=[0.75, 5.6], log=True) # read in all bands and spectra for this star starobs = StarData("%s.dat" % star.lower(), path=data_path, use_corfac=True) # obtain flux values at a few wavelengths and fit a straight line through the data waves, fluxes, uncs = starobs.get_flat_data_arrays(["SpeX_SXD", "SpeX_LXD"]) print(star) for range in ranges: min_indx = np.abs(waves - range[0]).argmin() max_indx = np.abs(waves - range[1]).argmin() func = Linear1D() fit = LinearLSQFitter() fit_result = fit(func, waves[min_indx:max_indx], fluxes[min_indx:max_indx]) residu = fluxes[min_indx:max_indx] - fit_result(waves[min_indx:max_indx]) # calculate the SNR from the data data_sxd = Table.read( spex_path + star + "_sxd.txt", format="ascii", ) data_lxd = Table.read( spex_path + star + "_lxd.txt", format="ascii", ) data = vstack([data_sxd, data_lxd]) data.sort("col1") print("wave_range", range) min_indx2 = np.abs(data["col1"] - range[0]).argmin() max_indx2 = np.abs(data["col1"] - range[1]).argmin() SNR_data = np.nanmedian((data["col2"] / data["col3"])[min_indx2:max_indx2]) print("SNR from data", SNR_data) # calculate the SNR from the noise around the linear fit mean, median, stddev = sigma_clipped_stats(residu) SNR_fit = np.median(fluxes[min_indx:max_indx] / stddev) print("SNR from fit", SNR_fit) # plot the fitted lines on top of the spectrum ax.plot( waves[min_indx:max_indx], fit_result(waves[min_indx:max_indx]), lw=2, alpha=0.8, color="k", ) fig.savefig(plot_path + star + "_SNR_measure.pdf")
def get_colors(starnames): # standard stars n_stars = len(starnames) xvals = np.zeros((n_stars, 2)) yvals = np.zeros((n_stars, 2)) for i in range(n_stars): stardata = StarData(subpath + starnames[i] + ".dat", path=path, use_corfac=True) b1vals = stardata.data["BAND"].get_band_mag(xbands[0]) b2vals = stardata.data["BAND"].get_band_mag(xbands[1]) if (b1vals is not None) and (b2vals is not None): xvals[i, 0] = b1vals[0] - b2vals[0] xvals[i, 1] = np.sqrt((b1vals[1]**2) + (b2vals[1]**2)) b1vals = stardata.data["BAND"].get_band_mag(ybands[0]) b2vals = stardata.data["BAND"].get_band_mag(ybands[1]) if (b1vals is not None) and (b2vals is not None): yvals[i, 0] = b1vals[0] - b2vals[0] yvals[i, 1] = np.sqrt((b1vals[1]**2) + (b2vals[1]**2)) return (xvals, yvals)
def test_load_stardata(): # get the location of the data files data_path = pkg_resources.resource_filename("measure_extinction", "data/") # read in the observed data on the star star = StarData("hd229238.dat", path=data_path) assert "BAND" in star.data.keys() assert "IUE" in star.data.keys()
def test_calc_AV_RV(): # get the location of the data files data_path = pkg_resources.resource_filename("measure_extinction", "data/") # read in the observed data of the stars redstar = StarData("hd229238.dat", path=data_path) compstar = StarData("hd204172.dat", path=data_path) # calculate the extinction curve ext = ExtData() ext.calc_elx(redstar, compstar) # calculate A(V) ext.calc_AV() np.testing.assert_almost_equal(ext.columns["AV"], 2.5626900237367805) # calculate R(V) ext.calc_RV() np.testing.assert_almost_equal(ext.columns["RV"], 2.614989769244703)
def test_calc_ext(): # get the location of the data files data_path = pkg_resources.resource_filename("measure_extinction", "data/") # read in the observed data of the stars redstar = StarData("hd229238.dat", path=data_path) compstar = StarData("hd204172.dat", path=data_path) # calculate the extinction curve ext = ExtData() ext.calc_elx(redstar, compstar) # test that the quantities have units (or not as appropriate) for cursrc in ext.waves.keys(): assert isinstance(ext.waves[cursrc], u.Quantity) assert not isinstance(ext.exts[cursrc], u.Quantity) assert not isinstance(ext.uncs[cursrc], u.Quantity) assert not isinstance(ext.npts[cursrc], u.Quantity) # check that the wavelengths can be converted to microns for cursrc in ext.waves.keys(): twave = ext.waves[cursrc].to(u.micron) assert twave.unit == u.micron
def plot_mir_set( ax, starnames, extra_off_val=0.0, plam4=True, norm_wave_range=[6.0, 10.0] * u.micron, col_vals=["b", "g", "r", "m", "c", "y"], ann_xvals=[35.0, 42.0] * u.micron, ann_wave_range=[9.0, 15.0] * u.micron, ann_rot=5.0, ann_offset=0.2, fontsize=12, path="/home/kgordon/Python_git/extstar_data/", subpath="DAT_files/", ): """ Plot a set of spectra """ n_col = len(col_vals) for i in range(len(starnames)): stardata = StarData(subpath + starnames[i] + ".dat", path=path, use_corfac=True) stardata.plot( ax, mlam4=True, norm_wave_range=norm_wave_range, yoffset=extra_off_val + 0.5 * i, yoffset_type="add", pcolor=col_vals[i % n_col], annotate_key="IRS", annotate_wave_range=ann_wave_range, annotate_text=starnames[i] + " " + stardata.sptype, fontsize=fontsize, annotate_rotation=ann_rot, annotate_yoffset=ann_offset, )
def read_tlusty_models(self, filebase, path): """ Read in the TLusty stellar model atmosphere predictions. All are assumed to be in the measure_extinction data format. """ self.filebase = filebase # read in the model data model_files = glob.glob("%s/%s" % (path, filebase)) # basic stellar atmosphere data self.n_models = len(model_files) self.temps = np.zeros(self.n_models) self.gravs = np.zeros(self.n_models) self.mets = np.zeros(self.n_models) # read in the stellar atmosphere models self.model_spectra = [] for i, file in enumerate(model_files): # decode the filename to get the stellar parameters spos = file.rfind('/') Tpos = file.find('T', spos) gpos = file.find('g', spos) vpos = file.find('v', spos) zpos = file.find('z', spos) dpos = file.find('.dat', spos) self.temps[i] = np.log10(float(file[Tpos + 1:gpos])) self.gravs[i] = float(file[gpos + 1:vpos]) * 1e-2 self.mets[i] = np.log10(float(file[zpos + 1:dpos])) # get the data self.model_spectra.append(StarData(file), path='../') # provide the width in model space for each parameter # used in calculating the nearest neighbors self.temp_min = min(self.temps) self.temp_max = max(self.temps) self.temp_width2 = (self.temp_max - self.temp_min)**2 self.temp_width2 = 1.0 self.grav_min = min(self.gravs) self.grav_max = max(self.gravs) self.grav_width2 = (self.grav_max - self.grav_min)**2 self.met_min = min(self.mets) self.met_max = max(self.mets) self.met_width2 = (self.met_max - self.met_min)**2 self.met_width2 *= 4.0
def test_units_stardata(): # get the location of the data files data_path = pkg_resources.resource_filename("measure_extinction", "data/") # read in the observed data of the star star = StarData("hd229238.dat", path=data_path) # test that the quantities have units for cursrc in star.data.keys(): assert isinstance(star.data[cursrc].waves, u.Quantity) assert isinstance(star.data[cursrc].wave_range, u.Quantity) assert isinstance(star.data[cursrc].fluxes, u.Quantity) assert isinstance(star.data[cursrc].uncs, u.Quantity) fluxunit = u.erg / ((u.cm**2) * u.s * u.angstrom) # check that the wavelengths can be converted to microns and the # flux units can be converted to spectral density for cursrc in star.data.keys(): twave = star.data[cursrc].waves.to(u.micron) assert twave.unit == u.micron tflux = star.data[cursrc].fluxes.to( fluxunit, equivalencies=u.spectral_density(twave)) assert tflux.unit == fluxunit
def plot_spectrum( star, path, mlam4=False, HI_lines=False, range=None, norm_range=None, exclude=[], pdf=False, ): """ Plot the observed band and spectral data of a star Parameters ---------- star : string Name of the star for which to plot the spectrum path : string Path to the data files mlam4 : boolean [default=False] Whether or not to multiply the flux F(lambda) by lambda^4 to remove the Rayleigh-Jeans slope HI_lines : boolean [default=False] Whether or not to indicate the HI-lines in the plot range : list of 2 floats [default=None] Wavelength range to be plotted (in micron) - [min,max] norm_range : list of 2 floats [default=None] Wavelength range to use to normalize the data (in micron)- [min,max] exclude : list of strings [default=[]] List of data type(s) to exclude from the plot (e.g., IRS) pdf : boolean [default=False] Whether or not to save the figure as a pdf file Returns ------- Figure with band data points and spectrum """ # plotting setup for easier to read plots fontsize = 18 font = {"size": fontsize} plt.rc("font", **font) plt.rc("lines", linewidth=1) plt.rc("axes", linewidth=2) plt.rc("xtick.major", width=2) plt.rc("xtick.minor", width=2) plt.rc("ytick.major", width=2) plt.rc("ytick.minor", width=2) # create the plot fig, ax = plt.subplots(figsize=(13, 10)) # read in and plot all bands and spectra for this star starobs = StarData("%s.dat" % star.lower(), path=path, use_corfac=True) if norm_range is not None: norm_range = norm_range * u.micron starobs.plot(ax, norm_wave_range=norm_range, mlam4=mlam4, exclude=exclude) # plot HI-lines if requested if HI_lines: plot_HI(path, ax) # define the output name outname = star.lower() + "_spec.pdf" # zoom in on a specific region if requested if range is not None: zoom(ax, range) outname = outname.replace(".pdf", "_zoom.pdf") # finish configuring the plot ax.set_xscale("log") ax.set_yscale("log") ax.set_title(star.upper(), fontsize=50) ax.set_xlabel(r"$\lambda$ [$\mu m$]", fontsize=1.5 * fontsize) if mlam4: ax.set_ylabel( r"$F(\lambda)\ \lambda^4$ [$ergs\ cm^{-2}\ s^{-1}\ \AA^{-1}\ \mu m^4$]", fontsize=1.5 * fontsize, ) outname = outname.replace("spec", "spec_mlam4") else: ax.set_ylabel( r"$F(\lambda)$ [$ergs\ cm^{-2}\ s^{-1}\ \AA^{-1}$]", fontsize=1.5 * fontsize, ) ax.tick_params("both", length=10, width=2, which="major") ax.tick_params("both", length=5, width=1, which="minor") # show the figure or save it to a pdf file if pdf: fig.savefig(path + outname, bbox_inches="tight") plt.close() else: plt.show()
parser.add_argument("--pdf", help="save figure as a pdf file", action="store_true") args = parser.parse_args() filename = args.filelist f = open(filename, 'r') file_lines = list(f) starnames = [] stardata = [] for line in file_lines: if (line.find('#') != 0) & (len(line) > 0): name = line.rstrip() starnames.append(name) tstar = StarData('DAT_files/' + name + '.dat', path='/home/kgordon/Dust/Ext/') stardata.append(tstar) fontsize = 14 font = {'size': fontsize} mpl.rc('font', **font) mpl.rc('lines', linewidth=1) mpl.rc('axes', linewidth=2) mpl.rc('xtick.major', width=2) mpl.rc('xtick.minor', width=2) mpl.rc('ytick.major', width=2) mpl.rc('ytick.minor', width=2) fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(16, 6))
def plot_uv_set(ax, starnames, extra_off_val=0.0, norm_wave_range=[0.2, 0.3], col_vals=['b', 'g', 'r', 'm', 'c', 'y'], ann_xvals=[0.25], ann_wave_range=[0.2, 0.3], fontsize=12): """ Plot a set of spectra """ spec_name = 'STIS' for i in range(len(starnames)): stardata = StarData('DAT_files/' + starnames[i] + '.dat', path='/home/kgordon/Python_git/extstar_data/', use_corfac=True) ymult = np.full((len(stardata.data[spec_name].waves)), 1.0) # get the value to use for normalization and offset norm_indxs = np.where( (stardata.data[spec_name].waves >= norm_wave_range[0]) & (stardata.data[spec_name].waves <= norm_wave_range[1])) norm_val = 1.0 / np.average( stardata.data[spec_name].fluxes[norm_indxs] * ymult[norm_indxs]) off_val = extra_off_val + 10.0 * (i) + 1.0 print(off_val) # plot the spectroscopic data gindxs = np.where(stardata.data[spec_name].npts > 0) # max_gwave = max(stardata.data[spec_name].waves[gindxs]) bnpts = 11 xvals = smooth(stardata.data[spec_name].waves[gindxs], bnpts) yvals = smooth(stardata.data[spec_name].fluxes[gindxs], bnpts) ax.plot(xvals[0:-5], (yvals[0:-5] * ymult[gindxs][0:-5] * norm_val * off_val), col_vals[i % 6] + '-') # annotate the spectra # ann_wave_range = np.array([max_gwave-5.0, max_gwave-1.0]) ann_indxs = np.where( (stardata.data[spec_name].waves >= ann_wave_range[0]) & (stardata.data[spec_name].waves <= ann_wave_range[1]) & (stardata.data[spec_name].npts > 0)) ann_val = np.median(stardata.data[spec_name].fluxes[ann_indxs] * ymult[ann_indxs]) ann_val *= norm_val ann_val += off_val + 2.0 # ax.annotate(starnames[i]+' '+stardata.sptype, xy=(ann_xvals[0], # ann_val), # xytext=(ann_xvals[1], ann_val), # verticalalignment="center", # arrowprops=dict(facecolor=col_vals[i % 6], shrink=0.1), # fontsize=0.85*fontsize, rotation=-0.) # plot the band fluxes ymult = np.full((len(stardata.data['BAND'].waves)), 1.0) ax.plot(stardata.data['BAND'].waves, stardata.data['BAND'].fluxes * ymult * norm_val * off_val, col_vals[i % 6] + 'o')
def plot_multi_spectra( starlist, path, mlam4=False, HI_lines=False, range=None, norm_range=None, spread=False, exclude=[], log=False, class_offset=True, text_offsets=[], text_angles=[], pdf=False, outname="all_spec.pdf", ): """ Plot the observed band and spectral data of multiple stars in the same plot Parameters ---------- starlist : list of strings List of stars for which to plot the spectrum path : string Path to the data files mlam4 : boolean [default=False] Whether or not to multiply the flux F(lambda) by lambda^4 to remove the Rayleigh-Jeans slope HI_lines : boolean [default=False] Whether or not to indicate the HI-lines in the plot range : list of 2 floats [default=None] Wavelength range to be plotted (in micron) - [min,max] norm_range : list of 2 floats [default=None] Wavelength range to use to normalize the data (in micron)- [min,max] spread : boolean [default=False] Whether or not to spread the spectra out by adding a vertical offset to each spectrum exclude : list of strings [default=[]] List of data type(s) to exclude from the plot (e.g., IRS) log : boolean [default=False] Whether or not to plot the wavelengths on a log-scale class_offset : boolean [default=True] Whether or not to add an extra offset between main sequence and giant stars (only relevant when spread=True; this only works when the stars are sorted by spectral class, i.e. first the main sequence and then the giant stars) text_offsets : list of floats [default=[]] List of the same length as starlist with offsets for the annotated text text_angles : list of integers [default=[]] List of the same length as starlist with rotation angles for the annotated text pdf : boolean [default=False] Whether or not to save the figure as a pdf file outname : string [default="all_spec.pdf"] Name for the output pdf file Returns ------- Figure with band data points and spectra of multiple stars """ # plotting setup for easier to read plots fontsize = 18 font = {"size": fontsize} plt.rc("font", **font) plt.rc("lines", linewidth=1) plt.rc("axes", linewidth=2) plt.rc("xtick.major", width=2) plt.rc("xtick.minor", width=2) plt.rc("ytick.major", width=2) plt.rc("ytick.minor", width=2) # create the plot fig, ax = plt.subplots(figsize=(15, len(starlist) * 1.25)) colors = plt.get_cmap("tab10") if norm_range is not None: norm_range = norm_range * u.micron # set default text offsets and angles if text_offsets == []: text_offsets = np.full(len(starlist), 0.2) if text_angles == []: text_angles = np.full(len(starlist), 10) for i, star in enumerate(starlist): # read in all bands and spectra for this star starobs = StarData("%s.dat" % star.lower(), path=path, use_corfac=True) # spread out the spectra if requested # add extra whitespace when the luminosity class changes from main sequence to giant if spread: extra_off = 0 if "V" not in starobs.sptype and class_offset: extra_off = 1 yoffset = extra_off + 0.5 * i else: yoffset = 0 # determine where to add the name of the star and its spectral type # find the shortest plotted wavelength, and give preference to spectral data when available exclude2 = [] if "BAND" in starobs.data.keys() and len(starobs.data.keys()) > 1: exclude2 = ["BAND"] (waves, fluxes, flux_uncs) = starobs.get_flat_data_arrays(starobs.data.keys() - (exclude + exclude2)) if range is not None: waves = waves[waves >= range[0]] min_wave = waves[0] # find out which data type corresponds with this wavelength for data_type in starobs.data.keys(): if data_type in exclude: continue used_waves = starobs.data[data_type].waves[ starobs.data[data_type].npts > 0] if min_wave in used_waves.value: ann_key = data_type ann_range = [min_wave, min_wave] * u.micron # plot the spectrum starobs.plot( ax, pcolor=colors(i % 10), norm_wave_range=norm_range, mlam4=mlam4, exclude=exclude, yoffset=yoffset, yoffset_type="add", annotate_key=ann_key, annotate_wave_range=ann_range, annotate_text=star.upper() + " " + starobs.sptype, annotate_yoffset=text_offsets[i], annotate_rotation=text_angles[i], annotate_color=colors(i % 10), ) # plot HI-lines if requested if HI_lines: plot_HI(path, ax) # zoom in on a specific region if requested if range is not None: zoom(ax, range) outname = outname.replace(".pdf", "_zoom.pdf") # finish configuring the plot if not spread: ax.set_yscale("log") if log: ax.set_xscale("log") ax.set_xlabel(r"$\lambda$ [$\mu m$]", fontsize=1.5 * fontsize) ylabel = r"$F(\lambda)$" if norm_range is not None: if norm_range[0].unit == "micron": units = r"$\mu m$" else: units = norm_range[0].unit ylabel += "/$F$(" + str(int(np.mean(norm_range).value)) + units + ")" else: ylabel += r" [$ergs\ cm^{-2}\ s^{-1}\ \AA^{-1}$]" if mlam4: ylabel = r"$\lambda^4$" + ylabel.replace("]", r" $\mu m^4$]") outname = outname.replace("spec", "spec_mlam4") if spread: ylabel += " + offset" ax.set_ylabel(ylabel, fontsize=1.5 * fontsize) ax.tick_params("both", length=10, width=2, which="major") ax.tick_params("both", length=5, width=1, which="minor") # show the figure or save it to a pdf file if pdf: fig.savefig(path + outname, bbox_inches="tight") else: plt.show() # return the figure and axes for additional manipulations return fig, ax
def __init__( self, modelfiles, path="./", band_names=["U", "B", "V", "J", "H", "K"], spectra_names=["BAND", "STIS"], ): self.n_models = len(modelfiles) self.model_files = np.array(modelfiles) # physical parameters of models self.temps = np.zeros(self.n_models) self.gravs = np.zeros(self.n_models) self.mets = np.zeros(self.n_models) self.vturb = np.zeros(self.n_models) # photometric band data self.n_bands = len(band_names) self.band_names = band_names # photometric and spectroscopic data self.n_spectra = len(spectra_names) + 1 self.spectra_names = spectra_names self.waves = {} self.fluxes = {} self.flux_uncs = {} for cspec in self.spectra_names: self.fluxes[cspec] = None self.flux_uncs[cspec] = None # initialize the BAND dictonary entry as the number of elements # is set by the desired bands, not the bands in the files self.waves["BAND"] = np.zeros((self.n_bands)) self.fluxes["BAND"] = np.zeros((self.n_models, self.n_bands)) self.flux_uncs["BAND"] = np.zeros((self.n_models, self.n_bands)) # read and store the model data for k, cfile in enumerate(modelfiles): moddata = StarData(cfile, path=path) # model parameters self.temps[k] = np.log10(float(moddata.model_params["Teff"])) self.gravs[k] = float(moddata.model_params["logg"]) self.mets[k] = np.log10(float(moddata.model_params["Z"])) self.vturb[k] = float(moddata.model_params["vturb"]) # spectra for cspec in self.spectra_names: # initialize the spectra vectors if self.fluxes[cspec] is None: self.waves[cspec] = moddata.data[cspec].waves self.fluxes[cspec] = np.zeros( (self.n_models, len(moddata.data[cspec].fluxes)) ) self.flux_uncs[cspec] = np.zeros( (self.n_models, len(moddata.data[cspec].fluxes)) ) # photometric bands if cspec == "BAND": for i, cband in enumerate(self.band_names): band_flux = moddata.data["BAND"].get_band_flux(cband) self.waves[cspec][i] = band_flux[2] self.fluxes[cspec][k, i] = band_flux[0] self.flux_uncs[cspec][k, i] = band_flux[1] else: # get the spectral data self.fluxes[cspec][k, :] = moddata.data[cspec].fluxes self.flux_uncs[cspec][k, :] = moddata.data[cspec].uncs # add units self.waves["BAND"] = self.waves["BAND"] * u.micron # provide the width in model space for each parameter # used in calculating the nearest neighbors self.n_nearest = 11 self.temps_min = min(self.temps) self.temps_max = max(self.temps) self.temps_width2 = (self.temps_max - self.temps_min) ** 2 # self.temp_width2 = 1.0 self.gravs_min = min(self.gravs) self.gravs_max = max(self.gravs) self.gravs_width2 = (self.gravs_max - self.gravs_min) ** 2 self.mets_min = min(self.mets) self.mets_max = max(self.mets) self.mets_width2 = (self.mets_max - self.mets_min) ** 2
mpl.rc("axes", linewidth=2) mpl.rc("xtick.major", width=2) mpl.rc("xtick.minor", width=2) mpl.rc("ytick.major", width=2) mpl.rc("ytick.minor", width=2) # setup the plot fig, ax = plt.subplots(ncols=2, figsize=(13, 8)) # plot the spectra in two columns half_num = len(starnames) // 2 + 1 col_vals = ["b", "g", "c"] n_cols = len(col_vals) for k, cstarname in enumerate(starnames): fstarname, file_path = get_full_starfile(cstarname) starobs = StarData(fstarname, path=file_path) if k // half_num > 0: yoff = 2.5**(k - half_num) else: yoff = 2.5**k starobs.plot( ax[k // half_num], norm_wave_range=[0.2, 0.3] * u.micron, yoffset=yoff, pcolor=col_vals[k % n_cols], annotate_key="IUE", annotate_wave_range=[0.25, 0.27] * u.micron, annotate_text=cstarname, annotate_rotation=-10., annotate_yoffset=0.0, fontsize=12,
parser.add_argument("--path", help="path to star files", default="./") parser.add_argument("--png", help="save figure as a png file", action="store_true") parser.add_argument("--eps", help="save figure as an eps file", action="store_true") parser.add_argument("--pdf", help="save figure as a pdf file", action="store_true") return parser if __name__ == "__main__": # commandline parser parser = plot_spec_parser() args = parser.parse_args() # read in the observed data on the star fstarname, file_path = get_full_starfile("m33_j013334.26+303327") starobs = StarData(fstarname, path=file_path) band_names = starobs.data["BAND"].get_band_names() # get the model filenames print("reading in the model spectra") file_path = "/home/kgordon/Python_git/extstar_data/" tlusty_models_fullpath = glob.glob("{}/Models/tlusty_*v10.dat".format(file_path)) tlusty_models_fullpath = tlusty_models_fullpath[0:10] tlusty_models = [ tfile[tfile.rfind("/") + 1 : len(tfile)] for tfile in tlusty_models_fullpath ] spectra_names = ["BAND", "STIS"] # band_names = ['ACS_F814W', 'V', 'WFC3_F336W', 'WFC3_F160W', # 'ACS_F475W', 'WFC3_F110W', 'WFC3_F275W'] # get the models with just the reddened star band data and spectra
gt['G_mag'][ri[0]]*gt['G_flux_error'][ri[0]] / gt['G_flux'][ri[0]]) compplx = (gt['parallax'][ci[0]], gt['parallax_error'][ci[0]]) compmag = (gt['G_mag'][ci[0]], gt['G_mag'][ci[0]]*gt['G_flux_error'][ci[0]] / gt['G_flux'][ci[0]]) absext = compute_absext(redplx, compplx, redmag, compmag) if absext[0] is not None: gext.append(absext[0]) gext_unc.append(absext[1]) # calculate the V band abs extinction redname = '/home/kgordon/Python_git/measured_extcurves/data/DAT_files/%s.dat' % (rname) compname = '/home/kgordon/Python_git/measured_extcurves/data/DAT_files/%s.dat' % (cname) if os.path.isfile(redname) and os.path.isfile(compname): redstar = StarData(redname, photonly=True) compstar = StarData(compname, photonly=True) v_absext = compute_absext(redplx, compplx, redstar.data['BAND'].bands['V'], compstar.data['BAND'].bands['V']) abs_av.append(v_absext[0]) abs_av_unc.append(v_absext[1]) else: abs_av.append(-1.0) abs_av_unc.append(-1.0) # get the extrapolated derived value from FITS extinction curve fname = "%s/%s_%s/%s_%s_ext_bin.fits" \ % (fitspath, rname.lower(), cname.lower(), rname.lower(), cname.lower()) if os.path.isfile(fname):
zip(*np.percentile(new_samples, [16, 50, 84], axis=0))) return per_params if __name__ == '__main__': # commandline parser parser = fit_model_parser() args = parser.parse_args() # get the full starfilename and path fstarname, file_path = get_full_starfile(args.starname) # get the observed reddened star data reddened_star = StarData(fstarname, path=file_path) band_names = reddened_star.data['BAND'].get_band_names() spectra_names = reddened_star.data.keys() # override for now print('possible', spectra_names) # spectra_names = ['BAND', 'STIS_Opt'] # spectra_names = ['BAND', 'STIS_Opt'] print('only using', spectra_names) # override for now # band_names = ['U', 'B', 'V'] # band_names = ['U', 'B', 'V', 'J', 'H', 'K'] print(band_names) # get just the filenames
def fit_features_spec(star, path): """ Fit the features directly from the spectrum with different profiles Parameters ---------- star : string Name of the reddened star for which to fit the features in the spectrum path : string Path to the data files Returns ------- waves : np.ndarray Numpy array with wavelengths flux_sub : np.ndarray Numpy array with continuum subtracted fluxes results : list List with the fitted models for different profiles """ # obtain the spectrum of the reddened star stardata = StarData(star + ".dat", path) npts = stardata.data["SpeX_LXD"].npts waves = stardata.data["SpeX_LXD"].waves.value flux_unc = stardata.data["SpeX_LXD"].uncs # "manually" obtain the continuum from the spectrum (i.e. read the flux at 2.4 and 3.6 micron) plot_spectrum( star, path, mlam4=True, range=[2, 4.5], exclude=["IRS", "STIS_Opt"], ) # fit the continuum reference points with a straight line ref_waves = [2.4, 3.6] fluxes = [3.33268e-12, 4.053e-12] func = Linear1D() fit = LinearLSQFitter() fit_result = fit(func, ref_waves, fluxes) # subtract the continuum from the fluxes fluxes = stardata.data["SpeX_LXD"].fluxes.value * waves ** 4 - fit_result(waves) # define different profiles # 2 Gaussians (stddev=FWHM/(2sqrt(2ln2))) gauss = Gaussian1D(mean=3, stddev=0.13) + Gaussian1D( mean=3.4, stddev=0.06, fixed={"mean": True} ) # 2 Drudes drude = Drude1D(x_0=3, fwhm=0.3) + Drude1D(x_0=3.4, fwhm=0.15, fixed={"x_0": True}) # 2 Lorentzians lorentz = Lorentz1D(x_0=3, fwhm=0.3) + Lorentz1D( x_0=3.4, fwhm=0.15, fixed={"x_0": True} ) # 2 asymmetric Gaussians Gaussian_asym = custom_model(gauss_asymmetric) gauss_asym = Gaussian_asym(x_o=3, gamma_o=0.3) + Gaussian_asym( x_o=3.4, gamma_o=0.15, fixed={"x_o": True} ) # 2 "asymmetric" Drudes Drude_asym = custom_model(drude_asymmetric) drude_asym = Drude_asym(x_o=3, gamma_o=0.3) + Drude_asym( x_o=3.4, gamma_o=0.15, fixed={"x_o": True} ) # 2 asymmetric Lorentzians Lorentzian_asym = custom_model(lorentz_asymmetric) lorentz_asym = Lorentzian_asym(x_o=3, gamma_o=0.3) + Lorentzian_asym( x_o=3.4, gamma_o=0.15, fixed={"x_o": True} ) # 1 asymmetric Drude drude_asym1 = Drude_asym(x_o=3, gamma_o=0.3) profiles = [ gauss, drude, lorentz, gauss_asym, drude_asym, lorentz_asym, drude_asym1, ] # fit the different profiles fit2 = LevMarLSQFitter() results = [] mask1 = (waves > 2.4) & (waves < 3.6) mask2 = mask1 * (npts > 0) for profile in profiles: fit_result = fit2( profile, waves[mask2], fluxes[mask2], weights=1 / flux_unc[mask2], maxiter=10000, ) results.append(fit_result) print(fit_result) print( "Chi2", np.sum(((fluxes[mask2] - fit_result(waves[mask2])) / flux_unc[mask2]) ** 2), ) return waves[mask1], fluxes[mask1], npts[mask1], results
mpl.rc("font", **font) mpl.rc("lines", linewidth=1) mpl.rc("axes", linewidth=2) mpl.rc("xtick.major", width=2) mpl.rc("xtick.minor", width=2) mpl.rc("ytick.major", width=2) mpl.rc("ytick.minor", width=2) # setup the plot fig, ax = plt.subplots(figsize=(13, 10)) # plot the bands and all spectra for this star # plot all the spectra on the same plot for k, cstarname in enumerate(starnames): fstarname, file_path = get_full_starfile(cstarname) starobs = StarData(fstarname, path=file_path) starobs.plot(ax, norm_wave_range=[0.2, 0.3] * u.micron, yoffset=2**k) # finish configuring the plot ax.set_yscale("log") ax.set_xscale("log") ax.set_xlabel(r"$\lambda$ [$\mu m$]", fontsize=1.3 * fontsize) ax.set_ylabel(r"$F(\lambda)$ [$ergs\ cm^{-2}\ s\ \AA$]", fontsize=1.3 * fontsize) ax.tick_params("both", length=10, width=2, which="major") ax.tick_params("both", length=5, width=1, which="minor") # use the whitespace better fig.tight_layout() # plot or save to a file
if __name__ == "__main__": # commandline parser parser = argparse.ArgumentParser() parser.add_argument("redstarname", help="name of reddened star") parser.add_argument("compstarname", help="name of comparision star") parser.add_argument( "--path", help="base path to observed data", default="/home/kgordon/Python_git/extstar_data/", ) args = parser.parse_args() # read in the observed data for both stars redstarobs = StarData("DAT_files/%s.dat" % args.redstarname, path=args.path) compstarobs = StarData("DAT_files/%s.dat" % args.compstarname, path=args.path) # output filebase filebase = "fits/%s_%s" % (args.redstarname, args.compstarname) # calculate the extinction curve extdata = ExtData() extdata.calc_elx(redstarobs, compstarobs) # save the extinction curve out_fname = "fits/%s_%s_ext.fits" % (args.redstarname, args.compstarname) extdata.save(out_fname)
def print_BV(star): path = "/Users/mdecleir/Documents/NIR_ext/Data/" star_data = StarData("%s.dat" % star.lower(), path=path, use_corfac=False) V = star_data.data["BAND"].get_band_mag("V") B = star_data.data["BAND"].get_band_mag("B") print(star, ", B:", B, ", V:", V, ", B-V:", B[0] - V[0])
def plot_color_color(stars, bands, div): """ Make a color-color plot Parameters ---------- stars : list of strings List of stars bands : list of strings List of bands div : float Location of division line Returns ------- IR color-color plot """ # create the figure plt.rc("axes", linewidth=0.8) fig, ax = plt.subplots(figsize=(8, 7)) for i, star in enumerate(stars): # categorize the star if star in comp_stars: color = "black" marker = "P" elif star in red_stars: color = "green" marker = "d" elif star == "HD014250": color = "purple" marker = "s" else: color = "red" marker = "o" # obtain the photometry star_data = StarData("%s.dat" % star.lower(), path=inpath) band_data = star_data.data["BAND"] mags = np.full(len(bands), np.nan) errs = np.full(len(bands), np.nan) for j, band in enumerate(bands): if band == "K_S": band = "K" if band in band_data.get_band_names(): mags[j] = band_data.get_band_mag(band)[0] errs[j] = band_data.get_band_mag(band)[1] # plot colors ax.errorbar( mags[0] - mags[1], mags[2] - mags[3], xerr=np.sqrt((errs[0]**2) + (errs[1]**2)), yerr=np.sqrt((errs[2]**2) + (errs[3]**2)), marker=marker, color=color, markersize=6, markeredgewidth=0, elinewidth=0.8, alpha=0.7, ) # finalize and save the plot ax.axhline(div, color="grey", ls=":") ax.set_xlabel(r"$" + bands[0] + "-" + bands[1] + "$", fontsize=fs) ax.set_ylabel(r"$" + bands[2] + "-$" + bands[3], fontsize=fs) ax.tick_params(width=1) labels = ["comparison", "reddened", "windy", "bad"] handle1 = Line2D([], [], lw=1, color="black", marker="P", alpha=0.7) handle2 = Line2D([], [], lw=1, color="green", marker="d", alpha=0.7) handle3 = Line2D([], [], lw=1, color="red", marker="o", alpha=0.7) handle4 = Line2D([], [], lw=1, color="purple", marker="s", alpha=0.7) handles = [handle1, handle2, handle3, handle4] ax.legend(handles, labels, fontsize=fs * 0.8) fig.savefig(outpath + "wind_" + bands[3] + ".pdf", bbox_inches="tight")
# commandline parser parser = argparse.ArgumentParser() parser.add_argument("filelist", help="file with list of stars to use") args = parser.parse_args() filename = args.filelist f = open(filename, "r") file_lines = list(f) starnames = [] stardata = [] bvcol = [] for line in file_lines: if (line.find("#") != 0) & (len(line) > 0): name = line.rstrip() starnames.append(name) tstar = StarData( "DAT_files/" + name + ".dat", path="/home/kgordon/Python_git/extstar_data/", ) if "IRS_slope" in tstar.corfac.keys(): print("%s & %.3f & %.3f & %.3f \\\\" % ( name.upper(), tstar.corfac["IRS"], tstar.corfac["IRS_slope"], tstar.corfac["IRS_zerowave"], )) else: print("%s & %.3f & \\nodata & \\nodata \\\\" % (name.upper(), tstar.corfac["IRS"]))
def fit_spex_ext( starpair, path, functype="pow", dense=False, profile="drude_asym", exclude=None, bootstrap=False, fixed=False, ): """ Fit the observed SpeX NIR extinction curve Parameters ---------- starpair : string Name of the star pair for which to fit the extinction curve, in the format "reddenedstarname_comparisonstarname" (no spaces), or "average" to fit the average extinction curve path : string Path to the data files functype : string [default="pow"] Fitting function type ("pow" for powerlaw or "pol" for polynomial) dense : boolean [default=False] Whether or not to fit the features around 3 and 3.4 micron profile : string [default="drude_asym"] Profile to use for the features if dense = True (options are "gauss", "drude", "lorentz", "gauss_asym", "drude_asym", "lorentz_asym") exclude : list of tuples [default=None] list of tuples (min,max) with wavelength regions (in micron) that need to be excluded from the fitting, e.g. [(0.8,1.2),(2.2,5)] bootstrap : boolean [default=False] Whether or not to do a quick bootstrap fitting to get more realistic uncertainties on the fitting results fixed : boolean [default=False] Whether or not to add a fixed feature around 3 micron (for diffuse sightlines) Returns ------- Updates extdata.model["type", "waves", "exts", "residuals", "chi2", "params"] and extdata.columns["AV"] with the fitting results: - type: string with the type of model (e.g. "pow_elx_Drude") - waves: np.ndarray with the SpeX wavelengths - exts: np.ndarray with the fitted model to the extinction curve at "waves" wavelengths - residuals: np.ndarray with the residuals, i.e. data-fit, at "waves" wavelengths - chi2 : float with the chi square of the fitting - params: list with output Parameter objects """ # retrieve the SpeX data to be fitted, and sort the curve from short to long wavelengths filename = "%s%s_ext.fits" % (path, starpair.lower()) if fixed: filename = filename.replace(".", "_ice.") extdata = ExtData(filename) (waves, exts, exts_unc) = extdata.get_fitdata(["SpeX_SXD", "SpeX_LXD"]) indx = np.argsort(waves) waves = waves[indx].value exts = exts[indx] exts_unc = exts_unc[indx] # exclude wavelength regions if requested if exclude: mask = np.full_like(waves, False, dtype=bool) for region in exclude: mask += (waves > region[0]) & (waves < region[1]) waves = waves[~mask] exts = exts[~mask] exts_unc = exts_unc[~mask] # get a quick estimate of A(V) if extdata.type == "elx": extdata.calc_AV() AV_guess = extdata.columns["AV"] else: AV_guess = None # convert to A(lambda)/A(1 micron) # ind1 = np.abs(waves - 1).argmin() # exts = exts / exts[ind1] # exts_unc = exts_unc / exts[ind1] # obtain the function to fit if "SpeX_LXD" not in extdata.waves.keys(): dense = False fixed = False func = fit_function( dattype=extdata.type, functype=functype, dense=dense, profile=profile, AV_guess=AV_guess, fixed=fixed, ) # for dense sightlines, add more weight to the feature region weights = 1 / exts_unc if dense: mask_ice = (waves > 2.88) & (waves < 3.19) mask_tail = (waves > 3.4) & (waves < 4) weights[mask_ice + mask_tail] *= 2 # use the Levenberg-Marquardt algorithm to fit the data with the model fit = LevMarLSQFitter() fit_result_lev = fit(func, waves, exts, weights=weights, maxiter=10000) # set up the backend to save the samples for the emcee runs emcee_samples_file = path + "Fitting_results/" + starpair + "_emcee_samples.h5" # do the fitting again, with MCMC, using the results from the first fitting as input fit2 = EmceeFitter(nsteps=10000, burnfrac=0.1, save_samples=emcee_samples_file) # add parameter bounds for param in fit_result_lev.param_names: if "amplitude" in param: getattr(fit_result_lev, param).bounds = (0, 2) elif "alpha" in param: getattr(fit_result_lev, param).bounds = (0, 4) elif "Av" in param: getattr(fit_result_lev, param).bounds = (0, 10) fit_result_mcmc = fit2(fit_result_lev, waves, exts, weights=weights) # create standard MCMC plots fit2.plot_emcee_results( fit_result_mcmc, filebase=path + "Fitting_results/" + starpair ) # choose the fit result to save fit_result = fit_result_mcmc # fit_result = fit_result_lev print(fit_result) # determine the wavelengths at which to evaluate and save the fitted model curve: all SpeX wavelengths, sorted from short to long (to avoid problems with overlap between SXD and LXD), and shortest and longest wavelength should have data if "SpeX_LXD" not in extdata.waves.keys(): full_waves = extdata.waves["SpeX_SXD"].value full_npts = extdata.npts["SpeX_SXD"] else: full_waves = np.concatenate( (extdata.waves["SpeX_SXD"].value, extdata.waves["SpeX_LXD"].value) ) full_npts = np.concatenate((extdata.npts["SpeX_SXD"], extdata.npts["SpeX_LXD"])) # sort the wavelengths indxs_sort = np.argsort(full_waves) full_waves = full_waves[indxs_sort] full_npts = full_npts[indxs_sort] # cut the wavelength region indxs = np.logical_and(full_waves >= np.min(waves), full_waves <= np.max(waves)) full_waves = full_waves[indxs] full_npts = full_npts[indxs] # calculate the residuals and put them in an array of the same length as "full_waves" for plotting residuals = exts - fit_result(waves) full_res = np.full_like(full_npts, np.nan) if exclude: mask = np.full_like(full_waves, False, dtype=bool) for region in exclude: mask += (full_waves > region[0]) & (full_waves < region[1]) full_res[(full_npts > 0) * ~mask] = residuals else: full_res[(full_npts > 0)] = residuals # bootstrap to get more realistic uncertainties on the parameter results if bootstrap: red_star = StarData(extdata.red_file, path=path, use_corfac=True) comp_star = StarData(extdata.comp_file, path=path, use_corfac=True) red_V_unc = red_star.data["BAND"].get_band_mag("V")[1] comp_V_unc = comp_star.data["BAND"].get_band_mag("V")[1] unc_V = np.sqrt(red_V_unc ** 2 + comp_V_unc ** 2) fit_result_mcmc_low = fit2(fit_result_lev, waves, exts - unc_V, weights=weights) fit_result_mcmc_high = fit2( fit_result_lev, waves, exts + unc_V, weights=weights ) # save the fitting results to the fits file if dense: functype += "_" + profile extdata.model["type"] = functype + "_" + extdata.type extdata.model["waves"] = full_waves extdata.model["exts"] = fit_result(full_waves) extdata.model["residuals"] = full_res extdata.model["chi2"] = np.sum((residuals / exts_unc) ** 2) print("Chi2", extdata.model["chi2"]) extdata.model["params"] = [] for param in fit_result.param_names: # update the uncertainties when bootstrapping if bootstrap: min_val = min( getattr(fit_result_mcmc, param).value, getattr(fit_result_mcmc_low, param).value, getattr(fit_result_mcmc_high, param).value, ) max_val = max( getattr(fit_result_mcmc, param).value, getattr(fit_result_mcmc_low, param).value, getattr(fit_result_mcmc_high, param).value, ) sys_unc = (max_val - min_val) / 2 getattr(fit_result, param).unc_minus = np.sqrt( getattr(fit_result, param).unc_minus ** 2 + sys_unc ** 2 ) getattr(fit_result, param).unc_plus = np.sqrt( getattr(fit_result, param).unc_plus ** 2 + sys_unc ** 2 ) extdata.model["params"].append(getattr(fit_result, param)) # save the column information (A(V), E(B-V) and R(V)) if "Av" in param: extdata.columns["AV"] = ( getattr(fit_result, param).value, getattr(fit_result, param).unc_minus, getattr(fit_result, param).unc_plus, ) # calculate the distrubtion of R(V) and 1/R(V) from the distributions of A(V) and E(B-V) nsamples = getattr(fit_result, param).posterior.n_samples av_dist = unc.normal( extdata.columns["AV"][0], std=(extdata.columns["AV"][1] + extdata.columns["AV"][2]) / 2, n_samples=nsamples, ) b_indx = np.abs(extdata.waves["BAND"] - 0.438 * u.micron).argmin() ebv_dist = unc.normal( extdata.exts["BAND"][b_indx], std=extdata.uncs["BAND"][b_indx], n_samples=nsamples, ) ebv_per = ebv_dist.pdf_percentiles([16.0, 50.0, 84.0]) extdata.columns["EBV"] = ( ebv_per[1], ebv_per[1] - ebv_per[0], ebv_per[2] - ebv_per[1], ) rv_dist = av_dist / ebv_dist rv_per = rv_dist.pdf_percentiles([16.0, 50.0, 84.0]) extdata.columns["RV"] = ( rv_per[1], rv_per[1] - rv_per[0], rv_per[2] - rv_per[1], ) inv_rv_dist = ebv_dist / av_dist inv_rv_per = inv_rv_dist.pdf_percentiles([16.0, 50.0, 84.0]) extdata.columns["IRV"] = ( inv_rv_per[1], inv_rv_per[1] - inv_rv_per[0], inv_rv_per[2] - inv_rv_per[1], ) print(extdata.columns) # save the fits file extdata.save(filename) # print information about the ice feature if fixed: print( "Ice feature strength: ", extdata.model["params"][3].value, extdata.model["params"][3].unc_minus, extdata.model["params"][3].unc_plus, )
action="store_true") parser.add_argument("--pdf", help="save figure as a pdf file", action="store_true") return parser if __name__ == "__main__": # commandline parser parser = plot_spec_parser() args = parser.parse_args() # read in the observed data on the star fstarname, file_path = get_full_starfile(args.starname) starobs = StarData(fstarname, path=file_path) # plotting setup for easier to read plots fontsize = 18 font = {'size': fontsize} mpl.rc('font', **font) mpl.rc('lines', linewidth=1) mpl.rc('axes', linewidth=2) mpl.rc('xtick.major', width=2) mpl.rc('xtick.minor', width=2) mpl.rc('ytick.major', width=2) mpl.rc('ytick.minor', width=2) # setup the plot fig, ax = plt.subplots(figsize=(13, 10))