def plot_runners(self, pltletter): """Plot running periodograms for each detected signal. """ coldict = { 0: 'black', 1: 'blue', 2: 'purple', 3: 'pink', 4: 'red', 5: 'green', 6: 'brown', 7: 'grey' } ax = pl.gca() #ax.set_xlabel('JD - 2450000', fontweight='bold') ax.set_xlabel(r'$\mathbf{\mathrm{N}_\mathrm{obs}}$') ax.set_xscale('log') #ax.set_ylabel('Running power', fontweight='bold') ax.set_ylabel(r'$\mathbf{\mathcal{F}(RV_\mathrm{N})}$', fontweight='bold') ax.set_yscale('log') plot.labelfig(pltletter) if self.num_known_planets > 0: nobs = len(self.runners[0]) runtimes = np.sort(self.rvtimes) - 2450000. runtimes = runtimes[(len(runtimes) - len(self.runners[0])):] num_obs = np.arange(len(runtimes)) + 12 #ax.set_xlim([np.amin(runtimes), np.amax(runtimes)]) ax.set_xlim([num_obs[0], num_obs[-1]]) ax.xaxis.set_major_formatter(CustomTicker()) for i in np.arange(self.num_known_planets): ax.plot(num_obs, self.runners[i], color=coldict[i], alpha=0.75, linewidth=2, label=label_dict[i]) ax.legend(loc='lower right') else: ax.annotate('No Signals', xy=(0.5, 0.5), xycoords='axes fraction', horizontalalignment='center', verticalalignment='center', fontsize=self.text_size + 8)
def plot_window(self, pltletter): """Plot the window function of the data, for each instrument. """ ax = pl.gca() #Put axis and label on the right side of the plot. #ax.yaxis.tick_right() #ax.yaxis.set_label_position('right') ax.set_xlabel('Period [day]', fontweight='bold') ax.set_ylabel('Window function power', fontweight='bold') ax.set_xscale('log') ax.set_xlim([np.amin(self.pers), np.amax(self.pers)]) plot.labelfig(pltletter) # Loop over all instruments, generate separate window function for each. for like in self.like_list: times = like.x tel = like.telvec[0] baseline = np.amax(times) - np.amin(times) window = utils.window(times, np.flip(1 / self.pers)) if tel in self.telfmts.keys(): tel = self.telfmts[tel]['label'] min = np.amax([3, np.amin(self.pers)]) max = baseline / 2 window_safe = window[np.where( np.logical_and(self.pers < max, self.pers > min))] pers_safe = self.pers[np.where( np.logical_and(self.pers < max, self.pers > min))] # skip plotting if baseline < min search period if len(window_safe) == 0: continue ax.set_ylim([0, 1.1 * np.amax(window_safe)]) ax.plot(pers_safe, window_safe, alpha=0.75, label=tel) ax.xaxis.set_major_formatter(CustomTicker()) ax.legend()
def plot_multipanel(self, nophase=False): """ Provision and plot an RV multipanel plot for a Posterior object containing one or more Gaussian Process Likelihood objects. Args: nophase (bool, optional): if True, don't include phase plots. Default: False. Returns: tuple containing: - current matplotlib Figure object - list of Axes objects """ if not self.plot_likelihoods_separately: super(GPMultipanelPlot, self).plot_multipanel() else: if nophase: scalefactor = 1 else: scalefactor = self.phase_nrows n_likes = len(self.like_list) figheight = self.ax_rv_height * ( n_likes + 0.5) + self.ax_phase_height * scalefactor # provision figure fig = pl.figure(figsize=(self.figwidth, figheight)) fig.subplots_adjust(left=0.12, right=0.95) hrs = np.zeros(n_likes + 1) + 1. hrs[-1] = 0.5 gs_rv = gridspec.GridSpec(n_likes + 1, 1, height_ratios=hrs) divide = 1 - self.ax_rv_height * len(self.like_list) / figheight gs_rv.update(left=0.12, right=0.93, top=0.93, bottom=divide + self.rv_phase_space * 0.5, hspace=0.0) # orbit plot for each likelihood pltletter = ord('a') i = 0 ci = 0 for like in self.like_list: ax = pl.subplot(gs_rv[i, 0]) i += 1 self.ax_list += [ax] pl.sca(ax) ax.axhline(0, color='0.5', linestyle='--') if self.subtract_orbit_model: orbit_model4data = np.zeros(self.rvmod.shape) else: orbit_model4data = self.rvmod self.plot_gp_like(like, orbit_model4data, ci) # plot data plot.mtelplot( # data = residuals + model self.plttimes, self.rawresid + orbit_model4data, self.rverr, self.post.likelihood.telvec, ax, telfmts=self.telfmts) ax.set_xlim( min(self.plttimes) - 0.01 * self.dt, max(self.plttimes) + 0.01 * self.dt) pl.setp(ax.get_xticklabels(), visible=False) # legend if self.legend and i == 1: ax.legend(numpoints=1, **self.legend_kwargs) # years on upper axis if i == 1: axyrs = ax.twiny() xl = np.array(list(ax.get_xlim())) + self.epoch 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') plot.labelfig(pltletter) pltletter += 1 # residuals ax_resid = pl.subplot(gs_rv[-1, 0]) self.ax_list += [ax_resid] pl.sca(ax_resid) self.plot_residuals() plot.labelfig(pltletter) pltletter += 1 # phase-folded plots if not nophase: gs_phase = gridspec.GridSpec(self.phase_nrows, self.phase_ncols) if self.phase_ncols == 1: gs_phase.update(left=0.12, right=0.93, top=divide - self.rv_phase_space * 0.5, bottom=0.07, hspace=0.003) else: gs_phase.update(left=0.12, right=0.93, top=divide - self.rv_phase_space * 0.5, bottom=0.07, hspace=0.25, wspace=0.25) for i in range(self.num_planets): i_row = int(i / self.phase_ncols) i_col = int(i - i_row * self.phase_ncols) ax_phase = pl.subplot(gs_phase[i_row, i_col]) self.ax_list += [ax_phase] pl.sca(ax_phase) self.plot_phasefold(pltletter, i + 1) pltletter += 1 if self.saveplot is not None: pl.savefig(self.saveplot, dpi=150) print("RV multi-panel plot saved to %s" % self.saveplot) return fig, self.ax_list
def plot_multipanel(self, nophase=False, letter_labels=True): """ Provision and plot an RV multipanel plot Args: nophase (bool, optional): if True, don't include phase plots. Default: False. letter_labels (bool, optional): if True, include letter labels on orbit and residual plots. Default: True. Returns: tuple containing: - current matplotlib Figure object - list of Axes objects """ if nophase: scalefactor = 1 else: scalefactor = self.phase_nrows figheight = self.ax_rv_height + self.ax_phase_height * scalefactor # provision figure fig = pl.figure(figsize=(self.figwidth, figheight)) fig.subplots_adjust(left=0.12, right=0.95) gs_rv = gridspec.GridSpec(2, 1, height_ratios=[1., 0.5]) divide = 1 - self.ax_rv_height / figheight gs_rv.update(left=0.12, right=0.93, top=0.93, bottom=divide + self.rv_phase_space * 0.5, hspace=0.) # orbit plot ax_rv = pl.subplot(gs_rv[0, 0]) self.ax_list += [ax_rv] pl.sca(ax_rv) self.plot_timeseries() if letter_labels: pltletter = ord('a') plot.labelfig(pltletter) pltletter += 1 # residuals ax_resid = pl.subplot(gs_rv[1, 0]) self.ax_list += [ax_resid] pl.sca(ax_resid) self.plot_residuals() if letter_labels: plot.labelfig(pltletter) pltletter += 1 # phase-folded plots if not nophase: gs_phase = gridspec.GridSpec(max([1, self.phase_nrows]), max([1, self.phase_ncols])) if self.phase_ncols == 1: gs_phase.update(left=0.12, right=0.93, top=divide - self.rv_phase_space * 0.5, bottom=0.07, hspace=0.003) else: gs_phase.update(left=0.12, right=0.93, top=divide - self.rv_phase_space * 0.5, bottom=0.07, hspace=0.25, wspace=0.25) for i in range(self.num_planets): i_row = int(i / self.phase_ncols) i_col = int(i - i_row * self.phase_ncols) ax_phase = pl.subplot(gs_phase[i_row, i_col]) self.ax_list += [ax_phase] pl.sca(ax_phase) self.plot_phasefold(pltletter, i + 1) pltletter += 1 if self.saveplot is not None: pl.savefig(self.saveplot, dpi=150) print("RV multi-panel plot saved to %s" % self.saveplot) return fig, self.ax_list
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 = 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 plot_summary(self, letter_labels=True): """Provision and plot a search summary plot Args: letter_labels (bool, optional): if True, include letter labels on orbit and residual plots. Default: True. Returns: tuple containing: - current matplotlib Figure object - list of Axes objects """ scalefactor = self.phase_nrows + 1 #figheight = self.ax_rv_height + self.ax_phase_height * scalefactor figheight = self.ax_rv_height + self.ax_summary_height * scalefactor # provision figure fig = pl.figure(figsize=(self.figwidth, figheight)) right_edge = 0.90 top_edge = 0.92 bottom_edge = 0.05 fig.subplots_adjust(left=0.12, right=right_edge) gs_rv = gridspec.GridSpec(2, 1, height_ratios=[1., 0.5]) divide = 0.95 - self.ax_rv_height / figheight ipl = 5 - self.num_known_planets while ipl > 0: top_edge -= 0.01 bottom_edge += 0.005 divide += 0.015 self.rv_phase_space += 0.012 ipl -= 1 gs_rv.update(left=0.12, right=right_edge, top=top_edge, bottom=divide + self.rv_phase_space * 0.5, hspace=0.) # orbit plot ax_rv = pl.subplot(gs_rv[0, 0]) self.ax_list += [ax_rv] pl.sca(ax_rv) self.plot_timeseries() if letter_labels: pltletter = ord('a') plot.labelfig(pltletter) pltletter += 1 # residuals ax_resid = pl.subplot(gs_rv[1, 0]) self.ax_list += [ax_resid] pl.sca(ax_resid) self.plot_residuals() if letter_labels: plot.labelfig(pltletter) pltletter += 1 # phase-folded plots and periodograms gs_phase = gridspec.GridSpec(self.phase_nrows + 1, self.summary_ncols) if self.summary_ncols == 1: gs_phase.update(left=0.12, right=right_edge, top=divide - self.rv_phase_space * 0.2, bottom=bottom_edge, hspace=0.003) else: gs_phase.update(left=0.12, right=right_edge, top=divide - self.rv_phase_space * 0.2, bottom=bottom_edge, hspace=0.003, wspace=0.05) for i in range(self.num_planets): # Plot phase. # i_row = int(i / self.summary_ncols) i_row = i # i_col = int(i - i_row * self.summary_ncols) i_col = 0 ax_phase = pl.subplot(gs_phase[i_row, i_col]) self.ax_list += [ax_phase] pl.sca(ax_phase) self.plot_phasefold(pltletter, i + 1) pltletter += 1 # Plot periodogram. i_row = i i_col = 1 ax_per = pl.subplot(gs_phase[i_row, i_col]) self.ax_list += [ax_per] pl.sca(ax_per) self.plot_periodogram(pltletter, i) pltletter += 1 # Plot final row, window function & non-detection. ''' gs_phase.update(left=0.12, right=0.93, top=divide - self.rv_phase_space * 0.2, bottom=0.07, hspace=0.003, wspace=0.05) ''' ''' ax_window = pl.subplot(gs_phase[self.num_planets, 0]) self.ax_list += [ax_window] pl.sca(ax_window) self.plot_window(pltletter) ''' ax_runners = pl.subplot(gs_phase[self.num_planets, 0]) self.ax_list += [ax_runners] pl.sca(ax_runners) self.plot_runners(pltletter) pltletter += 1 ax_non = pl.subplot(gs_phase[self.num_planets, 1]) self.ax_list += [ax_non] pl.sca(ax_non) self.plot_periodogram(pltletter, self.num_planets) pltletter += 1 pl.suptitle(self.search.starname, fontsize=self.text_size + 6, weight='bold') if self.saveplot is not None: pl.savefig(self.saveplot, dpi=150) print("Search summary plot saved to %s" % self.saveplot) return fig, self.ax_list
def plot_periodogram(self, pltletter, pnum=0, alias=True, floor=True): """Plot periodogram for a given search iteration. """ ax = pl.gca() ax.yaxis.tick_right() ax.yaxis.set_label_position('right') plot.labelfig(pltletter) # TO-DO: WORK IN AIC/BIC OPTION, INCLUDE IN PLOT TITLE try: peak = np.argmax(self.periodograms[pnum]) except KeyError: # No periodogram for this planet, assume it was previously-known. ax = pl.gca() ax.annotate('Pre-defined Orbit', xy=(0.5, 0.5), xycoords='axes fraction', horizontalalignment='center', verticalalignment='center', fontsize=self.text_size + 8) return f_real = 1 / self.pers[peak] # Plot periodogram, and maximum value. ax.plot(self.pers, self.periodograms[pnum], c='b') ax.scatter(self.pers[peak], self.periodograms[pnum][peak], c='black', label='{} days'.format(np.round(self.pers[peak], decimals=1))) # Plot DBIC threshold, set floor periodogram floor if pnum == 0: fap_label = '{} FAP'.format(self.fap) else: fap_label = None ax.axhline(self.bic_threshes[pnum], ls=':', c='y', label=fap_label) upper = 1.1 * (max(np.amax(self.periodograms[pnum]), self.bic_threshes[pnum])) if floor: # Set periodogram plot floor according to circular-fit BIC min. lower = -2 * np.log(len(self.rvtimes)) else: lower = np.amin(self.periodograms[pnum]) ax.set_ylim([lower, upper]) ax.set_xlim([self.pers[0], self.pers[-1]]) if alias: # Plot sidereal day, lunation period, and sidereal year aliases. if self.pers[0] <= 1: colors = ['r', 'g', 'b'] alias_preset = [365.256, 29.531, 0.997] else: colors = ['r', 'g'] alias_preset = [365.256, 29.531] for j in np.arange(len(alias_preset)): f_ap = 1. / alias_preset[j] + f_real f_am = 1. / alias_preset[j] - f_real if pnum == 0: label = '{} day alias'.format( np.round(alias_preset[j], decimals=1)) else: label = None ax.axvline(1. / f_am, linestyle='--', c=colors[j], alpha=0.66, label=label) ax.axvline(1. / f_ap, linestyle='--', c=colors[j], alpha=0.66) # Annotate each alias with the associated timescale. #ax.text(0.66/f_ap, 0.5*(lower + upper), label, rotation=90, # size=self.phasetext_size, weight='bold', # verticalalignment='bottom') # 0.5*(lower + upper) ax.set_xscale('log') # TO-DO: WORK IN AIC/BIC OPTION ax.set_ylabel(r'$\Delta$BIC$_{}$'.format(pnum + 1), fontweight='bold') ax.legend(loc=0, prop=dict(size=self.phasetext_size, weight='bold')) # frameon=False, framealpha=0.8) # Set tick mark formatting based on gridspec location. if pnum < self.num_known_planets: ax.tick_params(axis='x', which='both', direction='in', bottom='on', top='on', labelbottom='off') elif pnum == self.num_known_planets: # Print units and axis label at the bottom. ax.set_xlabel('Period [day]', fontweight='bold') ax.tick_params(axis='x', which='both', direction='out', bottom='on', top='off', labelbottom='on') ax.xaxis.set_major_formatter(CustomTicker())