def __init__(self, mass, distance, age, Av, Rin=5): self.mass = mass #Msun self.dist = distance #pc self.age = age #Myr self.Av = Av #mag #derived variables #self.Teff = MtoTfunc(self.mass, self.age) #self.radius = MtoRfunc(self.mass, self.age) #1d interpolation method done #can't incorporate age errors this way self.Teff = a.mass_to_Teff(self.mass, self.age) self.radius = a.Teff_to_params(self.Teff, self.age)[1] self.SpTy = a.Teff_to_SpTy(self.Teff) self.Rin = Rin * self.radius #ideal mdot, Lacc self.ideal_mdot = a.empiricalMdot(self.mass) self.ideal_Lacc = a.Mdot_to_Lacc(self.ideal_mdot, self.mass, self.radius, self.Rin) self.mdot = self.ideal_mdot
def build_figure(observed, df): fig = go.Figure() fig.add_trace( go.Scatter( x=df["Mass (M$_\odot$)"], y=df["Mdot (M$_\odot$)"], mode='markers', name="Simulated", opacity=0.7, marker=dict(color='salmon'), )) fig.add_trace( go.Scatter( x=observed["Object Mass M_Solar"], y=observed["Accretion Rate M_solar yr-1"], mode='markers', name='Observed', opacity=0.6, marker=dict(symbol='x', color='#44749D'), )) fig.add_trace( go.Scatter( x=observed["Object Mass M_Solar"], y=a.empiricalMdot(observed["Object Mass M_Solar"]), mode='lines', name='Empirical Relationship', opacity=0.9, marker=dict(color='gray'), )) fig.update_layout( width=1200, height=675, title={ 'text': "Accretion Monte Carlo Error Propagation", 'y': 0.9, 'x': 0.46, 'xanchor': 'center', 'yanchor': 'top', }, xaxis_title="Mass (solar masses)", yaxis_title="Mass Accretion Rate (solar masses/yr)", legend_title=None, font=dict(), xaxis=dict(tickmode='array', tickvals=[0, 0.01, 0.05, 0.1, 0.5, 1, 1.5, 2], showgrid=False), yaxis=dict( showexponent='all', tickmode='array', tickvals=[1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6], ticktext=[1e-13, 1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6], showgrid=True), ) fig.update_xaxes(type="log") fig.update_yaxes(type="log") return fig
def build_residuals(observed, df): residual_fig = go.Figure() observed_difference = np.log10( observed['Accretion Rate M_solar yr-1']) - np.log10( a.empiricalMdot(observed['Object Mass M_Solar'])) simulated_difference = np.log10(df['Mdot (M$_\\odot$)']) - np.log10( a.empiricalMdot(df['Mass (M$_\\odot$)'])) residual_fig.add_trace( go.Scatter( x=df["Mass (M$_\odot$)"], y=simulated_difference, mode='markers', name="Simulated", opacity=0.7, marker=dict(color='salmon'), )) residual_fig.add_trace( go.Scatter( x=observed["Object Mass M_Solar"], y=observed_difference, mode='markers', name='Observed', opacity=0.6, marker=dict(symbol='x', color='#44749D'), )) residual_fig.add_trace( go.Scatter( x=observed["Object Mass M_Solar"], y=np.zeros(len(observed["Object Mass M_Solar"])), mode='lines', name='Empirical Relationship', opacity=0.9, marker=dict(color='gray'), )) residual_fig.update_layout( width=1200, height=575, title={ 'text': "Residuals", 'y': 0.9, 'x': 0.46, 'xanchor': 'center', 'yanchor': 'top', }, xaxis_title="Mass (solar masses)", yaxis_title="Residual (log space)", legend_title=None, font=dict(), xaxis=dict(tickmode='array', tickvals=[0, 0.01, 0.05, 0.1, 0.5, 1, 1.5, 2], showgrid=False), yaxis=dict(showexponent='all', tickmode='array', tickvals=[-3, -2, -1, 0, 1, 2, 3], showgrid=True), ) residual_fig.update_xaxes(type="log") return residual_fig
def UVExcessErrorProp(self, SpTyUnc, distUnc, ageUnc, AvUnc, bc, bcUnc, UVExcessUnc, numMC, Rin=5, RinUnc=0, variability=0, age_scatter=False): #propagate errors forward and obtain uncertainty distributions if age_scatter == True: #self.shifted_ideal_mdot = a.empiricalMdot(self.mass, intercept=-a.age_to_intercept_func(self.age)) self.shifted_ideal_mdot = a.empiricalMdot( self.mass, intercept=-a.age_intercept_exponential(self.age)) self.ideal_UVExcess = a.Mdot_to_UVExcess(self.shifted_ideal_mdot, bc, self.dist, self.mass, self.radius, self.Av, self.Rin) else: self.ideal_UVExcess = a.Mdot_to_UVExcess(self.ideal_mdot, bc, self.dist, self.mass, self.radius, self.Av, self.Rin) #add in uncertainties to observable itself if numMC == 1: self.UVExcessUncDist = np.random.normal(self.ideal_UVExcess, UVExcessUnc * self.ideal_UVExcess, size=numMC)[0] else: self.UVExcessUncDist = np.random.normal(self.ideal_UVExcess, UVExcessUnc * self.ideal_UVExcess, size=numMC) #add in uncertainties to variables specific to observable x = np.linspace(0, 20000, 100000) if bcUnc == 0: if numMC == 1: self.bcUncDist = bc else: self.bcUncDist = np.ones(numMC) * bc else: self.bcUncDist = a.uncdist(x, bc, bcUnc, numMC) #build uncertainty distributions if SpTyUnc == 0: if numMC == 1: self.SpTyUncDist = self.SpTy else: self.SpTyUncDist = np.ones(numMC) * self.SpTy else: self.SpTyUncDist = a.uncdist(x, self.SpTy, SpTyUnc, numMC) if distUnc == 0: if numMC == 1: self.distUncDist = self.dist else: self.distUncDist = np.ones(numMC) * self.dist else: self.distUncDist = a.uncdist(x, self.dist, distUnc, numMC) if ageUnc == 0: if numMC == 1: self.ageUncDist = self.age else: self.ageUncDist = np.ones(numMC) * self.age else: self.ageUncDist = a.uncdist(x, self.age, ageUnc, numMC) if AvUnc == 0: if numMC == 1: self.AvUncDist = self.Av else: self.AvUncDist = np.ones(numMC) * self.Av else: self.AvUncDist = a.uncdist(x, self.Av, AvUnc, numMC) if RinUnc == 0: if numMC == 1: self.RinUncDist = Rin else: self.RinUncDist = np.ones(numMC) * Rin else: self.RinUncDist = a.uncdist(x, Rin, RinUnc, numMC) self.TeffUncDist = a.SpTy_to_Teff(self.SpTyUncDist) self.massUncDist = a.Teff_to_params(self.TeffUncDist, (self.ageUncDist))[0] self.radiusUncDist = a.Teff_to_params(self.TeffUncDist, (self.ageUncDist))[1] self.RinUncDist = self.RinUncDist * self.radiusUncDist #self.RinUncDist = Rin*self.radiusUncDist #Generate synthetic Mdot distribution #Generate synthetic Lacc distribution self.mdot = a.UVExcess_to_Mdot(self.UVExcessUncDist, self.bcUncDist, self.distUncDist, self.massUncDist, self.radiusUncDist, self.AvUncDist, self.RinUncDist) if variability != 0: log_mdot = np.log10(self.mdot) if numMC == 1: draw = np.random.normal(log_mdot, variability, size=numMC)[0] else: draw = np.random.normal(log_mdot, variability, size=numMC) self.mdot = 10**draw ''' #specify lower and upper bounds for the truncated gaussian lower, upper = 0,1 mu, sigma = (self.mdot), (self.mdot*variability) variability_distribution = st.truncnorm( (lower - mu) / sigma, (upper - mu) / sigma, loc=mu, scale=sigma) if numMC == 1: self.mdot = variability_distribution.rvs(numMC)[0] else: self.mdot = variability_distribution.rvs(numMC) ''' self.Lacc = a.Mdot_to_Lacc(self.mdot, self.massUncDist, self.radiusUncDist, self.RinUncDist)
def residuals(observed, simulated): #load in data logmass = np.log10(simulated['Mass (M$_\\odot$)']) logMdot = np.log10(simulated['Mdot (M$_\\odot$)']) logaccepted_relation = np.log10(simulated['"true" Mdot (M$_\\odot$)']) observed_mass = np.log10(observed['Object Mass M_Solar']) observed_mdot = np.log10(observed['Accretion Rate M_solar yr-1']) #Figure Dimensions left, width = 0.1, 0.4 bottom, height = 0.1, 0.7 spacing = 0.0075 #create figure fig = plt.figure(figsize=(16, 12)) #Residual Plot rect_frame2 = [left, bottom, width, height] rect_ax2_hist = [left + width + spacing, bottom, 0.3, height] #create axes frame2 = fig.add_axes(rect_frame2) ax2_hist = fig.add_axes(rect_ax2_hist) ax = plt.gca() #Calculate Residuals observed_difference = np.log10( observed['Accretion Rate M_solar yr-1']) - np.log10( a.empiricalMdot(observed['Object Mass M_Solar'])) simulated_difference = np.log10(simulated['Mdot (M$_\\odot$)']) - np.log10( a.empiricalMdot(simulated['Mass (M$_\\odot$)'])) #Residual Marginal Distribution #remove ticks ax2_hist.tick_params(axis="y", labelleft=False) #bins by hand residualbinwidth = 0.25 residualmax = np.max(np.abs(observed_difference)) residuallim = (int(residualmax / residualbinwidth) + 1) * residualbinwidth residualbins = np.arange(-residuallim, residuallim + residualbinwidth, residualbinwidth) #plot ax2_hist.hist(observed_difference, bins=residualbins, orientation='horizontal', color='black', density=True, alpha=0.225, label='Observed') ax2_hist.hist(simulated_difference, bins=residualbins, orientation='horizontal', color='darkseagreen', density=True, alpha=0.3, label='Simulated') ax2_hist.set_ylim(-3.3, 3.2) ax2_hist.axhline(0, color='tomato', label='Empirical Relationship') ax2_hist.legend() #Residual Plot frame2.axhline(0, color='tomato', label='Empirical Relationship') frame2.set_xlabel('log(Mass) (M$_\odot$)', size=16) frame2.set_ylabel('Residual (log space)', size=16) frame2.set_ylim(-3.3, 3.2) frame2.scatter(np.log10(observed['Object Mass M_Solar']), observed_difference, color='black', marker='x', alpha=0.4, label='Observed Residuals') frame2.scatter(np.log10(simulated['Mass (M$_\\odot$)']), simulated_difference, color='darkseagreen', alpha=0.4, label='Simulated Residuals') frame2.legend(frameon=True) return fig
def MarginalDistribution(observed, simulated): #load in data logmass = np.log10(simulated['Mass (M$_\\odot$)']) logMdot = np.log10(simulated['Mdot (M$_\\odot$)']) logaccepted_relation = np.log10(simulated['"true" Mdot (M$_\\odot$)']) observed_mass = np.log10(observed['Object Mass M_Solar']) observed_mdot = np.log10(observed['Accretion Rate M_solar yr-1']) #Figure Dimensions left, width = 0.1, 0.7 bottom, height = 0.3, 0.55 spacing = 0.0075 #create figure fig = plt.figure(figsize=(16, 12)) #Mass vs Mdot rect_frame1 = [left, bottom, width, height] #Marginal Distributions rect_histx = [left, bottom + height + spacing, width, 0.1] rect_histy = [left + width + spacing, bottom, 0.1, height] #create axes frame1 = fig.add_axes(rect_frame1) ax_histx = fig.add_axes(rect_histx, sharex=frame1) ax_histy = fig.add_axes(rect_histy, sharey=frame1) ax = plt.gca() #Marginal Distributions # no labels ax_histx.tick_params(axis="x", labelbottom=False) ax_histy.tick_params(axis="y", labelleft=False) # determine nice limits by hand: binwidth = 0.25 xymax = max(np.max(np.abs(observed_mass)), np.max(np.abs(observed_mdot))) lim = (int(xymax / binwidth) + 1) * binwidth bins = np.arange(-lim, lim + binwidth, binwidth) #Plot histograms ax_histx.hist(observed_mass, bins=bins, color='black', density=True, alpha=0.225, label='Observed') ax_histy.hist(observed_mdot, bins=bins, orientation='horizontal', color='black', density=True, alpha=0.225, label='Observed') ax_histx.hist(logmass, bins=bins, color='darkseagreen', density=True, alpha=0.3, label='Simulated') ax_histy.hist(logMdot, bins=bins, orientation='horizontal', color='darkseagreen', density=True, alpha=0.3, label='Simulated') ax_histx.legend() ax_histy.legend() #Mass vs Mdot frame1.scatter(logmass, logMdot, color='darkseagreen', s=130, alpha=0.4, label='Simulated') frame1.scatter(observed_mass, observed_mdot, color='black', s=50, marker='x', alpha=0.4, label='Observed') frame1.plot(logmass, logaccepted_relation, color='tomato', label='Empirical Relationship') frame1.axvline(x=np.log10(0.012), color='black', linestyle='-.', label='Deuterium Burning Limit') frame1.axvline(x=np.log10(0.1), color='black', linestyle=':', label='Hydrogen Burning Limit') frame1.set_xlim(-2.6, 0.6) frame1.set_ylim(-14, -5.75) frame1.set_xlabel('log(Mass) (M$_\odot$)', size=16) frame1.set_ylabel('log(Mass Accretion Rate) (M$_\odot$/yr)', size=16) frame1.text(-2.3, -6.6, 'Planets', size=15, fontstyle='italic') frame1.text(-1.64, -6.6, 'Brown Dwarfs', size=15, fontstyle='italic') frame1.text(-0.29, -6.6, 'Stars', size=15, fontstyle='italic') ax_histx.set_title('Monte Carlo Error Propagation', size=20, fontweight='heavy') frame1.legend(loc='lower right', prop={ 'family': 'sans-serif', 'style': 'normal', 'size': 16 }, frameon=False, shadow=True) #Residual Plot rect_frame2 = [left, bottom - 0.2, width, bottom - 0.1 - spacing] rect_ax2_hist = [ left + width + spacing, bottom - 0.2, 0.1, bottom - 0.1 - spacing ] #create axes frame2 = fig.add_axes(rect_frame2) ax2_hist = fig.add_axes(rect_ax2_hist) ax = plt.gca() #Calculate Residuals observed_difference = np.log10( observed['Accretion Rate M_solar yr-1']) - np.log10( a.empiricalMdot(observed['Object Mass M_Solar'])) simulated_difference = np.log10(simulated['Mdot (M$_\\odot$)']) - np.log10( a.empiricalMdot(simulated['Mass (M$_\\odot$)'])) #Residual Marginal Distribution #remove ticks ax2_hist.tick_params(axis="y", labelleft=False) #bins by hand residualbinwidth = 0.25 residualmax = np.max(np.abs(observed_difference)) residuallim = (int(residualmax / residualbinwidth) + 1) * residualbinwidth residualbins = np.arange(-residuallim, residuallim + residualbinwidth, residualbinwidth) #plot ax2_hist.hist(observed_difference, bins=residualbins, orientation='horizontal', color='black', density=True, alpha=0.225, label='Observed') ax2_hist.hist(simulated_difference, bins=residualbins, orientation='horizontal', color='darkseagreen', density=True, alpha=0.3, label='Simulated') ax2_hist.set_ylim(-3.3, 3.2) ax2_hist.axhline(0, color='tomato') ax2_hist.legend() #Residual Plot frame2.axhline(0, color='tomato') frame2.set_xlabel('log(Mass) (M$_\odot$)', size=16) frame2.set_ylabel('Residual (log space)', size=16) frame2.set_ylim(-3.3, 3.2) frame2.scatter(np.log10(observed['Object Mass M_Solar']), observed_difference, color='black', marker='x', alpha=0.4, label='Observed Residuals') frame2.scatter(np.log10(simulated['Mass (M$_\\odot$)']), simulated_difference, color='darkseagreen', alpha=0.4, label='Simulated Residuals') frame2.legend(frameon=True) return fig
def MoneyPlot(observed, simulated): logmass = np.log10(simulated['Mass (M$_\\odot$)']) logMdot = np.log10(simulated['Mdot (M$_\\odot$)']) logaccepted_relation = np.log10(simulated['"true" Mdot (M$_\\odot$)']) observed_mass = np.log10(observed['Object Mass M_Solar']) observed_mdot = np.log10(observed['Accretion Rate M_solar yr-1']) fig = plt.figure(figsize=(16, 12)) frame1 = fig.add_axes((.1, .3, .8, .6)) ax = plt.gca() ax.scatter(logmass, logMdot, color='darkseagreen', s=130, alpha=0.4, label='Simulated') ax.scatter(observed_mass, observed_mdot, color='black', s=50, marker='x', alpha=0.4, label='Observed') ax.plot(logmass, logaccepted_relation, color='tomato', label='Empirical Relationship') ax.axvline(x=np.log10(0.012), color='black', linestyle='-.', label='Deuterium Burning Limit') ax.axvline(x=np.log10(0.1), color='black', linestyle=':', label='Hydrogen Burning Limit') ax.set_xlim(-2.6, 0.6) ax.set_xlabel('log(Mass) (M$_\odot$)', size=16) ax.set_ylabel('log(Mass Accretion Rate) (M$_\odot$/yr)', size=16) ax.text(-2.3, -6.6, 'Planets', size=15, fontstyle='italic') ax.text(-1.64, -6.6, 'Brown Dwarfs', size=15, fontstyle='italic') ax.text(-0.29, -6.6, 'Stars', size=15, fontstyle='italic') ax.set_title('Monte Carlo Error Propagation', size=20, fontweight='heavy') ax.legend(loc='lower right', prop={ 'family': 'sans-serif', 'style': 'normal', 'size': 16 }, frameon=False, shadow=True) frame2 = fig.add_axes((.1, .1, .8, .2)) ax = plt.gca() observed_difference = np.log10( observed['Accretion Rate M_solar yr-1']) - np.log10( a.empiricalMdot(observed['Object Mass M_Solar'])) simulated_difference = np.log10(simulated['Mdot (M$_\\odot$)']) - np.log10( a.empiricalMdot(simulated['Mass (M$_\\odot$)'])) ax.axhline(0, color='tomato') ax.set_xlabel('log(Mass) (M$_\odot$)', size=16) ax.set_ylabel('Residual (log space)', size=16) ax.scatter(np.log10(observed['Object Mass M_Solar']), observed_difference, color='black', marker='x', alpha=0.4, label='Observed Residuals') ax.scatter(np.log10(simulated['Mass (M$_\\odot$)']), simulated_difference, color='darkseagreen', alpha=0.4, label='Simulated Residuals') ax.legend(frameon=True) return fig
def linefluxErrorProp(self, SpTyUnc, distUnc, ageUnc, AvUnc, linefluxUnc, numMC, Rin=5, RinUnc=0, line=None, A=None, AUnc=None, B=None, BUnc=None, variability=0, age_scatter=False): #propagate errors forward and obtain uncertainty distributions if line == None: A = A aUnc = AUnc B = B bUnc = BUnc elif line == 'Ha': A = 1.13 #+/- 0.05 aUnc = 0.05 B = 1.74 #+/- 0.19 bUnc = 0.19 elif line == 'Pab': A = 1.06 #+/- 0.07 aUnc = 0.07 B = 2.76 #+/- 0.34 bUnc = 0.34 elif line == 'Brg': A = 1.19 #+/- 0.10 aUnc = 0.10 B = 4.02 #+/- 0.51 bUnc = 0.51 else: print('Line not found.') return if age_scatter == True: #self.shifted_ideal_mdot = a.empiricalMdot(self.mass, intercept=-a.age_to_intercept_func(self.age)) self.shifted_ideal_mdot = a.empiricalMdot( self.mass, intercept=-a.age_intercept_exponential(self.age)) self.ideal_lineflux = a.Mdot_to_lineflux(self.shifted_ideal_mdot, self.dist, self.mass, self.radius, self.Av, Rin=self.Rin, line=line, A=A, B=B) else: self.ideal_lineflux = a.Mdot_to_lineflux(self.ideal_mdot, self.dist, self.mass, self.radius, self.Av, Rin=self.Rin, line=line, A=A, B=B) #add in uncertainties to observable itself if numMC == 1: self.linefluxUncDist = np.random.normal(self.ideal_lineflux, linefluxUnc * self.ideal_lineflux, size=numMC)[0] else: self.linefluxUncDist = np.random.normal(self.ideal_lineflux, linefluxUnc * self.ideal_lineflux, size=numMC) x = np.linspace(0, 1000, 100000) #add in uncertainties to variables specific to observable #self.AUncDist = a.uncdist(x, A, aUnc, numMC) #A #self.BUncDist = a.uncdist(x, B, bUnc, numMC) #B #Ignore uncertainties of the empirical fit self.AUncDist = A #A self.BUncDist = B #B #build uncertainty distributions if SpTyUnc == 0: if numMC == 1: self.SpTyUncDist = self.SpTy else: self.SpTyUncDist = np.ones(numMC) * self.SpTy else: self.SpTyUncDist = a.uncdist(x, self.SpTy, SpTyUnc, numMC) if distUnc == 0: if numMC == 1: self.distUncDist = self.dist else: self.distUncDist = np.ones(numMC) * self.dist else: self.distUncDist = a.uncdist(x, self.dist, distUnc, numMC) if ageUnc == 0: if numMC == 1: self.ageUncDist = self.age else: self.ageUncDist = np.ones(numMC) * self.age else: self.ageUncDist = a.uncdist(x, self.age, ageUnc, numMC) if AvUnc == 0: if numMC == 1: self.AvUncDist = self.Av else: self.AvUncDist = np.ones(numMC) * self.Av else: self.AvUncDist = a.uncdist(x, self.Av, AvUnc, numMC) if RinUnc == 0: if numMC == 1: self.RinUncDist = Rin else: self.RinUncDist = np.ones(numMC) * Rin else: self.RinUncDist = a.uncdist(x, Rin, RinUnc, numMC) self.TeffUncDist = a.SpTy_to_Teff(self.SpTyUncDist) self.massUncDist = a.Teff_to_params(self.TeffUncDist, (self.ageUncDist))[0] self.radiusUncDist = a.Teff_to_params(self.TeffUncDist, (self.ageUncDist))[1] self.RinUncDist = self.RinUncDist * self.radiusUncDist #Generate synthetic Mdot distribution #Generate synthetic Lacc distribution self.mdot = a.lineflux_to_Mdot(self.linefluxUncDist, self.distUncDist, self.massUncDist, self.radiusUncDist, self.AvUncDist, Rin=self.RinUncDist, A=self.AUncDist, B=self.BUncDist) if variability != 0: #specify lower and upper bounds for the truncated gaussian lower, upper = 0, 1 mu, sigma = (self.mdot), (self.mdot * variability) variability_distribution = st.truncnorm((lower - mu) / sigma, (upper - mu) / sigma, loc=mu, scale=sigma) if numMC == 1: self.mdot = variability_distribution.rvs(numMC)[0] else: self.mdot = variability_distribution.rvs(numMC) self.Lacc = a.Mdot_to_Lacc(self.mdot, self.massUncDist, self.radiusUncDist, self.RinUncDist)
def MoneyPlot(observed, simulated, numMC=1): mass = [] for r in range(len(simulated)): for i in range(numMC): mass.append(simulated['Mass (M$_\\odot$)'][r]) mass = np.array(mass) mdot = [] for r in range(len(simulated)): for i in range(numMC): if numMC == 1: mdot.append(simulated['Mdot (M$_\\odot$)'][r]) else: mdot.append(simulated['Mdot (M$_\\odot$)'][r][i]) mdot = np.array(mdot) true_mdot = [] for r in range(len(simulated)): for i in range(numMC): true_mdot.append(simulated['"true" Mdot (M$_\\odot$)'][r]) true_mdot = np.array(true_mdot) logmass = np.log10(mass) logMdot = np.log10(mdot) logaccepted_relation = np.log10(true_mdot) observed_mass = np.log10(observed['Object Mass M_Solar']) observed_mdot = np.log10(observed['Accretion Rate M_solar yr-1']) fig = plt.figure(figsize=(16, 12)) frame1 = fig.add_axes((.1, .3, .8, .6)) frame1.scatter(logmass, logMdot, facecolor='lightsteelblue', edgecolor='steelblue', s=130, alpha=0.4, label='Simulated') frame1.scatter(observed_mass, observed_mdot, edgecolor='black', facecolor='black', s=50, marker='x', alpha=0.4, label='Observed') frame1.plot(logmass, logaccepted_relation, color='tomato', label='Empirical Relationship') frame1.axvline(x=np.log10(0.012), color='black', linestyle='-.', label='Deuterium Burning Limit') frame1.axvline(x=np.log10(0.1), color='black', linestyle=':', label='Hydrogen Burning Limit') frame1.set_xlim(-2.6, 0.6) frame1.set_ylim(-14, -5.75) frame1.set_xlabel('log(Mass) (M$_\odot$)', size=16) frame1.set_ylabel('log(Mass Accretion Rate) (M$_\odot$/yr)', size=16) frame1.text(-2.3, -6.6, 'Planets', size=15, fontstyle='italic') frame1.text(-1.64, -6.6, 'Brown Dwarfs', size=15, fontstyle='italic') frame1.text(-0.29, -6.6, 'Stars', size=15, fontstyle='italic') frame1.set_title('Monte Carlo Error Propagation', size=20, fontweight='heavy') frame1.legend(loc='lower right', prop={ 'family': 'sans-serif', 'style': 'normal', 'size': 16 }, frameon=False, shadow=True) frame2 = fig.add_axes((.1, .1, .8, .2)) observed_difference = np.log10( observed['Accretion Rate M_solar yr-1']) - np.log10( a.empiricalMdot(observed['Object Mass M_Solar'])) simulated_difference = logMdot - np.log10(a.empiricalMdot(10**logmass)) frame2.axhline(0, color='tomato') frame2.set_xlabel('log(Mass) (M$_\odot$)', size=16) frame2.set_ylabel('Residual (log space)', size=16) frame2.set_ylim(-3.3, 3.2) frame2.scatter(logmass, simulated_difference, facecolor='lightsteelblue', edgecolor='steelblue', alpha=0.4, label='Simulated Residuals') frame2.scatter(np.log10(observed['Object Mass M_Solar']), observed_difference, facecolor='black', edgecolor='black', marker='x', alpha=0.4, label='Observed Residuals') frame2.legend(frameon=True) return fig
def residuals(observed, simulated, numMC=1): #load in data mass = [] for r in range(len(simulated)): for i in range(numMC): mass.append(simulated['Mass (M$_\\odot$)'][r]) mass = np.array(mass) mdot = [] for r in range(len(simulated)): for i in range(numMC): if numMC == 1: mdot.append(simulated['Mdot (M$_\\odot$)'][r]) else: mdot.append(simulated['Mdot (M$_\\odot$)'][r][i]) mdot = np.array(mdot) true_mdot = [] for r in range(len(simulated)): for i in range(numMC): true_mdot.append(simulated['"true" Mdot (M$_\\odot$)'][r]) true_mdot = np.array(true_mdot) logmass = np.log10(mass) logMdot = np.log10(mdot) logaccepted_relation = np.log10(true_mdot) observed_mass = np.log10(observed['Object Mass M_Solar']) observed_mdot = np.log10(observed['Accretion Rate M_solar yr-1']) #Figure Dimensions left, width = 0.1, 0.4 bottom, height = 0.1, 0.7 spacing = 0.0075 #create figure fig = plt.figure(figsize=(16, 12)) #Residual Plot rect_frame2 = [left, bottom, width, height] rect_ax2_hist = [left + width + spacing, bottom, 0.3, height] #create axes frame2 = fig.add_axes(rect_frame2) ax2_hist = fig.add_axes(rect_ax2_hist) ax = plt.gca() #Calculate Residuals observed_difference = np.log10( observed['Accretion Rate M_solar yr-1']) - np.log10( a.empiricalMdot(observed['Object Mass M_Solar'])) simulated_difference = logMdot - np.log10(a.empiricalMdot(10**logmass)) #Residual Marginal Distribution #remove ticks ax2_hist.tick_params(axis="y", labelleft=False) #bins by hand residualbinwidth = 0.25 residualmax = np.max(np.abs(observed_difference)) residuallim = (int(residualmax / residualbinwidth) + 1) * residualbinwidth residualbins = np.arange(-residuallim, residuallim + residualbinwidth, residualbinwidth) #plot ax2_hist.hist(observed_difference, bins=residualbins, orientation='horizontal', histtype='stepfilled', facecolor='gray', edgecolor='black', density=True, alpha=0.4, label='Observed') ax2_hist.hist(simulated_difference, bins=residualbins, orientation='horizontal', histtype='stepfilled', facecolor='lightsteelblue', edgecolor='royalblue', density=True, alpha=0.3, label='Simulated') ax2_hist.set_ylim(-3.3, 3.2) ax2_hist.axhline(0, color='tomato', label='Empirical Relationship') ax2_hist.tick_params(labelsize=13.5) #Residual Plot frame2.axhline(0, color='tomato', label='Empirical Relationship') frame2.set_xlabel('log(Mass) (M$_\odot$)', size=16) frame2.set_ylabel('Residual (log space)', size=16) frame2.set_ylim(-3.3, 3.2) frame2.scatter(logmass, simulated_difference, facecolor='lightsteelblue', edgecolor='steelblue', alpha=0.4, label='Simulated Residuals') frame2.scatter(np.log10(observed['Object Mass M_Solar']), observed_difference, color='black', marker='x', alpha=0.4, label='Observed Residuals') frame2.tick_params(labelsize=13.5) frame2.legend(frameon=True, fontsize=15) return fig