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 _fit_ellipse(burst_npy, acf, geometry, aper, sigma_t, sigma_f, plot=True): #Fit Ellipse to 2D ACF try: ellipse = Ellipse(acf, geometry) isolist = ellipse.fit_image() model_image = build_ellipse_model(acf.shape, isolist) residual = acf - model_image if plot == True: fig = plt.figure() smas = np.linspace(0, int(sigf3), 8) for sma in smas: iso = isolist.get_closest(sma) x, y, = iso.sampled_coordinates() plt.imshow(acf, aspect='auto') plt.plot(x, y, color='white') plt.show() fig.savefig(str(burst_npy) + '_ellipse_fit.png') except OverflowError: print('Note: Overflow Error') pass except ValueError: print('Note: Value Error') pass except IndexError: print('Ellipse Fit Failed!') pass print('Fit completed!') slope = np.tan(np.max(isolist.pa)) std_sma_dr_unround = np.tan(np.std(isolist.pa)) std_sma_dr = '%s' % float('%.2g' % std_sma_dr_unround) drift_rate_unround = -1 * (slope * (subfres / tres)) #MHz/ms drift_rate = '%s' % float('%.4g' % drift_rate_unround) #MHz/ms print('Drift Slope: ', str(drift_rate) + ' +/- ' + str(std_sma_dr) + ' MHz/ms') return drift_rate
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], # maxsma=nsize/2, fflag=0.3, sclip=3.0, nclip=3) # Join two list excluding the last solution from the outer fit since stop_code=4
def _Generate_Profile(IMG, results, R, E, Ee, PA, PAe, options): # Create image array with background and mask applied try: if np.any(results['mask']): mask = results['mask'] else: mask = None except: mask = None dat = IMG - results['background'] zeropoint = options['ap_zeropoint'] if 'ap_zeropoint' in options else 22.5 sb = [] sbE = [] cogdirect = [] sbfix = [] sbfixE = [] count_neg = 0 medflux = np.inf end_prof = None for i in range(len(R)): isobandwidth = R[i] * (options['ap_isoband_width'] if 'ap_isoband_width' in options else 0.025) if medflux > (results['background noise'] * (options['ap_isoband_start'] if 'ap_isoband_start' in options else 2)) or isobandwidth < 0.5: isovals = _iso_extract( dat, R[i], E[i], PA[i], results['center'], mask=mask, rad_interp=(options['ap_iso_interpolate_start'] if 'ap_iso_interpolate_start' in options else 5) * results['psf fwhm'], sigmaclip=options['ap_isoclip'] if 'ap_isoclip' in options else False, sclip_iterations=options['ap_isoclip_iterations'] if 'ap_isoclip_iterations' in options else 10, sclip_nsigma=options['ap_isoclip_nsigma'] if 'ap_isoclip_nsigma' in options else 5) isovalsfix = _iso_extract( dat, R[i], results['init ellip'], results['init pa'], results['center'], mask=mask, rad_interp=(options['ap_iso_interpolate_start'] if 'ap_iso_interpolate_start' in options else 5) * results['psf fwhm'], sigmaclip=options['ap_isoclip'] if 'ap_isoclip' in options else False, sclip_iterations=options['ap_isoclip_iterations'] if 'ap_isoclip_iterations' in options else 10, sclip_nsigma=options['ap_isoclip_nsigma'] if 'ap_isoclip_nsigma' in options else 5) else: isovals = _iso_between( dat, R[i] - isobandwidth, R[i] + isobandwidth, E[i], PA[i], results['center'], mask=mask, sigmaclip=options['ap_isoclip'] if 'ap_isoclip' in options else False, sclip_iterations=options['ap_isoclip_iterations'] if 'ap_isoclip_iterations' in options else 10, sclip_nsigma=options['ap_isoclip_nsigma'] if 'ap_isoclip_nsigma' in options else 5) isovalsfix = _iso_between( dat, R[i] - isobandwidth, R[i] + isobandwidth, results['init ellip'], results['init pa'], results['center'], mask=mask, sigmaclip=options['ap_isoclip'] if 'ap_isoclip' in options else False, sclip_iterations=options['ap_isoclip_iterations'] if 'ap_isoclip_iterations' in options else 10, sclip_nsigma=options['ap_isoclip_nsigma'] if 'ap_isoclip_nsigma' in options else 5) isotot = np.sum( _iso_between(dat, 0, R[i], E[i], PA[i], results['center'], mask=mask)) medflux = _average( isovals, options['ap_isoaverage_method'] if 'ap_isoaverage_method' in options else 'median') scatflux = _scatter( isovals, options['ap_isoaverage_method'] if 'ap_isoaverage_method' in options else 'median') medfluxfix = _average( isovalsfix, options['ap_isoaverage_method'] if 'ap_isoaverage_method' in options else 'median') scatfluxfix = _scatter( isovalsfix, options['ap_isoaverage_method'] if 'ap_isoaverage_method' in options else 'median') sb.append( flux_to_sb(medflux, options['ap_pixscale'], zeropoint ) if medflux > 0 else 99.999) sbE.append((2.5 * scatflux / (np.sqrt(len(isovals)) * medflux * np.log(10))) if medflux > 0 else 99.999) sbfix.append( flux_to_sb(medfluxfix, options['ap_pixscale'], zeropoint ) if medfluxfix > 0 else 99.999) sbfixE.append((2.5 * scatfluxfix / (np.sqrt(len(isovalsfix)) * np.median(isovalsfix) * np.log(10))) if medfluxfix > 0 else 99.999) cogdirect.append( flux_to_mag(isotot, zeropoint) if isotot > 0 else 99.999) if medflux <= 0: count_neg += 1 if 'ap_truncate_evaluation' in options and options[ 'ap_truncate_evaluation'] and count_neg >= 2: end_prof = i + 1 break # Compute Curve of Growth from SB profile cog, cogE = SBprof_to_COG_errorprop(R[:end_prof] * options['ap_pixscale'], np.array(sb), np.array(sbE), 1. - E[:end_prof], Ee[:end_prof], N=100, method=0, symmetric_error=True) cogE[cog > 99] = 99.999 cogfix, cogfixE = SBprof_to_COG_errorprop(R[:end_prof] * options['ap_pixscale'], np.array(sbfix), np.array(sbfixE), 1. - E[:end_prof], Ee[:end_prof], N=100, method=0, symmetric_error=True) cogfixE[cogfix > 99] = 99.999 # For each radius evaluation, write the profile parameters params = [ 'R', 'SB', 'SB_e', 'totmag', 'totmag_e', 'ellip', 'ellip_e', 'pa', 'pa_e', 'totmag_direct', 'SB_fix', 'SB_fix_e', 'totmag_fix', 'totmag_fix_e' ] SBprof_data = dict((h, None) for h in params) 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', 'totmag_direct': 'mag', 'SB_fix': 'mag*arcsec^-2', 'SB_fix_e': 'mag*arcsec^-2', 'totmag_fix': 'mag', 'totmag_fix_e': 'mag' } SBprof_format = { 'R': '%.4f', 'SB': '%.4f', 'SB_e': '%.4f', 'totmag': '%.4f', 'totmag_e': '%.4f', 'ellip': '%.3f', 'ellip_e': '%.3f', 'pa': '%.2f', 'pa_e': '%.2f', 'totmag_direct': '%.4f', 'SB_fix': '%.4f', 'SB_fix_e': '%.4f', 'totmag_fix': '%.4f', 'totmag_fix_e': '%.4f' } SBprof_data['R'] = list(R[:end_prof] * options['ap_pixscale']) SBprof_data['SB'] = list(sb) SBprof_data['SB_e'] = list(sbE) SBprof_data['totmag'] = list(cog) SBprof_data['totmag_e'] = list(cogE) SBprof_data['ellip'] = list(E[:end_prof]) SBprof_data['ellip_e'] = list(Ee[:end_prof]) SBprof_data['pa'] = list(PA[:end_prof] * 180 / np.pi) SBprof_data['pa_e'] = list(PAe[:end_prof] * 180 / np.pi) SBprof_data['totmag_direct'] = list(cogdirect) SBprof_data['SB_fix'] = list(sbfix) SBprof_data['SB_fix_e'] = list(sbfixE) SBprof_data['totmag_fix'] = list(cogfix) SBprof_data['totmag_fix_e'] = list(cogfixE) if 'ap_doplot' in options and options['ap_doplot']: CHOOSE = np.logical_and( np.array(SBprof_data['SB']) < 99, np.array(SBprof_data['SB_e']) < 1) errscale = 1. if np.all(np.array(SBprof_data['SB_e'])[CHOOSE] < 0.5): errscale = 1 / np.max(np.array(SBprof_data['SB_e'])[CHOOSE]) lnlist = [] lnlist.append( plt.errorbar(np.array(SBprof_data['R'])[CHOOSE], np.array(SBprof_data['SB'])[CHOOSE], yerr=errscale * np.array(SBprof_data['SB_e'])[CHOOSE], elinewidth=1, linewidth=0, marker='.', markersize=5, color='r', label='Surface Brightness (err$\\cdot$%.1f)' % errscale)) plt.errorbar(np.array(SBprof_data['R'])[np.logical_and( CHOOSE, np.arange(len(CHOOSE)) % 4 == 0)], np.array(SBprof_data['SB'])[np.logical_and( CHOOSE, np.arange(len(CHOOSE)) % 4 == 0)], yerr=np.array(SBprof_data['SB_e'])[np.logical_and( CHOOSE, np.arange(len(CHOOSE)) % 4 == 0)], elinewidth=1, linewidth=0, marker='.', markersize=5, color='limegreen') # plt.errorbar(np.array(SBprof_data['R'])[CHOOSE], np.array(SBprof_data['totmag'])[CHOOSE], yerr = np.array(SBprof_data['totmag_e'])[CHOOSE], # elinewidth = 1, linewidth = 0, marker = '.', markersize = 5, color = 'orange', label = 'Curve of Growth') plt.xlabel('Semi-Major-Axis [arcsec]', fontsize=16) plt.ylabel('Surface Brightness [mag arcsec$^{-2}$]', fontsize=16) bkgrdnoise = -2.5 * np.log10( results['background noise']) + zeropoint + 2.5 * np.log10( options['ap_pixscale']**2) lnlist.append( plt.axhline( bkgrdnoise, color='purple', linewidth=0.5, linestyle='--', label='1$\\sigma$ noise/pixel: %.1f mag arcsec$^{-2}$' % bkgrdnoise)) plt.gca().invert_yaxis() plt.tick_params(labelsize=14) # ax2 = plt.gca().twinx() # lnlist += ax2.plot(np.array(SBprof_data['R'])[CHOOSE], np.array(SBprof_data['pa'])[CHOOSE]/180, color = 'b', label = 'PA/180') # lnlist += ax2.plot(np.array(SBprof_data['R'])[CHOOSE], np.array(SBprof_data['ellip'])[CHOOSE], color = 'orange', linestyle = '--', label = 'ellipticity') labs = [l.get_label() for l in lnlist] plt.legend(lnlist, labs, fontsize=11) # ax2.set_ylabel('Position Angle, Ellipticity', fontsize = 16) # ax2.tick_params(labelsize = 14) plt.tight_layout() if not ('ap_nologo' in options and options['ap_nologo']): AddLogo(plt.gcf()) plt.savefig( '%sphotometry_%s.jpg' % (options['ap_plotpath'] if 'ap_plotpath' in options else '', options['ap_name']), dpi=options['ap_plotdpi'] if 'ap_plotdpi' in options else 300) plt.close() useR = np.array(SBprof_data['R'])[CHOOSE] / options['ap_pixscale'] useE = np.array(SBprof_data['ellip'])[CHOOSE] usePA = np.array(SBprof_data['pa'])[CHOOSE] ranges = [[ max(0, int(results['center']['x'] - useR[-1] * 1.2)), min(dat.shape[1], int(results['center']['x'] + useR[-1] * 1.2)) ], [ max(0, int(results['center']['y'] - useR[-1] * 1.2)), min(dat.shape[0], int(results['center']['y'] + useR[-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(useR)): plt.gca().add_patch( Ellipse( (results['center']['x'] - ranges[0][0], results['center']['y'] - ranges[1][0]), 2 * useR[i], 2 * useR[i] * (1. - useE[i]), usePA[i], fill=False, linewidth=((i + 1) / len(useR))**2, color='limegreen' if (i % 4 == 0) else 'r', linestyle='-' if useR[i] < results['fit R'][-1] else '--')) if not ('ap_nologo' in options and options['ap_nologo']): AddLogo(plt.gcf()) plt.savefig( '%sphotometry_ellipse_%s.jpg' % (options['ap_plotpath'] if 'ap_plotpath' in options else '', options['ap_name']), dpi=options['ap_plotdpi'] if 'ap_plotdpi' in options else 300) plt.close() return { 'prof header': params, 'prof units': SBprof_units, 'prof data': SBprof_data, 'prof format': SBprof_format }
def imod2snrconvseries(magdata, bandmod, frac=0.5): from scipy import signal from photutils.isophote import EllipseGeometry from photutils.isophote import Ellipse from photutils.isophote import build_ellipse_model cr = csstpkg.mag2cr(magdata['MOD_' + bandmod], band=bandmod) cr300poiss = poisson.rvs(cr * texp, size=1)[0] agalaxy = csstpkg.galser(lumtot=cr300poiss, reff=magdata['reff'], nser=magdata['nser'], ellip=1 - magdata['Eab']) # agalaxy.plotmodel() # Generating convolution image: apsf = csstpkg.psfgauss() normpsf = apsf.gauss()[2] / np.sum(apsf.gauss()[2]) agalconv = signal.fftconvolve(agalaxy.sermod()[2], normpsf, mode='same') # FITS file generating: # hduagalaxy = fits.PrimaryHDU(agalaxy.sermod()[2]) # hduagalaxy.writeto('test_agalaxy.fits',overwrite=True) # hduapsf = fits.PrimaryHDU(normpsf) # hduapsf.writeto('test_apsf.fits', overwrite=True) # hdr = fits.Header() # hdr['UVUDFID']=magdata['ID'] # hduagalconv = fits.PrimaryHDU(data=agalconv,header=hdr) # hduagalconv.writeto('test_agalconv.fits', overwrite=True) # build ellipse model and fit to convolved: ellipgeo = EllipseGeometry(x0=agalaxy.orig0[0], y0=agalaxy.orig0[1], sma=agalaxy.a, eps=agalaxy.ellip, pa=0) # aper = agalaxy.aperture0 ellipseinst = Ellipse(agalconv, geometry=ellipgeo) isophlist = ellipseinst.fit_image(minsma=1., maxsma=5*agalaxy.a) # print cr300poiss, isophlist.tflux_e[-1] if len(isophlist.valid) > 0: # model_image = build_ellipse_model(agalconv.shape, isophlist) # print 'sum of model:', np.sum(model_image) # residual = agalconv - model_image # # plot data, model and residual # fig, (ax1, ax2, ax3) = plt.subplots(figsize=(14, 5), nrows=1, ncols=3) # fig.subplots_adjust(left=0.04, right=0.98, bottom=0.02, top=0.98) # ax1.imshow(agalconv, origin='lower') # ax1.set_title('A Galaxy') # agalaxy.apers().plot(color='white',ax=ax1, lw=1) # ax2.imshow(model_image, origin='lower') # ax2.set_title('Ellipse Model') # ax3.imshow(residual, origin='lower') # ax3.set_title('Residual') # fig = plt.figure() # ax = fig.add_subplot(111, projection='3d') # ax.plot_wireframe(agalaxy.x, agalaxy.y, agalconv, color='blue', lw=1) # ax.plot_wireframe(agalaxy.x, agalaxy.y, model_image, color='red', lw=1) # plt.show() isophlist.fracflux = isophlist.tflux_e/cr300poiss # print isophlist.fracflux idx = find_nearest_idx(isophlist.fracflux, frac) # print isophlist[idx] snr = isolistsnr(isophlist[idx], bandmod='g') return snr else: return 'nan'
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
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
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
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
import Messier33 with fits.open("/home/s1539878/data/mphys/ellipse/m33_i_mosaic.fits") as d: head = d[0].header data = d[0].data x0 = head["CRPIX1"] y0 = head["CRPIX2"] #x1,y1 = np.unravel_index(np.argmax(data), data.shape) x2, y2 = (3013, 2651) PA = np.radians(112) sma = 500 e = np.cos(inclination) print(e, PA) geometry = isophote.EllipseGeometry(x2, y2, sma, e, PA) print(geometry.__dict__) #aper=EllipticalAperture((x2,y2),sma, sma*(1-e), PA) """ fig,ax = plt.subplots(1) plt.imshow(data) plt.scatter(x2,y2) aper.plot() plt.show() """ ellipse = Ellipse(data, geometry, threshold=0.01) #print(ellipse.fit_isophote(400)) isolist = ellipse.fit_image(300, 50, 2500, fix_pa=True) print(isolist.sma) isolist.to_table().to_pandas().to_csv("tmp")
#!/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 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
#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 count2mass(image, magzp, d, solar_abs_mag, gamma): app_mag = magzp - (2.5 * np.log10(image))
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
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) for sma in smas: iso = isolist.get_closest(sma)