def convolved(theta, **kwargs): amp1, reff1, amp2, reff2 = theta #, amp3, reff3, amp4, reff4 = theta # xs, ys = kwargs["xs"], kwargs["ys"] xs2, ys2 = kwargs["xs2"], kwargs["ys2"] #xs3, ys3 = kwargs["xs3"], kwargs["ys3"] #xs4, ys4 = kwargs["xs4"], kwargs["ys4"] arcIm = kwargs["arcIm"] #x2, y2 = 4013.63699909436, 4780.744281984086 # z10 #x3, y3 = 4016.430463104877, 4783.919833222558 # z10 xss, yss = kwargs["xss"], kwargs["yss"] star = kwargs["star"] #sersic1 = Sersic2D(amplitude=amp1, r_eff=reff1, n=n1, x_0=xs, y_0=ys) #sersic2 = Sersic2D(amplitude=amp2, r_eff=reff2, n=n2, x_0=xs2, y_0=ys2) #sersic3 = Sersic2D(amplitude=amp3, r_eff=reff3, n=n3, x_0=x3, y_0=y3) gauss1 = Gaussian2D(amp1, x_mean=xs, y_mean=ys, x_stddev=reff1, y_stddev=reff1) gauss2 = Gaussian2D(amp2, x_mean=xs2, y_mean=ys2, x_stddev=reff2, y_stddev=reff2) #gauss3 = Gaussian2D(amp3, x_mean=xs3, y_mean=ys3, x_stddev=reff3, y_stddev=reff3) #gauss4 = Gaussian2D(amp4, x_mean=xs4, y_mean=ys4, x_stddev=reff4, y_stddev=reff4) combined = gauss1 + gauss2 #+ gauss3 #+ gauss4 #S1S2_hires = gauss2d(xss, yss, amplitude=amp1, x_mean=xs, y_mean=ys, x_stddev=reff1, y_stddev=reff1, theta=0) S1S2 = combined(xss, yss) #S1S2 = rebin(S1S2_hires, arcIm.shape) S1conv = convolve(S1S2, star) return S1conv
def test_centroid_sym(): y, x = centered_grid_quadratic(51) img = Gaussian2D()(x, y) assert np.all(np.isclose(centroid(img), center_of_image(img))) y, x = centered_grid((51, 71)) img = Gaussian2D()(x, y) assert np.all(np.isclose(centroid(img), center_of_image(img)))
def test_subpixel_gauss_2D(): """ Test subpixel accuracy of the integrate mode with gaussian 2D model. """ gauss_2D = Gaussian2D(1, 0, 0, 0.1, 0.1) values = discretize_model(gauss_2D, (-1, 2), (-1, 2), mode='integrate', factor=100) assert_allclose(values.sum(), 2 * np.pi * 0.01, atol=0.00001)
def plot_heatmap_sigma(sigma,axi=None): if axi is None: fig,axi = plt.subplots(1) s = score_grid() board = boardsize() N = 201 fsize = 14 buff = 30 r = np.linspace(-board.c2od,board.c2od,N) x,y = np.meshgrid(r,r) g = Gaussian2D(1,0,0,sigma,sigma)(x,y) #Gaussian throw distribution Ex = fft(s,g,normalize_kernel=True) #expected 1-dart score aim = np.where(Ex == Ex.max()) xc,yc = np.median(x[aim]),np.median(y[aim]) im = axi.imshow(Ex*3,cmap='inferno',origin='lower',extent=[x.min(),x.max(),y.min(),y.max()]) axi.scatter(xc,yc,color='w',s=40,zorder=4) axi.scatter(xc,yc,color='r',s=20,zorder=5) axi.set_xticklabels([]) axi.set_yticklabels([]) axi.set_title('$\sigma=$%.1f mm'%sigma,fontsize=fsize) axi.set_xlim([x.min()-buff,x.max()+buff]) axi.set_ylim([x.min()-buff,x.max()+buff]) cbar = plt.colorbar(im,ax=axi) cbar.set_label('Expected 3-dart score',fontsize=fsize-3) drawBoard(ax=axi,color_on=False,zorder=3)
def setup_class(cls): cls.model = Gaussian2D(x_stddev=4, y_stddev=4, x_mean=50, y_mean=50) cls.data = np.zeros((101, 101)) cls.model.render(cls.data) cls.epsf = EPSFModel(data=cls.data) cls.epsf_os2 = EPSFModel(data=cls.data, oversampling=2)
def test_centroid_asym(xy): y_grid, x_grid = centered_grid_quadratic(101) xy = np.array(xy) xy_expected = xy + center_of_image(x_grid) img = Gaussian2D(x_mean=xy[0], y_mean=xy[1])(x_grid, y_grid) assert np.all(np.isclose(centroid(img), xy_expected))
def test_discretize_oversample(): gauss_2D = Gaussian2D(amplitude=1.0, x_mean=5., y_mean=125., x_stddev=0.75, y_stddev=3) values = discretize_model(gauss_2D, x_range=[0, 10], y_range=[100, 135], mode='oversample', factor=10) vmax = np.max(values) vmax_yx = np.unravel_index(values.argmax(), values.shape) values_osf1 = discretize_model(gauss_2D, x_range=[0, 10], y_range=[100, 135], mode='oversample', factor=1) values_center = discretize_model(gauss_2D, x_range=[0, 10], y_range=[100, 135], mode='center') assert values.shape == (35, 10) assert_allclose(vmax, 0.927, atol=1e-3) assert vmax_yx == (25, 5) assert_allclose(values_center, values_osf1)
def _setPSFModel(self, model): if model == 'gaussian': self._setGaussianModel() self._gaussianModel = Gaussian2D(amplitude=self._amplitude, x_stddev=self._sx, y_stddev=self._sy, x_mean=self._xMean, y_mean=self._yMean, theta=self._theta) self._gaussianModel.fluxname = 'amplitude' self._gaussianModel.xname = 'x_mean' self._gaussianModel.yname = 'y_mean' self._psfModel = self._gaussianModel elif model == 'moffat': self._setMoffatModel() self._moffatModel = Moffat2D(amplitude=self._amplitude, x_0=self._x0, y_0=self._y0, gamma=self._gamma, alpha=self._alpha) self._moffatModel.fluxname = 'amplitude' self._psfModel = self._moffatModel elif model == 'integrated gaussian': self._setIntGaussianModel() self._psfModel = IntegratedGaussianPRF(sigma=self._sigma, flux=self._flux, x_0=self._xPeak, y_0=self._yPeak) else: self._psfModel = model
def fit_gaus(image, x0, y0, gate, debug, fig_name=None, centring=False, silent=False): data_fit = image[y0 - gate:y0 + gate, x0 - gate:x0 + gate] if centring: if not silent: print("centring...") # ------------------------------------------------------------------ find brighter pixel and center it!!!! bx0, by0 = np.unravel_index(data_fit.argmax(), data_fit.shape) if not silent: print("bx, by=", bx0, by0) sx = by0 - gate sy = bx0 - gate data_fit = image[y0 - gate + sy:y0 + gate + sy, x0 - gate + sx:x0 + gate + sx] # ---------------------------------------------------------------------------------------- Z3 = data_fit X3 = np.arange(0, gate * 2, 1) Y3 = np.arange(0, gate * 2, 1) X3, Y3 = np.meshgrid(X3, Y3) sigma = np.std(Z3) g_init = Gaussian2D(amplitude=np.max(Z3), x_mean=gate, y_mean=gate) fit_g = fitting.LevMarLSQFitter() with warnings.catch_warnings(): # Ignore model linearity warning from the fitter warnings.simplefilter('ignore') g = fit_g(g_init, X3, Y3, Z3) # print("#####Moffat#########") # print(m.x_0.value) # print(m.y_0.value) Zmm = g(X3, Y3) RMSE, Rsquared = R2_calc(Zmm, Z3) # print("x=%2.3f y=%2.3f R^2=%2.4f" % (m.x_0.value + xs - gate, m.y_0.value + ys - gate, Rsquared)) amp = np.max(Z3) fwhm = (g.x_fwhm + g.y_fwhm) / 2. target = [ x0 - gate + g.x_mean.value, y0 - gate + g.y_mean.value, fwhm, Rsquared, amp ] if debug: # plotting(data_fit, par, save=True, filename=fig_name, par=target, gate=gate) par = [g.x_mean.value, g.y_mean.value, fwhm] plotting(data_fit, par, save=True, filename=fig_name, par=par, err=[0., 0.], tar=target, gate=gate) return target
def make_gauss_kernel(σ=1.0, N=5): """create a gaussian convolution kernel for the EPSF smoothing step""" mod = Gaussian2D(x_stddev=σ, y_stddev=σ) y, x = np.mgrid[-N / 2:N / 2:N * 1j, -N / 2:N / 2:N * 1j] ev = mod(y, x) return ev / np.sum(ev)
def test_gaussian_eval_2D_integrate_mode(): """ Discretize Gaussian with integrate mode """ model_list = [Gaussian2D(.01, 0, 0, 2, 2), Gaussian2D(.01, 0, 0, 1, 2), Gaussian2D(.01, 0, 0, 2, 1)] x = np.arange(-2, 3) y = np.arange(-2, 3) x, y = np.meshgrid(x, y) for model in model_list: values = model(x, y) disc_values = discretize_model(model, (-2, 3), (-2, 3), mode='integrate') assert_allclose(values, disc_values, atol=1e-2)
def gauss2D_fit_erf(self, p, fjac=None, x=None, y=None, z=None, err=None): ''' Computes the residuals to be minimized by mpfit, given a model and data. ''' model = Gaussian2D(p[0], p[1], p[2], p[3], p[4], np.radians(p[5]))(x, y) status = 0 return ([status, ((z - model) / err).ravel()])
def gaussian(self, cen=psf_cen): ampl = 1 theta = 0 sigma = self.seeing.value / 2 / np.sqrt(2 * np.log(2)) m = Gaussian2D(ampl, cen[0], cen[1], sigma, sigma, theta) self.z = m.evaluate(self.x, self.y, ampl, cen[0], cen[1], sigma, sigma, theta) self.sigma = m.x_stddev self.fwhm = m.x_fwhm
def make_seeing_psf(): scale = 0.2 # arcsec/pixel resolution = 0.65 # arcsec resolution /= scale x, y = np.mgrid[0:100, 0:100] psf = Gaussian2D.eval(x, y, 1, 50, 50, resolution) return psf
def makeGaussian_astropy(size,amplitude, std, bpa, center): """ Make a square gaussian kernel. size is the length of a side of the square fwhm is full-width-half-maximum, which can be thought of as an effective radius. """ x, y = np.mgrid[0:size:size,0:size:size] return Gaussian2D(amplitude=amplitude, x_mean=center[0], y_mean=center[1], x_stddev=std[0], y_stddev=std[1], theta=bpa*-1, cov_matrix=None)(x,y)
def generate_gaussian(*, amplitude: float, fwhm: float, canvas_radius: float, px_size_nm: float) -> np.ndarray: """ Generates a 2D gaussian pattern. """ stddev = fwhm / px_size_nm * gaussian_fwhm_to_sigma model = Gaussian2D(amplitude=amplitude, x_stddev=stddev, y_stddev=stddev) x, y = _canvas_meshgrid(canvas_radius, px_size_nm) result = model(x, y) return result
def gaussian2d(xx, yy, x0, y0, amp, width, e, pa): # creates a 2d gaussian (w/ ellipticity and pa) given the # mesharrays xx and yy with the x and y values of the 2d array sigxp = width sigyp = width * np.sqrt((1 - e) / (1 + e)) model = Gaussian2D(amplitude=amp, x_mean=x0, y_mean=y0, x_stddev=sigxp, y_stddev=sigyp, theta=np.pi * pa / 180) return model(xx, yy)
def _realisticTransmissionMap(self): ima = np.ones(self._shape) y, x = np.indices(ima.shape) vign_model = Gaussian2D(amplitude=1, x_mean=self._shape[1] / 2, y_mean=self._shape[0] / 2, x_stddev=2 * self._shape[1], y_stddev=2 * self._shape[0]) vign_im = vign_model(x, y) ima *= vign_im return ima
def make_seeing_psf(filt_name): psf_file = "seeing_psf_{0:s}.pickle".format(filt_name) seeing = 0.8 # arcsec specified at 5000 Angstrom wave = filt_wave[filt_name] # In Angstroms print "Seeing at 5000 Angstroms:", seeing seeing *= (wave / 5000) ** (-1.0 / 5.0) print "Seeing at {0:s} band:".format(filt_name), seeing # Make a very over-sampled PSF and do integrals # on that... faster than scipy.integrate. print "Prep" pix_scale = 0.01 # arcsec xy1d = np.arange(-10 * seeing, 10 * seeing, pix_scale) x, y = np.meshgrid(xy1d, xy1d) # Use a 2D Gaussian as our PSF. print "Make Gaussian sigma=", seeing / 2.35 psf = Gaussian2D.eval(x, y, 1, 0, 0, seeing / 2.35, seeing / 2.35, 0) # Integrate over each pixel print "Integrate and normalize" psf *= pix_scale ** 2 # Normalize psf /= psf.sum() # Get the radius of each pixel r = np.hypot(x, y) # Make an encircled energy curve. r_save = np.arange(0.025, 2, 0.025) ee_save = np.zeros(len(r_save), dtype=float) for rr in range(len(r_save)): print "Integrating for ", r_save[rr] idx = np.where(r < r_save[rr]) ee_save[rr] = psf[idx].sum() print "Save" _psf = open(psf_file, "w") pickle.dump(r_save, _psf) pickle.dump(ee_save, _psf) _psf.close() return
def test_gaussian_eval_2D(mode): """ Discretize Gaussian with different modes and check if result is at least similar to Gaussian2D.eval() """ model = Gaussian2D(0.01, 0, 0, 1, 1) x = np.arange(-2, 3) y = np.arange(-2, 3) x, y = np.meshgrid(x, y) values = model(x, y) disc_values = discretize_model(model, (-2, 3), (-2, 3), mode=mode) assert_allclose(values, disc_values, atol=1e-2)
def multi_source_testimage(): img = np.zeros((301, 301)) xs = [50, 50, 120.1, 100, 20] ys = [50, 57, 130, 20.3, 100.8] fluxes = [10, 20, 20, 10, 30] model = Gaussian2D(x_mean=0, y_mean=0, x_stddev=1.5, y_stddev=1.5) for x, y, f in zip(xs, ys, fluxes): model.x_mean = x model.y_mean = y model.amplitude = f model.render(img) tab = Table((xs, ys, fluxes, flux_to_magnitude(fluxes)), names=COLUMN_NAMES) return img, tab
def plot_heatmap(parent=None): #get the scores on the board if parent is not None: frame = Frame(parent,width=600,height=500,bg='grey') frame.grid(row=0,column=1,padx=10,pady=50) s = score_grid() board = boardsize() N = 201 buff = 40 #buffer for plotting fsize = 14 r = np.linspace(-board.c2od,board.c2od,N) x,y = np.meshgrid(r,r) fig,ax = plt.subplots(2,2) for j,sigma in enumerate([3,15,30,60]): g = Gaussian2D(1,0,0,sigma,sigma)(x,y) #Gaussian throw distribution Ex = fft(s,g,normalize_kernel=True) #expected 1-dart score axi = ax.flatten()[j] aim = np.where(Ex == Ex.max()) xc,yc = np.median(x[aim]),np.median(y[aim]) im = axi.imshow(Ex*3,cmap='inferno',origin='lower',extent=[x.min(),x.max(),y.min(),y.max()]) axi.scatter(xc,yc,color='w',s=40,zorder=4) axi.scatter(xc,yc,color='r',s=20,zorder=5) axi.set_xticklabels([]) axi.set_yticklabels([]) axi.set_title('$\sigma=$%.1f mm'%sigma,fontsize=fsize) axi.set_xlim([x.min()-buff,x.max()+buff]) axi.set_ylim([x.min()-buff,x.max()+buff]) cbar = plt.colorbar(im,ax=axi) cbar.set_label('Expected 3-dart score',fontsize=fsize-3) drawBoard(ax=axi,color_on=False,zorder=3) plt.tight_layout() #plt.show() if parent is not None: canvas = FigureCanvasTkAgg(fig, master=frame) #canvas.show() canvas.get_tk_widget().place(x=5,y=5,width=590,height=490) else: plt.show()
def gaussian_fit_psf_photometry(image, obj_pos, box_size=15, bkgd_poly_deg=1, x_std=0.5, y_std=2, theta=np.pi / 4, interpolate=False): """ performs PSF photometry by fitting a plane background model and a gaussian :param image: 2D array image :param obj_pos: location of the satellite spot (in pixels) :param box_size: box size in which to perform the fit :param bkgd_poly_deg: degree polynomial with which to it the background :param x_std: standard deviation of the gaussian with which to fit the satellite spot - x direction :param y_std: standard deviation of the gaussian with which to fit the satellite spot - y direction :param theta: angle off 'up' that the spot makes :param interpolate: is True will interpolate the image before performing the fit - recommended for non drizzled data :return: total satellite spot counts (in counts/sec) """ x_pos = int(obj_pos[1]) y_pos = int(obj_pos[0]) frame = image[x_pos - box_size:x_pos + box_size, y_pos - box_size:y_pos + box_size] if len(frame[frame == 0]) > (len(frame.flatten()) / 2): print( 'More than half of the frame values are 0 - returning None for the flux' ) return None, None else: if interpolate: frame = interpolateImage(frame) x, y = np.meshgrid(np.arange(np.shape(frame)[0]), np.arange(np.shape(frame)[0])) p_spot_init = Gaussian2D(x_mean=box_size, y_mean=box_size, x_stddev=x_std, y_stddev=y_std, theta=theta) p_back_init = Polynomial2D(degree=bkgd_poly_deg) p_init = p_spot_init + p_back_init fit_p = fitting.LevMarLSQFitter() p = fit_p(p_init, x, y, frame) signal = p[0](x, y) return np.sum(signal)
def KDE_Gaussian(self): X = self.X Y = self.Y Z = self.KDE() kg2D_init = Gaussian2D( amplitude=np.max(Z), x_mean=X[np.unravel_index(np.argmax(Z), Z.shape)], y_mean=Y[np.unravel_index(np.argmax(Z), Z.shape)], x_stddev=np.std(X), y_stddev=np.std(Y), bounds={ 'theta': (-2 * np.pi, 2 * np.pi), 'x_mean': (np.min(X), np.max(X)), 'y_mean': (np.min(Y), np.max(Y)), 'x_stddev': (0.001, 1), 'y_stddev': (0.001, 1) }) kg2D = fitter(kg2D_init, X, Y, Z, weights=Z) kde_G = kg2D.evaluate(X, Y, kg2D.amplitude.value, kg2D.x_mean.value, kg2D.y_mean.value, kg2D.x_stddev.value, kg2D.y_stddev.value, kg2D.theta.value) return kg2D, kde_G
def create_frame(background=0, std=100, crpix=None, keys=None): size = (100, 100) # Update WCS header wcs = create_wcs(crpix) y, x = numpy.mgrid[:100, :100] data = numpy.random.normal(background, std, size) model = Gaussian2D(amplitude=30 * background, x_mean=wcs.wcs.crpix[0] - 3.5, y_mean=wcs.wcs.crpix[1] - 12.8, x_stddev=3.0, y_stddev=4.0) data += model(x, y) hdu = fits.PrimaryHDU(data) hdu.header = wcs.to_header() if keys: for k, v in keys.items(): hdu.header[k] = v return fits.HDUList([hdu])
def estimate_fwhm(psf: phot.psf.EPSFModel) -> float: """ Use a 2D symmetric gaussian fit to estimate the FWHM of an empirical psf :param psf: psfmodel to estimate :return: FWHM in pixel coordinates, takes into account oversampling parameter of EPSF """ from astropy.modeling import fitting from astropy.modeling.functional_models import Gaussian2D # Not sure if this would work for non-quadratic images assert (psf.data.shape[0] == psf.data.shape[1]) assert (psf.oversampling[0] == psf.oversampling[1]) dim = psf.data.shape[0] center = int(dim / 2) gauss_in = Gaussian2D(x_mean=center, y_mean=center, x_stddev=5, y_stddev=5) # force a symmetric gaussian gauss_in.y_stddev.tied = lambda model: model.x_stddev x, y = np.mgrid[:dim, :dim] gauss_out = fitting.LevMarLSQFitter()(gauss_in, x, y, psf.data) # have to divide by oversampling to get back to original scale return gauss_out.x_fwhm / psf.oversampling[0]
def make_anisocado_model(*, oversampling=2, degree=5, seed=0, offaxis=(0, 14), lowpass=0): img = AnalyticalScaoPsf(pixelSize=0.004 / oversampling, N=400 * oversampling + 1, seed=seed).shift_off_axis(*offaxis) if lowpass != 0: y, x = np.indices(img.shape) # find center of PSF image x_mean, y_mean = centroid_quadratic(img, fit_boxsize=5) img = img * Gaussian2D(x_mean=x_mean, y_mean=y_mean, x_stddev=lowpass * oversampling, y_stddev=lowpass * oversampling)(x, y) img /= np.sum(img) origin = centroid_quadratic(img, fit_boxsize=5) return AnisocadoModel(img, oversampling=oversampling, degree=degree, origin=origin)
def __init__(self, q=None, u=None): self.q = q self.u = u self.muq = self.q.mean() self.muu = self.u.mean() self.mu = np.array([self.muq, self.muu]) max_range = np.max( [self.q.max() - self.q.min(), self.u.max() - self.u.min()]) self.X, self.Y = np.meshgrid( np.linspace(self.muq - max_range / 2, self.muq + max_range / 2, 100), np.linspace(self.muu - max_range / 2, self.muu + max_range / 2, 100)) self.cov = (1 / self.q.size) * np.sum([ np.outer(np.array([Q, U]) - self.mu, np.array([Q, U]) - self.mu) for Q, U in zip(self.q, self.u) ], axis=0) self.g2D = Gaussian2D(x_mean=self.muq, y_mean=self.muu, cov_matrix=self.cov) self.G = self.g2D.evaluate(self.X, self.Y, self.g2D.amplitude.value, self.g2D.x_mean.value, self.g2D.y_mean.value, self.g2D.x_stddev.value, self.g2D.y_stddev.value, self.g2D.theta.value) self.stdq = np.sqrt(np.var(self.q)) self.stdu = np.sqrt(np.var(self.u)) self.theta = np.rad2deg(self.g2D.theta.value) self.r, self.p = pearsonr(self.q, self.u) self.L = 2 * self.stdq * self.stdu * np.sqrt(1 - self.r**2) / ( self.stdq**2 + self.stdu**2) self.sig = self.L**(self.q.size - 2)
plt.loglog(Ns, [psf_to_sigma(img, N, 5, 0) for N in Ns]) plt.loglog(Ns, [psf_to_sigma(img, N, 2, 0) for N in Ns]) plt.loglog(Ns, [psf_to_sigma(img, N, 0, 0) for N in Ns]) plt.loglog(Ns, [psf_to_sigma_d(img, N, 10, 0) for N in Ns]) plt.loglog(Ns, [psf_to_sigma_d(img, N, 5, 0) for N in Ns]) plt.loglog(Ns, [psf_to_sigma_d(img, N, 2, 0) for N in Ns]) plt.loglog(Ns, [psf_to_sigma_d(img, N, 0, 0) for N in Ns]) # plt.loglog(Ns,[psf_to_sigma(img, N, 50, 1) for N in Ns]) # plt.loglog(Ns,[psf_to_sigma(img, N, 10, 0) for N in Ns]) # plt.loglog(Ns,[psf_to_sigma(img, N, 0, 0) for N in Ns]) # %% from astropy.modeling.functional_models import Gaussian2D, AiryDisk2D y, x = np.mgrid[-10:10:512j, -10:10:512j] g3 = Gaussian2D(x_stddev=3, y_stddev=3)(x, y) g15 = Gaussian2D(x_stddev=1.5, y_stddev=1.5)(x, y) airy = AiryDisk2D(radius=3)(x, y) figure() plt.loglog(Ns, [psf_to_sigma(g3, N, 0, 0) for N in Ns]) plt.loglog(Ns, [psf_to_sigma(g15, N, 0, 0) for N in Ns]) plt.loglog(Ns, [psf_to_sigma(airy, N, 0, 0) for N in Ns]) plt.loglog(Ns, [psf_to_sigma(img, N, 0, 0) for N in Ns]) # %% from sympy import Function, Sum, symbols, ln, Eq from sympy.abc import N, i η, ζ = symbols('ζ,η')
def KDE_fit(x, y): """ A function that performs a gaussian KDE on x/y data, then fits the result with a sum of 2 2D gaussians Parameters ---------- x : array-like x data y : array-like y data Returns ------- KDE_bandwidth : float Cross-validated kernel bandwidth KD_fit_sqresid : float The mean squared residual (fit - KDE)^2 amp_0 : float amplitude of largest gaussian xmean_0 : float x mean of largest gaussian ymean_0 : float y mean of largest gaussian major_std_0 : float Standard deviation along major axis of largest gaussian theta_0 : float Radians between positive X-axis and the major axis of the largest gaussian ecc_0 : float Eccentricity of an ellipse, taken at an arbitrary height of the largest gaussian amp_1 : float amplitude of smallest gaussian xmean_1 : float x mean of smallest gaussian ymean_1 : float y mean of smallest gaussian major_std_1 : float Standard deviation along major axis of smallest gaussian theta_1 : float Radians between positive X-axis and the major axis of the largest gaussian ecc_1 : float Eccentricity of an ellipse, taken at an arbitrary height of the smallest gaussian """ data = np.vstack([x, y]).T #Grid search for best KDE bandwidth params = { 'bandwidth': np.linspace(np.min(np.diff(y)), np.max(np.diff(y)), 100) } grid = GridSearchCV(KernelDensity(), params) grid.fit(data) KDE_bandwidth = grid.best_estimator_.bandwidth kde = grid.best_estimator_ X, Y = np.meshgrid(np.linspace(np.min(x), np.max(x), 100), np.linspace(np.min(y), np.max(y), 100)) xy = np.vstack([X.ravel(), Y.ravel()]).T #compute the KDE on a 100x100 grid of points Z = np.exp(kde.score_samples(xy)).reshape(X.shape) #fit KDE estimation with 2 Gaussian model g2D_init1 = Gaussian2D(amplitude=np.max(Z), x_mean=X[np.unravel_index(np.argmax(Z), Z.shape)], y_mean=Y[np.unravel_index(np.argmax(Z), Z.shape)], x_stddev=np.std(x), y_stddev=np.std(y), theta=0, bounds={ 'theta': (0, np.pi), 'x_mean': (np.min(x), np.max(x)), 'y_mean': (np.min(y), np.max(y)), 'x_stddev': (0.001, 1), 'y_stddev': (0.001, 1) }) g2D_init2 = Gaussian2D(amplitude=np.median(Z), x_mean=np.median(x), y_mean=np.median(y), x_stddev=np.std(x), y_stddev=np.std(y), theta=0, bounds={ 'theta': (0, np.pi), 'x_mean': (np.min(x), np.max(x)), 'y_mean': (np.min(y), np.max(y)), 'x_stddev': (0.001, 1), 'y_stddev': (0.001, 1) }) g2D_init = g2D_init1 + g2D_init2 fitter = fitting.LevMarLSQFitter() g2D = fitter(g2D_init, X, Y, Z) KD_fit_sqresid = np.mean(np.power(Z - g2D(X, Y), 2.0)) #Sort by largest and smallest amplitude gaussian i_large = np.argmax([g2D.amplitude_0, g2D.amplitude_1]) i_small = np.argmin([g2D.amplitude_0, g2D.amplitude_1]) g2D_large = g2D[i_large] g2D_small = g2D[i_small] amp_0 = g2D_large.amplitude.value amp_1 = g2D_small.amplitude.value xmean_0 = g2D_large.x_mean.value xmean_1 = g2D_small.x_mean.value ymean_0 = g2D_large.y_mean.value ymean_1 = g2D_small.y_mean.value if g2D_large.x_stddev >= g2D_large.y_stddev: major_std_0 = g2D_large.x_stddev.value theta_0 = g2D_large.theta.value ecc_0 = np.sqrt(1.0 - (g2D_large.y_stddev.value / g2D_large.x_stddev.value)**2.0) else: major_std_0 = g2D_large.y_stddev.value if g2D_large.theta <= np.pi / 2: theta_0 = np.pi / 2 + g2D_large.theta.value elif g2D_large.theta > np.pi / 2: theta_0 = g2D_large.theta.value - np.pi / 2 ecc_0 = np.sqrt(1.0 - (g2D_large.x_stddev.value / g2D_large.y_stddev.value)**2.0) if g2D_small.x_stddev >= g2D_small.y_stddev: major_std_1 = g2D_small.x_stddev.value theta_1 = g2D_small.theta.value ecc_1 = np.sqrt(1.0 - (g2D_small.y_stddev.value / g2D_small.x_stddev.value)**2.0) else: major_std_1 = g2D_small.y_stddev.value if g2D_small.theta <= np.pi / 2: theta_1 = np.pi / 2 + g2D_small.theta.value elif g2D_small.theta > np.pi / 2: theta_1 = g2D_small.theta.value - np.pi / 2 ecc_1 = np.sqrt(1.0 - (g2D_small.x_stddev.value / g2D_small.y_stddev.value)**2.0) return (KDE_bandwidth, KD_fit_sqresid, amp_0, xmean_0, ymean_0, major_std_0, theta_0, ecc_0, amp_1, xmean_1, ymean_1, major_std_1, theta_1, ecc_1)
def fit_gaussian(self, plot=True, verbose=False, save=None, **kwargs): """ Perform a fit of a 2D gaussian. Input: - plot: (optional) bool. If True, makes a plot of the image with the contours of the gaussian - verbose: (optional) bool. If True, prints the verbose of mpdfit - additional optional keywords can be 'amp', 'centerx', 'centery', 'sigmax','sigmay','fwhm' or 'theta' to set the value of the first guess of the fit. theta must be between 0 and 90 - save: (optional) string with the name to save a pdf of the fit (only valid if plot=True) and a ds9 reg file (still to be implemented) Output: - fit_result: a dictionary with the parameters of the best fit. The entries are 'AMP' 'X' 'FWHMX' 'Y' 'FWHMY' 'FWHM' 'THETA' 'ell' - fit_error: a dictionary with the parameters of the error on the previous parameters (same entries) - chi2: value of the chi square - chi2_reduced: value of the reduced chi squared """ # We first set a default guess filtered_image = gaussian_filter(self.subimage, 2) # if save is not None: # fits.writeto(save+'_initial.fits',self.subimage,clobber=True) argmax = np.nanargmax(filtered_image) ymax, xmax = np.unravel_index(argmax, self.subimage.shape) amp = np.nanmax(self.subimage) centerx = xmax - self.subimage_half_size_x # the x center is in the range -subimage_half_size_x .. subimage_half_size_x centery = ymax - self.subimage_half_size_y # the y center is in the range -subimage_half_size_y .. subimage_half_size_y guess_dico = { 'amp': amp, 'centerx': centerx, 'centery': centery, 'sigx': 2., 'sigy': 2., 'theta': 0. } for k, v in kwargs.items(): if k in guess_dico.keys(): guess_dico[k] = v elif k == 'fwhm': guess_dico['sigx'] = fwhm2sig(v) guess_dico['sigy'] = fwhm2sig(v) elif k == 'fwhmx': guess_dico['sigx'] = fwhm2sig(v) elif k == 'fwhmy': guess_dico['sigy'] = fwhm2sig(v) else: raise TypeError('Keyword {0:s} not understood'.format(k)) # We also set default boundaries parinfo = [ { 'fixed': 0, 'limited': [1, 1], 'limits': [0., 2 * np.max([guess_dico['amp'], amp])] }, # Force the amplitude to be >0 { 'fixed': 0, 'limited': [1, 1], 'limits': [ -self.subimage_half_size_x + 1, self.subimage_half_size_x - 2 ] }, # We restrain the center to be 1px { 'fixed': 0, 'limited': [1, 1], 'limits': [ -self.subimage_half_size_y + 1, self.subimage_half_size_y - 2 ] }, # away from the edge { 'fixed': 0, 'limited': [1, 1], 'limits': [0.5, np.max([10., guess_dico['sigx']])] }, # sigma_x between 0.5 and 10px { 'fixed': 0, 'limited': [1, 1], 'limits': [0.5, np.max([10., guess_dico['sigy']])] }, # sigma_y between 0.5 and 10px { 'fixed': 0, 'limited': [1, 1], 'limits': [0, 180.] } ] # We limit theta beween 0 and 90 deg x_vect = np.arange(-self.subimage_half_size_x, self.subimage_half_size_x) y_vect = np.arange(-self.subimage_half_size_y, self.subimage_half_size_y) x_array, y_array = np.meshgrid(x_vect, y_vect) fa = { 'x': x_array, 'y': y_array, 'z': self.subimage, 'err': np.ones_like(self.subimage) * self.sky_rms } guess = [ guess_dico['amp'], guess_dico['centerx'], guess_dico['centery'], guess_dico['sigx'], guess_dico['sigy'], guess_dico['theta'] ] m = mpfit.mpfit(self.gauss2D_fit_erf, guess, functkw=fa, parinfo=parinfo, quiet=(not verbose) * 1) if m.status == 0: print( 'Fit failed. Try to help the minimizer by providing a better first guess' ) if plot: plt.close(1) fig = plt.figure(1, figsize=(4.5, 3)) gs = gridspec.GridSpec(1, 2, height_ratios=[1], width_ratios=[1, 0.06]) gs.update(left=0.1, right=0.9, bottom=0.1, top=0.93, wspace=0.2, hspace=0.03) ax1 = plt.subplot(gs[0, 0]) # Area for the first plot ax3 = plt.subplot(gs[0, 1]) # Area for the second plot im = ax1.imshow( self.subimage, cmap='Greys', origin='lower', interpolation='nearest', extent=[ self.guess_x - self.subimage_half_size_x, self.guess_x + self.subimage_half_size_x - 1, self.guess_y - self.subimage_half_size_y, self.guess_y + self.subimage_half_size_y - 1 ], vmin=np.nanmin(self.subimage), vmax=np.nanmax(self.subimage)) ax1.set_xlabel('X in px') ax1.set_ylabel('Y in px') ax1.grid(True, c='w') ax1.text(0.95, 0.01, 'Fit failed',verticalalignment='bottom', horizontalalignment='right',\ transform=ax1.transAxes,color='red', fontsize=15) fig.colorbar(im, cax=ax3) if save is not None: fig.savefig(save + '.pdf') null_dico = { 'AMP': 0, 'X': 0, 'Y': 0, 'FWHMX': 0, 'FWHMY': 0, 'FWHM': 0, 'THETA': 0, 'ell': 0 } return null_dico, null_dico, 0., 0. residuals = self.gauss2D_fit_erf(m.params, x=x_array, y=y_array, z=self.subimage, err=np.ones_like(self.subimage) * self.sky_rms)[1].reshape( self.subimage.shape) chi2 = np.sum(residuals**2) chi2_reduced = chi2 / m.dof sig = np.array([m.params[3], m.params[4]]) sig_error = np.array([m.perror[3], m.perror[4]]) error_ell = 4 / (np.sum(sig)**2) * np.sqrt(np.sum( (sig * sig_error)**2)) fwhm = sig2fwhm(sig) fwhm_error = sig2fwhm(sig_error) fit_result = {'AMP':m.params[0],'X':m.params[1]+self.guess_x,'FWHMX':fwhm[0],\ 'Y':m.params[2]+self.guess_y,'FWHMY':fwhm[1],'FWHM':np.mean(fwhm),'THETA':m.params[5],'ell':(sig[1]-sig[0])/np.mean(sig)} fit_error = { 'AMP':m.perror[0],'X':m.perror[1],'Y':m.perror[2],'FWHMX':fwhm_error[0],\ 'FWHMY':fwhm_error[1],'FWHM':np.mean(fwhm_error),'THETA': m.perror[5],\ 'ell':error_ell} print('X={0:4.2f}+/-{1:4.2f} Y={2:4.2f}+/-{3:4.2f} FWHM={4:3.2f}+/-{5:4.2f} ell={6:4.2f}+/-{7:4.2f}'.format(fit_result['X'],\ fit_error['X'],fit_result['Y'],fit_error['Y'],fit_result['FWHM'],fit_error['FWHM'],fit_result['ell'],fit_error['ell'],)) print('AMP={0:4.2e}+/-{1:3.2e} theta={2:3.1f}+/-{3:3.1f}deg SKY={4:4.2f}+/-{5:4.2f}'.format(fit_result['AMP'],\ fit_error['AMP'],fit_result['THETA'],fit_error['THETA'],self.sky_median,self.sky_rms)) print('DOF={0:d} CHI2={1:.1f} CHI2_r={2:.1f}'.format( m.dof, chi2, chi2_reduced)) if plot: plt.close(1) fig = plt.figure(1, figsize=(7.5, 3)) gs = gridspec.GridSpec(1, 3, height_ratios=[1], width_ratios=[1, 1, 0.06]) gs.update(left=0.1, right=0.9, bottom=0.1, top=0.93, wspace=0.2, hspace=0.03) ax1 = plt.subplot(gs[0, 0]) # Area for the first plot ax2 = plt.subplot(gs[0, 1]) # Area for the second plot ax3 = plt.subplot(gs[0, 2]) # Area for the second plot im = ax1.imshow(self.subimage, cmap='CMRmap', origin='lower', interpolation='nearest', extent=[ self.guess_x - self.subimage_half_size_x, self.guess_x + self.subimage_half_size_x - 1, self.guess_y - self.subimage_half_size_y, self.guess_y + self.subimage_half_size_y - 1 ], vmin=np.nanmin(self.subimage), vmax=np.nanmax(self.subimage)) ax1.set_xlabel('X in px') ax1.set_ylabel('Y in px') ax1.contour(x_array + self.guess_x, y_array + self.guess_y, self.sky_median + Gaussian2D(m.params[0], m.params[1], m.params[2], m.params[3], m.params[4], np.radians(m.params[5]))(x_array, y_array), 3, colors='w') ax1.grid(True, c='w') im2 = ax2.imshow( residuals, cmap='CMRmap', origin='lower', interpolation='nearest', extent=[ self.guess_x - self.subimage_half_size_x, self.guess_x + self.subimage_half_size_x - 1, self.guess_y - self.subimage_half_size_y, self.guess_y + self.subimage_half_size_y - 1 ], vmin=np.nanmin(self.subimage), vmax=np.nanmax(self.subimage) ) #, extent=[np.min(x_array),np.max(x_array),np.min(y_array),np.max(y_array)]) ax2.set_xlabel('X in px') ax2.grid(True, c='w') fig.colorbar(im, cax=ax3) if save is not None: fig.savefig(save + '.pdf') return fit_result, fit_error, chi2, chi2_reduced