Exemplo n.º 1
0
def plot_gal_params(
        hdu: fits.HDUList, ras: Union[list, np.ndarray, float], decs: Union[list, np.ndarray, float],
        a: Union[list, np.ndarray, float], b: Union[list, np.ndarray, float],
        theta: Union[list, np.ndarray, float], colour: str = 'white',
        show_centre: bool = False,
        label: str = None, world: bool = True, world_axes: bool = True, **kwargs):
    """

    :param hdu:
    :param ras: In degrees.
    :param decs: In degrees.
    :param a: In degrees.
    :param b: In degrees.
    :param theta: In degrees, apparently.
    :param colour:
    :param offset:
    :param show_centre:
    :return:
    """
    # TODO: Rename parameters to reflect acceptance of pixel coordinates.

    _, pix_scale = ff.get_pixel_scale(hdu)
    n_y, n_x = hdu[0].data.shape
    header = hdu[0].header
    wcs_image = wcs.WCS(header=header)
    if world:
        xs, ys = wcs_image.all_world2pix(ras, decs, 0)
    else:
        xs = np.array(ras)
        ys = np.array(decs)

    theta = np.array(theta)
    # Convert to photutils angle format
    theta = u.world_angle_se_to_pu(theta, rot_angle=ff.get_rotation_angle(header))

    a = u.dequantify(a)
    b = u.dequantify(b)

    for i, x in enumerate(xs):
        u.debug_print(2, "plotting.plot_gal_params(): x, ys[i] ==", x, ys[i])
        if a[i] != 0 and b[i] != 0:
            if world_axes:
                ellipse = photutils.EllipticalAperture((x, ys[i]), a=a[i] / pix_scale, b=b[i] / pix_scale,
                                                       theta=theta[i])
            else:
                ellipse = photutils.EllipticalAperture((x, ys[i]), a=a[i], b=b[i], theta=theta[i])
            ellipse.plot(**kwargs)
            line_label = None
        else:
            line_label = label
        if show_centre:
            plt.plot((0.0, n_x), (ys[i], ys[i]), c=colour, label=line_label)
            plt.plot((x, x), (0.0, n_y), c=colour)
Exemplo n.º 2
0
def plot_gal_params(hdu: fits.HDUList, ras: Union[list, np.ndarray, float], decs: Union[list, np.ndarray, float],
                    a: Union[list, np.ndarray, float], b: Union[list, np.ndarray, float],
                    theta: Union[list, np.ndarray, float], colour: str = 'white',
                    show_centre: bool = False,
                    label: str = None, world: bool = True, world_axes: bool = True, line_style='-'):
    """

    :param hdu:
    :param ras: In degrees.
    :param decs: In degrees.
    :param a: In degrees.
    :param b: In degrees.
    :param theta: In degrees, apparently.
    :param colour:
    :param offset:
    :param show_centre:
    :return:
    """
    # TODO: Rename parameters to reflect acceptance of pixel coordinates.

    _, pix_scale = ff.get_pixel_scale(hdu)
    n_y, n_x = hdu[0].data.shape
    header = hdu[0].header
    wcs_image = wcs.WCS(header=header)
    if world:
        xs, ys = wcs_image.all_world2pix(ras, decs, 0)
    else:
        xs = np.array(ras)
        ys = np.array(decs)

    theta = np.array(theta)
    theta = -theta + ff.get_rotation_angle(header)
    # Convert to radians
    theta = theta * np.pi / 180

    for i, x in enumerate(xs):
        if a[i] != 0 and b[i] != 0:
            if world_axes:
                ellipse = photutils.EllipticalAperture((x, ys[i]), a=a[i] / pix_scale, b=b[i] / pix_scale,
                                                       theta=theta[i])
            else:
                ellipse = photutils.EllipticalAperture((x, ys[i]), a=a[i], b=b[i], theta=theta[i])
            ellipse.plot(color=colour, label=label, ls=line_style)
            line_label = None
        else:
            line_label = label
        if show_centre:
            plt.plot((0.0, n_x), (ys[i], ys[i]), c=colour, label=line_label)
            plt.plot((x, x), (0.0, n_y), c=colour)
Exemplo n.º 3
0
def ellipses(ax, ap_center, a, b, theta, ap_radii, color="w"):
    """Plot apertures onto an image.

    inputs
    ------
    ax: matplotlib.Axes instance with pixel stamp already plotted

    ap_centers: array-like
        ra and dec pixel coordinates

    ap_radii: array-like
        radii of apertures in pixel coordinates
    """

    #plot_center = np.array([ap_center[1], ap_center[0]])

    for rad in ap_radii:
        logging.debug("rad %f", rad)
        ap = photutils.EllipticalAperture(ap_center,
                                          a * rad,
                                          b * rad,
                                          theta=theta)
        ap.plot(ax=ax, color=color,
                linewidth=2)  #kwargs={"color":color,"linewidth":2})
Exemplo n.º 4
0
    def photometry(self, ZP, ifilter, radius=3., show=False, outfile=None):
        """
        Perform photometry

        Fills self.photom in place
        
        Half-light radii:
            https://iopscience.iop.org/article/10.1086/444475/pdf

        Args:
            ZP (float):
                Zero point magnitude
            ifilter (str): Filter name to be used in the anaysis
            radius (float, optional):
                Scaling for semimajor/minor axes for Elliptical apertures
            show:
            outfile:
        """

        # Init
        if self.segm is None:
            raise ValueError("segm not set!")
        if self.hdu is None:
            self.load_image()

        # Zero point
        if isinstance(ZP, str):
            ZP = self.header[ZP]

        self.cat = photutils.segmentation.SourceCatalog(
            self.hdu.data - self.bkg.background,
            self.segm,
            background=self.bkg.background)

        # Apertures
        apertures = []
        for obj in self.cat:
            position = np.transpose((obj.xcentroid, obj.ycentroid))
            a = obj.semimajor_sigma.value * radius
            b = obj.semiminor_sigma.value * radius
            theta = obj.orientation.to(units.rad).value
            apertures.append(
                photutils.EllipticalAperture(position, a, b, theta=theta))
        self.apertures = apertures

        # Magnitudes
        self.filter = ifilter
        self.photom = Table(self.cat.to_table()).to_pandas()
        self.photom[ifilter] = -2.5 * np.log10(
            self.photom['segment_flux']) + ZP

        # Add in ones lost in the pandas conversion Kron
        for key in ['kron_radius']:
            self.photom[key] = getattr(self.cat, key).value  # pixel

        # Plot?
        if show or outfile is not None:
            norm = ImageNormalize(stretch=SqrtStretch())
            fig = plt.figure(figsize=(6, 6))

            # fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 12.5))
            plt.clf()
            ax1 = plt.gca()
            ax1.imshow(self.hdu.data,
                       origin='lower',
                       cmap='Greys_r',
                       norm=norm)
            ax1.set_title('Data')
            #
            for aperture in apertures:
                aperture.plot(axes=ax1, color='white', lw=1.5)
            if outfile is not None:  # This must come first
                plt.savefig(outfile, dpi=300)
            if show:
                plt.show()
Exemplo n.º 5
0
        of the galaxy in the data. Then, make an elliptical aperture for each
        edge listed for this galaxy. The apertures should have a b/a equal to
        the convolved axis ratio we calculated above. Make sure to check the 
        theta to make sure it matches the convention we expect. '''
		# find (x,y) location of galaxy in the arry
        pixY, pixX = self.get_pix(wcs)
        
        # initialize aperture list
		apertureList = []
		
        # for each radius, make an elliptical aperture.
        # make sure to keep the sub-pixel shifts (galaxy centers not exactly 
        # on a single pixel)
        for r in self.edges:
			apertureList.append(photutils.EllipticalAperture(positions=
			(self.pscale+pixY%1, self.pscale+pixX%1),
			a=r, b=r*self.qConv,
			theta=math.radians(paIm)-math.radians(self.pa)))
            
        # return the whole list to use later    
		return apertureList

	def calcPhotometry_detectionband(self, filterName, photflam, data, wcs, weight, seg, paIm, SNthresh=10.):
		'''Calculates aperture photometry for the detection band. The detection band
        is a different function from the rest of the bands because we'll use it to 
        determine the total number of annuli. Essentially, we want to use the full
        list of apertures we calculated above, but *stop calculating* after we reach
        a given S/N threshold. We use a threshold of 10 in Suess+19, but this
        can be tuned depending on the use. Each annulus is 1 PSF FWHM wide.'''

        # make sure the catalog photometry is good for this object
		if self.flag != 1:
Exemplo n.º 6
0
    def rff_plot(self, rpet_scale=2, rhalf_scale=1):
        assert_data(["galfit/fit", "galfit/residual"], self.data)
        assert_properties(["rff", "rff_in", "rff_out"], self.data["galfit"])

        fig, axs = plt.subplots(1, 3, figsize=(15, 5))
        self._plot_normalized(self.data["img"], axs[0])
        self._plot_normalized(self.data["galfit/fit"], axs[1])
        self._plot_normalized(self.data["galfit/residual"], axs[2])

        # Define values needed for calculation
        pxscale = self.data.attrs["pxscale"]
        rpet = self.data["statmorph"].attrs["rpetro_circ"] / pxscale
        rhalf = self.data["galfit"].attrs["rad"] / pxscale
        xc = self.data["galfit"].attrs["xc"]
        yc = self.data["galfit"].attrs["yc"]
        e = self.data["galfit"].attrs["e"]
        pa = self.data["galfit"].attrs["theta"]
        th = (pa - 90) * np.pi / 180
        rff = self.data["galfit"].attrs["rff"]
        rff_in = self.data["galfit"].attrs["rff_in"]
        rff_out = self.data["galfit"].attrs["rff_out"]
        n = self.data["galfit"].attrs["sersic_n"]

        ap_pet1 = phot.CircularAperture((xc, yc), rpet_scale * rpet)
        # ap_pet2 = phot.CircularAperture( (xc, yc), rpet)
        ap_ser = phot.EllipticalAperture((xc, yc),
                                         rhalf_scale * rhalf,
                                         rhalf_scale * rhalf * e,
                                         theta=th)

        for i in [1, 2]:
            ap_pet1.plot(axes=axs[i], color="y", ls="-")
            # ap_pet2.plot(axes=axs[i], color="orange", ls="--")
            ap_ser.plot(axes=axs[i], color="red", ls="-")

        axs[2].annotate(f"RFF = {rff:2.3f}",
                        xy=(0.05, 0.03),
                        xycoords="axes fraction",
                        ha="left",
                        va="bottom",
                        c="w",
                        size=14,
                        fontweight=800)
        axs[2].annotate(f"Inner RFF = {rff_in:2.3f}",
                        xy=(0.05, 0.97),
                        xycoords="axes fraction",
                        ha="left",
                        va="top",
                        c="w",
                        size=14,
                        fontweight=800)
        axs[2].annotate(f"Outer RFF = {rff_out:2.3f}",
                        xy=(0.05, 0.90),
                        xycoords="axes fraction",
                        ha="left",
                        va="top",
                        c="w",
                        size=14,
                        fontweight=800)
        axs[1].annotate(f"n = {n:2.1f}",
                        xy=(0.05, 0.03),
                        xycoords="axes fraction",
                        ha="left",
                        va="bottom",
                        c="w",
                        size=14,
                        fontweight=800)

        plt.subplots_adjust(wspace=0.02)
        return fig, axs
Exemplo n.º 7
0
for r in r_list:
    for subpix, method, label in subpix_list:
        line = "| ellipses r={0:2d}  {1:8s} |".format(int(r), label)

        t0 = time.time()
        flux, fluxerr, flag = sep.sum_ellipse(data,
                                              x,
                                              y,
                                              a,
                                              b,
                                              theta,
                                              r,
                                              subpix=subpix)
        t1 = time.time()
        t_sep = (t1 - t0) * 1.e6 / naper / nloop
        line += " {0:7.2f} us/aper |".format(t_sep)

        if HAVE_PHOTUTILS:
            apertures = photutils.EllipticalAperture((x, y), a * r, b * r,
                                                     theta)
            t0 = time.time()
            res = photutils.aperture_photometry(data,
                                                apertures,
                                                method=method,
                                                subpixels=subpix)
            t1 = time.time()
            t_pu = (t1 - t0) * 1.e6 / naper
            line += " {0:7.2f} us/aper | {1:6.2f} |".format(t_pu, t_pu / t_sep)

        print(line)
Exemplo n.º 8
0
    def get_rff(self,
                region="all",
                rpet_scale=2,
                rhalf_scale=1,
                overwrite=False):
        """Calculate the residual flux fraction, defined in Hoyos et al. (2011, 2012)
        RFF = (I(res) - 0.8 sky_rms )/I(model). We calculate RFF within a Petrosian
        radius, calculated by statmorph.
        There are 3 modes:
            1. Total RFF within KRpet
            2. RFF within inner KR_0.5
            3. RFF within outer KR_0.5 and Kxrpet
        INPUTS:
            region:         region of RFF calculation (all, inner, outer)
            rpet_scale:     number of Petrosian radii wihin which RFF is found
            rhalf_scale:    number of Sersic radii defining inner region for inner/outer
            overwrite:      overwrite existing RFF meausrement for this region?
            """

        # Check all required data exists
        assert_properties(["pxscale"], self.data)
        assert_data(["img", "mask", "galfit", "statmorph"], self.data)

        # Check if RFF is already computed
        kwords = {"all": "rff", "inner": "rff_in", "outer": "rff_out"}
        kword = kwords[region]
        if not clear_overwrite(kword, self.data["galfit"].attrs): return

        # Define values needed for calculation
        pxscale = self.data.attrs["pxscale"]
        rpet = self.data["statmorph"].attrs["rpetro_circ"] / pxscale
        xc = self.data["galfit"].attrs["xc"]
        yc = self.data["galfit"].attrs["yc"]
        mask = self.data["mask"]
        res = self.data["galfit/residual"]
        model = self.data["galfit/fit"]

        # 1. Calculate standard deviation of residual bg
        __, bgmed, bgdev = sigma_clipped_stats(res, mask=self.data["mask"])
        res = res - bgmed

        # 2. Define aperture based on RFF region
        ap_pet = phot.CircularAperture((xc, yc), rpet_scale * rpet)
        if region != "all":
            e = self.data["galfit"].attrs["e"]
            pa = self.data["galfit"].attrs["theta"]
            th = (pa - 90) * np.pi / 180
            rhalf = self.data["galfit"].attrs["rad"] / pxscale
            ap_ser = phot.EllipticalAperture((xc, yc),
                                             rhalf,
                                             rhalf * e,
                                             theta=th)

        if region == "inner":
            ap = ap_ser
        elif region == "outer":
            ap = ap_pet
            ap_mask = ap_ser.to_mask().to_image(mask.shape)
            mask = np.logical_or(mask, ap_mask)
        elif region == "all":
            ap = ap_pet

        # 3. Calculate residual and model flux
        resflux = ap.do_photometry(np.abs(res), mask=mask)[0][0]
        modflux = ap.do_photometry(model, mask=mask)[0][0]

        # 4. Number of pixels in the sum:
        numpix = ap.area - ap.do_photometry(mask)[0][0]
        bgflux = np.sqrt(2 / np.pi) * bgdev * numpix

        # 5. Compute RFF
        rff = (resflux - bgflux) / modflux
        self.data["galfit"].attrs[kword] = rff