def __call__(self, params): def _getpar(key): return synth_params['{}{}'.format(key, self.planet_num)].value synth_params = params.basis.to_synth(params) tp = _getpar('tp') per = _getpar('per') ecc = _getpar('e') omega = _getpar('w') ts = orbit.timeperi_to_timetrans(tp, per, ecc, omega, secondary=True) ts_phase = utils.t_to_phase(synth_params, ts, self.planet_num) pts = utils.t_to_phase(synth_params, self.ts, self.planet_num) epts = self.ts_err / per penalty = -0.5 * ((ts_phase - pts) / epts)**2 return penalty
def plot_phasefold(self, pltletter, pnum): """ Plot phased orbit plots for each planet in the fit. Args: pltletter (int): integer representation of letter to be printed in the corner of the first phase plot. Ex: ord("a") gives 97, so the input should be 97. pnum (int): the number of the planet to be plotted. Must be the same as the number used to define a planet's Parameter objects (e.g. 'per1' is for planet #1) """ ax = pl.gca() if len(self.post.likelihood.x) < 20: self.nobin = True bin_fac = 1.75 bin_markersize = bin_fac * rcParams['lines.markersize'] bin_markeredgewidth = bin_fac * rcParams['lines.markeredgewidth'] rvmod2 = self.model(self.rvmodt, planet_num=pnum) - self.slope modph = t_to_phase(self.post.params, self.rvmodt, pnum, cat=True) - 1 rvdat = self.rawresid + self.model(self.rvtimes, planet_num=pnum) - self.slope_low phase = t_to_phase(self.post.params, self.rvtimes, pnum, cat=True) - 1 rvdatcat = np.concatenate((rvdat, rvdat)) rverrcat = np.concatenate((self.rverr, self.rverr)) rvmod2cat = np.concatenate((rvmod2, rvmod2)) bint, bindat, binerr = fastbin(phase + 1, rvdatcat, nbins=25) bint -= 1.0 ax.axhline( 0, color='0.5', linestyle='--', ) ax.plot(sorted(modph), rvmod2cat[np.argsort(modph)], 'b-', linewidth=self.fit_linewidth) plot.labelfig(pltletter) telcat = np.concatenate( (self.post.likelihood.telvec, self.post.likelihood.telvec)) if self.highlight_last: ind = np.argmax(self.rvtimes) hphase = t_to_phase(self.post.params, self.rvtimes[ind], pnum, cat=False) if hphase > 0.5: hphase -= 1 pl.plot(hphase, rvdatcat[ind], **plot.highlight_format) plot.mtelplot(phase, rvdatcat, rverrcat, telcat, ax, telfmts=self.telfmts) if not self.nobin and len(rvdat) > 10: ax.errorbar(bint, bindat, yerr=binerr, fmt='ro', mec='w', ms=bin_markersize, mew=bin_markeredgewidth) if self.phase_limits: ax.set_xlim(self.phase_limits[0], self.phase_limits[1]) else: ax.set_xlim(-0.5, 0.5) if not self.yscale_auto: scale = np.std(rvdatcat) ax.set_ylim(-self.yscale_sigma * scale, self.yscale_sigma * scale) keys = [p + str(pnum) for p in ['per', 'k', 'e']] labels = [self.post.params.tex_labels().get(k, k) for k in keys] if pnum < self.num_planets: ticks = ax.yaxis.get_majorticklocs() ax.yaxis.set_ticks(ticks[1:-1]) ax.set_ylabel('RV [{ms:}]'.format(**plot.latex), weight='bold') ax.set_xlabel('Phase', weight='bold') print_params = ['per', 'k', 'e'] units = {'per': 'days', 'k': plot.latex['ms'], 'e': ''} anotext = [] for l, p in enumerate(print_params): val = self.post.params["%s%d" % (print_params[l], pnum)].value if self.uparams is None: _anotext = r'$\mathregular{%s}$ = %4.2f %s' % ( labels[l].replace("$", ""), val, units[p]) else: if hasattr(self.post, 'medparams'): val = self.post.medparams["%s%d" % (print_params[l], pnum)] else: print("WARNING: medparams attribute not found in " + "posterior object will annotate with " + "max-likelihood values and reported uncertainties " + "may not be appropriate.") err = self.uparams["%s%d" % (print_params[l], pnum)] if err > 1e-15: val, err, errlow = sigfig(val, err) _anotext = r'$\mathregular{%s}$ = %s $\mathregular{\pm}$ %s %s' \ % (labels[l].replace("$", ""), val, err, units[p]) else: _anotext = r'$\mathregular{%s}$ = %4.2f %s' % ( labels[l].replace("$", ""), val, units[p]) anotext += [_anotext] if hasattr(self.post, 'derived'): chains = pd.read_csv(self.status['derive']['chainfile']) self.post.nplanets = self.num_planets dp = mcmc_plots.DerivedPlot(chains, self.post) labels = dp.labels texlabels = dp.texlabels units = dp.units derived_params = ['mpsini'] for l, par in enumerate(derived_params): par_label = par + str(pnum) if par_label in self.post.derived.columns: index = np.where(np.array(labels) == par_label)[0][0] unit = units[index] if unit == "M$_{\\rm Jup}$": conversion_fac = 0.00315 elif unit == "M$_{\\odot}$": conversion_fac = 0.000954265748 else: conversion_fac = 1 val = self.post.derived["%s%d" % (derived_params[l], pnum)].loc[0.500] * conversion_fac low = self.post.derived["%s%d" % (derived_params[l], pnum)].loc[0.159] * conversion_fac high = self.post.derived[ "%s%d" % (derived_params[l], pnum)].loc[0.841] * conversion_fac err_low = val - low err_high = high - val err = np.mean([err_low, err_high]) err = radvel.utils.round_sig(err) if err > 1e-15: val, err, errlow = sigfig(val, err) _anotext = r'$\mathregular{%s}$ = %s $\mathregular{\pm}$ %s %s' \ % (texlabels[index].replace("$", ""), val, err, units[index]) else: _anotext = r'$\mathregular{%s}$ = %4.2f %s' % ( texlabels[index].replace("$", ""), val, units[index]) anotext += [_anotext] anotext = '\n'.join(anotext) plot.add_anchored(anotext, loc=1, frameon=True, prop=dict(size=self.phasetext_size, weight='bold'), bbox=dict(ec='none', fc='w', alpha=0.8))
def plot_phasefold(self, pltletter, pnum): """ Plot phased orbit plots for each planet in the fit. Args: pltletter (int): integer representation of letter to be printed in the corner of the first phase plot. Ex: ord("a") gives 97, so the input should be 97. pnum (int): the number of the planet to be plotted. Must be the same as the number used to define a planet's Parameter objects (e.g. 'per1' is for planet #1) """ ax = plt.gca() if len(self.post.likelihood.x) < 20: self.nobin = True bin_fac = 1.75 bin_markersize = bin_fac * rcParams['lines.markersize'] bin_markeredgewidth = bin_fac * rcParams['lines.markeredgewidth'] rvmod2 = self.model(self.rvmodt, planet_num=pnum) - self.slope modph = t_to_phase(self.post.params, self.rvmodt, pnum, cat=True) - 1 rvdat = self.rawresid + self.model(self.rvtimes, planet_num=pnum) - self.slope_low phase = t_to_phase(self.post.params, self.rvtimes, pnum, cat=True) - 1 rvdatcat = np.concatenate((rvdat, rvdat)) rverrcat = np.concatenate((self.rverr, self.rverr)) rvmod2cat = np.concatenate((rvmod2, rvmod2)) bint, bindat, binerr = fastbin(phase + 1, rvdatcat, nbins=25) bint -= 1.0 ax.axhline(0, color='k', linestyle=':', linewidth=1) ax.plot(sorted(modph), rvmod2cat[np.argsort(modph)], 'k-', linewidth=self.fit_linewidth) #plot.labelfig(pltletter) telcat = np.concatenate( (self.post.likelihood.telvec, self.post.likelihood.telvec)) if self.highlight_last: ind = np.argmax(self.rvtimes) hphase = t_to_phase(self.post.params, self.rvtimes[ind], pnum, cat=False) if hphase > 0.5: hphase -= 1 plt.plot(hphase, rvdatcat[ind], **plot.highlight_format) mtelplot(phase, rvdatcat, rverrcat, telcat, ax, telfmts=self.telfmts) if not self.nobin and len(rvdat) > 10: pass #ax.errorbar( # bint, bindat, yerr=binerr, fmt='ro', mec='w', ms=bin_markersize, # mew=bin_markeredgewidth #) if self.phase_limits: ax.set_xlim(self.phase_limits[0], self.phase_limits[1]) else: ax.set_xlim(-0.5, 0.5) if not self.yscale_auto: scale = np.std(rvdatcat) ax.set_ylim(-self.yscale_sigma * scale, self.yscale_sigma * scale) ax.set_ylim((-510, 510)) keys = [p + str(pnum) for p in ['per', 'k', 'e']] labels = [self.post.params.tex_labels().get(k, k) for k in keys] if pnum < self.num_planets: ticks = ax.yaxis.get_majorticklocs() ax.yaxis.set_ticks(ticks[1:-1]) ax.set_ylabel('RV [{ms:}]'.format(**plot.latex)) ax.set_xlabel('Phase') ax.get_yaxis().set_tick_params(which='both', direction='in') ax.get_xaxis().set_tick_params(which='both', direction='in') ax.tick_params(right=True, which='both', direction='in') ax.tick_params(top=True, which='both', direction='in') print_params = ['per', 'k', 'e'] units = {'per': 'days', 'k': plot.latex['ms'], 'e': ''} anotext = [] for l, p in enumerate(print_params): val = self.post.params["%s%d" % (print_params[l], pnum)].value if self.uparams is None: _anotext = '$\\mathregular{%s}$ = %4.2f %s' % ( labels[l].replace("$", ""), val, units[p]) else: if hasattr(self.post, 'medparams'): val = self.post.medparams["%s%d" % (print_params[l], pnum)] else: print("WARNING: medparams attribute not found in " + "posterior object will annotate with " + "max-likelihood values and reported uncertainties " + "may not be appropriate.") err = self.uparams["%s%d" % (print_params[l], pnum)] if err > 1e-15: val, err, errlow = sigfig(val, err) _anotext = '$\\mathregular{%s}$ = %s $\\mathregular{\\pm}$ %s %s' \ % (labels[l].replace("$", ""), val, err, units[p]) else: _anotext = '$\\mathregular{%s}$ = %4.2f %s' % ( labels[l].replace("$", ""), val, units[p]) anotext += [_anotext] #anotext = '\n'.join(anotext) anotext = anotext[1] # just the semi-amplitude logk1_limit = 4.68726682 #anotext = ( # f'K < {np.exp(logk1_limit):.1f}' +' m$\,$s$^{-1}$ (3$\sigma$)\n' # '$M_{\mathrm{p}} \sin i < 1.20\,M_{\mathrm{Jup}}$' #) anotext = ( #f'K < {np.exp(logk1_limit):.1f}' +' m$\,$s$^{-1}$ (3$\sigma$)\n' '$M_{\mathrm{p}} \sin i < 1.20\,M_{\mathrm{Jup}}\ (3\sigma)$') add_anchored(anotext, loc='lower left', frameon=True, prop=dict(size=self.phasetext_size), bbox=dict(ec='none', fc='w', alpha=0.8))
def rv_multipanel_plot(post, saveplot=None, **kwargs): """ Multi-panel RV plot to display model using post.params orbital paramters. Args: post (radvel.Posterior): Radvel posterior object. The model plotted will be generated from post.params saveplot (string): (optional) Name of output file, will show as interactive matplotlib window if not defined. nobin (bool): (optional) If True do not show binned data on phase plots. Will default to True if total number of measurements is less then 20. yscale_auto (bool): (optional) Use matplotlib auto y-axis scaling (default: False) yscale_sigma (float): (optional) Scale y-axis limits to be +/- yscale_sigma*(RMS of data plotted) (default: 3.0) telfmts (dict): (optional) dictionary mapping instrument code to plotting format code nophase (bool): (optional) Will omit phase-folded plots if true epoch (float): (optional) Subtract this value from the time axis for more compact axis labels (default: 245000) uparams (dict): (optional) parameter uncertainties, must contain 'per', 'k', and 'e' keys (default: None) Returns: None """ nobin = kwargs.pop('nobin', False) yscale_sigma = kwargs.pop('yscale_sigma', 3.0) yscale_auto = kwargs.pop('yscale_auto', False) telfmts = kwargs.pop('telfmts', globals()['telfmts']) nophase = kwargs.pop('nophase', False) e = kwargs.pop('epoch', 2450000) uparams = kwargs.pop('uparams', None) if len(post.likelihood.x) < 20: nobin = True if saveplot != None: resolution = 1e4 else: resolution = 2000 cpspost = copy.deepcopy(post) cpsparams = post.params.basis.to_cps(post.params) cpspost.params.update(cpsparams) model = cpspost.likelihood.model rvtimes = cpspost.likelihood.x rvdat = cpspost.likelihood.y rverr = cpspost.likelihood.errorbars() n = model.num_planets if isinstance(cpspost.likelihood, radvel.likelihood.CompositeLikelihood): like_list = cpspost.likelihood.like_list else: like_list = [cpspost.likelihood] periods = [] for i in range(model.num_planets): periods.append(cpsparams['per%d' % (i + 1)]) longp = max(periods) shortp = min(periods) dt = max(rvtimes) - min(rvtimes) rvmodt = np.linspace( min(rvtimes) - 0.05 * dt, max(rvtimes) + 0.05 * dt + longp, resolution) rvmod2 = model(rvmodt) rvmod = model(rvtimes) if ((rvtimes - e) < -2.4e6).any(): plttimes = rvtimes mplttimes = rvmodt elif e == 0: e = 2450000 plttimes = rvtimes - e mplttimes = rvmodt - e else: plttimes = rvtimes - e mplttimes = rvmodt - e rawresid = cpspost.likelihood.residuals() resid = rawresid + cpsparams['dvdt'] * ( rvtimes - model.time_base) + cpsparams['curv'] * (rvtimes - model.time_base)**2 slope = cpsparams['dvdt'] * ( rvmodt - model.time_base) + cpsparams['curv'] * (rvmodt - model.time_base)**2 slope_low = cpsparams['dvdt'] * ( rvtimes - model.time_base) + cpsparams['curv'] * (rvtimes - model.time_base)**2 if nophase: fig = pl.figure(figsize=(19.0, 16.0)) n = 0 rect = [0.10, 0.12, 0.865, 1 - 0.12 - 0.06] elif n == 1: fig = pl.figure(figsize=(19.0, 18.0)) rect = [0.10, 0.55, 0.865, 1 - 0.55 - 0.06] else: fig = pl.figure(figsize=(19.0, 16.0 + 4 * n)) rect = [0.10, 0.64, 0.865, 1 - 0.64 - 0.06] axRV = pl.axes(rect) pl.subplots_adjust(left=0.1, top=0.865, right=0.95) plotindex = 1 pltletter = ord('a') ax = axRV #Unphased plot ax.axhline(0, color='0.5', linestyle='--', lw=2) ax.plot(mplttimes, rvmod2, 'b-', linewidth=1, rasterized=False) ax.annotate("%s)" % chr(pltletter), xy=(0.01, 0.85), xycoords='axes fraction', fontsize=28, fontweight='bold') pltletter += 1 _mtelplot(plttimes, rawresid + rvmod, rverr, cpspost.likelihood.telvec, ax, telfmts) ax.set_xlim(min(plttimes) - 0.01 * dt, max(plttimes) + 0.01 * dt) pl.setp(axRV.get_xticklabels(), visible=False) # Years on upper axis axyrs = axRV.twiny() axyrs.set_xlim(min(plttimes) - 0.01 * dt, max(plttimes) + 0.01 * dt) #yrticklocs = [date2jd(datetime(y, 1, 1, 0, 0, 0))-e for y in [1998, 2002, 2006, 2010, 2014]] yrticklocs = [] yrticklabels = [] for y in [1988, 1992, 1996, 2000, 2004, 2008, 2012, 2016]: jd = Time("%d-01-01T00:00:00" % y, format='isot', scale='utc').jd - e if jd > ax.get_xlim()[0] and jd < ax.get_xlim()[1]: yrticklocs.append(jd) yrticklabels.append("%d" % y) axyrs.set_xticks(yrticklocs) axyrs.set_xticklabels(yrticklabels) if len(yrticklabels) > 0: pl.xlabel('Year') axyrs.grid(False) if not yscale_auto: ax.set_ylim(-yscale_sigma * np.std(rawresid + rvmod), yscale_sigma * np.std(rawresid + rvmod)) ax.set_ylabel('RV [m s$^{-1}$]') ticks = ax.yaxis.get_majorticklocs() ax.yaxis.set_ticks(ticks[1:]) divider = make_axes_locatable(axRV) axResid = divider.append_axes("bottom", size="50%", pad=0.0, sharex=axRV, sharey=None) ax = axResid #Residuals ax.plot(mplttimes, slope, 'b-', linewidth=3) ax.annotate("%s)" % chr(pltletter), xy=(0.01, 0.80), xycoords='axes fraction', fontsize=28, fontweight='bold') pltletter += 1 _mtelplot(plttimes, resid, rverr, cpspost.likelihood.telvec, ax, telfmts) if not yscale_auto: ax.set_ylim(-yscale_sigma * np.std(resid), yscale_sigma * np.std(resid)) ax.set_xlim(min(plttimes) - 0.01 * dt, max(plttimes) + 0.01 * dt) ticks = ax.yaxis.get_majorticklocs() ax.yaxis.set_ticks([ticks[0], 0.0, ticks[-1]]) xticks = ax.xaxis.get_majorticklocs() pl.xlabel('BJD$_{\\mathrm{TDB}}$ - %d' % e) ax.set_ylabel('Residuals') # Define the locations for the axes axbounds = ax.get_position().bounds bottom = axbounds[1] height = (bottom - 0.15) / n textloc = bottom / 2 bottom -= height + 0.05 left, width = 0.10, 0.72 #Phase plots for i in range(n): if nophase: break pnum = i + 1 #print "Planet %d" % pnum rvdat = rvdat.copy() rvmod2 = model(rvmodt, planet_num=pnum) - slope modph = t_to_phase(cpspost.params, rvmodt, pnum, cat=True) - 1 rvdat = rawresid + model(rvtimes, planet_num=pnum) - slope_low phase = t_to_phase(cpspost.params, rvtimes, pnum, cat=True) - 1 p2 = t_to_phase(cpspost.params, rvtimes, pnum, cat=False) - 1 rvdatcat = np.concatenate((rvdat, rvdat)) rverrcat = np.concatenate((rverr, rverr)) rvmod2cat = np.concatenate((rvmod2, rvmod2)) bint, bindat, binerr = fastbin(phase + 1, rvdatcat, nbins=25) bint -= 1.0 rect = [left, bottom - (i) * height, (left + width) + 0.045, height] if n == 1: rect[1] -= 0.03 ax = pl.axes(rect) ax.axhline(0, color='0.5', linestyle='--', lw=2) ax.plot(sorted(modph), rvmod2cat[np.argsort(modph)], 'b-', linewidth=3) ax.annotate("%s)" % chr(pltletter), xy=(0.01, 0.85), xycoords='axes fraction', fontsize=28, fontweight='bold') pltletter += 1 _mtelplot( phase, rvdatcat, rverrcat, np.concatenate( (cpspost.likelihood.telvec, cpspost.likelihood.telvec)), ax, telfmts) if not nobin and len(rvdat) > 10: ax.errorbar(bint, bindat, yerr=binerr, fmt='ro', ecolor='r', markersize=msize * 2.5, markeredgecolor='w', markeredgewidth=2) pl.xlim(-0.5, 0.5) #meanlim = np.mean([-min(rvdat), max(rvdat)]) #meanlim += 0.10*meanlim #pl.ylim(-meanlim, meanlim) if not yscale_auto: pl.ylim(-yscale_sigma * np.std(rvdatcat), yscale_sigma * np.std(rvdatcat)) letters = string.lowercase planetletter = letters[i + 1] keys = [p + str(pnum) for p in ['per', 'k', 'e']] labels = [cpspost.params.tex_labels().get(k, k) for k in keys] units = ['days', 'm s$^{-1}$', ''] indicies = [0, 4, 2, 2] spacing = 0.09 xstart = 0.65 ystart = 0.89 if i < n - 1: ticks = ax.yaxis.get_majorticklocs() ax.yaxis.set_ticks(ticks[1:-1]) if n > 1: fig.text(0.01, textloc, 'RV [m s$^{-1}$]', rotation='vertical', ha='center', va='center', fontsize=28) else: pl.ylabel('RV [m s$^{-1}$]') pl.xlabel('Phase') print_params = ['per', 'k', 'e'] for l, p in enumerate(print_params): val = cpsparams["%s%d" % (print_params[l], pnum)] if uparams is None: anotext = '%s = %4.2f %s' % (labels[l], val, units[l]) else: err = uparams["%s%d" % (print_params[l], pnum)] if err > 0: val, err, errlow = radvel.utils.sigfig(val, err) anotext = '%s = %s $\\pm$ %s %s' % (labels[l], val, err, units[l]) else: anotext = '%s = %4.2f %s' % (labels[l], val, units[l]) txt = ax.annotate(anotext, (xstart, ystart - l * spacing), xycoords='axes fraction', fontsize=28) if saveplot != None: pl.savefig(saveplot, dpi=150) print "RV multi-panel plot saved to %s" % saveplot else: pl.show()
def plot_phasefold(self, pltletter, pnum): """ Plot phased orbit plots for each planet in the fit. Args: pltletter (int): integer representation of letter to be printed in the corner of the first phase plot. Ex: ord("a") gives 97, so the input should be 97. pnum (int): the number of the planet to be plotted. Must be the same as the number used to define a planet's Parameter objects (e.g. 'per1' is for planet #1) """ ax = pl.gca() if len(self.post.likelihood.x) < 20: self.nobin = True bin_fac = 1.75 bin_markersize = bin_fac * rcParams['lines.markersize'] bin_markeredgewidth = bin_fac * rcParams['lines.markeredgewidth'] rvmod2 = self.model(self.rvmodt, planet_num=pnum) - self.slope modph = t_to_phase(self.post.params, self.rvmodt, pnum, cat=True) - 1 rvdat = self.rawresid + self.model(self.rvtimes, planet_num=pnum) - self.slope_low phase = t_to_phase(self.post.params, self.rvtimes, pnum, cat=True) - 1 rvdatcat = np.concatenate((rvdat, rvdat)) rverrcat = np.concatenate((self.rverr, self.rverr)) rvmod2cat = np.concatenate((rvmod2, rvmod2)) bint, bindat, binerr = fastbin(phase + 1, rvdatcat, nbins=25) bint -= 1.0 ax.axhline( 0, color='0.5', linestyle='--', ) ax.plot(sorted(modph), rvmod2cat[np.argsort(modph)], 'b-', linewidth=self.fit_linewidth) plot.labelfig(pltletter) telcat = np.concatenate( (self.post.likelihood.telvec, self.post.likelihood.telvec)) plot.mtelplot(phase, rvdatcat, rverrcat, telcat, ax, telfmts=self.telfmts) if not self.nobin and len(rvdat) > 10: ax.errorbar(bint, bindat, yerr=binerr, fmt='ro', mec='w', ms=bin_markersize, mew=bin_markeredgewidth) if self.phase_limits: ax.set_xlim(self.phase_limits[0], self.phase_limits[1]) else: ax.set_xlim(-0.5, 0.5) if not self.yscale_auto: scale = np.std(rvdatcat) ax.set_ylim(-self.yscale_sigma * scale, self.yscale_sigma * scale) keys = [p + str(pnum) for p in ['per', 'k', 'e']] labels = [self.post.params.tex_labels().get(k, k) for k in keys] if pnum < self.num_planets: ticks = ax.yaxis.get_majorticklocs() ax.yaxis.set_ticks(ticks[1:-1]) ax.set_ylabel('RV [{ms:}]'.format(**plot.latex), weight='bold') ax.set_xlabel('Phase', weight='bold') print_params = ['per', 'k', 'e'] units = {'per': 'days', 'k': plot.latex['ms'], 'e': ''} anotext = [] for l, p in enumerate(print_params): val = self.post.params["%s%d" % (print_params[l], pnum)].value if self.uparams is None: _anotext = '$\\mathregular{%s}$ = %4.2f %s' % ( labels[l].replace("$", ""), val, units[p]) else: if hasattr(self.post, 'medparams'): val = self.post.medparams["%s%d" % (print_params[l], pnum)] else: print("WARNING: medparams attribute not found in " + "posterior object will annotate with " + "max-likelihood values and reported uncertainties " + "may not be appropriate.") err = self.uparams["%s%d" % (print_params[l], pnum)] if err > 0: val, err, errlow = sigfig(val, err) _anotext = '$\\mathregular{%s}$ = %s $\\mathregular{\\pm}$ %s %s' \ % (labels[l].replace("$", ""), val, err, units[p]) else: _anotext = '$\\mathregular{%s}$ = %4.2f %s' % ( labels[l].replace("$", ""), val, units[p]) anotext += [_anotext] anotext = '\n'.join(anotext) plot.add_anchored(anotext, loc=1, frameon=True, prop=dict(size=self.phasetext_size, weight='bold'), bbox=dict(ec='none', fc='w', alpha=0.8))
def rv_multipanel_plot(post, saveplot=None, telfmts={}, nobin=False, yscale_auto=False, yscale_sigma=3.0, nophase=False, epoch=2450000, uparams=None, phase_ncols=None, phase_nrows=None, legend=True, rv_phase_space=0.08): """Multi-panel RV plot to display model using post.params orbital parameters. Args: post (radvel.Posterior): Radvel posterior object. The model plotted will be generated from post.params saveplot (string, optional): Name of output file, will show as interactive matplotlib window if not defined. nobin (bool, optional): If True do not show binned data on phase plots. Will default to True if total number of measurements is less then 20. yscale_auto (bool, optional): Use matplotlib auto y-axis scaling (default: False) yscale_sigma (float, optional): Scale y-axis limits to be +/- yscale_sigma*(RMS of data plotted) if yscale_auto==False telfmts (dict, optional): dictionary of dictionaries mapping instrument code to plotting format code. nophase (bool, optional): Will omit phase-folded plots if true epoch (float, optional): Subtract this value from the time axis for more compact axis labels (default: 245000) uparams (dict, optional): parameter uncertainties, must contain 'per', 'k', and 'e' keys. phase_ncols (int, optional): number of columns in the phase folded plots. Default behavior is 1. phase_nrows (int, optional): number of columns in the phase folded plots. Default is nplanets. legend (bool, optional): include legend on plot? (default: True) rv_phase_space (float, optional): verticle space between rv plot and phase-folded plots (in units of fraction of figure height) Returns: figure: current matplotlib figure object list: list of axis objects """ figwidth = 7.5 # spans a page with 0.5in margins phasefac = 1.4 ax_rv_height = figwidth * 0.6 ax_phase_height = ax_rv_height / phasefac bin_fac = 1.75 bin_markersize = bin_fac * rcParams['lines.markersize'] bin_markeredgewidth = bin_fac * rcParams['lines.markeredgewidth'] fit_linewidth = 2.0 cpspost = copy.deepcopy(post) model = cpspost.likelihood.model cpsparams = post.params.basis.to_cps(post.params) cpspost.params.update(cpsparams) rvtimes = cpspost.likelihood.x rvdat = cpspost.likelihood.y rverr = cpspost.likelihood.errorbars() num_planets = model.num_planets if nophase: num_planets = 1 periods = [max(rvtimes) - min(rvtimes)] if phase_ncols is None: phase_ncols = 1 if phase_nrows is None: phase_nrows = num_planets ax_phase_height /= phase_ncols e = epoch if len(post.likelihood.x) < 20: nobin = True if saveplot != None: resolution = 10000 else: resolution = 2000 if isinstance(cpspost.likelihood, radvel.likelihood.CompositeLikelihood): like_list = cpspost.likelihood.like_list else: like_list = [ cpspost.likelihood ] if not nophase: periods = [] for i in range(num_planets): periods.append(cpsparams['per%d' % (i+1)]) longp = max(periods) shortp = min(periods) dt = max(rvtimes) - min(rvtimes) rvmodt = np.linspace( min(rvtimes) - 0.05 * dt, max(rvtimes) + 0.05 * dt + longp, int(resolution) ) rvmod2 = model(rvmodt) rvmod = model(rvtimes) if ((rvtimes - e) < -2.4e6).any(): plttimes = rvtimes mplttimes = rvmodt elif e == 0: e = 2450000 plttimes = rvtimes - e mplttimes = rvmodt - e else: plttimes = rvtimes - e mplttimes = rvmodt - e rawresid = cpspost.likelihood.residuals() resid = ( rawresid + cpsparams['dvdt']*(rvtimes-model.time_base) + cpsparams['curv']*(rvtimes-model.time_base)**2 ) slope = ( cpsparams['dvdt'] * (rvmodt-model.time_base) + cpsparams['curv'] * (rvmodt-model.time_base)**2 ) slope_low = ( cpsparams['dvdt'] * (rvtimes-model.time_base) + cpsparams['curv'] * (rvtimes-model.time_base)**2 ) # Provision figure figheight = ax_rv_height + ax_phase_height * phase_nrows divide = 1 - ax_rv_height / figheight fig = pl.figure(figsize=(figwidth, figheight)) fig.subplots_adjust(left=0.12, right=0.95) gs_rv = gridspec.GridSpec(1, 1) gs_rv.update(left=0.12, right=0.93, top=0.93, bottom=divide+rv_phase_space*0.5) gs_phase = gridspec.GridSpec(phase_nrows, phase_ncols) if phase_ncols == 1: gs_phase.update(left=0.12, right=0.93, top=divide - rv_phase_space * 0.5, bottom=0.07, hspace=0.003) else: gs_phase.update(left=0.12, right=0.93, top=divide - rv_phase_space * 0.5, bottom=0.07, hspace=0.25, wspace=0.25) axL = [] axRV = pl.subplot(gs_rv[0, 0]) plotindex = 1 pltletter = ord('a') ax = axRV axL += [axRV] # Unphased plot ax.axhline(0, color='0.5', linestyle='--') ax.plot(mplttimes,rvmod2,'b-', rasterized=False, lw=0.1) def labelfig(ax, pltletter): text = "{})".format(chr(pltletter)) add_anchored( text, loc=2, prop=dict(fontweight='bold', size='large'), frameon=False ) labelfig(ax, pltletter) pltletter += 1 _mtelplot( plttimes, rawresid+rvmod, rverr, cpspost.likelihood.telvec, ax, telfmts ) ax.set_xlim(min(plttimes)-0.01*dt, max(plttimes)+0.01*dt) pl.setp(axRV.get_xticklabels(), visible=False) # Legend if legend: pl.legend(numpoints=1, fontsize='x-small', loc='best') # Years on upper axis axyrs = axRV.twiny() # axyrs.set_xlim(min(plttimes)-0.01*dt,max(plttimes)+0.01*dt) xl = np.array(list(ax.get_xlim())) + e decimalyear = Time(xl,format='jd',scale='utc').decimalyear axyrs.plot(decimalyear, decimalyear) axyrs.get_xaxis().get_major_formatter().set_useOffset(False) axyrs.set_xlim(*decimalyear) axyrs.set_xlabel('Year', fontweight='bold') # axyrs.xaxis.set_major_locator(MaxNLocator(8)) if not yscale_auto: scale = np.std(rawresid+rvmod) ax.set_ylim(-yscale_sigma * scale , yscale_sigma * scale) ax.set_ylabel('RV [{ms:}]'.format(**latex), weight='bold') ticks = ax.yaxis.get_majorticklocs() ax.yaxis.set_ticks(ticks[1:]) divider = make_axes_locatable(axRV) axResid = divider.append_axes( "bottom",size="50%", pad=0.0, sharex=axRV, sharey=None ) ax = axResid axL += [axResid] # Residuals ax.plot(mplttimes, slope, 'b-', lw=fit_linewidth) labelfig(ax, pltletter) pltletter += 1 _mtelplot(plttimes, resid, rverr, cpspost.likelihood.telvec, ax, telfmts) if not yscale_auto: scale = np.std(resid) ax.set_ylim(-yscale_sigma * scale, yscale_sigma * scale) ax.set_xlim(min(plttimes)-0.01*dt,max(plttimes)+0.01*dt) ticks = ax.yaxis.get_majorticklocs() ax.yaxis.set_ticks([ticks[0],0.0,ticks[-1]]) xticks = ax.xaxis.get_majorticklocs() pl.xlabel('JD - {:d}'.format(int(np.round(e))), weight='bold') ax.set_ylabel('Residuals', weight='bold') ax.yaxis.set_major_locator(MaxNLocator(5,prune='both')) # Define the locations for the axes axbounds = ax.get_position().bounds bottom = axbounds[1] height = (bottom - 0.15) / num_planets textloc = bottom / 2 bottom -= height + 0.05 left, width = 0.10, 0.72 #Phase plots for i in range(num_planets): if nophase: break pnum = i+1 #print("Planet %d" % pnum) rvdat = rvdat.copy() rvmod2 = model(rvmodt, planet_num=pnum) - slope modph = t_to_phase(cpspost.params, rvmodt, pnum, cat=True) - 1 rvdat = rawresid + model(rvtimes, planet_num=pnum) - slope_low phase = t_to_phase(cpspost.params, rvtimes, pnum, cat=True) - 1 p2 = t_to_phase(cpspost.params, rvtimes, pnum, cat=False) - 1 rvdatcat = np.concatenate((rvdat,rvdat)) rverrcat = np.concatenate((rverr,rverr)) rvmod2cat = np.concatenate((rvmod2,rvmod2)) bint, bindat, binerr = fastbin(phase+1, rvdatcat, nbins=25) bint -= 1.0 i_row = i / phase_ncols i_col = i - i_row * phase_ncols ax = pl.subplot(gs_phase[i_row, i_col]) axL += [ax] ax.axhline(0, color='0.5', linestyle='--', ) ax.plot(sorted(modph),rvmod2cat[np.argsort(modph)],'b-',linewidth=fit_linewidth) labelfig(ax,pltletter) pltletter += 1 telcat = np.concatenate((cpspost.likelihood.telvec,cpspost.likelihood.telvec)) _mtelplot(phase,rvdatcat, rverrcat, telcat, ax, telfmts) if not nobin and len(rvdat) > 10: ax.errorbar( bint, bindat, yerr=binerr, fmt='ro',mec='w', ms=bin_markersize, mew=bin_markeredgewidth ) pl.xlim(-0.5,0.5) if not yscale_auto: scale = np.std(rvdatcat) pl.ylim(-yscale_sigma*scale, yscale_sigma*scale ) letters = string.lowercase planetletter = letters[i+1] keys = [p+str(pnum) for p in ['per', 'k', 'e'] ] labels = [cpspost.params.tex_labels().get(k, k) for k in keys] if i < num_planets-1: ticks = ax.yaxis.get_majorticklocs() ax.yaxis.set_ticks(ticks[1:-1]) pl.ylabel('RV [{ms:}]'.format(**latex), weight='bold') pl.xlabel('Phase', weight='bold') print_params = ['per', 'k', 'e'] units = {'per':'days','k':latex['ms'],'e':''} anotext = [] for l, p in enumerate(print_params): val = cpsparams["%s%d" % (print_params[l],pnum)] if uparams is None: _anotext = '$\\mathregular{%s}$ = %4.2f %s' % (labels[l].replace("$",""), val, units[p]) else: if hasattr(post, 'medparams'): val = post.medparams["%s%d" % (print_params[l],pnum)] else: print("WARNING: medparams attribute not found in " + "posterior object will annotate with " + "max-likelihood values and reported uncertainties " + "may not be appropriate.") err = uparams["%s%d" % (print_params[l],pnum)] if err > 0: val, err, errlow = radvel.utils.sigfig(val, err) _anotext = '$\\mathregular{%s}$ = %s $\\mathregular{\\pm}$ %s %s' % (labels[l].replace("$",""), val, err, units[p]) else: _anotext = '$\\mathregular{%s}$ = %4.2f %s' % (labels[l].replace("$",""), val, units[p]) anotext += [_anotext] anotext = '\n'.join(anotext) add_anchored( anotext, loc=1, frameon=True, prop=dict(size='large', weight='bold'), bbox=dict(ec='none', fc='w', alpha=0.8) ) if saveplot != None: pl.savefig(saveplot,dpi=150) print("RV multi-panel plot saved to %s" % saveplot) return fig, axL
def rv_multipanel_plot(post, saveplot=None, telfmts={}, nobin=False, yscale_auto=False, yscale_sigma=3.0, nophase=False, epoch=2450000, uparams=None, phase_ncols=None, phase_nrows=None, legend=True, legend_fontsize='x-small', rv_phase_space=0.08, phase_limits=[], subtract_gp_mean_model=False, plot_likelihoods_separately=True, subtract_orbit_model=False): """Multi-panel RV plot to display model using post.params orbital parameters. Args: post (radvel.Posterior): Radvel posterior object. The model plotted will be generated from post.params saveplot (string, optional): Name of output file, will show as interactive matplotlib window if not defined. nobin (bool, optional): If True do not show binned data on phase plots. Will default to True if total number of measurements is less then 20. yscale_auto (bool, optional): Use matplotlib auto y-axis scaling (default: False) yscale_sigma (float, optional): Scale y-axis limits to be +/- yscale_sigma*(RMS of data plotted) if yscale_auto==False telfmts (dict, optional): dictionary of dictionaries mapping instrument code to plotting format code. nophase (bool, optional): Will omit phase-folded plots if true epoch (float, optional): Subtract this value from the time axis for more compact axis labels (default: 245000) uparams (dict, optional): parameter uncertainties, must contain 'per', 'k', and 'e' keys. phase_ncols (int, optional): number of columns in the phase folded plots. Default behavior is 1. phase_nrows (int, optional): number of columns in the phase folded plots. Default is nplanets. legend (bool, optional): include legend on plot? (default: True) legend_fontsize (str, optional): fontsize parameter to be passed to matplotlib.legend. Choose from {'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'}. (default: 'x-small') rv_phase_space (float, optional): verticle space between rv plot and phase-folded plots (in units of fraction of figure height) phase_limits (list, optional): two element list specifying pyplot.xlim bounds for phase-folded array. Useful for partial orbits. subtract_gp_mean_model (bool, optional): if True, subtract the Gaussian process mean max likelihood model from the data and the model when plotting the results. plot_likelihoods_separately (bool, optional): if True, plot a separate panel for each Likelihood object. subtract_orbit_model (bool, optional): if True, subtract the best-fit orbit model from the data and the model when plotting the results. Useful for seeing the structure of correlated noise in the data. Returns: figure: current matplotlib figure object list: list of axis objects """ figwidth = 7.5 # spans a page with 0.5in margins phasefac = 1.4 ax_rv_height = figwidth * 0.6 ax_phase_height = ax_rv_height / phasefac bin_fac = 1.75 bin_markersize = bin_fac * rcParams['lines.markersize'] bin_markeredgewidth = bin_fac * rcParams['lines.markeredgewidth'] fit_linewidth = 2.0 synthpost = copy.deepcopy(post) model = synthpost.likelihood.model synthparams = post.params.basis.to_synth(post.params) synthpost.params.update(synthparams) rvtimes = synthpost.likelihood.x rverr = synthpost.likelihood.errorbars() num_planets = model.num_planets if nophase: num_planets = 1 periods = [max(rvtimes) - min(rvtimes)] if phase_ncols is None: phase_ncols = 1 if phase_nrows is None: phase_nrows = num_planets ax_phase_height /= phase_ncols e = epoch if len(post.likelihood.x) < 20: nobin = True if saveplot is not None: resolution = 10000 else: resolution = 2000 if isinstance(synthpost.likelihood, radvel.likelihood.CompositeLikelihood): like_list = synthpost.likelihood.like_list else: like_list = [synthpost.likelihood] if not nophase: periods = [] for i in range(num_planets): periods.append(synthparams['per%d' % (i + 1)].value) longp = max(periods) dt = max(rvtimes) - min(rvtimes) rvmodt = np.linspace( min(rvtimes) - 0.05 * dt, max(rvtimes) + 0.05 * dt + longp, int(resolution)) rvmod2 = model(rvmodt) rvmod = model(rvtimes) if ((rvtimes - e) < -2.4e6).any(): plttimes = rvtimes mplttimes = rvmodt elif e == 0: e = 2450000 plttimes = rvtimes - e mplttimes = rvmodt - e else: plttimes = rvtimes - e mplttimes = rvmodt - e rawresid = synthpost.likelihood.residuals() resid = (rawresid + synthparams['dvdt'].value * (rvtimes - model.time_base) + synthparams['curv'].value * (rvtimes - model.time_base)**2) slope = (synthparams['dvdt'].value * (rvmodt - model.time_base) + synthparams['curv'].value * (rvmodt - model.time_base)**2) slope_low = (synthparams['dvdt'].value * (rvtimes - model.time_base) + synthparams['curv'].value * (rvtimes - model.time_base)**2) # Provision figure figheight = ax_rv_height + ax_phase_height * phase_nrows divide = 1 - ax_rv_height / figheight fig = pl.figure(figsize=(figwidth, figheight)) fig.subplots_adjust(left=0.12, right=0.95) gs_rv = gridspec.GridSpec(1, 1) gs_rv.update(left=0.12, right=0.93, top=0.93, bottom=divide + rv_phase_space * 0.5) gs_phase = gridspec.GridSpec(phase_nrows, phase_ncols) if phase_ncols == 1: gs_phase.update(left=0.12, right=0.93, top=divide - rv_phase_space * 0.5, bottom=0.07, hspace=0.003) else: gs_phase.update(left=0.12, right=0.93, top=divide - rv_phase_space * 0.5, bottom=0.07, hspace=0.25, wspace=0.25) ax_list = [] ax_rv = pl.subplot(gs_rv[0, 0]) pltletter = ord('a') ax = ax_rv ax_list += [ax_rv] ax.axhline(0, color='0.5', linestyle='--') # Default formatting lw = 0.01 ci = 0 default_colors = ['orange', 'purple', 'magenta', 'pink'] numdatapoints = 0 for like in like_list: if isinstance(like, radvel.likelihood.GPLikelihood): gp_mean, _ = like.predict(like.x) if not subtract_gp_mean_model: rvmod[numdatapoints:numdatapoints + len(like.x)] += gp_mean numdatapoints += len(like.x) for like in like_list: if isinstance(like, radvel.likelihood.GPLikelihood): t = like.suffix kw = dict(fmt='o', capsize=0, mew=0, ecolor='0.6', lw=lw, color=default_colors[ci], label=t) # If not explicit format set, look among default formats telfmt = {} if t not in telfmts and t in telfmts_default: telfmt = telfmts_default[t] if t in telfmts: telfmt = telfmts[t] print(telfmt) if t not in telfmts and t not in telfmts_default: ci += 1 for k in telfmt: kw[k] = telfmt[k] xpred = np.linspace(np.min(like.x), np.max(like.x), num=int(3e3)) gpmu, stddev = like.predict(xpred) if ((xpred - e) < -2.4e6).any(): pass elif e == 0: e = 2450000 xpred = xpred - e else: xpred = xpred - e orbit_model = like.model(xpred) if subtract_gp_mean_model: gpmu = 0. if subtract_orbit_model: orbit_model = 0. ax.fill_between(xpred, gpmu + orbit_model - stddev, gpmu + orbit_model + stddev, color=kw['color'], alpha=0.5, lw=0) ax.plot(xpred, gpmu + orbit_model, 'b-', rasterized=False, lw=0.1) else: # Unphased plot orbit_model = rvmod2 if subtract_orbit_model: orbit_model = 0. ax.plot(mplttimes, orbit_model, 'b-', rasterized=False, lw=0.1) def labelfig(letter): text = "{})".format(chr(letter)) add_anchored(text, loc=2, prop=dict(fontweight='bold', size='large'), frameon=False) labelfig(pltletter) pltletter += 1 if subtract_orbit_model: _mtelplot( # data = residuals (best fit model subtracted out) plttimes, rawresid, rverr, synthpost.likelihood.telvec, ax, telfmts) else: _mtelplot( # data = residuals + best fit model plttimes, rawresid + rvmod, rverr, synthpost.likelihood.telvec, ax, telfmts) ax.set_xlim(min(plttimes) - 0.01 * dt, max(plttimes) + 0.01 * dt) pl.setp(ax_rv.get_xticklabels(), visible=False) # Legend if legend: pl.legend(numpoints=1, fontsize=legend_fontsize, loc='best') # Years on upper axis axyrs = ax_rv.twiny() # axyrs.set_xlim(min(plttimes)-0.01*dt,max(plttimes)+0.01*dt) xl = np.array(list(ax.get_xlim())) + e decimalyear = Time(xl, format='jd', scale='utc').decimalyear axyrs.plot(decimalyear, decimalyear) axyrs.get_xaxis().get_major_formatter().set_useOffset(False) axyrs.set_xlim(*decimalyear) axyrs.set_xlabel('Year', fontweight='bold') # axyrs.xaxis.set_major_locator(MaxNLocator(8)) if not yscale_auto: scale = np.std(rawresid + rvmod) ax.set_ylim(-yscale_sigma * scale, yscale_sigma * scale) ax.set_ylabel('RV [{ms:}]'.format(**latex), weight='bold') ticks = ax.yaxis.get_majorticklocs() ax.yaxis.set_ticks(ticks[1:]) divider = make_axes_locatable(ax_rv) ax_resid = divider.append_axes("bottom", size="50%", pad=0.0, sharex=ax_rv, sharey=None) ax = ax_resid ax_list += [ax_resid] # Residuals ax.plot(mplttimes, slope, 'b-', lw=fit_linewidth) labelfig(pltletter) pltletter += 1 _mtelplot(plttimes, resid, rverr, synthpost.likelihood.telvec, ax, telfmts) if not yscale_auto: scale = np.std(resid) ax.set_ylim(-yscale_sigma * scale, yscale_sigma * scale) ax.set_xlim(min(plttimes) - 0.01 * dt, max(plttimes) + 0.01 * dt) ticks = ax.yaxis.get_majorticklocs() ax.yaxis.set_ticks([ticks[0], 0.0, ticks[-1]]) pl.xlabel('JD - {:d}'.format(int(np.round(e))), weight='bold') ax.set_ylabel('Residuals', weight='bold') ax.yaxis.set_major_locator(MaxNLocator(5, prune='both')) # Define the locations for the axes axbounds = ax.get_position().bounds bottom = axbounds[1] height = (bottom - 0.15) / num_planets bottom -= height + 0.05 # Phase plots for i in range(num_planets): if nophase: break pnum = i + 1 rvmod2 = model(rvmodt, planet_num=pnum) - slope modph = t_to_phase(synthpost.params, rvmodt, pnum, cat=True) - 1 rvdat = rawresid + model(rvtimes, planet_num=pnum) - slope_low phase = t_to_phase(synthpost.params, rvtimes, pnum, cat=True) - 1 rvdatcat = np.concatenate((rvdat, rvdat)) rverrcat = np.concatenate((rverr, rverr)) rvmod2cat = np.concatenate((rvmod2, rvmod2)) bint, bindat, binerr = fastbin(phase + 1, rvdatcat, nbins=25) bint -= 1.0 i_row = int(i / phase_ncols) i_col = int(i - i_row * phase_ncols) ax = pl.subplot(gs_phase[i_row, i_col]) ax_list += [ax] ax.axhline( 0, color='0.5', linestyle='--', ) ax.plot(sorted(modph), rvmod2cat[np.argsort(modph)], 'b-', linewidth=fit_linewidth) labelfig(pltletter) pltletter += 1 telcat = np.concatenate( (synthpost.likelihood.telvec, synthpost.likelihood.telvec)) _mtelplot(phase, rvdatcat, rverrcat, telcat, ax, telfmts) if not nobin and len(rvdat) > 10: ax.errorbar(bint, bindat, yerr=binerr, fmt='ro', mec='w', ms=bin_markersize, mew=bin_markeredgewidth) if not phase_limits: pl.xlim(-0.5, 0.5) else: pl.xlim(phase_limits[0], phase_limits[1]) if not yscale_auto: scale = np.std(rvdatcat) pl.ylim(-yscale_sigma * scale, yscale_sigma * scale) keys = [p + str(pnum) for p in ['per', 'k', 'e']] labels = [synthpost.params.tex_labels().get(k, k) for k in keys] if i < num_planets - 1: ticks = ax.yaxis.get_majorticklocs() ax.yaxis.set_ticks(ticks[1:-1]) pl.ylabel('RV [{ms:}]'.format(**latex), weight='bold') pl.xlabel('Phase', weight='bold') print_params = ['per', 'k', 'e'] units = {'per': 'days', 'k': latex['ms'], 'e': ''} anotext = [] for l, p in enumerate(print_params): val = synthparams["%s%d" % (print_params[l], pnum)].value if uparams is None: _anotext = '$\\mathregular{%s}$ = %4.2f %s' % ( labels[l].replace("$", ""), val, units[p]) else: if hasattr(post, 'medparams'): val = post.medparams["%s%d" % (print_params[l], pnum)] else: print("WARNING: medparams attribute not found in " + "posterior object will annotate with " + "max-likelihood values and reported uncertainties " + "may not be appropriate.") err = uparams["%s%d" % (print_params[l], pnum)] if err > 0: val, err, errlow = radvel.utils.sigfig(val, err) _anotext = '$\\mathregular{%s}$ = %s $\\mathregular{\\pm}$ %s %s' \ % (labels[l].replace("$", ""), val, err, units[p]) else: _anotext = '$\\mathregular{%s}$ = %4.2f %s' % ( labels[l].replace("$", ""), val, units[p]) anotext += [_anotext] anotext = '\n'.join(anotext) add_anchored(anotext, loc=1, frameon=True, prop=dict(size='large', weight='bold'), bbox=dict(ec='none', fc='w', alpha=0.8)) if saveplot is not None: pl.savefig(saveplot, dpi=150) print("RV multi-panel plot saved to %s" % saveplot) return fig, ax_list