def main(mkf_list, groups=['increasing', 'decreasing', 'extrema', 'touches']): fig, (ax, ax1) = plt.subplots(2, 1, figsize=(12, 12)) plt.subplots_adjust(hspace=0) ax = niutils.plotparams(ax) ax1 = niutils.plotparams(ax1) for mkf in tqdm(mkf_list): tab = Table.read(mkf, hdu=1) tab_list = dfsplit(tab, 2) for t in tab_list: if len(t) <= 5: continue if touches_200(t, 'BR_EARTH') and 'touches' in groups: ax.plot(t['TIME'] - t['TIME'].min(), t['BR_EARTH']) elif always_increasing(t, 'BR_EARTH') and 'increasing' in groups: ax.plot(t['TIME'] - t['TIME'].min(), t['BR_EARTH']) elif always_decreasing(t, 'BR_EARTH') and 'decreasing' in groups: ax.plot(t['TIME'] - t['TIME'].min(), t['BR_EARTH']) elif local_extrema(t, 'BR_EARTH') and 'extrema' in groups: ax.plot(t['TIME'] - t['TIME'].min(), t['BR_EARTH']) else: if len(groups) == 4: print(f'Problem with groups for {mkf}') #ax1.plot(t['TIME']-t['TIME'].min(), t['ELV']) ax1.set_xlabel("Time from start (s)", fontsize=20) ax.set_ylabel("Bright Earth Angle", fontsize=20) ax1.set_ylabel("Earth Elevation Angle", fontsize=20) plt.show()
def attitude_example(att_table): log.info('Print Attitude Table') print(att_table) print('ST_VALID values: ', list(set(att_table['ST_VALID']))) print('SUBMODE_AZ values', list(set(att_table['SUBMODE_AZ']))) print('SUBMODE_EL values', list(set(att_table['SUBMODE_EL']))) log.info("Generating Plot") colors = ["#cb6a49", "#a46cb7", "#7aa457"] fig, ax = plt.subplots(1, 1, figsize=(12, 6)) ax = plotparams(ax) ax.plot(att_table['TIME'], att_table['SUBMODE_EL'], color=colors[0], label='SUBMODE_EL') ax.plot(att_table['TIME'], att_table['SUBMODE_AZ'], color=colors[1], label='SUBMODE_AZ') ax.plot(att_table['TIME'], att_table['ST_VALID'], color=colors[2], label='ST_VALID') ax.legend(fontsize=12, edgecolor='black', loc='upper right') ax.set_xlabel('Time (s)', fontsize=15) ax.set_ylabel('Parameter Flag', fontsize=15) plt.show()
def events_per_second_plot(flist, savefig=None, ax=None): log.info("Generating EXP per s plot") d = {} for f in tqdm(flist): tab = Table.read(f, hdu=1) date = tab.meta['DATE-OBS'] exposure = tab.meta['EXPOSURE'] table_length = len(tab) if exposure == 0: continue if date in d.keys(): d[date] += table_length / exposure else: d[date] = table_length / exposure if ax is None: fig, ax = plt.subplots(1, 1, figsize=(12, 6)) plt.subplots_adjust(top=.98, right=.98) ax = niutils.plotparams(ax) created_fig = True else: created_fig = False dates = list(d.keys()) format_specifier = '%Y-%m-%dT%H:%M:%S' dates_formatted = [ datetime.datetime.strptime(s, format_specifier) for s in dates ] temp = [] for i in range(len(dates_formatted)): dtemp = datetime.datetime(year=2017, month=11, day=1) if dates_formatted[i] < dtemp: temp.append(d[dates[i]]) print(len(temp)) print(np.median(temp)) print(np.mean(temp)) #Need to fix this df = pd.DataFrame({'dates': dates_formatted, 'vals': list(d.values())}) df.sort_values('dates', inplace=True) print(df) color = niutils.get_colors()['br_colors'][-1] ax.plot_date(df['dates'], df['vals'], color=color, ls='-') ax.xaxis.set_minor_locator(MonthLocator()) ax.set_xlabel("Observation Start Date", fontsize=20) ax.set_ylabel(r'Count Rate (s$^{-1}$)', fontsize=20) if (savefig is None) and (created_fig): plt.show() elif savefig is not None: fig.savefig(savefig) else: return ax
def lc_from_evt(fname, savefig=None): tab = Table.read(fname, hdu=1) mintime = tab['TIME'].min() maxtime = tab['TIME'].max() nbins = len(tab) // 1000 bins = np.linspace(mintime, maxtime, nbins) counts = np.zeros(len(bins)) for i in tqdm(range(len(tab))): idx = np.where(tab['TIME'][i] >= bins)[0][-1] counts[idx] += 1 fig, ax = plt.subplots(1, 1, figsize=(12, 6)) ax = niutils.plotparams(ax) timezero = datetime.datetime(year=2014, month=1, day=1, hour=0, minute=0, second=0) bins = [timezero + datetime.timedelta(seconds=b) for b in bins] ax.scatter(bins, counts, color='xkcd:azure') ax.set_xlabel("Time (s)", fontsize=20) ax.set_ylabel("Number of Events", fontsize=20) ax.xaxis.set_minor_locator(MonthLocator()) if savefig is None: plt.show() else: fig.savefig(savefig)
def test_fselect(f, plot=False): t = Table.read(f, hdu=1) print(t['PULSE_PHASE'].min(), t['PULSE_PHASE'].max()) if plot: fig, ax = plt.subplots(1, 1, figsize=(8, 4)) ax.hist(t['PULSE_PHASE'], edgecolor='black', color='xkcd:violet') ax = niutils.plotparams(ax) plt.show()
def plot_data(fnames, column, savefig=None): if niutils.check_iter(fnames): df = merge_tables(fnames) tab_for_format = fnames[0] ntab = len(fnames) else: df = read_table(fnames) tab_for_format = fname ntab = 1 if column is None: raise ValueError("Column can not be None") df = add_datetime_col(df) fig, ax = plt.subplots(1, 1, figsize=(12*ntab, 6)) ax = niutils.plotparams(ax) if not niutils.check_iter(column): column = [column] mask = [ np.where(df[column[i]] != -9999.9)[0] for i in range(len(column)) ] colors = niutils.get_colors()['br_colors'] colors = [colors[0], colors[2]] ax.plot(df['datetime'][mask[0]], df[column[0]][mask[0]], color=colors[0], label=column[0]) ax.set_xlabel("Date", fontsize=20) ax.set_ylabel(format_ace_column(column[0], table=tab_for_format), fontsize=20) if len(column) > 1: ax, ax1 = niutils.DoubleY(ax, colors=(colors[0], colors[1])) ax1.plot(df['datetime'][mask[1]], df[column[1]][mask[1]], color=colors[1], label=column[1]) ax1.set_ylabel(format_ace_column(column[1], table=tab_for_format), fontsize=20) if max(df['day']) > 180: ax.xaxis.set_minor_locator(MonthLocator()) else: ax.xaxis.set_major_locator(MonthLocator()) ax.xaxis.set_minor_locator(MonthLocator(bymonthday=15)) myfmt = DateFormatter('%Y-%m') ax.xaxis.set_major_formatter(myfmt) if savefig is None: plt.show() else: fig.savefig(savefig)
def multi_window_plot(mkf_list, savefig=None): fig, ax = plt.subplots(2, 2, figsize=(12, 12)) plt.subplots_adjust(left=.1, bottom=.08, right=.99, top=.97, wspace=.11, hspace=.13) for a in ax.reshape(-1): a = niutils.plotparams(a) for mkf in tqdm(mkf_list): tab = Table.read(mkf, hdu=1) tab_list = dfsplit(tab, 2) for t in tab_list: if len(t) <= 5: continue if touches_200(t, 'BR_EARTH'): ax.reshape(-1)[0].plot(t['TIME'] - t['TIME'].min(), t['BR_EARTH']) elif always_increasing(t, 'BR_EARTH'): ax.reshape(-1)[1].plot(t['TIME'] - t['TIME'].min(), t['BR_EARTH']) elif always_decreasing(t, 'BR_EARTH'): ax.reshape(-1)[2].plot(t['TIME'] - t['TIME'].min(), t['BR_EARTH']) else: assert (local_extrema(t, 'BR_EARTH')) ax.reshape(-1)[3].plot(t['TIME'] - t['TIME'].min(), t['BR_EARTH']) for a, l in zip(ax.reshape(-1), ['Touches 200', 'Increasing', 'Decreasing', 'Extrema']): a.text(.95, .95, l, transform=a.transAxes, ha='right', va='top', fontsize=20) fig.text(.05, .5, 'Bright Earth Angle', ha='center', va='center', rotation='vertical', fontsize=25) fig.text(.55, .03, 'Time (s)', ha='center', va='center', fontsize=25) if savefig is None: plt.show() else: fig.savefig(savefig)
def astropy_fit(self): if self.counts is None: self.generate() if include_phases is None: phase_min = .75 phase_max = 1.75 else: phase_min = include_phases[0] phase_max = include_phases[1] phasebins_fitting = np.array( [p for p in self.phasebins_extended if phase_min <= p < phase_max]) counts_fitting = np.array([ self.counts_extended[i] for i in range(len(self.counts_extended)) if phase_min <= self.phasebins_extended[i] < phase_max ]) if ax is None: fig, ax = plt.subplots(1, 1, figsize=(8, 4)) created_fig = True else: created_fig = False ax.set_xlim(left=phase_min - .025, right=phase_max + .025) ax = niutils.plotparams(ax) p0_b = min(counts_fitting) p0_a_0 = max(counts_fitting) - p0_b p0_a_1 = p0_a_0 * 0.5 p0_sigma_0 = .3 p0_sigma_1 = .3 if self.peak_center()[0] > .5: p0_x0_0 = self.peak_center()[0] else: p0_x0_0 = self.peak_center()[0] + 1.0 p0_x0_1 = self.interpulse_center()[0] + 1.0 m_init = niutils.two_gauss() fit = astropy.modeling.fitting.LevMarLSQFitter() model = fit(m_init, phasebins_fitting, counts_fitting) ax.plot(phasebins_fitting, counts_fitting) ax.plot(phasebins_fitting, model(phasebins_fitting), color='xkcd:azure', lw=6, zorder=1, alpha=.4) ax.plot(self.phasebins_extended, self.counts_extended, marker='.', color='xkcd:violet', zorder=2) plt.show()
def plot_sun_angle_fill(br_data_list, br_ranges, sa_ranges, savefig=None, text=None): fig, ax = plt.subplots(3, 2, figsize=(20, 15)) plt.subplots_adjust(top=.98, right=.98, hspace=0, wspace=.1, bottom=.05) for i in range(len(br_data_list)): df_bottom = pd.read_csv(br_data_list[i][0], skiprows=3, delimiter=" ", header=None) df_bottom.columns = ['energy', 'energy_err', 'counts', 'counts_err'] df_top = pd.read_csv(br_data_list[i][1], skiprows=3, delimiter=" ", header=None) df_top.columns = ['energy', 'energy_err', 'counts', 'counts_err'] color = niutils.map_colors()[br_ranges[i]] dark_color = niutils.map_colors(dark=True)[br_ranges[i]] a = ax.reshape(-1)[i] a.fill_between(df_bottom['energy'], df_bottom['counts'], df_top['counts'], color='gray',zorder=1, alpha=.6) a.plot(df_bottom['energy'], df_bottom['counts'], color=color, label=niutils.sa_label(sa_ranges[i][0]), lw=3) a.plot(df_top['energy'], df_top['counts'], color=dark_color, label=niutils.sa_label(sa_ranges[i][1]), lw=3) a = niutils.plotparams(a) a.legend(edgecolor='black', fontsize=20, loc='upper right', bbox_to_anchor=(.98, .88), bbox_transform=a.transAxes) if i in [3,4]: a.set_xlabel('Energy (keV)', fontsize=20) else: a.set_xticklabels([]) a.set_xscale('log') a.set_yscale('log') a.set_ylim(bottom=.009, top=130) a.set_xlim(left=.15, right=11) a.xaxis.set_major_formatter(mticker.FormatStrFormatter('%.1f')) a.text(.95, .95, niutils.br_label(br_ranges[i]), fontsize=20, ha='right', va='top', transform=a.transAxes) fig.text(.05, .55, r'Normalized Counts (s$^{-1}$ keV$^{-1}$)', fontsize=35, rotation='vertical', ha='center', va='center') ax.reshape(-1)[-1].axis('off') axt = ax.reshape(-1)[-1] axt.axis('off') axt.text(.05, .8, text, ha='left', va='top', fontsize=30) if savefig is None: plt.show() else: fig.savefig(savefig) if savefig.endswith('pdf'): fig.savefig(savefig.replace('pdf', 'png'), dpi=300)
def plot_data_split(fnames, column, savefig=None): if niutils.check_iter(fnames): df_list = [read_table(f) for f in fnames] else: raise ValueError("Must input multiple filenames") if column is None: raise ValueError("Column can not be None") df_list = [add_datetime_col(df) for df in df_list] fig, ax = plt.subplots(len(df_list), 1, figsize=(12, 5.2*len(df_list))) plt.subplots_adjust(top=.98, bottom=.07) for a in ax: a = niutils.plotparams(a) if not niutils.check_iter(column): column = [column] colors = niutils.get_colors()['br_colors'] colors = [colors[0], colors[2]] for i in range(len(df_list)): df = df_list[i] mask = [ np.where(df[column[i]] != -9999.9)[0] for i in range(len(column)) ] ax[i].plot(df['datetime'][mask[0]], df[column[0]][mask[0]], color=colors[0], label=column[0]) ax[i].set_xlabel("Date", fontsize=20) ax[i].set_ylabel(format_ace_column(column[0], table=fnames[0]), fontsize=20) if len(column) > 1: ax[i], ax1 = niutils.DoubleY(ax[i], colors=(colors[0], colors[1])) ax1.plot(df['datetime'][mask[1]], df[column[1]][mask[1]], color=colors[1], label=column[1]) ax1.set_ylabel(format_ace_column(column[1], table=fnames[0]), fontsize=20) if max(df['day']) > 180: ax[i].xaxis.set_minor_locator(MonthLocator()) else: ax[i].xaxis.set_major_locator(MonthLocator()) ax[i].xaxis.set_minor_locator(MonthLocator(bymonthday=15)) myfmt = DateFormatter('%Y-%m') ax[i].xaxis.set_major_formatter(myfmt) if savefig is None: plt.show() else: fig.savefig(savefig)
def polynomial_integrate(fname, lower_energy, upper_energy, plot=True, degree=8): #Load data in with xspecdata object xd = xspeclog.xspecdata(fname) if plot: #Plotting Routine fig, ax = plt.subplots(1, 1, figsize=(12, 6)) ax = niutils.plotparams(ax) ax.scatter(xd.data['energy'], xd.data['model']) #ax.set_xscale('log') #ax.set_yscale('log') ax.set_ylim(top=1e-3, bottom=1e-8) ax.set_xlabel('Energy keV', fontsize=20) ax.set_ylabel(r'Photons cm$^{-2}$ s$^{-1}$ keV$^{-1}$', fontsize=20) ax.set_xlim(left=.2, right=10) ax.set_ylim(bottom=10e-6, top=.0001) coefs = poly.polyfit(xd.data['energy'], xd.data['model'], degree) ffit = poly.polyval(xd.data['energy'], coefs) def mypoly(x): return poly.polyval(x, coefs) full_integration = integrate.quad(mypoly, lower_energy, upper_energy)[0] ratios = [] nspace = 100000 ratios = [ integrate.quad(mypoly, lower_energy, upper)[0] / (full_integration / 2) for upper in np.linspace(lower_energy, upper_energy, nspace) ] idx = np.where( np.array(ratios) == min(ratios, key=lambda x: abs(x - 1)))[0][0] center_energy = np.linspace(lower_energy, upper_energy, nspace)[idx] print(f"The center of the integrated energy range is {center_energy} kev") if plot: ax.plot(xd.data['energy'], ffit, color='xkcd:violet') ax.axvline(center_energy, color='red') plt.show() return center_energy
def test_trumpet_cut(self, fconst, fastsig=1200, fastquart=0, n=1, ax=None, plot=False): #Define trumpet function def trumpet_cut(pi, c, s, q, n=1): return c + (s / 10) / pi**n + q * pi**3 #Create mask mask = [(self.piratio[i] < trumpet_cut( self.pi[i], fconst, fastsig, fastquart, n=n)) for i in range(len(self.piratio))] mask_flip = [not l for l in mask] #Store the number of photons cut self.n_cut = len(mask) - sum(mask) if self.n_cut != 0: log.info("Appling trumpet cut") #Apply the mask self.pi = self.pi[mask] self.ph = self.ph[mask] self.piratio = self.piratio[mask] if plot: if ax is None: fig, ax = plt.subplots(1, 1, figsize=(16, 8)) created_fig = True else: created_fig = False ax.scatter(self.pi, self.piratio, color='xkcd:blue', marker='.', alpha=.5) ax = niutils.plotparams(ax) if created_fig: plt.show() else: return ax else: return ax
def filter_example(mkf_table): print("List of all the columns:") print(mkf_table.colnames) log.info("Print Filter File") print(mkf_table) log.info("Generating Plot") fig, ax = plt.subplots(3, 1, figsize=(12, 15), sharex=True) plt.subplots_adjust(hspace=0) colors = ["#cb6a49", "#a46cb7", "#7aa457"] ax[0].plot(mkf_table['TIME'], mkf_table['SUN_ANGLE'], color=colors[0], label='Sun Angle') ax[0].plot(mkf_table['TIME'], mkf_table['MOON_ANGLE'], color=colors[1], label='Moon Angle') ax[0].plot(mkf_table['TIME'], mkf_table['ELV'], color=colors[2], label='Earth Elevation') ax[0].set_ylabel('Angle (Degrees)', fontsize=15) ax[1].plot(mkf_table['TIME'], mkf_table['SAT_LAT'], color=colors[0], label='Satellite Lattitude') ax[1].plot(mkf_table['TIME'], mkf_table['SAT_LON'], color=colors[1], label='Satellite Longitude') ax[1].set_ylabel('Degrees', fontsize=15) ax[2].plot(mkf_table['TIME'], mkf_table['COR_SAX'], color=colors[0]) ax[2].set_ylabel('Cutoff Rigidity (GeV/c)', fontsize=15) for a in ax: a = plotparams(a) if a.get_legend_handles_labels() != ([], []): a.legend(loc='upper right', fontsize=12, edgecolor='black') plt.show()
def br_earth_hist(table, bins=50, save=None): tab = Table.read(table, hdu=1) fig, ax = plt.subplots(1, 1, figsize=(12, 6)) ax = niutils.plotparams(ax) plt.subplots_adjust(top=.98, right=.98) br_earth = [b for b in tab['BR_EARTH'] if b < 180] ax.hist(br_earth, bins=bins, edgecolor='black', color=niutils.get_colors()['br_colors'][-1]) ax.set_ylabel("N Rows", fontsize=20) ax.set_xlabel('Bright Earth Angle', fontsize=20) plt.setp(ax.get_yticklabels()[0], visible=False) if save is not None: fig.savefig(save) else: plt.show()
def br_hist(table, bins=50, save=None): tab = Table.read(table, hdu=1) fig, ax = plt.subplots(2, 1, figsize=(12, 12)) for a in ax: a = niutils.plotparams(a) a.set_xlabel("BR\_EARTH", fontsize=25) a.set_ylabel("NRows", fontsize=25) ax[0].hist(tab[np.where(tab['SUNSHINE'] == 1)[0]]['BR_EARTH'], bins=bins, color='#FF5903', alpha=.7, edgecolor='black') ax[1].hist(tab[np.where(tab['SUNSHINE'] == 0)[0]]['BR_EARTH'], bins=bins, color='#6902CB', edgecolor='black') ax[0].text(.95, .95, r'SUNSHINE$=1$', ha='right', va='top', transform=ax[0].transAxes, fontsize=20) ax[1].text(.95, .95, r'SUNSHINE$=0$', ha='right', va='top', transform=ax[1].transAxes, fontsize=20) #Save or show if save is not None: fig.savefig(save) else: plt.show()
def mkf_hist(table, key, hdu=1, bins=50, pickle_file=None, save=None): if pickle_file is None: tab = Table.read(table, hdu=hdu) else: tab = pickle.load(open(pickle_file, 'rb')) fig, ax = plt.subplots(1, 1, figsize=(12, 6)) ax = niutils.plotparams(ax) assert (key in tab.colnames) ax.hist(tab[key], bins=bins, edgecolor='black', color=niutils.get_colors()['br_colors'][-1]) ax.set_ylabel("N Rows", fontsize=20) ax.set_xlabel(key, fontsize=20) if save is not None: fig.savefig(save) else: plt.show()
def plot_bsbs(br_earth_range, datafile_3c50, datafile_environ): fig, ax = plt.subplots(1, 1, figsize=(12, 6)) ax = niutils.plotparams(ax) labels = ['3c50', 'Environ'] for d, l in zip([datafile_3c50, datafile_environ], labels): assert (os.path.isfile(d)) df_bkg = pd.read_csv(d, skiprows=3, delimiter=" ", header=None) df_bkg.columns = ['energy', 'energy_err', 'counts', 'counts_err'] ax.errorbar(df_bkg['energy'], df_bkg['counts'], xerr=df_bkg['energy_err'], yerr=df_bkg['counts_err'], ls=' ', marker='.', label=l) ax.legend(edgecolor='black', fontsize=20) ax.set_ylabel(r'Normalized Counts (s$^{-1}$ keV$^{-1}$)', fontsize=20) ax.set_xlabel('Energy (keV)', fontsize=20) ax.text(.95, .95, br_earth_range, ha='right', va='top', fontsize=20, transform=ax.transAxes, bbox=dict(facecolor='white', edgecolor='none', alpha=.6)) ax.set_xscale('log') ax.set_xlim(.3, 4) ax.xaxis.set_major_formatter(mticker.FormatStrFormatter('%.1f')) plt.show()
def fit_two(self, model, ax=None, annotate=True, output_fit=False, label=False, plot=True): if self.counts is None: self.generate() phasebins_fitting = self.phasebins counts_fitting = self.counts if ax is None: fig, ax = plt.subplots(1, 1, figsize=(8, 4)) created_fig = True else: created_fig = False #ax.set_xlim(left=phase_min-.025, right=phase_max+.025) ax = niutils.plotparams(ax) if self.name == 'PSR B1821-24': p0_b = min(counts_fitting) p0_a_0 = max(counts_fitting) - p0_b p0_a_1 = p0_a_0 * 0.5 p0_sigma_0 = .01 p0_sigma_1 = .01 p0_x0_0 = self.pulse_centers()[0] p0_x0_1 = self.pulse_centers()[1] bounds = ([ 0, self.pulse_centers()[0] - .1, 0, 0, self.pulse_centers()[1] - .1, 0, 0 ], [ np.inf, self.pulse_centers()[0] + .1, 1, np.inf, self.pulse_centers()[1] + .1, 1, max(counts_fitting) ]) p0 = [ p0_a_0, p0_x0_0, p0_sigma_0, p0_a_1, p0_x0_1, p0_sigma_1, p0_b ] phase_min = 0 phase_max = phase_min + 1 #Initial values and bounds for 1937 elif self.name == 'PSR B1937+21': p0_b = min(counts_fitting) p0_a_0 = max(counts_fitting) - p0_b p0_a_1 = p0_a_0 * 0.1 p0_sigma_0 = .01 p0_sigma_1 = .01 p0_x0_0 = self.pulse_centers()[0] p0_x0_1 = self.pulse_centers()[1] bounds = ([ 0, self.pulse_centers()[0] - .1, 0, 0, p0_x0_1 - .1, 0, 0 ], [ np.inf, self.pulse_centers()[0] + .1, 1, np.inf, p0_x0_1 + .1, 1, max(counts_fitting) ]) p0 = [ p0_a_0, p0_x0_0, p0_sigma_0, p0_a_1, p0_x0_1, p0_sigma_1, p0_b ] phase_min = 0 phase_max = phase_min + 1 #Initial values and bounds for J0218 else: p0_b = min(counts_fitting) p0_a_0 = max(counts_fitting) - p0_b p0_a_1 = p0_a_0 * 0.5 p0_sigma_0 = .3 p0_sigma_1 = .3 p0_x0_0 = .4 p0_x0_1 = .8 #p0_x0_0 = self.pulse_centers()[0]+1.0 #p0_x0_1 = self.pulse_centers()[1] bounds = ([0, p0_x0_0 - .2, 0, 0, p0_x0_1 - .2, 0, 0], [ np.inf, p0_x0_0 + .2, 1, np.inf, p0_x0_1 + .2, 1, max(counts_fitting) ]) p0 = [ p0_a_0, p0_x0_0, p0_sigma_0, p0_a_1, p0_x0_1, p0_sigma_1, p0_b ] phase_min = 0.1 phase_max = phase_min + 1.0 phasebins_fitting = np.array([ p for p in self.phasebins_extended if phase_min <= p < phase_max ]) counts_fitting = np.array([ self.counts_extended[i] for i in range(len(self.counts_extended)) if phase_min <= self.phasebins_extended[i] < phase_max ]) valid = [] for i in range(len(p0)): valid.append(bounds[0][i] <= p0[i] <= bounds[1][i]) if not all(valid): print("Fit failed due to invalid bounds") for i in range(len(p0)): print(bounds[0][i], p0[i], bounds[1][i]) print(self.filters) raise ValueError #Perform scipy curve fit model = process.extract(model, ['gaussian', 'lorentzian'], limit=1)[0][0] if model == 'gaussian': popt, pcov = curve_fit(niutils.two_gaus, phasebins_fitting, counts_fitting, p0=p0, bounds=bounds) fit_counts = niutils.two_gaus(phasebins_fitting, *popt) elif model == 'lorentzian': p0[2] = p0[2] * 2.355 p0[5] = p0[5] * 2.355 popt, pcov = curve_fit(niutils.two_lorentzians, phasebins_fitting, counts_fitting, p0=p0, bounds=bounds) fit_counts = niutils.two_lorentzians(phasebins_fitting, *popt) fit_counts_extended = np.append(fit_counts, fit_counts) fit_counts_extended = np.append(fit_counts_extended, fit_counts) phasebins_fitting_extended = np.append(phasebins_fitting, phasebins_fitting + 1) phasebins_fitting_extended = np.append(phasebins_fitting_extended, phasebins_fitting + 2) phasebins_fitting_extended = phasebins_fitting_extended - phase_min if phase_min != 0: phasebins_fitting_extended = np.array( [pb - (1 - phase_min) for pb in phasebins_fitting_extended]) ax.plot(phasebins_fitting_extended, fit_counts_extended, color='xkcd:azure', lw=6, zorder=2, alpha=.4) ax.plot(self.phasebins_extended, self.counts_extended, marker='.', color='xkcd:violet', zorder=1) #plt.setp(ax.get_xticklabels()[0], visible=False) #plt.setp(ax.get_xticklabels()[-1], visible=False) ax.set_xlim(0, 2) """ n_phase = 3 fit_counts_extended = np.array([]) for i in range(n_phase): fit_counts_extended = np.append(fit_counts_extended, fit_counts) phasebins_fitting_extended = np.array([round(b,4) - 1.0 for b in np.arange(phase_min, phase_max+n_phase-1, self.bs) ]) """ if annotate: ax.text(.95, .95, f"{round(popt[1], 4)}, {round(popt[4], 4)}", fontsize=20, transform=ax.transAxes, ha='right', va='top') if model == 'gaussian': PoptTup = collections.namedtuple('PoptTup', [ 'primary_amplitude', 'primary_position', 'primary_sigma', 'secondary_amplitude', 'secondary_position', 'secondary_sigma', 'vertical_shift' ]) else: PoptTup = collections.namedtuple('PoptTup', [ 'primary_amplitude', 'primary_position', 'primary_fwhm', 'secondary_amplitude', 'secondary_position', 'secondary_fwhm', 'vertical_shift' ]) popt_tup = PoptTup(*popt) #if self.name == 'PSR J0218+4232': #ax.axhline(popt_tup.vertical_shift, color='gray', ls=':') #Add component labels if label: if self.name == 'PSR B1821-24': p1_coords, p2_coords = niutils.component_label( popt_tup, (-8, .7), (-4, 1.25)) elif self.name == 'PSR B1937+21': p1_coords, p2_coords = niutils.component_label( popt_tup, (10, .75), (8, 1.35)) else: #Name == 'PSR J0218+4232': p1_coords, p2_coords = niutils.component_label( popt_tup, (2.2, 0.8), (1.7, 1.1)) ax.text(p1_coords[0], p1_coords[1], "P1", fontsize=23, ha='center', va='center') ax.text(p2_coords[0], p2_coords[1], "P2", fontsize=23, ha='center', va='center') if output_fit: return phasebins_fitting_extended, fit_counts_extended, popt_tup elif created_fig: if plot: plt.show() return popt_tup else: return ax, popt_tup
def paper_plot(mkf_list): """ Go through all mkfs find out which split tables are longest in each of the four categories Plot the earth elevation and bright earth angles """ fig, ax = plt.subplots(1, 1, figsize=(12, 12)) d = { 'increasing': ['', 0], 'decreasing': ['', 0], 'touches200': ['', 0], 'localextrema': ['', 0] } for mkf in tqdm(mkf_list): tab = Table.read(mkf, hdu=1) tab_list = dfsplit(tab, 2) for t in tab_list: if len(t) <= 5: continue if touches_200(t, 'BR_EARTH'): if len(t) > d['touches200'][1]: d['touches200'][0] = t d['touches200'][1] = len(t) elif always_increasing(t, 'BR_EARTH'): if len(t) > d['increasing'][1]: d['increasing'][0] = t d['increasing'][1] = len(t) elif always_decreasing(t, 'BR_EARTH'): if len(t) > d['decreasing'][1]: d['decreasing'][0] = t d['decreasing'][1] = len(t) elif local_extrema(t, 'BR_EARTH'): if len(t) > d['localextrema'][1]: d['localextrema'][0] = t d['localextrema'][1] = len(t) else: if len(groups) == 4: print(f'Problem with groups for {mkf}') ax = niutils.plotparams(ax) colors = niutils.get_colors()['br_colors'] darkcolors = niutils.get_colors()['br_colors_dark'] for i in range(len(d.keys())): t = d[list(d.keys())[i]][0] ax.plot(t['TIME'] - t['TIME'].min(), t['BR_EARTH'], color=colors[i], lw=2) ax.plot(t['TIME'] - t['TIME'].min(), t['ELV'], color=darkcolors[i], lw=2) plt.show()
def numerical_integrate(fname, lower_energy, upper_energy, plot=True): #Load data in with xspecdata object xd = xspeclog.xspecdata(fname) if plot: #Plotting Routine fig, ax = plt.subplots(1, 1, figsize=(12, 6)) ax = niutils.plotparams(ax) ax.scatter(xd.data['energy'], xd.data['model']) #ax.set_xscale('log') #ax.set_yscale('log') ax.set_ylim(top=1e-3, bottom=1e-8) ax.set_xlabel('Energy keV', fontsize=20) ax.set_ylabel(r'Photons cm$^{-2}$ s$^{-1}$ keV$^{-1}$', fontsize=20) #ax.set_xlim(left=4.5, right=8.5) ax.set_xlim(left=.2, right=10) ax.set_ylim(bottom=10e-6, top=.0001) idx_lower = np.where(xd.data['energy'] == min( xd.data['energy'], key=lambda x: abs(x - lower_energy)))[0][0] idx_upper = np.where(xd.data['energy'] == min( xd.data['energy'], key=lambda x: abs(x - upper_energy)))[0][0] #First calculate the total integration over the energy range total_integration = 0 for i in range(idx_lower, idx_upper): #Use trapezoidal riemann sum total_integration += trapezoid_sum(xd, i) #We want to find the energy where half of the integration occurs ratios = [] idx_list = np.arange(idx_lower + 1, idx_upper) #Iterate by increasing the lower energy bound for i in idx_list: left_sum = 0 for left_i in range(idx_lower, i): left_sum += trapezoid_sum(xd, left_i) #At each index, compute the ratio between the calculated sum and the total integration/2 ratios.append(left_sum / (total_integration / 2)) #The middle will be where the ratio is closest to 1 ratio_idx_middle = np.where( np.array(ratios) == min(ratios, key=lambda x: abs(x - 1)))[0][0] #We want the idx corresponding to the original dataframe idx_middle = idx_list[ratio_idx_middle] print( f"The center of the integrated energy range is {xd.data['energy'][idx_middle]} keV" ) if plot: ax.axvline(xd.data['energy'][idx_lower], color='gray', ls=':') ax.axvline(xd.data['energy'][idx_upper], color='gray', ls=':') ax.axvline(xd.data['energy'][idx_middle], color='xkcd:azure', lw=4) plt.show() return xd.data['energy'][idx_middle]
def plot_multi_ufspec(sourcename, firsttxts, secondtxts, first_ranges, second_ranges, first_logs, second_logs, first_label, second_label, output="multispectra.pdf", vertical=True): #Init either horizontal or vertical figure if vertical: fig = plt.figure(figsize=(10, 11)) plt.subplots_adjust(top=.98, right=.98, hspace=.15, left=.15) outer = gridspec.GridSpec(2, 1, height_ratios=[1, 1]) else: fig = plt.figure(figsize=(20, 6.5)) plt.subplots_adjust(top=.98, right=.98, wspace=.08, left=.05, bottom=.17) outer = gridspec.GridSpec(1, 2, width_ratios=[1, 1]) #Each spec of outer contains ufspec and delchi inner_f = gridspec.GridSpecFromSubplotSpec(2, 1, subplot_spec=outer[0], hspace=0, height_ratios=[3, 1]) inner_s = gridspec.GridSpecFromSubplotSpec(2, 1, subplot_spec=outer[1], hspace=0, height_ratios=[3, 1]) #Make axes we can plot onto axf1 = plt.Subplot(fig, inner_f[1]) axf0 = plt.Subplot(fig, inner_f[0], sharex=axf1) axs1 = plt.Subplot(fig, inner_s[1]) axs0 = plt.Subplot(fig, inner_s[0], sharex=axs1) #Fill lists of xspecdata objects first_data = [] second_data = [] #Create xspeclog.xspecdata objects for i in range(len(firsttxts)): xd = xspeclog.xspecdata(firsttxts[i]) xd.set_phaserange(first_ranges[i][0], first_ranges[i][1]) if len(first_logs) != 0: xd.phot_index_from_log(first_logs[i]) first_data.append(xd) for i in range(len(secondtxts)): xd = xspeclog.xspecdata(secondtxts[i]) xd.set_phaserange(second_ranges[i][0], second_ranges[i][1]) if len(second_logs) != 0: xd.phot_index_from_log(second_logs[i]) second_data.append(xd) #Make one list with both to easily iterate through alldata = [first_data, second_data] #Match sourcename sourcename = process.extract( sourcename, [r'PSR B1821$-$24', r'PSR B1937$+$21', r'PSR J0218$+$4232'], limit=1)[0][0] #Labels for each plot labels = [first_label, second_label] #Plot data old_colors = [ "#d5483a", "#70c84c", "#853bce", #"#d4ae2f", #"#625cce", #"#c24ebe", "xkcd:azure" ] colors = [[ 'xkcd:crimson', 'xkcd:orangered', 'xkcd:azure', 'xkcd:darkblue' ], ['xkcd:green', 'xkcd:darkgreen', 'xkcd:violet', 'xkcd:indigo']] #Iterate through xspecdata and axes for i, ax in enumerate([axf0, axs0]): for j in range(len(alldata[i])): ax.errorbar(alldata[i][j].data['energy'], alldata[i][j].data['counts'], xerr=alldata[i][j].data['energy_err'], yerr=alldata[i][j].data['counts_err'], ls=' ', marker='.', color=colors[i][j], label=alldata[i][j].get_label(), zorder=i) ax.plot(alldata[i][j].data['energy'], alldata[i][j].data['model'], ls='-', lw=3, color=colors[i][j], zorder=len(alldata[i]) + i, label='_nolegend_') #Set plot parameters ax = niutils.plotparams(ax) ax.set_xscale('log') ax.set_yscale('log') if sourcename == r'PSR B1937$+$21': if i == 0: #ax.set_ylim(top=ax.get_ylim()[1]*2) ax.set_ylim(bottom=ax.get_ylim()[0] * .5) elif sourcename == r'PSR B1821$-$24': if i == 0: ax.set_ylim(bottom=1e-6) elif sourcename == r'PSR J0218$+$4232': if i == 0: ax.set_ylim(bottom=1.1e-6) ax.text(.95, .95, sourcename, transform=ax.transAxes, ha='right', va='top', fontsize=20) ax.text(.95, .85, labels[i], transform=ax.transAxes, fontsize=15, ha='right', va='top') if sourcename == r'PSR B1937$+$21': ax.legend(loc=(.6, .05), fontsize=13, edgecolor='black', framealpha=.9) else: ax.legend(loc=(.20, 0.05), fontsize=13, edgecolor='black', framealpha=.9) ax.set_xlim(right=10.1) fig.add_subplot(ax) #Adjust axis for 1937 if sourcename == r'PSR B1937$+$21': axs0.set_ylim(top=axs0.get_ylim()[1] * 2) axf0.set_ylim(top=axf0.get_ylim()[1] * 3) axs0.set_xlim(left=0.7) if axs0.get_ylim()[0] < 1e7: axs0.set_ylim(bottom=1.2e-6) #Plot residuals for i, ax in enumerate([axf1, axs1]): for j in range(len(alldata[i])): ax.errorbar( alldata[i][j].residuals['energy'].astype(float), alldata[i][j].residuals['delchi'].astype(float), xerr=alldata[i][j].residuals['energy_err'].astype(float), yerr=alldata[i][j].residuals['delchi_err'].astype(float), ls=' ', marker='.', color=colors[i][j], alpha=0.8, zorder=i) ax = niutils.plotparams(ax) ax.axhline(0, ls=':', lw=1.5, color='gray') ax.set_xscale('log') ax.xaxis.set_major_formatter(mticker.FormatStrFormatter('%.1f')) ax.set_xlim(right=10) if vertical: ax.set_ylabel(r'Residuals ($\chi$)', fontsize=15) else: ax.set_xlabel("Energy (keV)", fontsize=30) fig.add_subplot(ax) #Dont want to show xtick labels for ufspec plt.setp(axs0.get_xticklabels(), visible=False) plt.setp(axf0.get_xticklabels(), visible=False) #Add axes labels if vertical: axs1.set_xlabel("Energy (keV)", fontsize=30) fig.text(.03, .55, r'Photons cm$^{-2}$ s$^{-1}$ keV$^{-1}$', ha='center', va='center', rotation='vertical', fontsize=30) else: axf0.set_ylabel('Photons cm$^{-2}$ s$^{-1}$ keV$^{-1}$', fontsize=30) axf1.set_ylabel(r'Residuals ($\sigma$)', fontsize=18) #Add labels for figure caption axf0.text(.05, .95, '(a)', transform=axf0.transAxes, ha='right', va='top', fontsize=18) axs0.text(.05, .95, '(b)', transform=axs0.transAxes, ha='right', va='top', fontsize=18) #Write figure to file fig.savefig(output, dpi=2000)
def sun_angle_hist(mkf_list, ranges, savefig=None, multiple_panels=False, density=True): if multiple_panels: fig, ax = plt.subplots(3, 2, figsize=(20, 16)) for a in ax.reshape(-1): a = niutils.plotparams(a) plt.subplots_adjust(top=.98, right=.98, hspace=0, wspace=.1) else: fig, ax = plt.subplots(1, 1, figsize=(12, 6)) ax = niutils.plotparams(ax) for i in tqdm(range(len(mkf_list))): tab = Table.read(mkf_list[i], hdu=1) if multiple_panels: a = ax.reshape(-1)[i] a.text(.95, .95, niutils.br_label(ranges[i]), fontsize=20, ha='right', va='top', transform=ax.reshape(-1)[i].transAxes, bbox=dict(facecolor='white', edgecolor='black', boxstyle='round')) a.axvline(np.median(tab['SUN_ANGLE']), color='gray', ls=':', lw=3) if i in [3, 4]: a.set_xlabel('Sun Angle (Degrees)', fontsize=30) else: a.set_xticklabels([]) else: a = ax a.hist(tab['SUN_ANGLE'], bins=50, facecolor='none', edgecolor=niutils.map_colors()[ranges[i]], label=niutils.br_label(ranges[i]), density=density, lw=4) a.set_xlim(50, 190) plt.setp(a.get_yticklabels()[0], visible=False) if density: ylabel = 'Normalized Number of Rows' else: ylabel = 'Number of Rows' if multiple_panels: fig.text(.05, .5, ylabel, fontsize=40, rotation='vertical', ha='center', va='center') ax.reshape(-1)[-1].axis('off') else: ax.legend(edgecolor='black', fontsize=20) ax.set_xlabel("Sun Angle", fontsize=20) ax.set_ylabel(ylabel, fontsize=20) if savefig is None: plt.show() else: fig.savefig(savefig) if savefig.endswith('.pdf'): fig.savefig(savefig.replace('.pdf', '.png'), dpi=300)
def plot(self, output=None, extension='pdf', l1=None, l2=None, nsigma=3, ax=None, label=True): if output is not None: assert (type(output) == str) assert (type(extension) == str) if self.counts is None: self.generate() if ax is None: #Initialize matplotlib figure fig, ax = plt.subplots(1, 1, figsize=(8, 4)) plt.subplots_adjust(bottom=.2, top=.98, right=.98, left=.15) created_fig = True else: created_fig = False #Default plot paramaters ax = niutils.plotparams(ax) if label: ax.set_xlabel('Phase', fontsize=25) ax.set_ylabel('Counts', fontsize=25) ax.set_xlim(left=-.025, right=self.n_phase + .025) ax.plot(self.phasebins_extended, self.counts_extended, marker='.', ls='-', color='xkcd:violet') #Use l1 and l2 to define an offpeak region & determine onpeak region if l1 is not None and l2 is not None: cutofftup = self.peak_cutoff(l1, l2, nsigma=nsigma) #ax.axhline(cutofftup.median, ls='--', color='gray') ax.axhline(cutofftup.nsigma, ls=':', color='darkblue', label=str(cutofftup.n) + r'$\sigma$') default_span = dict(alpha=.2, color='gray') if cutofftup.min_phase_p2 is not None: for i in range(self.n_phase): ax.axvspan(cutofftup.min_phase_p2 + i, cutofftup.max_phase_p2 + i, **default_span) if cutofftup.min_phase_p1 > cutofftup.max_phase_p1: for i in range(self.n_phase): ax.axvspan(i, cutofftup.max_phase_p1 + i, **default_span) ax.axvspan(cutofftup.min_phase_p1 + i, i + 1, **default_span) else: for i in range(self.n_phase): ax.axvspan(cutofftup.min_phase_p1 + i, cutofftup.max_phase_p1 + i, **default_span) #ax.legend() ax, _ = niutils.add_CharErrBar(ax, self.counts, .95, .85) #ax.legend(loc=(.85, .85), fontsize=20, edgecolor='black') if self.name is not None and label: ax.text(.05, .95, self.name, ha='left', va='top', transform=ax.transAxes, fontsize=20) #Save/display/return plot if output is not None: fig.savefig(f"{output}.{extension}", dpi=500) #If the figure is within class, show if created_fig: plt.show() return 0 #If appending to input axis, return modifying axis else: return ax
def cumulative_exposure_plot(flist, savefig=None, ax=None): log.info("Generating cumulative exposure plot") d = {} format_specifier = '%Y-%m-%dT%H:%M:%S' for f in tqdm(flist): tab = Table.read(f, hdu=1) date = tab.meta['DATE-OBS'] exposure = tab.meta['EXPOSURE'] if exposure == 0: continue date_formatted = datetime.datetime.strptime(date, format_specifier) date_formatted = date_formatted.replace(hour=0, minute=0, second=0) if date_formatted in d.keys(): d[date_formatted] += exposure else: d[date_formatted] = exposure sorted_dates = list(d.keys()) sorted_dates.sort() mindate = min(list(d.keys())) maxdate = max(list(d.keys())) iterdate = mindate - datetime.timedelta(1) date_list = [] exposure_cumulative = [] while iterdate <= maxdate + datetime.timedelta(1): date_list.append(iterdate) if len(exposure_cumulative) == 0: exposure_next = 0 elif iterdate in d.keys(): exposure_next = exposure_cumulative[-1] + d[iterdate] else: exposure_next = exposure_cumulative[-1] exposure_cumulative.append(exposure_next) iterdate = iterdate + datetime.timedelta(1) if ax is None: fig, ax = plt.subplots(1, 1, figsize=(12, 6)) plt.subplots_adjust(top=.98, right=.98, bottom=.16) ax = niutils.plotparams(ax) created_fig = True else: created_fig = False exposure_cumulative = [e / (10e10) for e in exposure_cumulative] ax.plot(date_list, exposure_cumulative, color=niutils.get_colors()['3c50_color'], lw=3) ax.xaxis.set_minor_locator(MonthLocator()) ax.set_xlabel("Observation Start Date", fontsize=20) ax.set_ylabel(r'Cumulative Expsoure ($\times10^{10}$ s)', fontsize=20) if (savefig is None) and (created_fig): plt.show() elif savefig is not None: fig.savefig(savefig) else: return ax
def plot_bkgd_spectra(br_data_list, br_ranges, sa_ranges=None, environ=None, bkg3c50=None, two_panel=False, savefig=None, zoom_top=0.9, zoom_bottom=0.3, zoom_left=0.28, zoom_right=0.92): assert(len(br_data_list) == len(br_ranges)) br_data_list = reformat_input(br_data_list) if any( [ l > 1 for l in check_length(br_data_list)[1] ] ): assert(sa_ranges is not None) sa_ranges = reformat_input(sa_ranges) assert(check_length(br_data_list) == check_length(sa_ranges)) linestyles = ['-', '--', '-.', ':'] data_flat = [] br_ranges_flat = [] sa_ranges_flat = [] ls_flat = [] for i in range(len(br_data_list)): for j in range(len(br_data_list[i])): data_flat.append(br_data_list[i][j]) br_ranges_flat.append(br_ranges[i]) if sa_ranges is not None: sa_ranges_flat.append(sa_ranges[i][j]) ls_flat.append(linestyles[j]) colors_flat = [ niutils.map_colors()[r] for r in br_ranges_flat ] if sa_ranges is None: labels_flat = [ niutils.br_label(r) for r in br_ranges_flat ] else: labels_flat = [ f'{niutils.br_label(br_ranges_flat[i])}; {niutils.sa_label(sa_ranges_flat[i])}' for i in range(len(br_ranges_flat)) ] if environ is not None: data_flat.append(environ) colors_flat.append(niutils.get_colors()['environ_color']) labels_flat.append("Environmental Model") ls_flat.append('-') if bkg3c50 is not None: data_flat.append(bkg3c50) colors_flat.append(niutils.get_colors()['3c50_color']) labels_flat.append('3C50 Model') ls_flat.append('-') if two_panel: fig, (ax, ax1) = plt.subplots(2, 1, figsize=(16, 14)) plt.subplots_adjust(hspace=.1, top=.98, right=.98, bottom=.08, left=.08) ax_list = [ax, ax1] else: fig, ax = plt.subplots(1, 1, figsize=(15, 8)) ax_list = [ax] for a in ax_list: a = niutils.plotparams(a) markers = ['.', 'o'] for i in range(len(data_flat)): df = pd.read_csv(data_flat[i], skiprows=3, delimiter=" ", header=None) df.columns = ['energy', 'energy_err', 'counts', 'counts_err'] mi = 0 for a in ax_list: a.errorbar(df['energy'], df['counts'], xerr=df['energy_err'], yerr=df['counts_err'], ls=ls_flat[i], marker=markers[mi], color=colors_flat[i], label=labels_flat[i]) mi += 1 ax.legend(edgecolor='black', fontsize=20) for a in ax_list: a.set_ylabel(r'Normalized Counts (s$^{-1}$ keV$^{-1}$)', fontsize=20) a.set_xscale('log') a.set_yscale('log') a.set_xlabel('Energy (keV)', fontsize=20) ax.xaxis.set_major_formatter(mticker.FormatStrFormatter('%.1f')) if two_panel: ax1.xaxis.set_minor_formatter(mticker.FormatStrFormatter('%.01f')) ax1.set_xlim(left=zoom_left, right=zoom_right) ax1.set_ylim(bottom=zoom_bottom, top=zoom_top) con1 = ConnectionPatch(xyA=(ax1.get_xlim()[0], ax1.get_ylim()[1]), xyB=(ax1.get_xlim()[0], ax1.get_ylim()[0]), coordsA='data', coordsB='data', axesA=ax1, axesB=ax, color='black', ls='-') con2 = ConnectionPatch(xyA=(ax1.get_xlim()[1], ax1.get_ylim()[1]), xyB=(ax1.get_xlim()[1], ax1.get_ylim()[0]), coordsA='data', coordsB='data', axesA=ax1, axesB=ax, color='black', ls='-') rect = Rectangle((ax1.get_xlim()[0], ax1.get_ylim()[0]), (ax1.get_xlim()[1]-ax1.get_xlim()[0]), (ax1.get_ylim()[1]-ax1.get_ylim()[0]), facecolor='none', edgecolor='black', alpha=.5) ax.add_patch(rect) ax1.add_patch(con1) ax1.add_patch(con2) if savefig is not None: fig.savefig(savefig) if savefig.endswith('pdf'): fig.savefig(savefig.replace('pdf', 'png')) else: plt.show()
def plot_joint_telescope(fname, source, output): #Init figure fig = plt.figure(figsize=(8.5, 5.5)) plt.subplots_adjust(top=.98, right=.98, wspace=.1, left=.15, bottom=.18) #Outer gridspec of size 2 #Each spec of outer contains ufspec and delchi inner = gridspec.GridSpec(2, 1, height_ratios=[3, 1.2], hspace=0) #Make axes we can plot onto ax1 = plt.Subplot(fig, inner[1]) ax0 = plt.Subplot(fig, inner[0], sharex=ax1) #Use joint data class to parse text file xd = joint_data(fname) xd.set_source(source) source = process.extract( source, [r'PSR B1937$+$21', r'PSR B1821$-$24', r'PSR J0218$+$4232'], limit=1)[0][0] if source == r'PSR B1937$+$21': labels = [r'$NICER$', r'$NuSTAR$', r'$XMM-Newton$'] colors = [ "#d5483a", "#70c84c", "#853bce", #"#d4ae2f", #"#625cce", #"#c24ebe", "xkcd:azure" ] elif source == r'PSR B1821$-$24': labels = [r'$NICER$', r'$NuSTAR$', r'$RXTE$'] colors = [ "#d5483a", "#70c84c", #"#853bce", #"#d4ae2f", "#625cce", #"#c24ebe", "xkcd:azure" ] elif source == r'PSR J0218$+$4232': labels = [r'$NICER$', r'$NuSTAR$', r'$XMM-Newton$'] colors = [ "#d5483a", "#70c84c", "#853bce", #"#d4ae2f", #"#625cce", #"#c24ebe", "xkcd:azure" ] else: return -1 zorders = [2, 1.5, 1] #Iterate through each data and residual pair for i in range(len(xd.data)): ax0.errorbar(xd.data[i]['energy'], xd.data[i]['counts'], xerr=xd.data[i]['energy_err'], yerr=xd.data[i]['counts_err'], ls=' ', marker='.', color=colors[i], label=labels[i], zorder=zorders[i]) ax0.plot(xd.data[i]['energy'], xd.data[i]['model'], ls='-', lw=3, color=colors[i], zorder=zorders[i], label='_nolegend_') ax1.errorbar(xd.residuals[i]['energy'].astype(float), xd.residuals[i]['delchi'].astype(float), xerr=xd.residuals[i]['energy_err'].astype(float), yerr=xd.residuals[i]['delchi_err'].astype(float), ls=' ', marker='.', color=colors[i], alpha=0.8, zorder=zorders[i]) #Misc plot params ax0 = plotparams(ax0) ax1 = plotparams(ax1) #ax0.set_ylim(bottom=5e-7) ax0.set_xscale('log') ax0.set_yscale('log') ax0.text(.95, .95, source, transform=ax0.transAxes, ha='right', va='top', fontsize=20) ax0.legend(loc=(.05, 0.05), fontsize=16, edgecolor='black', framealpha=.9) ax1.axhline(0, ls=':', lw=1.5, color='gray') ax1.set_xscale('log') ax1.xaxis.set_major_formatter(mticker.FormatStrFormatter('%.1f')) ax1.set_xlabel('Energy (keV)', fontsize=20) #Add subplots to figure fig.add_subplot(ax0) fig.add_subplot(ax1) #Dont want to show xtick labels for ufspec plt.setp(ax0.get_xticklabels(), visible=False) #ax_top0.set_ylim(ax_top0.get_ylim()[0] * .4) #Add axes labels ax0.set_ylabel(r'Photons cm$^{-2}$ s$^{-1}$ keV$^{-1}$', ha='center', va='center', fontsize=20) ax1.set_ylabel(r'Residuals ($\chi$)', fontsize=15) ax0.yaxis.set_label_coords(-0.115, ax0.yaxis.get_label().get_position()[1]) #Save figure fig.savefig(output, dpi=2000)