def variable_aper_phot(target, centroided_sources, multiplicative_factors, an_in=12., an_out=30., plots=False, gain=8.21, qe=0.9, plate_scale=0.579): pines_path = pines_dir_check() short_name = short_name_creator(target) #Remove any leading/trailing spaces in the column names. centroided_sources.columns = centroided_sources.columns.str.lstrip() centroided_sources.columns = centroided_sources.columns.str.rstrip() #Get list of reduced files for target. reduced_path = pines_path / ('Objects/' + short_name + '/reduced') reduced_filenames = natsort.natsorted( [x.name for x in reduced_path.glob('*red.fits')]) reduced_files = np.array([reduced_path / i for i in reduced_filenames]) #Get source names. source_names = get_source_names(centroided_sources) #Get seeing. seeing = np.array(centroided_sources['Seeing']) #Loop over multiplicative factors for i in range(len(multiplicative_factors)): fact = multiplicative_factors[i] print( 'Doing variable aperture photometry for {}, multiplicative seeing factor = {}, inner annulus radius = {} pix, outer annulus radius = {} pix.' .format(target, fact, an_in, an_out)) #Declare a new dataframe to hold the information for all targets for this aperture. columns = [ 'Filename', 'Time UT', 'Time JD UTC', 'Time BJD TDB', 'Airmass', 'Seeing' ] for j in range(0, len(source_names)): columns.append(source_names[j] + ' Flux') columns.append(source_names[j] + ' Flux Error') columns.append(source_names[j] + ' Background') columns.append(source_names[j] + ' Interpolation Flag') var_df = pd.DataFrame(index=range(len(reduced_files)), columns=columns) output_filename = pines_path / ( 'Objects/' + short_name + '/aper_phot/' + short_name + '_variable_aper_phot_' + str(float(fact)) + '_seeing_factor.csv') #Loop over all images. pbar = ProgressBar() for j in pbar(range(len(reduced_files))): data = fits.open(reduced_files[j])[0].data #Read in some supporting information. log_path = pines_path / ( 'Logs/' + reduced_files[j].name.split('.')[0] + '_log.txt') log = pines_log_reader(log_path) log_ind = np.where( log['Filename'] == reduced_files[j].name.split('_')[0] + '.fits')[0][0] header = fits.open(reduced_files[j])[0].header date_obs = header['DATE-OBS'] #Catch a case that can cause datetime strptime to crash; Mimir headers sometimes have DATE-OBS with seconds specified as 010.xx seconds, when it should be 10.xx seconds. if len(date_obs.split(':')[-1].split('.')[0]) == 3: date_obs = date_obs.split(':')[0] + ':' + date_obs.split( ':')[1] + ':' + date_obs.split(':')[-1][1:] if date_obs.split(':')[-1] == '60.00': date_obs = date_obs.split(':')[0] + ':' + str( int(date_obs.split(':')[1]) + 1) + ':00.00' #Keep a try/except clause here in case other unknown DATE-OBS formats pop up. try: date = datetime.datetime.strptime(date_obs, '%Y-%m-%dT%H:%M:%S.%f') except: print( 'Header DATE-OBS format does not match the format code in strptime! Inspect/correct the DATE-OBS value.' ) pdb.set_trace() #Get the closest date master_dark_stddev image for this exposure time. #We'll use this to measure read noise and dark current. date_str = date_obs.split('T')[0].replace('-', '') master_dark_stddev = master_dark_stddev_chooser( pines_path / ('Calibrations/Darks/Master Darks Stddev/'), header) days = date.day + hmsm_to_days(date.hour, date.minute, date.second, date.microsecond) jd = date_to_jd(date.year, date.month, days) var_df['Filename'][j] = reduced_files[j].name var_df['Time UT'][j] = header['DATE-OBS'] var_df['Time JD UTC'][j] = jd var_df['Time BJD TDB'][j] = jd_utc_to_bjd_tdb( jd, header['TELRA'], header['TELDEC']) var_df['Airmass'][j] = header['AIRMASS'] var_df['Seeing'][j] = log['X seeing'][np.where( log['Filename'] == reduced_files[j].name.split('_')[0] + '.fits')[0][0]] #If the shift quality has been flagged, skip this image. if log['Shift quality flag'].iloc[log_ind] == 1: continue #Get the source positions in this image. positions = [] for k in range(len(source_names)): positions.append( (centroided_sources[source_names[k] + ' Image X'][j], centroided_sources[source_names[k] + ' Image Y'][j])) #Create an aperture centered on this position with radius (in pixels) of (seeing*multiplicative_factor[j])/plate_scale. try: apertures = CircularAperture(positions, r=(seeing[j] * fact) / plate_scale) except: pdb.set_trace() #Create an annulus centered on this position. annuli = CircularAnnulus(positions, r_in=an_in, r_out=an_out) photometry_tbl = iraf_style_photometry(apertures, annuli, data * gain, master_dark_stddev * gain, header, var_df['Seeing'][j]) for k in range(len(photometry_tbl)): var_df[source_names[k] + ' Flux'][j] = photometry_tbl['flux'][k] var_df[source_names[k] + ' Flux Error'][j] = photometry_tbl['flux_error'][k] var_df[source_names[k] + ' Background'][j] = photometry_tbl['background'][k] var_df[source_names[k] + ' Interpolation Flag'][j] = int( photometry_tbl['interpolation_flag'][k]) #Write output to file. print( 'Saving multiplicative factor = {} variable aperture photometry output to {}.' .format(fact, output_filename)) print('') with open(output_filename, 'w') as f: for j in range(len(var_df)): #Write in the header. if j == 0: f.write( '{:>21s}, {:>22s}, {:>17s}, {:>17s}, {:>7s}, {:>7s}, '. format('Filename', 'Time UT', 'Time JD UTC', 'Time BJD TDB', 'Airmass', 'Seeing')) for k in range(len(source_names)): if k != len(source_names) - 1: f.write( '{:>22s}, {:>28s}, {:>28s}, {:>34s}, '.format( source_names[k] + ' Flux', source_names[k] + ' Flux Error', source_names[k] + ' Background', source_names[k] + ' Interpolation Flag')) else: f.write( '{:>22s}, {:>28s}, {:>28s}, {:>34s}\n'.format( source_names[k] + ' Flux', source_names[k] + ' Flux Error', source_names[k] + ' Background', source_names[k] + ' Interpolation Flag')) #Write in Filename, Time UT, Time JD, Airmass, Seeing values. format_string = '{:21s}, {:22s}, {:17.9f}, {:17.9f}, {:7.2f}, {:7.1f}, ' #If the seeing value for this image is 'nan' (a string), convert it to a float. #TODO: Not sure why it's being read in as a string, fix that. if type(var_df['Seeing'][j]) == str: var_df['Seeing'][j] = float(var_df['Seeing'][j]) #Do a try/except clause for writeout, in case it breaks in the future. try: f.write( format_string.format(var_df['Filename'][j], var_df['Time UT'][j], var_df['Time JD UTC'][j], var_df['Time BJD TDB'][j], var_df['Airmass'][j], var_df['Seeing'][j])) except: print( 'Writeout failed! Inspect quantities you are trying to write out.' ) pdb.set_trace() #Write in Flux, Flux Error, and Background values for every source. for i in range(len(source_names)): if i != len(source_names) - 1: format_string = '{:22.5f}, {:28.5f}, {:28.5f}, {:34d}, ' else: format_string = '{:22.5f}, {:28.5f}, {:28.5f}, {:34d}\n' try: f.write( format_string.format( var_df[source_names[i] + ' Flux'][j], var_df[source_names[i] + ' Flux Error'][j], var_df[source_names[i] + ' Background'][j], var_df[source_names[i] + ' Interpolation Flag'][j])) except: if i != len(source_names) - 1: format_string = '{:22.5f}, {:28.5f}, {:28.5f}, {:34f}, ' else: format_string = '{:22.5f}, {:28.5f}, {:28.5f}, {:34f}\n' f.write( format_string.format( var_df[source_names[i] + ' Flux'][j], var_df[source_names[i] + ' Flux Error'][j], var_df[source_names[i] + ' Background'][j], var_df[source_names[i] + ' Interpolation Flag'][j])) print('') return
def fixed_aper_phot(target, centroided_sources, ap_radii, an_in=12., an_out=30., plots=False, gain=8.21, qe=0.9): '''Authors: Patrick Tamburo, Boston University, June 2020 Purpose: Performs *fixed* aperture photometry on a set of reduced images given dataframe of source positions. The iraf_style_photometry, compute_phot_error, perture_stats_tbl, and calc_aperture_mmm routines are from Varun Bajaj on github: https://github.com/spacetelescope/wfc3_photometry/blob/master/photometry_tools/photometry_with_errors.py. Inputs: target (str): The target's full 2MASS name. sources (pandas dataframe): List of source names, x and y positions in every image. ap_radii (list of floats): List of aperture radii in pixels for which aperture photometry wil be performed. an_in (float, optional): The inner radius of the annulus used to estimate background, in pixels. an_out (float, optional): The outer radius of the annulus used to estimate background, in pixels. plots (bool, optional): Whether or not to output surface plots. Images output to aper_phot directory within the object directory. gain (float, optional): The gain of the detector in e-/ADU. qe (float, optional): The quantum efficiency of the detector. Outputs: Saves aperture photometry csv to PINES_analysis_toolkit/Objects/short_name/aper_phot/ for each aperture. TODO: ''' pines_path = pines_dir_check() short_name = short_name_creator(target) #Remove any leading/trailing spaces in the column names. centroided_sources.columns = centroided_sources.columns.str.lstrip() centroided_sources.columns = centroided_sources.columns.str.rstrip() #Get list of reduced files for target. reduced_path = pines_path / ('Objects/' + short_name + '/reduced') reduced_filenames = natsort.natsorted( [x.name for x in reduced_path.glob('*red.fits')]) reduced_files = np.array([reduced_path / i for i in reduced_filenames]) #source_names = natsort.natsorted(list(set([i.replace('X','').replace('Y','').replace('Centroid Warning','').strip() for i in centroided_sources.keys() if i != 'Filename']))) source_names = get_source_names(centroided_sources) #Create output plot directories for each source. if plots: #Camera angles for surface plots azim_angles = np.linspace(0, 360 * 1.5, len(reduced_files)) % 360 elev_angles = np.zeros(len(azim_angles)) + 25 for name in source_names: #If the folders are already there, delete them. source_path = ( pines_path / ('Objects/' + short_name + '/aper_phot/' + name + '/')) if source_path.exists(): shutil.rmtree(source_path) #Create folders. os.mkdir(source_path) #Loop over all aperture radii. for ap in ap_radii: print( 'Doing fixed aperture photometry for {}, aperture radius = {:1.1f} pix, inner annulus radius = {} pix, outer annulus radius = {} pix.' .format(target, ap, an_in, an_out)) #Declare a new dataframe to hold the information for all targets for this aperture. columns = [ 'Filename', 'Time UT', 'Time JD UTC', 'Time BJD TDB', 'Airmass', 'Seeing' ] for i in range(0, len(source_names)): columns.append(source_names[i] + ' Flux') columns.append(source_names[i] + ' Flux Error') columns.append(source_names[i] + ' Background') columns.append(source_names[i] + ' Interpolation Flag') ap_df = pd.DataFrame(index=range(len(reduced_files)), columns=columns) output_filename = pines_path / ( 'Objects/' + short_name + '/aper_phot/' + short_name + '_fixed_aper_phot_{:1.1f}_pix_radius.csv'.format(float(ap))) #Loop over all images. pbar = ProgressBar() for j in pbar(range(len(reduced_files))): data = fits.open(reduced_files[j])[0].data #Read in some supporting information. log_path = pines_path / ( 'Logs/' + reduced_files[j].name.split('.')[0] + '_log.txt') log = pines_log_reader(log_path) log_ind = np.where( log['Filename'] == reduced_files[j].name.split('_')[0] + '.fits')[0][0] header = fits.open(reduced_files[j])[0].header date_obs = header['DATE-OBS'] #Catch a case that can cause datetime strptime to crash; Mimir headers sometimes have DATE-OBS with seconds specified as 010.xx seconds, when it should be 10.xx seconds. if len(date_obs.split(':')[-1].split('.')[0]) == 3: date_obs = date_obs.split(':')[0] + ':' + date_obs.split( ':')[1] + ':' + date_obs.split(':')[-1][1:] if date_obs.split(':')[-1] == '60.00': date_obs = date_obs.split(':')[0] + ':' + str( int(date_obs.split(':')[1]) + 1) + ':00.00' #Keep a try/except clause here in case other unknown DATE-OBS formats pop up. try: date = datetime.datetime.strptime(date_obs, '%Y-%m-%dT%H:%M:%S.%f') except: print( 'Header DATE-OBS format does not match the format code in strptime! Inspect/correct the DATE-OBS value.' ) pdb.set_trace() #Get the closest date master_dark_stddev image for this exposure time. #We'll use this to measure read noise and dark current. date_str = date_obs.split('T')[0].replace('-', '') master_dark_stddev = master_dark_stddev_chooser( pines_path / ('Calibrations/Darks/Master Darks Stddev/'), header) days = date.day + hmsm_to_days(date.hour, date.minute, date.second, date.microsecond) jd = date_to_jd(date.year, date.month, days) ap_df['Filename'][j] = reduced_files[j].name ap_df['Time UT'][j] = header['DATE-OBS'] ap_df['Time JD UTC'][j] = jd ap_df['Time BJD TDB'][j] = jd_utc_to_bjd_tdb( jd, header['TELRA'], header['TELDEC'] ) #Using the telescope ra and dec should be accurate enough for our purposes ap_df['Airmass'][j] = header['AIRMASS'] ap_df['Seeing'][j] = log['X seeing'][log_ind] #If the shift quality has been flagged, skip this image. if log['Shift quality flag'].iloc[log_ind] == 1: continue #Get the source positions in this image. positions = [] for i in range(len(source_names)): positions.append((float(centroided_sources[source_names[i] + ' Image X'][j]), float(centroided_sources[source_names[i] + ' Image Y'][j]))) #Create an aperture centered on this position with radius = ap. try: apertures = CircularAperture(positions, r=ap) except: pdb.set_trace() #Create an annulus centered on this position. annuli = CircularAnnulus(positions, r_in=an_in, r_out=an_out) photometry_tbl = iraf_style_photometry(apertures, annuli, data * gain, master_dark_stddev * gain, header, ap_df['Seeing'][j]) for i in range(len(photometry_tbl)): ap_df[source_names[i] + ' Flux'][j] = photometry_tbl['flux'][i] ap_df[source_names[i] + ' Flux Error'][j] = photometry_tbl['flux_error'][i] ap_df[source_names[i] + ' Background'][j] = photometry_tbl['background'][i] ap_df[source_names[i] + ' Interpolation Flag'][j] = int( photometry_tbl['interpolation_flag'][i]) #Make surface plots. if plots: for i in range(len(photometry_tbl)): x_p = photometry_tbl['X'][i] y_p = photometry_tbl['Y'][i] fig = plt.figure() ax = fig.add_subplot(111, projection='3d') xx, yy = np.meshgrid( np.arange(int(x_p) - 10, int(x_p) + 10 + 1), np.arange(int(y_p) - 10, int(y_p) + 10 + 1)) theta = np.linspace(0, 2 * np.pi, 201) y_circ = ap * np.cos(theta) + y_p x_circ = ap * np.sin(theta) + x_p vmin = np.nanmedian(data[yy, xx]) vmax = vmin + 2.5 * np.nanstd(data[yy, xx]) ax.plot_surface(xx, yy, data[yy, xx], cmap=cm.viridis, alpha=0.8, rstride=1, cstride=1, edgecolor='k', lw=0.2, vmin=vmin, vmax=vmax) current_z = ax.get_zlim() ax.set_zlim(current_z[0] - 150, current_z[1]) current_z = ax.get_zlim() cset = ax.contourf(xx, yy, data[yy, xx], zdir='z', offset=current_z[0], cmap=cm.viridis) ax.plot(x_circ, y_circ, np.zeros(len(x_circ)) + current_z[0], color='r', lw=2, zorder=100) ax.set_xlabel('X') ax.set_ylabel('Y') ax.set_zlabel('Counts') ax.set_title('SURFACE DIAGNOSTIC PLOT, ' + ', Ap. = ' + str(ap) + '\n' + source_names[i] + ', ' + reduced_files[j].name + ' (image ' + str(j + 1) + ' of ' + str(len(reduced_files)) + ')') ax.view_init(elev=elev_angles[j], azim=azim_angles[j]) plot_output_path = ( pines_path / ('Objects/' + short_name + '/aper_phot/' + source_names[i] + '/' + str(j).zfill(4) + '.jpg')) plt.tight_layout() plt.savefig(plot_output_path) plt.close() #Write output to file. print('Saving ap = {:1.1f} aperture photometry output to {}.'.format( ap, output_filename)) print('') with open(output_filename, 'w') as f: for j in range(len(ap_df)): #Write in the header. if j == 0: f.write( '{:>21s}, {:>22s}, {:>17s}, {:>17s}, {:>7s}, {:>7s}, '. format('Filename', 'Time UT', 'Time JD UTC', 'Time BJD TDB', 'Airmass', 'Seeing')) for i in range(len(source_names)): if i != len(source_names) - 1: f.write( '{:>22s}, {:>28s}, {:>28s}, {:>34s}, '.format( source_names[i] + ' Flux', source_names[i] + ' Flux Error', source_names[i] + ' Background', source_names[i] + ' Interpolation Flag')) else: f.write( '{:>22s}, {:>28s}, {:>28s}, {:>34s}\n'.format( source_names[i] + ' Flux', source_names[i] + ' Flux Error', source_names[i] + ' Background', source_names[i] + ' Interpolation Flag')) #Write in Filename, Time UT, Time JD, Airmass, Seeing values. format_string = '{:21s}, {:22s}, {:17.9f}, {:17.9f}, {:7.2f}, {:7.1f}, ' #If the seeing value for this image is 'nan' (a string), convert it to a float. #TODO: Not sure why it's being read in as a string, fix that. if type(ap_df['Seeing'][j]) == str: ap_df['Seeing'][j] = float(ap_df['Seeing'][j]) #Do a try/except clause for writeout, in case it breaks in the future. try: f.write( format_string.format(ap_df['Filename'][j], ap_df['Time UT'][j], ap_df['Time JD UTC'][j], ap_df['Time BJD TDB'][j], ap_df['Airmass'][j], ap_df['Seeing'][j])) except: print( 'Writeout failed! Inspect quantities you are trying to write out.' ) pdb.set_trace() #Write in Flux, Flux Error, and Background values for every source. for i in range(len(source_names)): if i != len(source_names) - 1: format_string = '{:22.5f}, {:28.5f}, {:28.5f}, {:34d}, ' else: format_string = '{:22.5f}, {:28.5f}, {:28.5f}, {:34d}\n' try: f.write( format_string.format( ap_df[source_names[i] + ' Flux'][j], ap_df[source_names[i] + ' Flux Error'][j], ap_df[source_names[i] + ' Background'][j], ap_df[source_names[i] + ' Interpolation Flag'][j])) except: if i != len(source_names) - 1: format_string = '{:22.5f}, {:28.5f}, {:28.5f}, {:34f}, ' else: format_string = '{:22.5f}, {:28.5f}, {:28.5f}, {:34f}\n' f.write( format_string.format( ap_df[source_names[i] + ' Flux'][j], ap_df[source_names[i] + ' Flux Error'][j], ap_df[source_names[i] + ' Background'][j], ap_df[source_names[i] + ' Interpolation Flag'][j])) print('') return
def corr_all_sources_plot(target): print('Generating corrected flux plots for all sources...\n') pines_path = pines_dir_check() short_name = short_name_creator(target) analysis_path = pines_path / ('Objects/' + short_name + '/analysis/') photometry_path = pines_path / ('Objects/' + short_name + '/aper_phot/') #Grab the data for the best aperture. if os.path.exists(analysis_path / ('optimal_aperture.txt')): with open(analysis_path / ('optimal_aperture.txt'), 'r') as f: best_ap = f.readlines()[0].split(': ')[1].split('\n')[0] phot_type = best_ap.split('_')[1] if phot_type == 'fixed': s = 'r' elif phot_type == 'variable': s = 'f' else: raise RuntimeError( 'No optimal_aperture.txt file for {}.\nUsing first photometry file in {}.' .format(target, phot_path)) filename = short_name.replace( ' ', '') + '_' + phot_type + '_aper_phot_' + s + '=' + best_ap.split( '_')[0] + '_nightly_weighted_lc.csv' best_phot_path = analysis_path / ('aper_phot_analysis/' + best_ap + '/') output_path = best_phot_path / ('corr_ref_plots/') if not os.path.exists(output_path): os.mkdir(output_path) data = pines_log_reader(best_phot_path / filename) ref_names = get_source_names(data)[1:] num_refs = len(ref_names) times = np.array(data['Time BJD TDB']) night_inds = night_splitter(times) num_nights = len(night_inds) cmap = plt.get_cmap('viridis') for i in range(num_refs + 1): fig, ax = plt.subplots(nrows=1, ncols=num_nights, figsize=(17, 5), sharey=True) plt.subplots_adjust(left=0.07, wspace=0.05, top=0.92, bottom=0.17) if i == 0: color = cmap(0) flux = np.array(data[short_name + ' Corrected Flux'], dtype='float64') flux_err = np.array(data[short_name + ' Corrected Flux Error'], dtype='float64') title = short_name output_name = short_name + '_corrected_flux.png' else: color = cmap(95) ref_name = ref_names[i - 1] flux = np.array(data[ref_name + ' Corrected Flux'], dtype='float64') flux_err = np.array(data[ref_name + ' Corrected Flux Error'], dtype='float64') if i < 10: num = '0' + str(i) else: num = str(i) output_name = 'reference_' + num + '_corrected_flux.png' for j in range(num_nights): if i != 0: weight = np.array(data[ref_name + ' ALC Weight'])[night_inds[j]][0] title = ref_name.replace( 'erence', '.') + ', weight = {:1.3f}'.format(weight) if j == 0: ax[j].set_ylabel('Normalized Flux', fontsize=20) inds = night_inds[j] block_inds = block_splitter(times[inds]) binned_time = [] binned_flux = [] binned_err = [] for k in range(len(block_inds)): binned_time.append(np.nanmean(times[inds][block_inds[k]])) binned_flux.append(np.nanmean(flux[inds][block_inds[k]])) binned_err.append( np.nanstd(flux[inds][block_inds[k]]) / np.sqrt(len(block_inds[k]))) ax[j].plot(times[inds], flux[inds], color=color, linestyle='', marker='.', alpha=0.25) ax[j].errorbar(binned_time, binned_flux, binned_err, color=color, linestyle='', marker='o', ms=10, mfc='none', mew=2) ax[j].set_xlabel('Time (BJD$_{TDB}$)', fontsize=20) ax[j].tick_params(labelsize=16) ax[j].axhline(1, color='k', alpha=0.7, lw=1, zorder=0) ax[j].grid(alpha=0.2) ax[j].set_title(title, fontsize=20, color=color) ax[j].set_ylim(0.9, 1.1) plt.savefig(output_path / output_name, dpi=300) plt.close()
def seeing_plot(target, centroided_sources): pines_path = pines_dir_check() short_name = short_name_creator(target) #Get plot style parameters. title_size, axis_title_size, axis_ticks_font_size, legend_font_size = plot_style( ) #Get list of souce names in the centroid output. source_names = get_source_names(centroided_sources) centroided_sources.columns = centroided_sources.keys().str.strip() #Read in times and seeing values. times_full = np.array(centroided_sources['Time (JD UTC)']) seeing = np.array(centroided_sources['Seeing']) #Split up times by nights. night_inds = night_splitter(times_full) num_nights = len(night_inds) times_nights = [times_full[night_inds[i]] for i in range(num_nights)] standard_x = standard_x_range(times_nights) fig, ax = plt.subplots(nrows=1, ncols=num_nights, figsize=(17, 5), sharey=True) for i in range(num_nights): if i == 0: ax[i].set_ylabel('Seeing (")', fontsize=axis_title_size) inds = night_inds[i] ax[i].plot(times_nights[i], seeing[inds], marker='.', linestyle='', alpha=0.3, label='Raw seeing') ax[i].tick_params(labelsize=axis_ticks_font_size) ax[i].set_xlabel('Time (JD UTC)', fontsize=axis_title_size) ax[i].grid(alpha=0.2) ax[i].set_xlim( np.mean(times_nights[i]) - standard_x / 2, np.mean(times_nights[i]) + standard_x / 2) #bin block_inds = block_splitter(times_nights[i]) block_x = np.zeros(len(block_inds)) block_y = np.zeros(len(block_inds)) block_y_err = np.zeros(len(block_inds)) for j in range(len(block_inds)): block_x[j] = np.mean(times_nights[i][block_inds[j]]) block_y[j] = np.mean(seeing[inds][block_inds[j]]) block_y_err[j] = np.std(seeing[inds][block_inds[j]]) / np.sqrt( len(seeing[inds][block_inds[j]])) ax[i].errorbar(block_x, block_y, block_y_err, marker='o', linestyle='', color='tab:blue', ms=8, mfc='none', mew=2, label='Bin seeing') #Interpolate each night's seeing. fit_times = np.linspace(block_x[0], block_x[-1], 1000) interp = CubicSpline(block_x, block_y) interp_fit = interp(fit_times) ax[i].plot(fit_times, interp_fit, color='r', lw=2, zorder=0, alpha=0.7, label='CS Interp.') ax[i].legend(bbox_to_anchor=(1.01, 0.5), fontsize=legend_font_size) plt.suptitle(short_name + ' Seeing Measurements', fontsize=title_size) plt.subplots_adjust(left=0.07, wspace=0.05, top=0.92, bottom=0.17) output_filename = pines_path / ('Objects/' + short_name + '/analysis/diagnostic_plots/' + short_name + '_seeing.png') plt.savefig(output_filename, dpi=300) return
def absolute_image_position_plot(target, centroided_sources): pines_path = pines_dir_check() short_name = short_name_creator(target) #Get plot style parameters. title_size, axis_title_size, axis_ticks_font_size, legend_font_size = plot_style( ) #Get list of souce names in the centroid output. source_names = get_source_names(centroided_sources) centroided_sources.columns = centroided_sources.keys().str.strip() #Get times from the centroid output and split them by night. times_full = np.array(centroided_sources['Time (JD UTC)']) night_inds = night_splitter(times_full) num_nights = len(night_inds) times_nights = [times_full[night_inds[i]] for i in range(num_nights)] standard_x = standard_x_range(times_nights) source = source_names[0] fig, ax = plt.subplots(nrows=2, ncols=num_nights, figsize=(17, 9), sharex='col', sharey='row') plt.subplots_adjust(left=0.07, hspace=0.05, wspace=0.05, top=0.92, bottom=0.17) for j in range(num_nights): if j == 0: ax[0, j].set_ylabel('Image X', fontsize=axis_title_size) ax[1, j].set_ylabel('Image Y', fontsize=axis_title_size) inds = night_inds[j] times = times_nights[j] absolute_x = np.array(centroided_sources[source + ' Image X'][inds], dtype='float') absolute_y = np.array(centroided_sources[source + ' Image Y'][inds], dtype='float') ax[0, j].plot(times, absolute_x, marker='.', linestyle='', alpha=0.3, color='tab:blue', label='Raw x') ax[1, j].plot(times, absolute_y, marker='.', linestyle='', alpha=0.3, color='tab:orange', label='Raw y') #bin block_inds = block_splitter(times) block_times = np.zeros(len(block_inds)) block_x = np.zeros(len(block_inds)) block_x_err = np.zeros(len(block_inds)) block_y = np.zeros(len(block_inds)) block_y_err = np.zeros(len(block_inds)) for k in range(len(block_inds)): try: block_times[k] = np.nanmean(times[block_inds[k]]) block_x[k] = np.nanmean(absolute_x[block_inds[k]]) block_x_err[k] = np.nanstd( absolute_x[block_inds[k]]) / np.sqrt( len(absolute_x[block_inds[k]])) block_y[k] = np.nanmean(absolute_y[block_inds[k]]) block_y_err[k] = np.nanstd( absolute_y[block_inds[k]]) / np.sqrt( len(absolute_y[block_inds[k]])) except: pdb.set_trace() ax[0, j].errorbar(block_times, block_x, block_x_err, marker='o', linestyle='', color='tab:blue', ms=8, mfc='none', mew=2, label='Bin x') ax[1, j].errorbar(block_times, block_y, block_y_err, marker='o', linestyle='', color='tab:orange', ms=8, mfc='none', mew=2, label='Bin y') ax[0, j].tick_params(labelsize=axis_ticks_font_size) ax[1, j].tick_params(labelsize=axis_ticks_font_size) ax[0, j].grid(alpha=0.2) ax[1, j].grid(alpha=0.2) ax[1, j].set_xlabel('Time (JD UTC)', fontsize=axis_title_size) if j == num_nights - 1: ax[0, j].legend(bbox_to_anchor=(1.29, 1), fontsize=legend_font_size) ax[1, j].legend(bbox_to_anchor=(1.29, 1), fontsize=legend_font_size) plt.suptitle(source + ' Image Centroid Positions', fontsize=title_size) #plt.subplots_adjust(left=0.07, hspace=0.05, wspace=0.05, top=0.92, bottom=0.08, right=0.85) #ax.legend(bbox_to_anchor=(1.01, 1), fontsize=14) ax[0, j].set_xlim( np.mean(times) - standard_x / 2, np.mean(times) + standard_x / 2) ax[1, j].set_xlim( np.mean(times) - standard_x / 2, np.mean(times) + standard_x / 2) output_filename = pines_path / ('Objects/' + short_name + '/analysis/diagnostic_plots/' + source + '_image_positions.png') plt.savefig(output_filename, dpi=300) return
def relative_cutout_position_plot(target, centroided_sources): pines_path = pines_dir_check() short_name = short_name_creator(target) #Get plot style parameters. title_size, axis_title_size, axis_ticks_font_size, legend_font_size = plot_style( ) #Get list of souce names in the centroid output. source_names = get_source_names(centroided_sources) centroided_sources.columns = centroided_sources.keys().str.strip() #Get times from the centroid output and split them by night. times_full = np.array(centroided_sources['Time (JD UTC)']) night_inds = night_splitter(times_full) num_nights = len(night_inds) times_nights = [times_full[night_inds[i]] for i in range(num_nights)] standard_x = standard_x_range(times_nights) #Get the box size (I don't like that this is being determined by using the mean of the data...output it from centroider?) box_w = int( np.round( 2 * np.nanmean( np.array(centroided_sources['Reference 1 Cutout X'], dtype='float')), 0)) fig, ax = plt.subplots(nrows=2, ncols=num_nights, figsize=(17, 9), sharey=True) plt.subplots_adjust(left=0.07, hspace=0.05, wspace=0.05, top=0.92, bottom=0.17) markers = ['+', 'x', '*', 'X'] for j in range(num_nights): inds = night_inds[j] if j == 0: ax[0, j].set_ylabel('Cutout X Position', fontsize=axis_title_size) ax[1, j].set_ylabel('Cutout Y Position', fontsize=axis_title_size) for i in range(len(source_names)): cutout_x = np.array(centroided_sources[source_names[i] + ' Cutout X'][inds], dtype='float') cutout_y = np.array(centroided_sources[source_names[i] + ' Cutout Y'][inds], dtype='float') if i == 0: marker = 'o' label = 'Target' else: marker = markers[(i - 1) % len(markers)] label = 'Ref. ' + str(i) ax[0, j].plot(times_nights[j], cutout_x, marker=marker, label=label, linestyle='') ax[1, j].plot(times_nights[j], cutout_y, marker=marker, linestyle='') ax[0, j].tick_params(labelsize=axis_ticks_font_size) ax[0, j].set_xticklabels([]) ax[0, j].axhline(box_w / 2, zorder=0, color='r', label='Center pix.', lw=2) ax[0, j].set_xlim( np.mean(times_nights[j]) - standard_x / 2, np.mean(times_nights[j]) + standard_x / 2) ax[0, j].grid(alpha=0.2) ax[1, j].tick_params(labelsize=axis_ticks_font_size) ax[1, j].axhline(box_w / 2, zorder=0, color='r', label='Center pix.', lw=2) ax[1, j].set_xlim( np.mean(times_nights[j]) - standard_x / 2, np.mean(times_nights[j]) + standard_x / 2) ax[1, j].set_xlabel('Time (JD UTC)', fontsize=axis_title_size) ax[1, j].grid(alpha=0.2) if j == num_nights - 1: ax[0, j].legend(bbox_to_anchor=(1.01, 1.0), fontsize=legend_font_size) plt.suptitle(short_name + ' Cutout Centroid Positions', fontsize=title_size) output_filename = pines_path / ('Objects/' + short_name + '/analysis/diagnostic_plots/' + short_name + '_cutout_positions.png') plt.savefig(output_filename, dpi=300) return