def Photutils_Fit(IMG, results, options): """ Function to run the photutils automated isophote analysis on an image. """ dat = IMG - results['background'] geo = EllipseGeometry(x0=results['center']['x'], y0=results['center']['y'], sma=results['init R'] / 2, eps=results['init ellip'], pa=results['init pa']) ellipse = Photutils_Ellipse(dat, geometry=geo) isolist = ellipse.fit_image(fix_center=True, linear=False) res = { 'fit R': isolist.sma[1:], 'fit ellip': isolist.eps[1:], 'fit ellip_err': isolist.ellip_err[1:], 'fit pa': isolist.pa[1:], 'fit pa_err': isolist.pa_err[1:], 'auxfile fitlimit': 'fit limit semi-major axis: %.2f pix' % isolist.sma[-1] } if 'ap_doplot' in options and options['ap_doplot']: ranges = [[ max(0, int(results['center']['y'] - res['fit R'][-1] * 1.2)), min(dat.shape[1], int(results['center']['y'] + res['fit R'][-1] * 1.2)) ], [ max(0, int(results['center']['x'] - res['fit R'][-1] * 1.2)), min(dat.shape[0], int(results['center']['x'] + res['fit R'][-1] * 1.2)) ]] LSBImage(dat[ranges[1][0]:ranges[1][1], ranges[0][0]:ranges[0][1]], results['background noise']) for i in range(len(res['fit R'])): plt.gca().add_patch( Ellipse( (int(res['fit R'][-1] * 1.2), int(res['fit R'][-1] * 1.2)), 2 * res['fit R'][i], 2 * res['fit R'][i] * (1. - res['fit ellip'][i]), res['fit pa'][i] * 180 / np.pi, fill=False, linewidth=0.5, color='r')) if not ('ap_nologo' in options and options['ap_nologo']): AddLogo(plt.gcf()) plt.savefig( '%sfit_ellipse_%s.jpg' % (options['ap_plotpath'] if 'ap_plotpath' in options else '', options['ap_name']), dpi=300) plt.close() return IMG, res
def maximize_intens(self, par): if self.photomorph == 'ellipse': geom = EllipseGeometry( par[0], par[1], par[2], par[3], par[4], ) sample = EllipseSample(self.im, sma=geom.sma, astep=0, sclip=0.3, nclip=0, linear_growth=False, geometry=geom, integrmode='bilinear') data2min = np.mean(sample.extract()[2]) elif self.photomorph == 'annulus': aper = EllipticalAnnulus( (par[0], par[1]), par[2] - self.beam_size_pix / 2., par[2] + self.beam_size_pix / 2., (par[2] + self.beam_size_pix / 2.) * (1. - par[3]), par[4]) annulus_mask = aper.to_mask() data2min = annulus_mask.multiply(self.im) elif self.photomorph == 'circle': aper = CircularAperture((par[0], par[1]), par[2]) circular_mask = aper.to_mask() data2min = circular_mask.multiply(self.im) elif self.photomorph == 'ellipse_area': aper = EllipticalAperture((par[0], par[1]), par[2], par[2] * (1. - par[3]), par[4]) ellipse_mask = aper.to_mask() data2min = ellipse_mask.multiply(self.im) if self.q2min == 'sum': tominimize = np.sum(data2min) elif self.q2min == 'mean': tominimize = np.mean(data2min) return -tominimize
def burst_drift(npy, fslice=':', tslice=':'): #Load npy array burst = np.load(npy) #Subband in Frequency subfac = 16 rb_sub = np.nanmean(R3H.reshape(-1, subfac, R3H.shape[1]), axis=1) rb_sub_zm = rb_sub[fslice, tslice] ynorm = (rb_sub_zm.sum(0) / np.max(rb_sub_zm.sum(0))) x = np.linspace(0, len(ynorm) - 1, len(ynorm)) #Smooth sav = ss.savgol_filter(rb_sub_zm, 49, 6) #Calculate 2D ACF acf = ss.correlate(sav, sav) #Provide the initial Ellipse to be fitted #Calculate Ellipse Geometry geometry = EllipseGeometry(x0=acf.shape[1] / 2, y0=acf.shape[0] / 2, sma=20, eps=0.4, pa=60 * np.pi / 180.) #Show Initial Guess Ellipsee aper = EllipticalAperture((geometry.x0, geometry.y0), geometry.sma, geometry.sma * (1 - geometry.eps), geometry.pa) #Plot Initial Guess Ellipse on ACF #plt.imshow(acf, aspect = 'auto') #aper.plot(color='white') #Fit Ellipse to 2D ACF ellipse = Ellipse(acf, geometry) isolist = ellipse.fit_image() model_image = build_ellipse_model(acf.shape, isolist) residual = acf - model_image fig = plt.figure(figsize=(40, 10)) ax1 = fig.add_subplot(131) plt.gca().invert_yaxis() x = np.linspace(0, acf.shape[1] - 1, acf.shape[1]) y = lambda x: (0.809) * x + 37.65 plt.plot(x, y(x), color='white', label='Drift Rate = -33 MHz/ms') plt.imshow(sav, interpolation=None) plt.yticks(np.arange(0, sav.shape[0], 60), [1000, 900, 800, 700, 600]) plt.xticks(np.arange(0, sav.shape[1], 48), [0, 2, 4, 6, 8, 10]) plt.ylabel('Frequency (MHz)') plt.xlabel('Time (ms)') plt.title('Dynamic Spectrum R3H') plt.legend() ax2 = fig.add_subplot(132) plt.imshow(acf) #, origin='lower') plt.ylabel('Frequency Shift (MHz)') plt.xlabel('Time Shfit (ms)') plt.yticks(np.arange(0, acf.shape[0], 79), [1000, 600, 200, 0, -200, -600, -1000]) plt.xticks(np.arange(0, acf.shape[1], 49), [-10, -8, -6, -4, -3, 0, 2, 4, 6, 8, 10]) #plt.plot(x, y(x)) plt.title('2D ACF R3H') smas = np.linspace(10, 100, 8) for sma in smas: iso = isolist.get_closest(sma) x, y, = iso.sampled_coordinates() plt.plot(x, y, color='white') #ax3.imshow(model_image, origin='lower') #ax3.set_title('Ellipse Model') #ax3.imshow(residual, origin='lower') ax3 = fig.add_subplot(133) #plt.set_aspect('auto') x = np.linspace(0, len(ynorm) - 1, len(ynorm)) plt.plot(x, ss.savgol_filter(ynorm, 19, 6)) plt.title('Timeseries R3H') plt.ylabel('Normalized Intensity') plt.xlabel('Time (ms)') plt.xticks(np.arange(0, sav.shape[1], 48), [0, 2, 4, 6, 8, 10]) #ax3.set_title('Residual') fig.savefig('Drift Rate R3H') return
bkg_rms = np.std(phot['aperture_sum'] / box.area) # 4.568966255984001 plt.figure(figsize=(8, 8)) norm = simple_norm(data*~boolmask, 'sqrt', percent=99.) im=plt.imshow(data*~boolmask, cmap='viridis',interpolation='nearest',norm=norm) plt.colorbar(im) aperture.plot(color='#d62728') box.plot(color='#d62728') print(bkg_mean,bkg_rms,bkg_mean - 1*bkg_rms,bkg_mean + 1*bkg_rms,bkg_mean - 3*bkg_rms,bkg_mean + 3*bkg_rms) #data = data - (bkg_mean+3*bkg_rms)#(bkg_mean - 1*bkg_rms) ### np.median(data[box_cutout.data==0]) # == 15.167292 ### np.std(data[box_cutout.data==0]) #== 10.078673 # ---------------------------------------------------------------------------- #datamask = deepcopy(data) #datamask[mask>0]=0 geometry = EllipseGeometry(x0=cat.xcentroid, y0=cat.ycentroid, sma=a, eps=1-b/a, pa=(theta+90)*np.pi/180.) ellipse = Ellipse(ma.masked_where(mask > 0, data), geometry) #isolist = ellipse.fit_image(integrmode='median', step=5, linear=True, # maxsma=nsize/2, fflag=0.3, sclip=3, nclip=3) isolist = ellipse.fit_image(integrmode='median', step=.1, linear=False, maxsma=nsize/2, fflag=0.3, sclip=3, nclip=3) # Try to fit further more (from the last ellipse) with larger step to increase S/N # and capture outer parts of the galaxy #geometry = EllipseGeometry(x0=cat.xcentroid, y0=cat.ycentroid, sma=np.max(isolist.sma), # eps=1-b/a, pa=(theta+90)*np.pi/180.) #ellipse = Ellipse(data, geometry) #isolist_outer = ellipse.fit_image(integrmode='median', step=0.3, minsma=isolist.sma[-1],
def _prep_2dacf(time_smooth, freq_smooth, time_res, subband_freq_res, diagnostic=True): #Calculate 2d acf acf2d = ss.correlate(savts_2d_c, savsp_2d_c) #Cap spiked central values in acf cap = np.mean( acf2d[len(acf2d.sum(1)) // 2 + 10:len(acf2d.sum(1)) // 2 + 10, len(acf2d.sum(0)) // 2 + 10:len(acf2d.sum(0)) // 2 + 10]) acf2d_cap = np.where(acf2d > cap, cap, acf2d) #Smooth Data w Savitzky Golay filter (t - time) (s - spectrum) twinlen = acf2d.shape[1] // 4 if twinlen % 2 == 0: twinlen = twinlen + 1 swinlen = acf2d.shape[0] // 4 if swinlen % 2 == 0: swinlen = swinlen + 1 polyo = 6 savacft = ss.savgol_filter(acf2d, twinlen, polyo, axis=1) savacff = ss.savgol_filter(acf2d, swinlen, polyo, axis=0) print('ACF Time Window Length: ', twinlen) print('ACF Freq Window Length: ', swinlen) #Calculate initial guess parameters spectrum acf time savt = savacft.sum(0) / np.max(savacft.sum(0)) maximt = np.max(savt) stdt = np.std(savt) meant = np.where(savt == maximt)[0][0] xt = np.linspace(0, len(savt), len(savt)) #Fit 1D Gaussian to Spectrum fittert = modeling.fitting.LevMarLSQFitter() modelt = modeling.models.Gaussian1D(amplitude=maximt, mean=meant, stddev=stdt) fitted_modelt = fittert(modelt, xt, savt) #Calculate initial guess parameters spectrum acf freq savsp = savacff.sum(1) / np.max(savacff.sum(1)) maximsp = np.max(savsp) stdsp = np.std(savsp) meansp = np.where(savsp == maximsp)[0][0] xsp = np.linspace(0, len(savsp), len(savsp)) #Fit 1D Gaussian to Spectrum fittersp = modeling.fitting.LevMarLSQFitter() modelsp = modeling.models.Gaussian1D(amplitude=maximsp, mean=meansp, stddev=stdsp) fitted_modelsp = fittersp(modelsp, xsp, savsp) #Get Ellipse Ratio sigmat = fitted_modelt.stddev.value sigmaf = fitted_modelsp.stddev.value #Up to sig 3 -- MAKE EDIT TO ADJUST ITERATIVELY IN FIT FUNCTION sigt1 = sigmat sigf1 = sigmaf sigt2 = sigmat * 2 sigf2 = sigmaf * 2 sigt3 = sigmat * 3 sigf3 = sigmaf * 3 sigmat = sigmat * 0.3 sigmaf = sigmaf * 0.3 #Sigmas form a rectangle, get slope of the rectangle diagonal to estimate semi major axis PA hyp = np.sqrt(sigmat**2 + sigmaf**2) estpa = np.arccos(sigmat / hyp) #in radians #Estimate ellipticity (eps) with sigma ratio oppestpa = np.arccos(sigmaf / hyp) estsmajax = np.tan(oppestpa) * (hyp / 2) estsminax = hyp / 2 esteps = 1 - (estsminax / estsmajax) print(estsmajax, estsminax) print('Estimated Ellipticity: ', esteps) print('Estmated Semimajor Axis: ', estsmajax) print('Estimated PA: ', estpa) print('Initial guess ellipse applied!') #Provide the initial ellipse to be fitted #Calculate ellipse geometry geometry = EllipseGeometry(x0 = acf2d.shape[1]/2, \ y0 = acf2d.shape[0]/2, sma = estsmajax, eps = esteps, pa = estpa) #Show initial guess ellipse aper = EllipticalAperture((geometry.x0, geometry.y0), \ geometry.sma, geometry.sma*(1-geometry.eps),geometry.pa) if diagnostic == True: fig = plt.figure() plt.imshow(acf2d, aspect='auto') aper.plot(color='white') plt.title('Diagnostic - Pre-fit Estimate') plt.show() fig.savefig('Diagnostic_' + str(burst_npy) + '.png') print('Now for the fit...') return acf2d, geometry, aper, sigmat, sigmaf, sigf3
def fit_ellipse_for_source( friendid=None, detectid=None, coords=None, shotid=None, subcont=True, convolve_image=False, pixscale=pixscale, imsize=imsize, wave_range=None, ): if detectid is not None: global deth5 detectid_obj = detectid if detectid_obj <= 2190000000: det_info = deth5.root.Detections.read_where("detectid == detectid_obj")[0] linewidth = det_info["linewidth"] wave_obj = det_info["wave"] redshift = wave_obj / (1216) - 1 else: det_info = conth5.root.Detections.read_where("detectid == detectid_obj")[0] redshift = 0 wave_obj = 4500 coords_obj = SkyCoord(det_info["ra"], det_info["dec"], unit="deg") shotid_obj = det_info["shotid"] fwhm = surveyh5.root.Survey.read_where("shotid == shotid_obj")["fwhm_virus"][0] amp = det_info["multiframe"] if wave_range is not None: wave_range_obj = wave_range else: if detectid_obj <= 2190000000: wave_range_obj = [wave_obj - 2 * linewidth, wave_obj + 2 * linewidth] else: wave_range_obj = [4100, 4200] if coords is not None: coords_obj = coords if shotid is not None: shotid_obj = shotid fwhm = surveyh5.root.Survey.read_where("shotid == shotid_obj")[ "fwhm_virus" ][0] try: hdu = make_narrowband_image( coords=coords_obj, shotid=shotid_obj, wave_range=wave_range_obj, imsize=imsize * u.arcsec, pixscale=pixscale * u.arcsec, subcont=subcont, convolve_image=convolve_image, include_error=True, ) except: print("Could not make narrowband image for {}".format(detectid)) return np.nan, np.nan elif friendid is not None: global friend_cat sel = friend_cat["friendid"] == friendid group = friend_cat[sel] coords_obj = SkyCoord(ra=group["icx"][0] * u.deg, dec=group["icy"][0] * u.deg) wave_obj = group["icz"][0] redshift = wave_obj / (1216) - 1 linewidth = group["linewidth"][0] shotid_obj = group["shotid"][0] fwhm = group["fwhm"][0] amp = group["multiframe"][0] if wave_range is not None: wave_range_obj = wave_range else: wave_range_obj = [wave_obj - 2 * linewidth, wave_obj + 2 * linewidth] if shotid is not None: shotid_obj = shotid fwhm = surveyh5.root.Survey.read_where("shotid == shotid_obj")[ "fwhm_virus" ][0] try: hdu = make_narrowband_image( coords=coords_obj, shotid=shotid_obj, wave_range=wave_range_obj, imsize=imsize * u.arcsec, pixscale=pixscale * u.arcsec, subcont=subcont, convolve_image=convolve_image, include_error=True, ) except: print("Could not make narrowband image for {}".format(friendid)) return None elif coords is not None: coords_obj = coords if wave_range is not None: wave_range_obj = wave_range else: print( "You need to supply wave_range=[wave_start, wave_end] for collapsed image" ) if shotid is not None: shotid_obj = shotid fwhm = surveyh5.root.Survey.read_where("shotid == shotid_obj")[ "fwhm_virus" ][0] else: print("Enter the shotid to use (eg. 20200123003)") hdu = make_narrowband_image( coords=coords_obj, shotid=shotid_obj, wave_range=wave_range_obj, imsize=imsize * u.arcsec, pixscale=pixscale * u.arcsec, subcont=subcont, convolve_image=convolve_image, include_error=True, ) else: print("You must provide a detectid, friendid or coords/wave_range/shotid") return np.nan, np.nan w = wcs.WCS(hdu[0].header) if friendid is not None: sel_friend_group = friend_cat["friendid"] == friendid group = friend_cat[sel_friend_group] eps = 1 - group["a2"][0] / group["b2"][0] pa = group["pa"][0] * np.pi / 180.0 - 90 sma = group["a"][0] * 3600 / pixscale coords = SkyCoord(ra=group["icx"][0] * u.deg, dec=group["icy"][0] * u.deg) wave_obj = group["icz"][0] redshift = wave_obj / (1216) - 1 linewidth = np.nanmedian(group["linewidth"]) shotid_obj = group["shotid"][0] fwhm = group["fwhm"][0] geometry = EllipseGeometry( x0=w.wcs.crpix[0], y0=w.wcs.crpix[0], sma=sma, eps=eps, pa=pa ) else: geometry = EllipseGeometry( x0=w.wcs.crpix[0], y0=w.wcs.crpix[0], sma=20, eps=0.2, pa=20.0 ) geometry = EllipseGeometry( x0=w.wcs.crpix[0], y0=w.wcs.crpix[0], sma=20, eps=0.2, pa=20.0 ) # geometry.find_center(hdu.data) # aper = EllipticalAperture((geometry.x0, geometry.y0), geometry.sma, # geometry.sma*(1 - geometry.eps), geometry.pa) # plt.imshow(hdu.data, origin='lower') # aper.plot(color='white') ellipse = Ellipse(hdu[0].data) isolist = ellipse.fit_image() iso_tab = isolist.to_table() if len(iso_tab) == 0: geometry.find_center(hdu[0].data, verbose=False, threshold=0.5) ellipse = Ellipse(hdu[0].data, geometry) isolist = ellipse.fit_image() iso_tab = isolist.to_table() if len(iso_tab) == 0: return np.nan, np.nan, np.nan try: # compute iso's manually in steps of 3 pixels ellipse = Ellipse(hdu[0].data) # reset ellipse iso_list = [] for sma in np.arange(1, 60, 2): iso = ellipse.fit_isophote(sma) if np.isnan(iso.intens): # print('break at {}'.format(sma)) break else: iso_list.append(iso) isolist = IsophoteList(iso_list) iso_tab = isolist.to_table() except: return np.nan, np.nan, np.nan try: model_image = build_ellipse_model(hdu[0].data.shape, isolist) residual = hdu[0].data - model_image except: return np.nan, np.nan, np.nan sma = iso_tab["sma"] * pixscale const_arcsec_to_kpc = cosmo.kpc_proper_per_arcmin(redshift).value / 60.0 def arcsec_to_kpc(sma): dist = const_arcsec_to_kpc * sma return dist def kpc_to_arcsec(dist): sma = dist / const_arcsec_to_kpc return sma dist_kpc = ( sma * u.arcsec.to(u.arcmin) * u.arcmin * cosmo.kpc_proper_per_arcmin(redshift) ) dist_arcsec = kpc_to_arcsec(dist_kpc) # print(shotid_obj, fwhm) # s_exp1d = models.Exponential1D(amplitude=0.2, tau=-50) alpha = 3.5 s_moffat = models.Moffat1D( amplitude=1, gamma=(0.5 * fwhm) / np.sqrt(2 ** (1.0 / alpha) - 1.0), x_0=0.0, alpha=alpha, fixed={"amplitude": False, "x_0": True, "gamma": True, "alpha": True}, ) s_init = models.Exponential1D(amplitude=0.2, tau=-50) fit = fitting.LevMarLSQFitter() s_r = fit(s_init, dist_kpc, iso_tab["intens"]) # Fitting can be done using the uncertainties as weights. # To get the standard weighting of 1/unc^2 for the case of # Gaussian errors, the weights to pass to the fitting are 1/unc. # fitted_line = fit(line_init, x, y, weights=1.0/yunc) # s_r = fit(s_init, dist_kpc, iso_tab['intens'])#, weights=iso_tab['intens']/iso_tab['intens_err'] ) print(s_r) try: r_n = -1.0 * s_r.tau # _0 #* const_arcsec_to_kpc except: r_n = np.nan # r_n = -1. * s_r.tau_0 try: sel_iso = np.where(dist_kpc >= 2 * r_n)[0][0] except: sel_iso = -1 aper = EllipticalAperture( (isolist.x0[sel_iso], isolist.y0[sel_iso]), isolist.sma[sel_iso], isolist.sma[sel_iso] * (1 - isolist.eps[sel_iso]), isolist.pa[sel_iso], ) phottable = aperture_photometry(hdu[0].data, aper, error=hdu[1].data) flux = phottable["aperture_sum"][0] * 10 ** -17 * u.erg / (u.cm ** 2 * u.s) flux_err = phottable["aperture_sum_err"][0] * 10 ** -17 * u.erg / (u.cm ** 2 * u.s) lum_dist = cosmo.luminosity_distance(redshift).to(u.cm) lum = flux * 4.0 * np.pi * lum_dist ** 2 lum_err = flux_err * 4.0 * np.pi * lum_dist ** 2 if detectid: name = detectid elif friendid: name = friendid # Get Image data from Elixer catlib = catalogs.CatalogLibrary() try: cutout = catlib.get_cutouts( position=coords_obj, side=imsize, aperture=None, dynamic=False, filter=["r", "g", "f606W"], first=True, allow_bad_image=False, allow_web=True, )[0] except: print("Could not get imaging for " + str(name)) zscale = ZScaleInterval(contrast=0.5, krej=1.5) vmin, vmax = zscale.get_limits(values=hdu[0].data) fig = plt.figure(figsize=(20, 12)) fig.suptitle( "{} ra={:3.2f}, dec={:3.2f}, wave={:5.2f}, z={:3.2f}, mf={}".format( name, coords_obj.ra.value, coords_obj.dec.value, wave_obj, redshift, amp ), fontsize=22, ) ax1 = fig.add_subplot(231, projection=w) plt.imshow(hdu[0].data, vmin=vmin, vmax=vmax) plt.xlabel("RA") plt.ylabel("Dec") plt.colorbar() plt.title("Image summed across 4*linewidth") ax2 = fig.add_subplot(232, projection=w) plt.imshow(model_image, vmin=vmin, vmax=vmax) plt.xlabel("RA") plt.ylabel("Dec") plt.colorbar() plt.title("model") ax3 = fig.add_subplot(233, projection=w) plt.imshow(residual, vmin=vmin, vmax=vmax) plt.xlabel("RA") plt.ylabel("Dec") plt.colorbar() plt.title("residuals (image-model)") # fig = plt.figure(figsize=(10,5)) im_zscale = ZScaleInterval(contrast=0.5, krej=2.5) im_vmin, im_vmax = im_zscale.get_limits(values=cutout["cutout"].data) ax4 = fig.add_subplot(234, projection=cutout["cutout"].wcs) plt.imshow( cutout["cutout"].data, vmin=im_vmin, vmax=im_vmax, origin="lower", cmap=plt.get_cmap("gray"), interpolation="none", ) plt.text( 0.8, 0.9, cutout["instrument"] + cutout["filter"], transform=ax4.transAxes, fontsize=20, color="w", ) plt.contour(hdu[0].data, transform=ax4.get_transform(w)) plt.xlabel("RA") plt.ylabel("Dec") aper.plot( color="white", linestyle="dashed", linewidth=2, transform=ax4.get_transform(w) ) ax5 = fig.add_subplot(235) plt.errorbar( dist_kpc.value, iso_tab["intens"], yerr=iso_tab["intens_err"] * iso_tab["intens"], linestyle="none", marker="o", label="Lya SB profile", ) plt.plot(dist_kpc, s_r(dist_kpc), color="r", label="Lya exp SB model", linewidth=2) plt.xlabel("Semi-major axis (kpc)") # plt.xlabel('Semi-major axis (arcsec)') plt.ylabel("Flux ({})".format(10 ** -17 * (u.erg / (u.s * u.cm ** 2)))) plt.text(0.4, 0.7, "r_n={:3.2f}".format(r_n), transform=ax5.transAxes, fontsize=16) plt.text( 0.4, 0.6, "L_lya={:3.2e}".format(lum), transform=ax5.transAxes, fontsize=16 ) secax = ax5.secondary_xaxis("top", functions=(kpc_to_arcsec, kpc_to_arcsec)) secax.set_xlabel("Semi-major axis (arcsec)") # secax.set_xlabel('Semi-major axis (kpc)') plt.xlim(0, 100) # plt.plot(sma, s_r(sma), label='moffat psf') # plt.plot(dist_kpc.value, s1(kpc_to_arcsec(dist_kpc.value)), # linestyle='dashed', linewidth=2, # color='green', label='PSF seeing:{:3.2f}'.format(fwhm)) # These two are the exact same # s1 = models.Moffat1D() # s1.amplitude = iso_tab['intens'][0] # alpha=3.5 # s1.gamma = 0.5*(fwhm*const_arcsec_to_kpc)/ np.sqrt(2 ** (1.0 / alpha) - 1.0) # s1.alpha = alpha # plt.plot(r_1d, moffat_1d, color='orange') # plt.plot(dist_kpc.value, (s1(dist_kpc.value)), # linestyle='dashed', linewidth=2, # color='blue', label='PSF seeing:{:3.2f}'.format(fwhm)) E = Extract() E.load_shot(shotid_obj) moffat_psf = E.moffat_psf(seeing=fwhm, boxsize=imsize, scale=pixscale) moffat_shape = np.shape(moffat_psf) xcen = int(moffat_shape[1] / 2) ycen = int(moffat_shape[2] / 2) moffat_1d = ( moffat_psf[0, xcen:-1, ycen] / moffat_psf[0, xcen, ycen] * iso_tab["intens"][0] ) r_1d = moffat_psf[1, xcen:-1, ycen] E.close() plt.plot( arcsec_to_kpc(pixscale * np.arange(80)), iso_tab["intens"][0] * (moffat_psf[0, 80:-1, 80] / moffat_psf[0, 80, 80]), linestyle="dashed", color="green", label="PSF seeing:{:3.2f}".format(fwhm), ) plt.legend() if friendid is not None: ax6 = fig.add_subplot(236, projection=cutout["cutout"].wcs) plot_friends(friendid, friend_cat, cutout, ax=ax6, label=False) plt.savefig("fit2d_{}.png".format(name)) # filename = 'param_{}.txt'.format(name) # np.savetxt(filename, (r_n.value, lum.value)) return r_n, lum, lum_err
from photutils.datasets import make_noise_image from photutils.isophote import EllipseGeometry, Ellipse from photutils import EllipticalAperture #=================================== #Reading fits file containing data to be fitted #=================================== bulge = fits.getdata('/home/elismar/Documentos/Fisica/IC/imfit-1.7.1/ngc2992-93/images/NICMOS/n4sb08040/bulge.fits') #=================================== #Fitting elliptical isophotes to bulge #=================================== geometry = EllipseGeometry(x0=50, y0=65, sma=3, eps=0.1, pa=0) ellipse = Ellipse(bulge, geometry) isolist = ellipse.fit_image() #=================================== #Plotting results #=================================== fig = plt.figure() axs = fig.add_subplot(111) norm = plt.Normalize(-2, 10) axs.imshow(bulge, origin='lower', norm=norm) axs.set_title('Data') smas = np.linspace(1, 10, 10)
def __init__(self, image_cube, header, db_name='database', x0=None, y0=None, sma=None, eps=None, pa=None, box='init', **kwargs): """ Kwargs can be: init_chan """ self.params = {'x0': x0, 'y0': y0, 'sma': sma, 'eps': eps, 'pa': pa} for param in self.params: self.params[param] = self.params[param] \ if self.params[param] is not None \ else self.init_params[param] self.geom = EllipseGeometry(**self.params) self.box = self.init_box if box == 'init' else box self.fig = plt.figure(figsize=(8, 8)) self.fig.subplots_adjust(left=0.25, bottom=0.35) self.header = header self.nchans = self.header['NAXIS3'] self.init_chan = int(np.round(self.nchans / 2)) if self.header is not None: self.wcs = WCS(header).celestial self.beam_size_pix = (self.header['BMAJ'] + self.header['BMIN'] ) * 0.5 / self.header['CDELT2'] self.ax = plt.subplot(projection=self.wcs) else: self.header = None self.wcs = None self.beam_size_pix = None self.ax = self.fig.add_subplot() self.ax_text = self.fig.add_axes([0.05, 0.025, 0.1, 0.04]) self.ax_text.set_axis_off() self.chan = self.init_chan self.image_cube = image_cube self.operation = kwargs['operation'] if 'operation' in kwargs else None self.interpolation = kwargs['interpolation'] \ if 'interpolation' in kwargs \ else 'bilinear' self.filterrad = kwargs['filterrad'] if 'filterrad' in kwargs else 4.0 self.width_chan = 3 self.color_ref_ellip = 'r' self.max_vmax = np.max([np.max(x) for x in self.image_cube]) #self.max_vmax = 0.1 self.vmax = 0.08 self.vcenter = 0.03 self.vmin = 0.01 self.cmap = kwargs['cmap'] if 'cmap' in kwargs else mf.default_params[ 'cmap'] self.norm = 'divnorm' self.v0 = kwargs['v0'] if 'v0' in kwargs else mf.default_params['v0'] self.vf = kwargs['vf'] if 'vf' in kwargs else mf.default_params['vf'] self.photomorph = kwargs['photomorph'] if 'photomorph' in kwargs \ else 'ellipse' self.sample = None self.ellip_data = None self.q2min = kwargs['q2min'] if 'q2min' in kwargs else 'mean' self.mean_intens = 0 self.sum_intens = 0 self.fit_results = {} self.im = None self.fit_tol = 1 * 10**(-8) self.fit_method = None self.pickling = False self.db_name = db_name self.path_database = '{}{}.db'.format( mf.default_params['path_database'], self.db_name) self.limit_fit = kwargs['limit_fit'] if 'limit_fit' in kwargs \ else mf.default_params['limit_fit'] self.slider_ax = None self.channels_ax = None self.fit_button_ax = None self.next_chan_button_ax = None self.prev_chan_button_ax = None self.max_cbar_ax = None self.center_cbar_ax = None self.min_cbar_ax = None self.create_axes() self.param_sliders = None self.channels_slider = None self.max_cbar_slider = None self.center_cbar_slider = None self.min_cbar_slider = None self.fit_button = None self.next_chan_button = None self.prev_chan_button = None self.update_buttons() self.plot_image() self.update_ellipse(first_time=True)
def Isophote_Extract_Photutils(IMG, results, options): """Wrapper of photutils method for extracting SB profiles. This simply gives users access to the photutils isophote extraction methods. The one exception is that SB values are taken as the median instead of the mean, as recomended in the photutils documentation. See: `photutils <https://photutils.readthedocs.io/en/stable/isophote.html>`_ for more information. Parameters ---------- ap_zeropoint : float, default 22.5 Photometric zero point. For converting flux to mag units. ap_fluxunits : str, default "mag" units for outputted photometry. Can either be "mag" for log units, or "intensity" for linear units. ap_plot_sbprof_ylim : tuple, default None Tuple with axes limits for the y-axis in the SB profile diagnostic plot. Be careful when using intensity units since this will change the ideal axis limits. ap_plot_sbprof_xlim : tuple, default None Tuple with axes limits for the x-axis in the SB profile diagnostic plot. ap_plot_sbprof_set_errscale : float, default None Float value by which to scale errorbars on the SB profile this makes them more visible in cases where the statistical errors are very small. Notes ---------- :References: - 'background' - 'background noise' - 'psf fwhm' - 'center' - 'init R' (optional) - 'init ellip' (optional) - 'init pa' (optional) - 'fit R' (optional) - 'fit ellip' (optional) - 'fit pa' (optional) - 'fit photutils isolist' (optional) Returns ------- IMG : ndarray Unaltered galaxy image results : dict .. code-block:: python {'prof header': , # List object with strings giving the items in the header of the final SB profile (list) 'prof units': , # dict object that links header strings to units (given as strings) for each variable (dict) 'prof data': # dict object linking header strings to list objects containing the rows for a given variable (dict) } """ zeropoint = options["ap_zeropoint"] if "ap_zeropoint" in options else 22.5 fluxunits = options["ap_fluxunits"] if "ap_fluxunits" in options else "mag" if fluxunits == "intensity": params = [ "R", "I", "I_e", "totflux", "totflux_e", "ellip", "ellip_e", "pa", "pa_e", "a3", "a3_e", "b3", "b3_e", "a4", "a4_e", "b4", "b4_e", ] SBprof_units = { "R": "arcsec", "I": "flux*arcsec^-2", "I_e": "flux*arcsec^-2", "totflux": "flux", "totflux_e": "flux", "ellip": "unitless", "ellip_e": "unitless", "pa": "deg", "pa_e": "deg", "a3": "unitless", "a3_e": "unitless", "b3": "unitless", "b3_e": "unitless", "a4": "unitless", "a4_e": "unitless", "b4": "unitless", "b4_e": "unitless", } else: params = [ "R", "SB", "SB_e", "totmag", "totmag_e", "ellip", "ellip_e", "pa", "pa_e", "a3", "a3_e", "b3", "b3_e", "a4", "a4_e", "b4", "b4_e", ] SBprof_units = { "R": "arcsec", "SB": "mag*arcsec^-2", "SB_e": "mag*arcsec^-2", "totmag": "mag", "totmag_e": "mag", "ellip": "unitless", "ellip_e": "unitless", "pa": "deg", "pa_e": "deg", "a3": "unitless", "a3_e": "unitless", "b3": "unitless", "b3_e": "unitless", "a4": "unitless", "a4_e": "unitless", "b4": "unitless", "b4_e": "unitless", } SBprof_data = dict((h, []) for h in params) res = {} dat = IMG - results["background"] if not "fit R" in results and not "fit photutils isolist" in results: logging.info( "%s: photutils fitting and extracting image data" % options["ap_name"] ) geo = EllipseGeometry( x0=results["center"]["x"], y0=results["center"]["y"], sma=results["init R"] / 2, eps=results["init ellip"], pa=results["init pa"], ) ellipse = Photutils_Ellipse(dat, geometry=geo) isolist = ellipse.fit_image(fix_center=True, linear=False) res.update( { "fit photutils isolist": isolist, "auxfile fitlimit": "fit limit semi-major axis: %.2f pix" % isolist.sma[-1], } ) elif not "fit photutils isolist" in results: logging.info("%s: photutils extracting image data" % options["ap_name"]) list_iso = [] for i in range(len(results["fit R"])): if results["fit R"][i] <= 0: continue # Container for ellipse geometry geo = EllipseGeometry( sma=results["fit R"][i], x0=results["center"]["x"], y0=results["center"]["y"], eps=results["fit ellip"][i], pa=results["fit pa"][i], ) # Extract the isophote information ES = EllipseSample(dat, sma=results["fit R"][i], geometry=geo) ES.update(fixed_parameters=None) list_iso.append(Isophote(ES, niter=30, valid=True, stop_code=0)) isolist = IsophoteList(list_iso) res.update( { "fit photutils isolist": isolist, "auxfile fitlimit": "fit limit semi-major axis: %.2f pix" % isolist.sma[-1], } ) else: isolist = results["fit photutils isolist"] for i in range(len(isolist.sma)): SBprof_data["R"].append(isolist.sma[i] * options["ap_pixscale"]) if fluxunits == "intensity": SBprof_data["I"].append( np.median(isolist.sample[i].values[2]) / options["ap_pixscale"] ** 2 ) SBprof_data["I_e"].append(isolist.int_err[i]) SBprof_data["totflux"].append(isolist.tflux_e[i]) SBprof_data["totflux_e"].append(isolist.rms[i] / np.sqrt(isolist.npix_e[i])) else: SBprof_data["SB"].append( flux_to_sb( np.median(isolist.sample[i].values[2]), options["ap_pixscale"], zeropoint, ) ) SBprof_data["SB_e"].append( 2.5 * isolist.int_err[i] / (isolist.intens[i] * np.log(10)) ) SBprof_data["totmag"].append(flux_to_mag(isolist.tflux_e[i], zeropoint)) SBprof_data["totmag_e"].append( 2.5 * isolist.rms[i] / (np.sqrt(isolist.npix_e[i]) * isolist.tflux_e[i] * np.log(10)) ) SBprof_data["ellip"].append(isolist.eps[i]) SBprof_data["ellip_e"].append(isolist.ellip_err[i]) SBprof_data["pa"].append(isolist.pa[i] * 180 / np.pi) SBprof_data["pa_e"].append(isolist.pa_err[i] * 180 / np.pi) SBprof_data["a3"].append(isolist.a3[i]) SBprof_data["a3_e"].append(isolist.a3_err[i]) SBprof_data["b3"].append(isolist.b3[i]) SBprof_data["b3_e"].append(isolist.b3_err[i]) SBprof_data["a4"].append(isolist.a4[i]) SBprof_data["a4_e"].append(isolist.a4_err[i]) SBprof_data["b4"].append(isolist.b4[i]) SBprof_data["b4_e"].append(isolist.b4_err[i]) for k in SBprof_data.keys(): if not np.isfinite(SBprof_data[k][-1]): SBprof_data[k][-1] = 99.999 res.update( {"prof header": params, "prof units": SBprof_units, "prof data": SBprof_data} ) if "ap_doplot" in options and options["ap_doplot"]: if fluxunits == "intensity": Plot_I_Profile( dat, np.array(SBprof_data["R"]), np.array(SBprof_data["I"]), np.array(SBprof_data["I_e"]), np.array(SBprof_data["ellip"]), np.array(SBprof_data["pa"]), results, options, ) else: Plot_SB_Profile( dat, np.array(SBprof_data["R"]), np.array(SBprof_data["SB"]), np.array(SBprof_data["SB_e"]), np.array(SBprof_data["ellip"]), np.array(SBprof_data["pa"]), results, options, ) return IMG, res
#!/usr/bin/env python import fitsio import numpy.ma as ma from photutils.isophote import EllipseGeometry, Ellipse img = fitsio.read('data/image.fits') img = ma.masked_array(img, img == 0) g = EllipseGeometry(x0=266, y0=266, eps=0.240, sma=110, pa=1.0558) ell = Ellipse(img, geometry=g) iso = ell.fit_image(3, integrmode='median', sclip=3, nclip=2, linear=False, step=0.1)
import numpy as np from photutils.datasets import make_noise_image from photutils.isophote import EllipseGeometry, Ellipse from photutils import EllipticalAperture g = Gaussian2D(100., 75, 75, 20, 12, theta=40. * np.pi / 180.) ny = nx = 150 y, x = np.mgrid[0:ny, 0:nx] noise = make_noise_image((ny, nx), distribution='gaussian', mean=0., stddev=2., random_state=12345) data = g(x, y) + noise #========================================== geometry = EllipseGeometry(x0=75, y0=75, sma=20, eps=0.5, pa=20. * np.pi / 180) aper = EllipticalAperture((geometry.x0, geometry.y0), geometry.sma, geometry.sma * (1 - geometry.eps), geometry.pa) plt.imshow(data, origin='lower') aper.plot(color='white') plt.show() ellipse = Ellipse(data, geometry) isolist = ellipse.fit_image()
def Photutils_Fit(IMG, results, options): """Photutils elliptical isophote wrapper. This simply gives users access to the photutils isophote fitting method. See: `photutils <https://photutils.readthedocs.io/en/stable/isophote.html>`_ for more information. Notes ---------- :References: - 'background' - 'center' - 'init R' - 'init ellip' - 'init pa' Returns ------- IMG : ndarray Unaltered galaxy image results : dict .. code-block:: python {'fit ellip': , # array of ellipticity values (ndarray) 'fit pa': , # array of PA values (ndarray) 'fit R': , # array of semi-major axis values (ndarray) 'fit ellip_err': , # optional, array of ellipticity error values (ndarray) 'fit pa_err': , # optional, array of PA error values (ndarray) 'auxfile fitlimit': # optional, auxfile message (string) } """ dat = IMG - results["background"] geo = EllipseGeometry( x0=results["center"]["x"], y0=results["center"]["y"], sma=results["init R"] / 2, eps=results["init ellip"], pa=results["init pa"], ) ellipse = Photutils_Ellipse(dat, geometry=geo) isolist = ellipse.fit_image(fix_center=True, linear=False) res = { "fit R": isolist.sma[1:], "fit ellip": isolist.eps[1:], "fit ellip_err": isolist.ellip_err[1:], "fit pa": isolist.pa[1:], "fit pa_err": isolist.pa_err[1:], "fit photutils isolist": isolist, "auxfile fitlimit": "fit limit semi-major axis: %.2f pix" % isolist.sma[-1], } if "ap_doplot" in options and options["ap_doplot"]: Plot_Isophote_Fit( dat, res["fit R"], res["fit ellip"], res["fit pa"], res["fit ellip_err"], res["fit pa_err"], results, options, ) return IMG, res
def get_amplitude_at_r(r, image, x0, y0, ellip, theta): """ Finds the amplitude at an isophotal radius `r`. Parameters ---------- r : float or int Isophotal radius in pixels. image : CCDData or array Image to of the source. x0, y0 : float The center pixel coordinate of the ellipse. ellip : ellipticity The ellipticity of the ellipse. theta : float The position angle (in radians) of the semimajor axis in relation to the positive x axis of the image array (rotating towards the positive y axis). Position angles are defined in the range :math:`0 < PA <= \pi`. Avoid using as starting position angle of 0., since the fit algorithm may not work properly. When the ellipses are such that position angles are near either extreme of the range, noise can make the solution jump back and forth between successive isophotes, by amounts close to 180 degrees. Returns ------- amplitude_at_r : float or np.nan """ if isinstance(image, CCDData) or isinstance(image, Cutout2D): image = image.data r = float(r) try: # Define EllipseGeometry using ellip and theta g = EllipseGeometry(x0, y0, 1., ellip, theta) # Create Ellipse model ellipse = Ellipse(image, geometry=g) # Fit isophote at r_eff iso = ellipse.fit_isophote(r) # Get flux at r_eff amplitude = iso.intens except Exception as exception: import warnings warnings.warn("Amplitude could not be computed, returning np.nan. Exception: {}".format(str(exception)), Warning) amplitude = np.nan return amplitude
import numpy as np from photutils.datasets import make_noise_image from photutils.isophote import EllipseGeometry, Ellipse from photutils import EllipticalAperture #================================ fits_file = '/home/elismar/Documentos/Fisica/IC/imfit-1.7.1/ngc2992-93/images/GMOS/ngc2992/ngc2992_model3.fits' data = fits.getdata(fits_file) #================================ geometry = EllipseGeometry(x0=237, y0=168, sma=87, eps=0.3, pa=-58. * np.pi / 180) aper = EllipticalAperture((geometry.x0, geometry.y0), geometry.sma, geometry.sma * (1 - geometry.eps), geometry.pa) norm = plt.Normalize(0, 5000) plt.imshow(data, origin='lower', norm=norm) aper.plot(color='white') plt.show() ellipse = Ellipse(data, geometry) isolist = ellipse.fit_image()
def update_params(self, x0, y0, sma, eps, pa): self.params = {'x0': x0, 'y0': y0, 'sma': sma, 'eps': eps, 'pa': pa} self.geom = EllipseGeometry(**self.params) self.update_ellipse()
def ellipsefit_multiband(objid, objdir, data, sample, mgefit, nowrite=False, verbose=False): """Ellipse-fit the multiband data. See https://github.com/astropy/photutils-datasets/blob/master/notebooks/isophote/isophote_example4.ipynb """ from photutils.isophote import (EllipseGeometry, Ellipse, EllipseSample, Isophote, IsophoteList) from photutils.isophote.sample import CentralEllipseSample from photutils.isophote.fitter import CentralEllipseFitter band, refband, pixscale = data['band'], data['refband'], data['pixscale'] ellipsefit = dict() ellipsefit['success'] = False ellipsefit['redshift'] = sample['z'] ellipsefit['band'] = band ellipsefit['refband'] = refband ellipsefit['pixscale'] = pixscale for filt in band: ellipsefit['psfsigma_{}'.format(filt)] = sample['psfsize_{}'.format(filt)] # Default parameters integrmode, sclip, nclip, step, fflag = 'bilinear', 3, 0, 0.1, 0.5 #integrmode, sclip, nclip, step, fflag = 'median', 3, 0, 0.1, 0.5 # http://photutils.readthedocs.io/en/stable/isophote_faq.html#isophote-faq # Note: position angle in photutils is measured counter-clockwise from the # x-axis, while .pa in MGE measured counter-clockwise from the y-axis. geometry = EllipseGeometry(x0=mgefit['xpeak'], y0=mgefit['ypeak'], eps=mgefit['eps'], #sma=0.5*mgefit['majoraxis'], sma=10, pa=np.radians(mgefit['pa']-90)) ellipsefit['geometry'] = geometry def _sky(data, ellipsefit, diameter=2.0): """Estimate the sky brightness in each band.""" #area = diameter**2 # arcsec^2 for filt in band: img = data['{}_masked'.format(filt)] #ellipsefit['{}_sky'.format(filt)] = 22.5 - 2.5 * np.log10( ma.std(img) ) #ellipsefit['mu_{}_sky'.format(filt)] = ellipsefit['{}_sky'.format(filt)] # + 2.5 * np.log10(area) ellipsefit['mu_{}_sky'.format(filt)] = 22.5 - 2.5 * np.log10( ma.std(img) ) _sky(data, ellipsefit) # Fit in the reference band... if verbose: print('Ellipse-fitting the reference {}-band image.'.format(refband)) img = data['{}_masked'.format(refband)] ellipse = Ellipse(img, geometry=geometry) # First fit with the default parameters. try: t0 = time.time() with warnings.catch_warnings(): warnings.simplefilter('ignore') for minsma in (10, 1, 5): # try a few different starting minor axes print(' Trying minimum sma = {:.1f} pixels.'.format(minsma)) isophot = ellipse.fit_image(minsma=minsma, maxsma=1.5*mgefit['majoraxis'], integrmode=integrmode, sclip=sclip, nclip=nclip, step=step, fflag=fflag) if len(isophot) > 0: break if verbose: print('Time = {:.3f} sec'.format( (time.time() - t0) / 1)) if len(isophot) == 0: print('Ellipse-fitting failed, likely due to complex morphology or poor initial geometry.') else: ellipsefit['success'] = True ellipsefit[refband] = isophot tall = time.time() for filt in band: t0 = time.time() if filt == refband: # we did it already! continue if verbose: print('Ellipse-fitting {}-band image.'.format(filt)) img = data['{}_masked'.format(filt)] # Loop on the reference band isophotes but skip the first isophote, # which is a CentralEllipseSample object (see below). isobandfit = [] for iso in isophot: #for iso in isophot[1:]: g = iso.sample.geometry # fixed geometry # Use the same integration mode and clipping parameters. sample = EllipseSample(img, g.sma, geometry=g, integrmode=integrmode, sclip=sclip, nclip=nclip) sample.update() # Create an Isophote instance with the sample. isobandfit.append(Isophote(sample, 0, True, 0)) # Now deal with the central pixel; see # https://github.com/astropy/photutils-datasets/blob/master/notebooks/isophote/isophote_example4.ipynb #import pdb ; pdb.set_trace() #g = EllipseGeometry(x0=geometry.x0, y0=geometry.y0, eps=mgefit['eps'], sma=1.0) #g.find_center(img) ## Use the same integration mode and clipping parameters. #sample = CentralEllipseSample(img, g.sma, geometry=g, integrmode=integrmode, # sclip=sclip, nclip=nclip) #cen = CentralEllipseFitter(sample).fit() #isobandfit.append(cen) #isobandfit.sort() # Build the IsophoteList instance with the result. ellipsefit[filt] = IsophoteList(isobandfit) if verbose: print('Time = {:.3f} sec'.format( (time.time() - t0) / 1)) if verbose: print('Time for all images = {:.3f} sec'.format( (time.time() - tall) / 1)) except: print('Ellipse-fitting failed, likely due to too many masked pixels.') # Write out if not nowrite: legacyhalos.io.write_ellipsefit(objid, objdir, ellipsefit, verbose=verbose) return ellipsefit
image = fits.getdata(image) #The center pixel coordinates of the bulge x0 = 98.5 y0 = 98.5 bulge_3D = abel.Transform(image, direction='inverse', method='three_point', center=(y0, x0)).transform #======================= #Fitting ellipses to the 3D image in order to get its brigthness profile #======================= # geometry = EllipseGeometry(x0=98, y0=98, sma=15, eps=0.19, pa=(np.pi/180)*226) geometry = EllipseGeometry(x0=98, y0=98, sma=15, eps=0.0, pa=0) ellipse = Ellipse(bulge_3D, geometry) isolist = ellipse.fit_image(fix_pa=True, fix_eps=True) #======================== #Converting to mass profile #======================== #Considering 2MASS H-band of course magzp = 20.4107 distance = 38e+6 #pc solar_abs_mag = 3.32 gamma = 1.0
def isophote_data() : from photutils.isophote import EllipseGeometry from photutils import EllipticalAperture from photutils.isophote import Ellipse test = 'a2744/cutouts/a2744_ID_5830_f160w.fits' (data, dim, photfnu, R_e, redshift, sma, smb, pa) = open_cutout(test) (noise, _, _, _, _, _, _, _) = open_cutout('a2744/cutouts/a2744_ID_5830_f160w_noise.fits') plt.display_image_simple(data, cmap=cm.viridis) xlen, ylen = dim[1], dim[0] geometry = EllipseGeometry(x0=xlen/2, y0=ylen/2, sma=20, eps=0.5, pa=70*np.pi/180) aper = EllipticalAperture((geometry.x0, geometry.y0), geometry.sma, geometry.sma*(1 - geometry.eps), geometry.pa) # pyp.imshow(data, origin='lower') # aper.plot(color='white') ellipse = Ellipse(data, geometry) isolist = ellipse.fit_image() # print(isolist.tflux_e) isophotes = True if isophotes : plt.display_isophotes(data, isolist, cmap=cm.viridis) # from photutils.isophote import build_ellipse_model # model = build_ellipse_model(data.shape, isolist) # residual = data - model # plt.display_image_simple(residual, norm=None) annuli = True if annuli : from photutils import EllipticalAnnulus from photutils import aperture_photometry center = (isolist[0].x0, isolist[0].y0) # print(center) last = np.where(isolist.stop_code == 0)[0][-1] isolist = isolist[last] pa = isolist.pa # print(pa*180/np.pi) a_outs = np.arange(1e-5, isolist.sma, isolist.sma/11) b_outs = a_outs*(1-isolist.eps) for i in range(len(a_outs) - 1) : a_in = a_outs[i] a_out = a_outs[i+1] b_in = b_outs[i] b_out = b_outs[i+1] # print(a_in, a_out, b_in, b_out) aper = EllipticalAnnulus(center, a_in, a_out, b_out, b_in=b_in, theta=isolist.pa) phot_table = aperture_photometry(data, aper, error=noise) flux = phot_table['aperture_sum'][0] flux_err = phot_table['aperture_sum_err'][0] # print(flux) # print(flux_err) annulus_mask = aper.to_mask() annulus_data = annulus_mask.multiply(data) # plt.display_image_simple(annulus_data, cmap=cm.viridis, norm=None) # print(np.sum(annulus_data)) err_table = aperture_photometry(noise, aper) flux_err_alt = err_table['aperture_sum'][0] # print(flux_err) err_data = annulus_mask.multiply(noise) # print(np.sum(err_data)) # print(flux/flux_err) print(flux/flux_err_alt) # print() return
head = fits.open(fitsfile)[0].header fig, ax = plt.subplots(figsize=(8, 7)) # ax0,ax1,ax2,ax3,ax4,ax5,ax6,ax7,ax8 = axarr[0,0],axarr[0,1],axarr[0,2],axarr[1,0],axarr[1,1],axarr[1,2],axarr[2,0],axarr[2,1],axarr[2,2] ax.set_xlabel('x (Pixels)', fontsize=axisfont) ax.set_ylabel('y (Pixels)', fontsize=axisfont) cb = ax.imshow(data, vmin=10**11, vmax=2*10**14, cmap='gray_r', norm=LogNorm()) ax.tick_params(labelsize=ticksize, size=ticks) colorbar = plt.colorbar(cb) colorbar.ax.set_ylabel('Flux (erg/s/cm^2)', rotation=270, fontsize=axisfont-8) colorbar.ax.tick_params(labelsize=ticksize-4) geometry = EllipseGeometry(x0=350, y0=350, sma=20, eps=0, pa=0.) aper = EllipticalAperture((geometry.x0, geometry.y0), geometry.sma, geometry.sma*(1 - geometry.eps), geometry.pa) ellipse = Ellipse(data, geometry) isolist = ellipse.fit_image() #model_image = build_ellipse_model(data.shape, isolist) #residual = data - model_image smas = np.linspace(10, 200, 5) for sma in smas: iso = isolist.get_closest(sma) x, y, = iso.sampled_coordinates() ax.plot(x, y, color='red') plt.tight_layout() fig.savefig(figout+'kormendy_iso.pdf')