def flux_arc(self, my_image_file, Rad, test_src_coord, wavelength): r = Rad * u.arcsec arc_r_in = r - (37. * u.arcsec) arc_r_out = r + (37. * u.arcsec) bkg_r_in = r * 1.1 bkg_r_out = r * 1.25 # load the file data, header, and wcs with fits.open(my_image_file) as hdulist: my_hdu = hdulist[0] my_hdu.data = np.nan_to_num(my_hdu.data) pixel_area = my_hdu.header['PXSCAL1']**2 position = SkyCoord(test_src_coord[0] * u.degree, test_src_coord[1] * u.degree, frame='icrs') print('Running arc aperture photometry {}-{} um'.format( self.name, str(wavelength))) arc_ap = SkyCircularAnnulus(position, r_in=arc_r_in, r_out=arc_r_out) phot_table_arc = aperture_photometry(my_hdu, arc_ap) bkg_ap = SkyCircularAnnulus(position, r_in=bkg_r_in, r_out=bkg_r_out) phot_table_bkg = aperture_photometry(my_hdu, bkg_ap) # bkg subtract flux_bkg_sub = phot_table_arc['aperture_sum'] - phot_table_bkg[ 'aperture_sum'] # convert to Jy if flux_bkg_sub.value > 0: ujy_arcsec = flux_bkg_sub.value * 23.5045 Jy = ujy_arcsec * pixel_area * 1.e-06 Jy = Jy[0] erg = (Jy * 1.e-23) * (2.997924e14 / ((wavelength)**2)) # we must divide the circumference by the MIRI imager FOV height to get # average flux in a MIRI Imager FOV circum = 2 * np.pi * Rad n_miri_ima = circum / 113. self.arc_flux_Jy = Jy / n_miri_ima self.arc_flux_erg = erg / n_miri_ima else: self.arc_flux_Jy = 0.0 self.arc_flux_erg = 0.0 return self.arc_flux_erg
def get_photometry_ingredients(fits_file, RAs, DECs, aperture_radii, annuli_inner_radii, annuli_outer_radii): # Get data, wcs data, h = fits.getdata(fits_file, header=True) w = WCS(h) # Define positions where aperture photometry will be performed positions = SkyCoord(ra=RAs, dec=DECs, unit='deg') # Create apertures at positions for photometry aperture_sky = [ SkyCircularAperture(positions, r=r) for r in aperture_radii ] # Turn apertures defined in sky coordinates into pixel coordinates aperture_pixel = [a_sky.to_pixel(wcs=w) for a_sky in aperture_sky] # Perform aperture photometry phot = aperture_photometry(data, aperture_pixel) # Get out Array of aperture sums and areas aperture_sums = [] aperture_areas = [] for ii in range(len(aperture_radii)): aperture_sums.append(phot['aperture_sum_' + str(ii)]) aperture_areas.append(aperture_pixel[ii].area) background_medians = [] # Get background medians for r_inner, r_outer in zip(annuli_inner_radii, annuli_outer_radii): # Define annulus aperture annulus_aperture_sky = SkyCircularAnnulus(positions, r_in=r_inner, r_out=r_outer) # Turn annulus defined in sky coordinates to pixel coordinates annulus_masks_pixel = annulus_aperture_sky.to_pixel(wcs=w) # Define annuli masks to get annuli values from data: annulus_masks = annulus_masks_pixel.to_mask(method='center') # Get median background value around each apperture position bkg_median = [] for mask in annulus_masks: annulus_data = mask.multiply(data) annulus_data_1d = annulus_data[mask.data > 0] _, median_sigclip, _ = sigma_clipped_stats(annulus_data_1d) bkg_median.append(median_sigclip) bkg_median = np.array(bkg_median) background_medians.append(bkg_median) return np.array(aperture_sums), np.array(aperture_areas), np.array( background_medians)
def aperature_f(field, band, aper_rad=2., annu_in=3., annu_out=6.): hdu = fits.open("final/coadd_c%s_%s.fits" % (field, band)) pos_filename = os.path.join('final', 'test%s_%s.fits' % (field, 'i')) if not os.path.isfile(pos_filename): print 'sextracting the i band position for %s' % field pos_filename = sex_band(field, 'i') t7 = Table.read(pos_filename) positions = SkyCoord(t7['XWIN_WORLD'], t7['YWIN_WORLD'], frame='icrs') apertures = SkyCircularAperture(positions, r=aper_rad * u.arcsec) annulus_apertures = SkyCircularAnnulus(positions, r_in=annu_in * u.arcsec, r_out=annu_out * u.arcsec) apers = [apertures, annulus_apertures] phot_table = aperture_photometry(hdu[0], apers) phot_table2 = phot_table[np.isfinite(phot_table['aperture_sum_0'])] phot_table3 = phot_table2[np.where(phot_table2['aperture_sum_0'] > 0)] snr = phot_table3['aperture_sum_0'] / (np.sqrt( phot_table3['aperture_sum_0'])) phot_table3['snr'] = snr for name in phot_table3.colnames[1:]: phot_table3.rename_column(name, name + '_%s' % band) return phot_table3
def photometry(): filters = ['I', 'B', 'V', 'R'] #filter names # create a table here for Photometry results photo_table = Table(names=('Residuals', 'Error', 'Time')) Photometry = open('photometry_' + str(sn_name) + '.txt', 'w') for f in filters: #create a txt file where the Photometry Results table will be saved #join the two paths given above search_str = os.path.join(date_search_path, str(sn_name) + str(f) + '.fits') #names will be the supernova fits files for different filters for name in glob(search_str): with fits.open(name) as analysis: N = analysis[0].header[ 'NCOMBINE'] # number of images stacked in the fit file final_date = convert_time( analysis) # The Time series must be MJD #Position of Supernova as coordinate, aperture is calculated with the coordinate cordinate = SkyCoord('01:48:08.66 +37:33:29.22', unit=(u.hourangle, u.deg)) #coordinates = SkyCoord('01:48:08.66 +37:33:29.22',unit = (u.hourangle, u.deg)) #exp_time= analysis[0].header['EXPTIME'] #data_error = np.sqrt(N*analysis[0].data) aperture = SkyCircularAperture(cordinate, r=5 * u.arcsec) annulus_apertures = SkyCircularAnnulus(cordinate, r_in=6 * u.arcsec, r_out=8 * u.arcsec) aperture_area = np.pi * 3**2 annulus_area = np.pi * (8**2 - 6**2) rawflux_table = aperture_photometry(analysis[0], aperture) bkgflux_table = aperture_photometry(analysis[0], annulus_apertures) residual_sum = rawflux_table[0]['aperture_sum'] - bkgflux_table[ 0]['aperture_sum'] * aperture_area / annulus_area error = np.sqrt(np.abs(residual_sum) * N) photo_table.add_row((residual_sum, error, final_date)) print "***** Photometry Results without Calibration ****" print photo_table print >> Photometry, photo_table Photometry.close() calibration(N)
def ap_phot(inp_img, rad_ap, rad_sky_i, rad_sky_o, show_plot=True): # Define Aperture Pars =========== ap = SkyCircularAperture(inp_img['coords_sky'], r=rad_ap) # Roughly WISE4 PSF sky = SkyCircularAnnulus(inp_img['coords_sky'], r_in=rad_sky_i, r_out=rad_sky_o) ap_px = ap.to_pixel(wcs=inp_img['wcs']) sky_px = sky.to_pixel(wcs=inp_img['wcs']) # Perform Photometry ============= phot_dat = aperture_photometry(inp_img['data'], ap, wcs=inp_img['wcs']) phot_sky = aperture_photometry(inp_img['data'], sky, wcs=inp_img['wcs']) bkg_mean = phot_sky['aperture_sum'] / sky_px.area() phot_dat['Phot'] = phot_dat['aperture_sum'] - (bkg_mean * ap_px.area()) # Compute S/N ==================== sky_stats = sample_comp.get_photmask_stats(sky_px, inp_img=inp_img['data']) ap__stats = sample_comp.get_photmask_stats(ap_px, inp_img=inp_img['data']) phot_dat['SN'] = (ap__stats['max'] - sky_stats['mean']) / sky_stats['std'] for col in ['aperture_sum', 'Phot', 'SN']: phot_dat[col].format = '10.2f' if show_plot: fig = plt.figure(figsize=[7, 7]) ax = plt.subplot(111) img = ax.imshow(inp_img['data'], origin='lower', cmap='viridis') ap_px.plot() sky_px.plot(color='red') plt.show() return { 'phot_tab': phot_dat, 'phot_ap_px': ap_px, 'phot_sky_px': sky_px }
def measure_aper_flux(hdu, aper): # create mask (set True for where you want to mask) im_mask = im == 0 # define circular aperture and annulus aperture for background subtraction aper = SkyCircularAperture(coords, r=radius) aper_annulus = SkyCircularAnnulus(coords, annulus[0], annulus[1]) mask = aper_annulus.to_pixel(w).to_mask(method="center").data annulus_data = aper_annulus.to_pixel(w).to_mask( method="center").multiply(im) annulus_data_1d = annulus_data[mask > 0] annulus_mask = aper_annulus.to_pixel(w).to_mask( method="center").multiply(im_mask) annulus_mask_1d = annulus_mask[mask > 0] # determine fractional fiber coverage apcor_im = aper.to_pixel(w).to_mask( method="center").multiply(im_mask) / aper.to_pixel(w).to_mask( method="center").multiply(np.ones_like(im)) apcor = np.sum(apcor_im == 0) / np.sum(np.isfinite(apcor_im)) # get median and standard deviation in background mean_sigclip, median_sigclip, stddev_sigclip = sigma_clipped_stats( annulus_data_1d, mask=annulus_mask_1d) bkg_median = median_sigclip * aper.to_pixel(w).area * apcor bkg_stddev = stddev_sigclip * aper.to_pixel(w).area * apcor phottable = aperture_photometry( hdu[0].data, [aper, aper_annulus], error=hdu[1].data, mask=im_mask, wcs=wcs.WCS(hdu[0].header), ) if np.abs(bkg_median) > 2 * bkg_stddev: flux = (phottable["aperture_sum_0"][0] - bkg_median) * u.Unit("10^-17 erg cm-2 s-1") else: flux = (phottable["aperture_sum_0"][0]) * u.Unit("10^-17 erg cm-2 s-1") flux_err = phottable["aperture_sum_err_0"][0] * u.Unit( "10^-17 erg cm-2 s-1") if plot: plt.subplot(111, projection=w) plt.imshow(im, vmin=0 * stddev_sigclip, vmax=3 * stddev_sigclip) aper.to_pixel(w).plot(color="white") # for SkyCircularAperture aper_annulus.to_pixel(w).plot(color="red", linestyle="dashed") plt.xlabel("RA") plt.ylabel("Dec") plt.colorbar() if plottitle is not None: plt.title(plottitle) return flux, flux_err, bkg_stddev * u.Unit("10^-17 erg cm-2 s-1"), apcor
def set_mask( self, *args, method: str = "source", inner: float = None, outer: float = None, position: SkyCoord = None, wcs: WCS = None, **kwargs, ): """ Set a mask to the data image :param method: the method to set mask, "source", or "annulus"defaults to "source" :type method: str, optional :param inner: the inner radius of the annulus, defaults to None :type inner: float, optional :param outer: the outer radius of the annulus, defaults to None :type outer: float, optional :param position: the center of the annulus, defaults to None :type position: SkyCoord, optional :param wcs: the wcs used to convert mask to pixel, defaults to None :type wcs: WCS, optional :raises ValueError: "annulus" must have position and inner/outer radius """ if method == "source": self._mask = make_source_mask(self.data, *args, **kwargs) elif method == "annulus": if not position or not inner or not outer: raise ValueError( "Use annulus mask but missing position or inner/outer radius" ) else: if not wcs: logging.warning( "Not assign the wcs, try the wcs from the header") wcs = self.header mask = (SkyCircularAnnulus( position, inner * u.arcsec, outer * u.arcsec).to_pixel(wcs).to_mask("center")) self._mask = self.ImageMask(shape="annulus", position=position, rin=inner, rout=outer, mask=mask) # self.mask = self.aper.to_mask("center") else: raise ValueError(f"No supported method: {method}")
def simpleapphot(fileName, pos, r, rI, rO, frame='image'): '''Performs simple circular aperture photometry with local bg subtraction ''' # Check Type of pos first if not isinstance(pos, np.ndarray): pos = np.array(pos) if pos.ndim == 1: pos = pos.reshape((-1, 2)) # Create Aperture frame = frame.lower() if frame == 'image': # Create the Aperatures cirAps = CircularAperture(pos, r) annAps = CircularAnnulus(pos, rI, rO) elif frame == 'fk5': # Create Sky Apertures pos = SkyCoord(frame=frame, ra=pos[:, 0] * u.deg, dec=pos[:, 1] * u.deg) cirAps = SkyCircularAperture(pos, r * u.arcsec) annAps = SkyCircularAnnulus(pos, rI * u.arcsec, rO * u.arcsec) else: raise ValueError('Unsupported coordinate system.') # Load in the files and do photometry hdu = fits.open(fileName) cirPhotTab = aperture_photometry(hdu, cirAps) annPhotTab = aperture_photometry(hdu, annAps) if frame == 'fk5': cirAps = cirAps.to_pixel(WCS(header=hdu['SCI'].header)) annAps = annAps.to_pixel(WCS(header=hdu['SCI'].header)) hdu.close() # Get Photometry as ndarray phot = cirPhotTab['aperture_sum'].data - \ (cirAps.area()/annAps.area())*annPhotTab['aperture_sum'].data return phot
def set_apertures(catalog, limit=16, r=10, r_in=15.5, r_out=25): ''' From Anna Marini: get a catalog and set apertures and annulus for photometry. ''' radec = catalog['ra', 'dec', 'phot_g_mean_mag'] mask = radec['phot_g_mean_mag'] < limit radec = radec[mask] positions = SkyCoord(radec['ra'], radec['dec'], frame='fk5', unit=(u.deg, u.deg)) aperture = SkyCircularAperture(positions, r=r * u.arcsec) annulus = SkyCircularAnnulus(positions, r_in=r_in * u.arcsec, r_out=r_out * u.arcsec) apers = [aperture, annulus] return apers
def ap_phot(self, my_image_file, Rad, test_src_coord, wavelength): """ ap_phot applies aperture photometry to calculate the flux of the source. It creates a circle aperture around the source referencing the radius of the snr as the radius of the circular aperture. It also creates 4 more apertures away from the source which are then averaged and subtracted from the target flux to remove background Input ========================== my_image_files (.fits): .fits file from coordinates Rad (float): radius in units of arcsec test_src_coord (float): coordinates of target in decimal degrees wavelength (float): waveband in units of um Output ========================== FluxIR (float): calculated flux in units of erg/s/cm^2 """ fluxes = [] r = Rad * u.arcsec r_in = r + (40. * u.arcsec) r_out = r + (100. * u.arcsec) # load the file data, header, and wcs with fits.open(my_image_file) as hdulist: my_hdu = hdulist[0] my_hdu.data = np.nan_to_num(my_hdu.data) pixel_area = my_hdu.header['PXSCAL1']**2 print('Running aperture photometry {}-{} um'.format( self.name, str(wavelength))) position = SkyCoord(test_src_coord[0] * u.degree, test_src_coord[1] * u.degree, frame='icrs') apertures = SkyCircularAperture(position, r=Rad * u.arcsec) phot_table = aperture_photometry(my_hdu, apertures) fluxes.append(phot_table['aperture_sum']) #print(phot_table['aperture_sum']) print('Running background aperture photometry {}-{} um'.format( self.name, str(wavelength))) bkg_ap = SkyCircularAnnulus(position, r_in=r_in, r_out=r_out) phot_table_bkg = aperture_photometry(my_hdu, bkg_ap) #print(phot_table_bkg['aperture_sum']) # bkg subtract flux_bkg_sub = phot_table['aperture_sum'] - phot_table_bkg[ 'aperture_sum'] # convert to Jy if flux_bkg_sub.value > 0: ujy_arcsec = flux_bkg_sub.value * 23.5045 Jy = ujy_arcsec * pixel_area * 1.e-06 Jy = Jy[0] erg = (Jy * 1.e-23) * (2.997924e14 / ((wavelength)**2)) self.flux_Jy = Jy self.flux_erg = erg else: erg = 0.0 self.flux_Jy = 0.0 self.flux_erg = 0.0 return erg
def qphot(data, coord, rad, skyradin, skyradout, wcs=None, calfctr=None, skycoord=None, unit='Jy', error=None, filter=None): if is_pix_coord(coord): coord = [np.float(coord[0]), np.float(coord[1])] aperture = CircularAperture(coord, r=rad) else: coord = SkyCoord(' '.join(coord), unit=(u.hourangle, u.deg), frame='icrs') aperture = SkyCircularAperture(coord, r=rad * u.arcsec) if skycoord: if is_pix_coord(skycoord): scoord = [np.float(skycoord[0]), np.float(skycoord[1])] annulus = CircularAnnulus(scoord, skyradin, skyradout) else: scoord = SkyCoord(' '.join(skycoord), unit=(u.hourangle, u.deg), frame='icrs') annulus = SkyCircularAnnulus(scoord, skyradin * u.arcsec, skyradout * u.arcsec) else: if isinstance(coord, SkyCoord): annulus = SkyCircularAnnulus(coord, skyradin * u.arcsec, skyradout * u.arcsec) else: annulus = CircularAnnulus(coord, skyradin, skyradout) #mask out nans or negative mask = np.logical_or(np.isnan(data), data < 0.) apflux = aperture_photometry(data, aperture, wcs=wcs, error=error, mask=mask) skyflux = aperture_photometry(data, annulus, wcs=wcs, error=error, mask=mask) phot_table = hstack([apflux, skyflux], table_names=['src', 'sky']) #calculate mean local background in annulus if isinstance(annulus, SkyCircularAnnulus): sky_area = annulus.to_pixel(wcs).area() else: sky_area = annulus.area() if isinstance(aperture, SkyCircularAperture): src_area = aperture.to_pixel(wcs).area() else: src_area = aperture.area() sky_mean = phot_table['aperture_sum_sky'] / sky_area sky_sum = sky_mean * src_area final_sum = phot_table['aperture_sum_src'] - sky_sum phot_table['residual_aperture_sum'] = final_sum phot_table['residual_aperture_sum'].unit = unit phot_table['aperture_area_sky'] = sky_area phot_table['aperture_area_src'] = src_area phot_table['aperture_mean_sky'] = sky_mean phot_table['aperture_mean_sky'].unit = unit phot_table['aperture_rad_src'] = rad phot_table['aperture_irad_sky'] = skyradin phot_table['aperture_orad_sky'] = skyradout phot_table['aperture_area_sky'].unit = u.pix**2 phot_table['aperture_area_src'].unit = u.pix**2 if error is not None: src_err = phot_table['aperture_sum_err_src'] sky_err = phot_table['aperture_sum_err_sky'] src_var = src_err / phot_table['residual_aperture_sum'] sky_var = sky_err / sky_sum color_err = 0. # 10 percent photoerr color_var = color_err * phot_table['residual_aperture_sum'] phot_table['residual_aperture_err'] = np.sqrt(src_var**2 + sky_var**2 + color_var**2) else: color_err = 0.07 # 7 percent photoerr color_var = color_err * sky_sum phot_table.add_column( Column([color_var for x in phot_table], name='residual_aperture_err')) phot_table.remove_columns( ['xcenter_src', 'ycenter_src', 'xcenter_sky', 'ycenter_sky']) if 'center_input' in phot_table.colnames: phot_table.remove_columns('center_input') if 'center_input_src' in phot_table.colnames: phot_table.remove_columns('center_input_src') if 'center_input_sky' in phot_table.colnames: phot_table.remove_columns('center_input_sky') if isinstance(coord, SkyCoord): phot_table['xcen'], phot_table['ycen'] = wcs2pix(coord, wcs) phot_table['ra'], phot_table['dec'] = coord.to_string('hmsdms', sep=':').split() else: phot_table['xcen'] = coord[0] phot_table['ycen'] = coord[1] if skycoord: if isinstance(scoord, SkyCoord): phot_table['xcensky'], phot_table['ycensky'] = wcs2pix(scoord, wcs) phot_table['rasky'], phot_table['decsky'] = scoord.to_string( 'hmsdms', sep=':').split() else: phot_table['xcensky'] = scoord[0] phot_table['ycensky'] = scoord[1] if wcs: if 'ra' not in phot_table.colnames: ra, dec = pix2wcs(coord, wcs) phot_table['ra'] = ra phot_table['dec'] = dec if skycoord: if 'rasky' not in phot_table.colnames: skyra, skydec = pix2wcs(scoord, wcs) phot_table['rasky'] = skyra phot_table['decsky'] = skydec if calfctr: flux = phot_table['residual_aperture_sum'] / calfctr phot_table.add_column(Column(flux, name='ap_flux', unit=unit)) #if error is not None: fluxerr = phot_table['residual_aperture_err'] / calfctr phot_table.add_column(Column(fluxerr, name='ap_err', unit=unit)) if filter: phot_table['filter'] = str(filter) return phot_table
def extract_photometry(ccddata, catalog, catalog_coords, target, image_path=None, aperture_radius=2. * u.arcsec, bg_radius_in=None, bg_radius_out=None): apertures = SkyCircularAperture(catalog_coords, aperture_radius) if bg_radius_in is not None and bg_radius_out is not None: apertures = [ apertures, SkyCircularAnnulus(catalog_coords, bg_radius_in, bg_radius_out) ] photometry = aperture_photometry(ccddata, apertures) target_row = photometry[target][0] if target_row['xcenter'].value < 0. or target_row['xcenter'].value > ccddata.shape[1] or \ target_row['ycenter'].value < 0. or target_row['ycenter'].value > ccddata.shape[0]: logging.error( 'target not contained in the image (or coordinate solution is bad)' ) return if 'aperture_sum_1' in photometry.colnames: flux = photometry['aperture_sum_0'] - photometry['aperture_sum_1'] dflux = (photometry['aperture_sum_err_0']**2. + photometry['aperture_sum_err_1']**2.)**0.5 else: flux = photometry['aperture_sum'] dflux = photometry['aperture_sum_err'] photometry['aperture_mag'] = u.Magnitude(flux / ccddata.meta['exptime']) photometry['aperture_mag_err'] = 2.5 / np.log(10.) * dflux / flux photometry = hstack([catalog, photometry]) photometry['zeropoint'] = photometry['catalog_mag'] - photometry[ 'aperture_mag'].value zeropoints = photometry['zeropoint'][~target].filled(np.nan) zp = np.nanmedian(zeropoints) zperr = mad_std( zeropoints, ignore_nan=True) / np.isfinite(zeropoints).sum()**0.5 # std error target_row = photometry[target][0] mag = target_row['aperture_mag'].value + zp dmag = (target_row['aperture_mag_err'].value**2. + zperr**2.)**0.5 with open(lc_file, 'a') as f: f.write( f'{ccddata.meta["MJD-OBS"]:11.5f} {mag:6.3f} {dmag:5.3f} {zp:6.3f} {zperr:5.3f} {ccddata.meta["FILTER"]:>6s} ' f'{ccddata.meta["TELESCOP"]:>16s} {ccddata.meta["filename"]:>22s}\n' ) if image_path is not None: ax = plt.axes() mark = ',' if np.isfinite( photometry['aperture_mag']).sum() > 1000 else '.' ax.plot(photometry['aperture_mag'], photometry['catalog_mag'], ls='none', marker=mark, zorder=1, label='calibration stars') ax.plot(mag - zp, mag, ls='none', marker='*', zorder=3, label='target') yfit = np.array([21., 13.]) xfit = yfit - zp ax.plot(xfit, yfit, label=f'$Z = {zp:.2f}$ mag', zorder=2) ax.set_xlabel('Instrumental Magnitude') ax.set_ylabel('AB Magnitude') ax.legend() plt.savefig(image_path, overwrite=True) plt.savefig('latest_cal.pdf', overwrite=True) plt.close() plt.figure(figsize=(6., 6.)) imshow_norm(ccddata.data, interval=ZScaleInterval()) plt.axis('off') plt.axis('tight') plt.tight_layout(pad=0.) if isinstance(apertures, list): for aperture in apertures: aperture.to_pixel(ccddata.wcs).plot(color='r', lw=1) else: apertures.to_pixel(ccddata.wcs).plot(color='r', lw=1) image_filename = ccddata.meta['filename'].replace('.fz', '').replace( '.fits', '.png') plt.savefig(os.path.join(image_dir, image_filename), overwrite=True) plt.savefig('latest_image.png', overwrite=True) plt.close()
def generate_regions(hdu, approx_location, centering_width=80, ap_rad=6.5, in_rad=7.0, out_rad=14.0): """ Generates source and background regions for aperture photometry. Given an image and the approximate RA/Dec of the source, finds the centroid within centering_width pixels and generates regions with the given parameters Parameters ---------- hdu : `~astropy.io.fits.hdu.image.PrimaryHDU` HDU object containing the FITS image from which regions are generated. Should be just the primary hdu (e.g., hdu[0]). approx_location : `~astropy.coordinates.SkyCoord` `astropy.coordinates.SkyCoord` with the RA and Dec of the object you want to generate a region for. centering_width : int, optional Size of box around source region to find the centroid of in pixels. ap_rad : float, optional Radius of source region in arcseconds. in_rad : float, optional Inner radius of background annulus in arcseconds out_rad : float, optional Outer radius of background annulus in arcseconds Returns ------- src : `~photutils.SkyCircularAperture` Aperture object for source bkg : `~photutils.SkyCircularAnnulus` Aperture object for background """ #Make data and wcs objects data = hdu.data wcs = WCS(hdu) #Make the right shape array of coordinates world_loc = np.array( [[approx_location.ra.value, approx_location.dec.value]]) #Convert to pixel coordinates from the FITS image, 0 indexed b.c. we're working with #a numpy array approx_pix = wcs.wcs_world2pix(world_loc, 0)[0] #Convert to pixel locations of the window. min_x = int(approx_pix[0] - centering_width / 2.0) min_y = int(approx_pix[1] - centering_width / 2.0) max_x = int(approx_pix[0] + centering_width / 2.0) max_y = int(approx_pix[1] + centering_width / 2.0) #Make a little cutout around the object #Numpy arrays are weird, so x->y, y->x stamp = data[min_y:max_y, min_x:max_x] #Calculate the centroid of the stamp x_stamp_centroid, y_stamp_centroid = centroid_com(stamp) #Add back in the boundaries of the box to get centroid in data coords x_centroid = x_stamp_centroid + min_x y_centroid = y_stamp_centroid + min_y #Convert back to RA/Dec. Remember, these are 0-indexed pixels. centroid = wcs.wcs_pix2world(np.array([[x_centroid, y_centroid]]), 0) #Convert centroid to SkyCoords object location = SkyCoord(ra=centroid[0, 0] * u.degree, dec=centroid[0, 1] * u.degree) #Generate regions based on coordinates and given radii. src = SkyCircularAperture(location, r=ap_rad * u.arcsecond) bkg = SkyCircularAnnulus(location, r_in=in_rad * u.arcsecond, r_out=out_rad * u.arcsecond) return src, bkg
def cal_image(img_path): image_path = os.path.join(basepath, img_path) # load img with WCS if not '.new' in image_path: img = image_path.strip('.fits') + '.new' else: img = image_path fits_file = fits.open(img, mode='update') hdr = fits_file[0].header #fits.getheader(img) data = fits_file[0].data # fits.getdata(img) wcs = WCS(hdr) # Obtain image center crval_ra= hdr['CRVAL1'] crval_dec = hdr['CRVAL2'] crval_x = hdr['CRPIX1'] crval_y = hdr['CRPIX2'] # Get sources in image mask = make_source_mask(data, snr=2, npixels=5, dilate_size=11) mask_zeros = data==0 mask = mask | mask_zeros mean, median, std = sigma_clipped_stats(data, sigma=3.0, mask=mask) sigma_clip = SigmaClip(sigma=3., iters=10) bkg_estimator = MedianBackground() bkg_estimator = SExtractorBackground() bkg = Background2D(data, (50, 50), filter_size=(3, 3), sigma_clip=sigma_clip, bkg_estimator=bkg_estimator, mask=mask) back = bkg.background * ~mask daofind = DAOStarFinder(fwhm=5.0, threshold=5.*std) sources = daofind(data - median) #print(sources) positions = (sources['xcentroid'], sources['ycentroid']) xypos = np.array([sources['xcentroid'], sources['ycentroid']]).T sky_pos = wcs.all_pix2world(xypos, 0) skycoords = coord.SkyCoord(sky_pos*u.deg, frame='icrs') radii = [5.*u.arcsec, 7.*u.arcsec, 10.*u.arcsec] annulus = [(6.*u.arcsec, 8.*u.arcsec), (9.*u.arcsec, 11.*u.arcsec), (11.*u.arcsec, 12.*u.arcsec)] apertures = [SkyCircularAperture(skycoords, r=r).to_pixel(wcs) for r in radii] annulii = [SkyCircularAnnulus(skycoords, r_in=ri, r_out=ro).to_pixel(wcs) for ri, ro in annulus] apers = apertures + annulii #~ tables = [aperture_photometry(data-back, aper) for aper in apers] phot_table = aperture_photometry(data-back, apers) bkg_sum_0 = apertures[0].area()*phot_table['aperture_sum_3']/annulii[0].area() bkg_sum_1 = apertures[0].area()*phot_table['aperture_sum_4']/annulii[1].area() bkg_sum_2 = apertures[0].area()*phot_table['aperture_sum_5']/annulii[2].area() final_sum_0 = phot_table['aperture_sum_0'] - bkg_sum_0 final_sum_1 = phot_table['aperture_sum_1'] - bkg_sum_1 final_sum_2 = phot_table['aperture_sum_2'] - bkg_sum_2 phot_table['resid_aper_sum_0'] = final_sum_0 phot_table['resid_aper_sum_1'] = final_sum_1 phot_table['resid_aper_sum_2'] = final_sum_2 phot_table['cmag_0'] = -2.5 * np.log10(final_sum_0) phot_table['cmag_1'] = -2.5 * np.log10(final_sum_1) phot_table['cmag_2'] = -2.5 * np.log10(final_sum_2) phot_table['mag_0'] = -2.5 * np.log10(phot_table['aperture_sum_0']) phot_table['mag_1'] = -2.5 * np.log10(phot_table['aperture_sum_1']) phot_table['mag_2'] = -2.5 * np.log10(phot_table['aperture_sum_2']) phot_table['RA'] = skycoords.ra phot_table['Dec'] = skycoords.dec # match the catalogs # attempt a xmatch phot_table.write('/tmp/sourcecat.csv', overwrite=True) try: from astroquery.xmatch import XMatch XMatch.TIMEOUT = 600 try: table = XMatch.query(cat1=open('/tmp/sourcecat.csv'), #cat2='vizier:II/336/apass9', #apass cat2='vizier:I/322A/out', # UCAC4 #cat2='vizier:II/246/out', # 2MASS max_distance=5 * u.arcsec, colRA1='RA', colDec1='Dec', colRA2='RAJ2000', colDec2='DEJ2000') print 'Using UCAC4' print table.colnames if 'Rmag' not in table.colnames and 'rmag' in table.colnames: table['Rmag'] = table['rmag'] except: try: table = XMatch.query(cat1=open('/tmp/sourcecat.csv'), cat2='vizier:II/336/apass9', #apass #cat2='vizier:I/322A/out', # UCAC4 #cat2='vizier:II/246/out', # 2MASS max_distance=5 * u.arcsec, colRA1='RA', colDec1='Dec', colRA2='RAJ2000', colDec2='DEJ2000') print 'Using APASS' print table.colnames if 'Rmag' not in table.colnames and 'rmag' in table.colnames: table['Rmag'] = table['rmag'] except: try: table = XMatch.query(cat1=open('/tmp/sourcecat.csv'), #cat2='vizier:II/336/apass9', #apass #cat2='vizier:I/322A/out', # UCAC4 cat2='vizier:II/246/out', # 2MASS max_distance=5 * u.arcsec, colRA1='RA', colDec1='Dec', colRA2='RAJ2000', colDec2='DEJ2000') print 'Using 2MASS' print table.colnames if 'Rmag' not in table.colnames and 'rmag' in table.colnames: table['Rmag'] = table['rmag'] except: print('\ntable 1 avaliable?:') print XMatch.is_table_available('vizier:II/336/apass9') print('\ntable 2 avaliable?:') print XMatch.is_table_available('vizier:I/322A/out') print('\ntable 3 avaliable?:') print XMatch.is_table_available('vizier:II/246/out') raise except: # query PanSTARRS DR1 #~ catalog = panstarrs_query(crval_ra, crval_dec, 0.5, maxsources=300) #~ if len(ps1_tab) < 20: #~ from astroquery.vizier import Vizier #~ catalog = Vizier.query_region(coord.SkyCoord(crval_ra*u.deg, #~ crval_dec*u.deg, #~ frame='icrs'), #~ radius=coord.Angle(0.3, "deg"), #~ catalog='UCAC4')[0] #~ ra = catalog['RAJ2000'] #~ dec = catalog['DEJ2000'] #~ cat = coord.SkyCoord(ra, dec, frame='icrs') #~ # cat to sources #~ idx_c2s, d2d_c2s, _ = skycoords.match_to_catalog_sky(cat) #~ # sources to cat #~ idx_s2c, d2d_s2c, _ = cat.match_to_catalog_sky(skycoords) #~ matches = cat[idx_c2s] # same length than skycoords #~ idx_c2s[idx_s2c] raise from sklearn import linear_model if 'UCAC4' in table.colnames: table['color'] = table['Bmag'] - table['Vmag'] if '2MASS' in table.colnames: table['color'] = table['Jmag'] - table['Kmag'] table['Bmag'] = table['Jmag'] # V Mag plt.subplot(221) reg = linear_model.LinearRegression() sub = table[['mag_1', 'Vmag']].to_pandas() sub = sub.dropna(axis=0, how='any') X = sub[['mag_1']].as_matrix() Y = sub['Vmag'].as_matrix() reg.fit(X,Y) print reg.coef_, reg.intercept_ regV = reg table['pred_Vmag'] = reg.coef_*table['mag_1']+reg.intercept_ plt.plot(table['mag_1'], table['Vmag'], 'r.') plt.plot(table['mag_1'], table['pred_Vmag'], 'k-', label='linear fit') plt.xlabel('mag_1') plt.ylabel('Vmag') plt.grid() # B mag plt.subplot(222) reg = linear_model.LinearRegression() sub = table[['mag_1', 'Bmag']].to_pandas() sub = sub.dropna(axis=0, how='any') X = sub[['mag_1']].as_matrix() Y = sub['Bmag'].as_matrix() reg.fit(X,Y) print reg.coef_, reg.intercept_ regB = reg table['pred_Bmag'] = reg.coef_*table['mag_1']+reg.intercept_ plt.plot(table['mag_1'], table['Bmag'], 'r.') plt.plot(table['mag_1'], table['pred_Bmag'], 'k-', label='linear fit') plt.xlabel('mag_1') plt.ylabel('Bmag') plt.grid() # R mag plt.subplot(223) reg = linear_model.LinearRegression() sub = table[['mag_1', 'Rmag']].to_pandas() sub = sub.dropna(axis=0, how='any') X = sub[['mag_1']].as_matrix() Y = sub['Rmag'].as_matrix() reg.fit(X,Y) print reg.coef_, reg.intercept_ regR = reg table['pred_Rmag'] = reg.coef_*table['mag_1']+reg.intercept_ plt.plot(table['mag_1'], table['Rmag'], 'r.') plt.plot(table['mag_1'], table['pred_Rmag'], 'k-', label='linear fit') plt.xlabel('mag_1') plt.ylabel('Rmag') plt.grid() # Residuals vs B-V plt.subplot(224) plt.plot(table['color'], table['pred_Vmag']-table['Vmag'], 'g.', label='Vmag') plt.plot(table['color'], table['pred_Bmag']-table['Bmag'], 'b.', label='Bmag') plt.plot(table['color'], table['pred_Rmag']-table['Rmag'], 'r.', label='Rmag') plt.xlabel('color') plt.ylabel('Residual') plt.legend(loc='best') plt.grid() plt.tight_layout() plt.savefig(image_path.strip('.new')+'_calibration.png') plt.clf() hdr['ZP_R'] = regR.intercept_ hdr['ZP_B'] = regB.intercept_ hdr['ZP_V'] = regV.intercept_ hdr['SLOPE_R'] = regR.coef_[0] hdr['SLOPE_B'] = regB.coef_[0] hdr['SLOPE_V'] = regV.coef_[0] chosen = {'band': None, 'res': 10} for band in ['R', 'B', 'V']: res = table['pred_'+band+'mag']-table[band+'mag'] residual = np.sqrt(np.sum(np.square(res))) if residual < chosen['res']: chosen['res'] = residual chosen['band'] = band hdr['CAL_BAND'] = chosen['band'] hdr['CAL_RES'] = chosen['res'] fits_file.flush() fits_file.close() band = chosen['band'] plt.hist(table['pred_'+band+'mag']) plt.xlabel('instrumental '+band+' mag') plt.savefig(image_path.strip('.new')+'_magnitudes.png') table.write(image_path.strip('.new')+'_sources.csv', overwrite=True) with open('calibrations.txt', 'a') as cals: cals.write(image_path) cals.write(' ') cals.write('{}'.format(np.max(table['pred_'+band+'mag']))) cals.write(' ') cals.write('{}'.format(np.std(table['pred_'+band+'mag']))) cals.write(' ') cals.write('{}'.format(hdr['ZP_R'])) cals.write(' ') cals.write('{}'.format(hdr['ZP_B'])) cals.write(' ') cals.write('{}'.format(hdr['ZP_V'])) cals.write(' ') cals.write('{}'.format(hdr['SLOPE_R'])) cals.write(' ') cals.write('{}'.format(hdr['SLOPE_B'])) cals.write(' ') cals.write('{}'.format(hdr['SLOPE_V'])) cals.write(' ') cals.write('{}'.format(hdr['CAL_BAND'])) cals.write(' ') cals.write('{}'.format(hdr['CAL_RES'])) cals.write('\n') print 'finished'
def calc_radial_profile(fitsfile, center, rstart, rend, rstep, verbose=False, detmaskfile=None, plot=True): """ Utility function to calculate the radial profile from an image `fitsfile` at a `center` """ # if (not os.path.isfile(fitsfile)): print(f"ERROR. FITS file {fitsfile} not found. Cannot continue.") return None # qhdu = fits.open(fitsfile) wcs = WCS(qhdu[0].header) # # if detmaskfile is provided then will use it for detector mask # doMask = False if (detmaskfile != None): if (not os.path.isfile(detmaskfile)): print(f"Warning. Detector mask file {detmaskfile} not found. Will not use detector mask!") doMask = False else: det = fits.open(detmaskfile) detmask = det['MASK'] # need the WCS wcs_det = WCS(detmask.header) doMask = True # if (not isinstance(center, SkyCoord)): print(f"ERROR: the input radial profile centre is not SkyCoord object. Cannot continue.") return None # j = 0 rx = rstart counts = [] counts_err = [] rmid = [] # emtpy = False while rx < rend: r0 = rstart + rstep * j rx = rstart + rstep * (j + 1) # the mid point, can be better the mid area point rmid.append((r0.value + rx.value) / 2.0) if (j == 0): xap = SkyCircularAperture(center, rx) photo = aperture_photometry(qhdu[0].data, xap, wcs=wcs) if (doMask): masked = aperture_photometry(detmask.data, xap, wcs=wcs_det) else: xap = SkyCircularAnnulus(center, r0, rx) photo = aperture_photometry(qhdu[0].data, xap, wcs=wcs) if (doMask): masked = aperture_photometry(detmask.data, xap, wcs=wcs_det) # ap_area = xap.to_pixel(wcs).area good_area = ap_area if (doMask): good_area = masked['aperture_sum'][0] # compare the two annuli areas: with and without bad pixels if (verbose): print( f"Annulus: {r0:.2f},{rx:.2f},geometric area: {ap_area:.1f} pixels,non-masked area {good_area:.1f} pixels, ratio: {ap_area / good_area:.2f}") # taking into account the masked pixels if (good_area == 0.0): counts.append(float('nan')) counts_err.append(float('nan')) else: counts.append(photo['aperture_sum'][0] / good_area) counts_err.append(np.sqrt(photo['aperture_sum'][0]) / good_area) j += 1 # # convert the results in numpy arrays # rmid = np.array(rmid) counts = np.array(counts) counts_err = np.array(counts_err) # # convert per pixel to per arcsec^2 pix_area = utils.proj_plane_pixel_area(wcs) * 3600.0 * 3600.0 # in arcsec^2 counts = counts / pix_area counts_err = counts_err / pix_area # if (plot): fig, ax = plt.subplots(figsize=(10, 8)) ax.errorbar(rmid, counts, xerr=rstep.value / 2.0, yerr=counts_err) ax.set_xscale('linear') ax.set_yscale('log') ax.set_xlabel('Radial distance (arcsec)') ax.set_ylabel(r'Counts/arcsec$^2$') ax.grid() ax.set_title(f"Radial profile"); qhdu.close() if (doMask): det.close() return rmid, counts, counts_err
def get_counts(dirtarget, ra, dec, fil, aper_rad, ann_in_rad, ann_out_rad, name, date, set_rad=False, centroid_plot=False): """Generates background-substracted aperture sums for a source in an image. Defines source region as a 20x20 square centered at the input R.A. and dec. Source region is checked to ensure it is below the CCD saturation level, and lies entirely in the image. Centroiding is then performed to locate the central pixel of the source. An aperture and annulus are placed around this pixel and the background-subtracted aperture sum is calculated. All returns have size (#source(s) x #image(s)). Parameters ---------- dirtarget : str Directory containing all bias, flat, and raw science images. ra : list List of string(s) of right ascension(s) of object(s) to be processed. dec : list List of string(s) of declination(s) of object(s) to be processed. fil : str Name of filter used for images which are currently being processed. aper_rad : float User-specified aperture radius in arcseconds. ann_in_rad : float User-specified annulus inner radius in arcseconds. ann_out_rad : float User-specified annulus outer radius in arcseconds. name : str Object type that get_counts is being ran on (e.g. target, comp, check). date : str Date of observation. set_rad : Boolean Determine whether user would like to use default aperture/annulus radii or specify their own. centroid_plot : Boolean Whether or not to plot centroid shifts for object. Returns ------- aper_sum : numpy.ndarray Array of floats corresponding to aperture sums of each source. err : numpy.ndarray Array of floats corresponding to uncertainty of each aperture sum. date_obs : numpy.ndarray Array of floats corresponding to Julian Date of each image. altitudes : numpy.ndarray Array of floats corresponding to the altitude of each image. saturated : list List of list(s) containing the file path of any image whose source meets or exceeds the expected saturation level. exptimes : numpy.ndarray Array of floats corresponding to exposure time of each image. init_coords : numpy.ndarray Array of strings corresponding to the pixel coordinates (x,y) of the R.A. and dec. of the image's source, according to its WCS solution. cent_coords : numpy.ndarray Array of strings corresponding to the central pixel coordinates (x,y) of the centroided aperture. If the centroid routine failed, the string 'init' is returned for that image. image_num : numpy.ndarray Array of integers containing the number of each image in dirtarget. sat_qual : numpy.ndarray Data quality mask that contains 0s for images that do not have a saturated source and 1s for source that do. cent_qual : numpy.ndarray Data quality mask that contains 0s for images with successful aperture centroiding and 1s for images with failed centoiding or poor WCS solutions. """ dirtarget_wcs = os.path.join(dirtarget, 'ISR_Images', fil, 'WCS') files = sorted(glob.glob(os.path.join(dirtarget_wcs, '*.fits'))) size_files = len(files) size_sources = len(ra) # Initialize output arrays. # Dimensions: #sources x #(images in dirtarget) aper_sum = np.empty([size_sources, size_files], dtype=float) aper_sum[:][:] = np.nan err = np.empty([size_sources, size_files], dtype=float) err[:][:] = np.nan date_obs = np.empty([size_sources, size_files], dtype=float) date_obs[:][:] = np.nan altitudes = np.empty([size_sources, size_files], dtype=float) altitudes[:][:] = np.nan saturated = [] exptimes = np.empty([size_sources, size_files], dtype=float) exptimes[:][:] = np.nan init_coords = np.empty([size_sources, size_files], dtype=object) init_coords[:][:] = 'init' cent_coords = np.empty([size_sources, size_files], dtype=object) cent_coords[:][:] = 'init' image_num = np.empty([size_sources, size_files], dtype=object) image_num[:][:] = 'init' pix_radius = np.empty(size_sources, dtype=float) pix_radius[:] = np.nan image_arr = np.empty([size_sources, size_files], dtype=float) image_arr[:][:] = np.nan sat_qual = np.empty([size_sources, size_files], dtype=int) sat_qual[:][:] = 0 cent_qual = np.empty([size_sources, size_files], dtype=int) cent_qual[:][:] = 0 for i, (ra_i, dec_i) in enumerate(zip(ra, dec)): print('\nProcessing {} star ({})...'.format(name, fil)) im = None p1 = None p2 = None circ = None fig = None ax = None pix_radius = None saturated_i = [] # Initialize nine evenly-spaced indices to plot a centroiding summary. cent_ind = np.linspace(0, size_files - 1, 9).astype(int) if centroid_plot: fig, ax = plt.subplots(nrows=3, ncols=3, figsize=(10, 8)) ax = ax.flatten() for k in range(0, 9): ax[k].set_title('Image {}'.format(cent_ind[k]), size=10) for l in (ax[k].get_xticklabels() + ax[k].get_yticklabels()): l.set_fontsize(8) # fig_anim, ax_anim = plt.subplots(nrows=1, ncols=1, figsize=(10,8)) # im_anim = plt.imshow() # def animate(i): for j, item in enumerate(files): o_file = os.path.join(dirtarget_wcs, item) hdulist = fits.open(o_file) header = hdulist[0].header data = hdulist[0].data im_str = str(o_file) im_n = im_str[-10:-7] try: int(im_n) except ValueError: im_n = j image_num[i][j] = im_n # Read output information from header of image being processed. exptimes[i][j] = float(header['EXPTIME']) date_j = header['DATE-OBS'] t = Time(date_j) time = t.jd date_obs[i][j] = float(time) altitudes[i][j] = float(header['OBJCTALT']) # Check if WCS solution was successful. if header['WCSMATCH'] < 10: print('\nLess than 10 stars matched in WCS calculation.') cent_qual[i][j] = 1 continue # Find pixel location of R.A. and dec. according to WCS solution w = WCS(header) coords = SkyCoord(ra_i, dec_i, unit=(u.hourangle, u.deg)) px_dec, py_dec = w.wcs_world2pix(coords.ra.deg, coords.dec.deg, 1) px, py = int(px_dec), int(py_dec) init_coords_pix = (px, py) init_coords[i][j] = ','.join(map(str, init_coords_pix)) # Define source region as a 20x20 square centered at (px,py) star = data[(py - 19):(py + 21), (px - 19):(px + 21)] # Check that region lies entirely within image. if ((py - 19) < 0) or ((py + 21) > 2084): print('\n{} star not entirely in the image for'.format(name) + ' image number {}'.format(im_n)) cent_qual[i][j] = 1 continue if ((px - 19) < 0) or ((px + 21) > 3072): print('\n{} star not entirely in the image for'.format(name) + ' image number {}'.format(im_n)) cent_qual[i][j] = 1 continue star_flat = star.reshape(1, len(star) * len(star[0])) # Check that source does not exceed the expected saturation level. max_pix = int(np.amax(star_flat)) if max_pix >= header['SATLEVEL']: print('\n{} star met or exceeded saturation '.format(name) + 'level for image number {}.'.format(im_n)) print('\nSaturation value: {}'.format(header['SATLEVEL'])) print('\nMax aperture value: {}'.format(max_pix)) saturated_i.append(item) sat_qual[i][j] = 1 continue # Peform aperture centroiding for the source. # If centroiding failed, then move onto the next image. FWHM = 4 try: mean, median, std = sigma_clipped_stats(star, sigma=3.0) daofind = DAOStarFinder(fwhm=FWHM, threshold=5. * std) sources = daofind(star - median) px_cent = np.average(sources['xcentroid']) py_cent = np.average(sources['ycentroid']) except TypeError: print('\nCentroiding failed for image {}.'.format(im_n)) cent_qual[i][j] = 1 continue # Return centroided pixel coordinates. x_cent = int(px - 19 + px_cent) y_cent = int(py - 19 + py_cent) cent_coords_pix = (x_cent, y_cent) cent_coords[i][j] = ','.join(map(str, cent_coords_pix)) cent_equa = SkyCoord.from_pixel(x_cent, y_cent, w) # Define aperture and annulus radii. radius = None r_in = None r_out = None if set_rad: radius = float(aper_rad) * u.arcsec r_in = float(ann_in_rad) * u.arcsec r_out = float(ann_out_rad) * u.arcsec else: radius = 4 * u.arcsec r_in = 25 * u.arcsec r_out = 27 * u.arcsec # Create SkyCircularAperture and SkyCircularAnnulus objects # centered at the position of the star whose counts are being # summed. aperture = SkyCircularAperture(cent_equa, radius) annulus = SkyCircularAnnulus(cent_equa, r_in=r_in, r_out=r_out) apers = (aperture, annulus) secpix1 = abs(hdulist[0].header['SECPIX1']) # Determine the area of the aperture and annulus using the # arcseconds per pixel in the horizontal dimension header keyword. aper_area = np.pi * (radius / secpix1)**2 area_out = np.pi * (r_out / secpix1)**2 area_in = np.pi * (r_in / secpix1)**2 annulus_area = area_out - area_in pix_radius = radius.value / secpix1 # Call aperture_photometry function in order to sum all of the # counts in both the aperture and annulus for item. phot_table = aperture_photometry(hdulist, apers) # Remove the background level from the aperture sum. bkg_mean = phot_table['aperture_sum_1'] / annulus_area bkg_sum = bkg_mean * aper_area final_sum = phot_table['aperture_sum_0'] - bkg_sum phot_table['residual_aperture_sum'] = final_sum # Determine the error in the aperture sum and background level. # source_err = np.sqrt(phot_table['residual_aperture_sum']) source = phot_table['residual_aperture_sum'] aper_sum[i][j] = phot_table['residual_aperture_sum'][0] err[i][j] = np.sqrt(source + bkg_sum) j_plot = np.where(cent_ind == j)[0] if centroid_plot: if j in cent_ind: j_plot = j_plot[0] p1 = ax[j_plot].scatter([px + 1], [py + 1], c="thistle", label="Original", edgecolors='mistyrose') p2 = ax[j_plot].scatter([x_cent + 1], [y_cent + 1], c="rebeccapurple", label="Corrected", edgecolors='mistyrose') im = ax[j_plot].imshow(star, extent=(px - 19, px + 21, py - 19, py + 21), cmap='magma', origin='lower') ax[j_plot].set_title('Image {}'.format(im_n), size=10) circ = Circle((x_cent + 1, y_cent + 1), radius.value / secpix1, fill=False, label='Aperture', ls='-', color='mistyrose') ax[j_plot].add_patch(circ) for label in (ax[j_plot].get_xticklabels() + ax[j_plot].get_yticklabels()): label.set_fontsize(8) hdulist.close() del data saturated.append(saturated_i) if centroid_plot: fig.subplots_adjust(right=0.8) cbar_ax = fig.add_axes([0.85, 0.15, 0.05, 0.7]) cb = fig.colorbar(im, cax=cbar_ax) plt.setp(cb.ax.get_yticklabels(), fontsize=8) plt.figlegend([p1, p2, circ], ['Original', 'Corrected', 'Aperture'], fontsize=14) fig.suptitle('Aperture Centroiding on {}, {}'.format(ra_i, dec_i), fontsize=16) fig.text(0.5, 0.04, 'x [pixel]', ha='center') fig.text(0.04, 0.5, 'y [pixel]', va='center', rotation='vertical') if name == 'comp': out_file = os.path.join('centroid_{}{}_{}_{}.pdf'.format( name, i + 1, date, fil)) else: out_file = os.path.join('centroid_{}_{}_{}.pdf'.format( name, date, fil)) plt.savefig( os.path.join(dirtarget, 'ISR_Images', fil, 'WCS', 'output', out_file)) return aper_sum, err, date_obs, altitudes, saturated, exptimes, \ init_coords, cent_coords, image_num, sat_qual, cent_qual
# import the channel used map. # fitsimage='NGC5258_12CO10_combine_uvrange_smooth_regrid21_nchan.fits' # chans=fits_import(fitsimage)[1] chans = 50 chans_10 = chans # define the aperture position = SkyCoord(dec=0.8309 * u.degree, ra=204.9906 * u.degree, frame='icrs') center_sky = SkyCircularAperture(position, r=3 * u.arcsec) center_pix = center_sky.to_pixel(wcs=wcs) apertures['center'] = center_pix ring_sky = SkyCircularAnnulus(position, r_in=3 * u.arcsec, r_out=7 * u.arcsec) ring_pix = ring_sky.to_pixel(wcs=wcs) apertures['ring'] = ring_pix position = SkyCoord(dec=0.8340 * u.degree, ra=204.9935 * u.degree, frame='icrs') northarm_sky = SkyEllipticalAperture(position, a=13 * u.arcsec, b=4 * u.arcsec, theta=185 * u.degree) northarm_pix = northarm_sky.to_pixel(wcs=wcs) apertures['northarm'] = northarm_pix position = SkyCoord(dec=0.8283 * u.degree, ra=204.9882 * u.degree,
def app_phot(self, imagefile, ras, decs, fwhm, plot=False, save=False): ''' Computes the aperture photometry on the image, for the coordinates given. Parameters ---------- imagefile : str The name of the fits file with the image. ras : array Array of floats with the RA positions for which aperture photometry is needed. decs : array Array of floats with the DEC positions for which aperture photometry is needed. fwhm : float Average FWHM of the field used to compute the aperture. plot : boolean Shall the apertures be plotted in the plot directory? save : boolean Save the aperture measurement to a file. Returns ------- phot : QTable A table of the photometry with the following columns: 'id': The source ID. 'xcenter', 'ycenter': The x and y pixel coordinates of the input aperture center(s). 'celestial_center': 'aperture_sum': The sum of the values within the aperture. 'aperture_sum_err': The corresponding uncertainty in the 'aperture_sum' values. Returned only if the input error is not None. ''' data = fits.open(imagefile)[self.ext].data filt = fitsutils.get_par(imagefile, 'FILTER', self.ext) mjd = Time(fitsutils.get_par(imagefile, "DATE-OBS", ext=self.ext)).mjd zp = fitsutils.get_par(imagefile, 'ZP', self.ext) color = fitsutils.get_par(imagefile, 'COLOR', self.ext) kcoef = fitsutils.get_par(imagefile, 'KCOEF', self.ext) zperr = fitsutils.get_par(imagefile, 'ZPERR', self.ext) if zp is None: zp = 0 if zperr is None: zperr = 0 wcs = astropy.wcs.WCS(fits.open(imagefile)[self.ext].header) positions = SkyCoord(ras*u.deg, decs*u.deg, frame='icrs') # Set aperture radius to three times the fwhm radius aperture_rad = np.median(fwhm)*2* u.arcsec aperture = SkyCircularAperture(positions, r=aperture_rad) annulus_apertures = SkyCircularAnnulus(positions, r_in=aperture_rad*2, r_out=aperture_rad*4) #Convert to pixels pix_aperture = aperture.to_pixel(wcs) pix_annulus = annulus_apertures.to_pixel(wcs) pix_annulus_masks = pix_annulus.to_mask(method='center') #Plot apertures from astropy.visualization import simple_norm try: if np.ndim(ras) == 0: c = wcs.wcs_world2pix(np.array([[ras, decs]]), 0) else: c = wcs.wcs_world2pix(np.array([ras, decs]).T, 0) except ValueError: self.logger.error('The vectors of RAs, DECs could not be converted into pixels using the WCS!') self.logger.error(str(np.array([ras, decs]).T)) if plot: x = c[:,0] y = c[:,1] plt.figure(figsize=(10,10)) norm = simple_norm(data, 'sqrt', percent=99) plt.imshow(data, norm=norm) pix_aperture.plot(color='white', lw=2) pix_annulus.plot(color='red', lw=2) plt.xlim(x[0]-200, x[0]+200) plt.ylim(y[0]-200, y[0]+200) plt.title('Apertures for filter %s'%filt) plt.savefig(os.path.join(self._plotpath, "apertures_cutout_%s.png"%os.path.basename(imagefile))) plt.clf() #Divide each pixel in 5 subpixels to make apertures apers = [pix_aperture, pix_annulus] phot_table = aperture_photometry(data, apers, method='subpixel', subpixels=5) for col in phot_table.colnames: phot_table[col].info.format = '%.8g' # for consistent table output bkg_median = [] std_counts = [] for mask in pix_annulus_masks: annulus_data = mask.multiply(data) annulus_data_1d = annulus_data[mask.data > 0] _, median_sigclip, stdv_clip = sigma_clipped_stats(annulus_data_1d) bkg_median.append(median_sigclip) std_counts.append(stdv_clip) bkg_median = np.array(bkg_median) std_counts = np.array(std_counts) phot = aperture_photometry(data, pix_aperture) phot['annulus_median'] = bkg_median phot['annulus_std'] = std_counts phot['aper_bkg'] = bkg_median * pix_aperture.area() phot['aper_sum_bkgsub'] = phot['aperture_sum'] - phot['aper_bkg'] # Flux = Gain * Counts / Exptime. exptime = fitsutils.get_par(imagefile, 'EXPTIME', self.ext) gain = fitsutils.get_par(imagefile, self.gain_keyword, self.ext) flux = gain * phot['aper_sum_bkgsub'] / exptime inst_mag = -2.5*np.log10(flux) phot['flux'] = flux phot['inst_mag'] = inst_mag #Noise is the poisson noise of the source plus the background noise for the extracted area err = np.sqrt (flux + pix_aperture.area() * std_counts**2) #Transform pixels to magnitudes flux2 = gain * (phot['aper_sum_bkgsub']+err) / exptime inst_mag2 = -2.5*np.log10(flux2) errmag = np.abs(inst_mag2 - inst_mag) phot['err_counts'] = err phot['err_mag'] = errmag for col in phot.colnames: phot[col].info.format = '%.8g' # for consistent table output if save: appfile = os.path.join(self._photpath, fitsutils.get_par(imagefile, "OBJECT", self.ext)+".app.phot.txt") self.logger.info('Creating aperture photometry out file as %s'%appfile) #Save the photometry into a file if (not os.path.isfile(appfile)): with open(appfile, 'w') as f: f.write("mjd filter instr_mag zp zperr color kcoef mag magerr\n") with open(appfile, 'a') as f: self.logger.info('Adding aperture photometry to file %s'%appfile) f.write("%.3f %s %.4f %.4f %.4f %s %.4f %.4f %.4f\n"%(mjd, filt, phot['inst_mag'].data[0], \ zp, zperr, color, kcoef, phot['inst_mag'].data[0]+ zp, phot['err_mag'].data[0])) return phot
data_masked = np.ma.masked_invalid(data) return wcs, data_masked ############################################################ # main program ### Draw different regions. position = SkyCoord(dec=0.8309 * u.degree, ra=204.9906 * u.degree, frame='icrs') apertures['center']['sky'] = SkyCircularAperture(position, r=3 * u.arcsec) apertures['ring around center']['sky'] = SkyCircularAnnulus(position, r_in=3 * u.arcsec, r_out=7 * u.arcsec) position = SkyCoord(dec=0.8349 * u.degree, ra=204.9930 * u.degree, frame='icrs') apertures['northarm']['sky'] = SkyEllipticalAperture(position, a=15 * u.arcsec, b=7 * u.arcsec, theta=340 * u.degree) position = SkyCoord(dec=0.8275 * u.degree, ra=204.9884 * u.degree, frame='icrs') apertures['southarm']['sky'] = SkyEllipticalAperture(position, a=10 * u.arcsec, b=5 * u.arcsec, theta=340 * u.degree)
print(r_pix) #sys.exit(0) #phot_table = aperture_photometry(imdata, aperture,wcs=wcs) phot_table = aperture_photometry(imdata, aperture_pix) print(phot_table) print(phot_table.colnames) #print(phot_table['sky_center']) print(phot_table['xcenter']) print(phot_table['ycenter']) aper_sum = phot_table['aperture_sum'] phot_table['aperture_sum'].info.format = '%.8g' # for consistent table output aper_annu = SkyCircularAnnulus(position, r5, r6) print(aper_annu) print(aper_annu.r_in) print(aper_annu.r_out) aper_annu_pix = aper_annu.to_pixel(wcs) print(aper_annu_pix) r_in_annu_pix = aper_annu_pix.r_in r_out_annu_pix = aper_annu_pix.r_out print(r_in_annu_pix, r_out_annu_pix) apper = [aperture_pix, aper_annu_pix] phot_annu_table = aperture_photometry(imdata, apper) print(phot_annu_table) print(phot_annu_table.colnames) aper_annu_sum0 = phot_annu_table['aperture_sum_0'] #print(aper_annu_sum0)
# print(i,j1,radec_deg[j1],ra_hhmmss[j1],dec_ddmmss[j1]) rmag[j1] = df_refstar['Rmag'][j2] rmag_err[j1] = df_refstar['Rmag_err'][j2] r_circle[j1] = df_refstar['R_circle_as'][j2] r_inner[j1] = df_refstar['R_inner_as'][j2] r_outer[j1] = df_refstar['R_outer_as'][j2] # position= SkyCoord(ra_deg[j1],dec_deg[j1],unit=(u.hourangle,u.deg),frame='icrs') position = SkyCoord(ra_deg[j1], dec_deg[j1], unit=(u.deg), frame='icrs') # print(position) r_circle_as = r_circle[j1] * u.arcsec # print(r_circle_as) aperture[j1] = SkyCircularAperture(position, r=r_circle_as) # print(aperture[j1]) r_inner_as = r_inner[j1] * u.arcsec r_outer_as = r_outer[j1] * u.arcsec aper_annu[j1] = SkyCircularAnnulus(position, r_inner_as, r_outer_as) # print(aper_annu[j1]) # print(aper_annu[j1].r_in) # print(aper_annu[j1].r_out) # refstarID[j1]=df_refstar['RefStarID'][j2] # refstarRA_deg[j1]=df_refstar['RefStarRA_deg'][j2] # refstarDEC_deg[j1]=df_refstar['RefStarDEC_deg'][j2] # print(refstarID[j1]) # print(refstarRA_deg[j1] # print(refstarDEC_deg[j1]) j1 = j1 + 1 dx = 500 dy = dx
def show_cutout_with_slit(hdr, data=None, slit_ra=None, slit_dec=None, slit_shape='rectangular', slit_width=0.2, slit_length=3.3, slit_angle=90, slit_radius=0.2, slit_rout=0.5, cmap='Greys_r', plotname='', **kwargs): """Show a cutout image with the slit(s) superimposed. Parameters ---------- hdr : dict Cutout image header. data : ndarray or `None`, optional Cutout image data. If not given, data is not shown. slit_ra, slit_dec : float or array or `None`, optional Slit RA and DEC in degrees. Default is to use object position from image header. If an array is given, each pair of RA and DEC becomes a slit. slit_shape : {'annulus', 'circular', 'rectangular'}, optional Shape of the slit (circular or rectangular). Default is rectangular. slit_width, slit_length : float, optional Rectangular slit width and length in arcseconds. Defaults are some fudge values. slit_angle : float, optional Rectangular slit angle in degrees for the display. Default is vertical. slit_radius : float, optional Radius of a circular or annulus slit in arcseconds. For annulus, this is the inner radius. Default is some fudge value. slit_rout : float, optional Outer radius of an annulus slit in arcseconds. Default is some fudge value. cmap : str or obj, optional Matplotlib color map for image display. Default is grayscale. plotname : str, optional Filename to save plot as. If not given, it is not saved. kwargs : dict, optional Keyword argument(s) for the aperture overlay. If ``ax`` is given, it will also be used for image display. See Also -------- make_cutouts """ # Optional dependencies... import matplotlib.pyplot as plt from photutils import (SkyCircularAnnulus, SkyCircularAperture, SkyRectangularAperture) if slit_ra is None: slit_ra = hdr['OBJ_RA'] if slit_dec is None: slit_dec = hdr['OBJ_DEC'] position = SkyCoord(slit_ra, slit_dec, unit='deg') if slit_shape == 'circular': slit_radius = u.Quantity(slit_radius, u.arcsec) aper = SkyCircularAperture(position, slit_radius) elif slit_shape == 'annulus': slit_rin = u.Quantity(slit_radius, u.arcsec) slit_rout = u.Quantity(slit_rout, u.arcsec) aper = SkyCircularAnnulus(position, slit_rin, slit_rout) else: # rectangular slit_width = u.Quantity(slit_width, u.arcsec) slit_length = u.Quantity(slit_length, u.arcsec) slit_angle = u.Quantity(slit_angle, u.degree) aper = SkyRectangularAperture(position, slit_width, slit_length, theta=slit_angle) wcs = WCS(hdr) aper_pix = aper.to_pixel(wcs) ax = kwargs.get('ax', plt) if data is not None: ax.imshow(data, cmap=cmap, origin='lower') aper_pix.plot(**kwargs) if plotname: ax.savefig(plotname)
aperture_pix = aperture.to_pixel(wcs) # print(aperture_pix) r_pix = aperture_pix.r print('r_pix =', r_pix) # phot_table = aperture_photometry(imdata, aperture,wcs=wcs) phot_table = aperture_photometry(imdata, aperture_pix) # print(phot_table) # print(phot_table.colnames) # print(phot_table['sky_center']) # print(phot_table['xcenter']) # print(phot_table['ycenter']) aper_sum = phot_table['aperture_sum'] phot_table[ 'aperture_sum'].info.format = '%.8g' # for consistent table output aper_annu = SkyCircularAnnulus(positions, r_inner_as, r_outer_as) # print(aper_annu) # print(aper_annu.r_in) # print(aper_annu.r_out) aper_annu_pix = aper_annu.to_pixel(wcs) # print(aper_annu_pix) r_in_annu_pix = aper_annu_pix.r_in r_out_annu_pix = aper_annu_pix.r_out # print(r_in_annu_pix,r_out_annu_pix) apper = [aperture_pix, aper_annu_pix] phot_annu_table = aperture_photometry(imdata, apper) # print(phot_annu_table) # print(phot_annu_table.colnames) aper_annu_sum0 = phot_annu_table['aperture_sum_0'] # print(aper_annu_sum0)
def plot_image(self, data, wcs, coords=None): """ convience function to plot data on a wcs projection Input: data - the data array wcs - the WCS object coords - the coordinates of the object for plotting (1x2 array, optional) """ # set up the plot fig, axs = plt.subplots(1, 1, figsize=(8, 8), subplot_kw={'projection': wcs}) # set up limits of the colour scale for plotting vmin = 1e-1 vmax = np.max(data) * 0.9 # plot axs.imshow(data, cmap='magma', interpolation='nearest', origin='lower', norm=LogNorm(vmin=vmin, vmax=vmax)) #axs.scatter(coords[0], coords[1], transform=axs.get_transform('fk5'), s=20000, lw=2, # edgecolor='white', facecolor='none') # define the apertures to plot (these are the same as in other functions) # SNR position = SkyCoord(self.ra_deg * u.degree, self.dec_deg * u.degree, frame='icrs') snr_aperture = SkyCircularAperture(position, r=self.radius * u.arcsec) snr_pix_aperture = snr_aperture.to_pixel(wcs) snr_pix_aperture.plot(color='white', lw=5, alpha=1.0) # BKG r = self.radius * u.arcsec r_in = r + (40. * u.arcsec) r_out = r + (100. * u.arcsec) bkg_ap = SkyCircularAnnulus(position, r_in=r_in, r_out=r_out) bkg_ap_pix = bkg_ap.to_pixel(wcs) bkg_ap_pix.plot(color='red', lw=3, ls='--', alpha=0.9) # MIRI Imager r = self.radius * u.arcsec r_in = r - (37. * u.arcsec) r_out = r + (37. * u.arcsec) arc_ap = SkyCircularAnnulus(position, r_in=r_in, r_out=r_out) arc_ap_pix = arc_ap.to_pixel(wcs) arc_ap_pix.plot(color='cyan', lw=3, ls=':', alpha=0.9) axs.set_facecolor('black') axs.coords.grid(True, color='white', ls='dotted') axs.coords[0].set_axislabel('Right Ascension (J2000)') axs.coords[1].set_axislabel('Declination (J2000)') # indicative MIRI FOV x = Angle(self.radius, u.arcsec) y = x.degree t3_pos = SkyCoord((self.ra_deg) * u.degree, (self.dec_deg + y) * u.degree, frame='icrs') ap3 = SkyRectangularAperture(t3_pos, 74 * u.arcsec, 113 * u.arcsec, 0 * u.degree) ap3_pix = ap3.to_pixel(wcs) ap3_pix.plot(color='yellow', lw=3, ls='-', alpha=0.9) axs.set_facecolor('black') axs.coords.grid(True, color='white', ls='dotted') axs.coords[0].set_axislabel('Right Ascension (J2000)') axs.coords[1].set_axislabel('Declination (J2000)') # display the plot plt.tight_layout() # save as a pdf plot_name = os.path.join( str(self.name), str(self.name) + '_' + str(self.wavelength) + '.pdf') try: os.remove(plot_name) except: pass fig.savefig(plot_name, dpi=200)