Example #1
0
def insert_skycomponent(im: Image, sc: Skycomponent, insert_method=''):
    """ Insert a Skycomponent into an image

    :param params:
    :param im:
    :param sc: SkyComponent or list of SkyComponents
    :returns: image

    """

    assert type(im) == Image

    nchan, npol, ny, nx = im.data.shape

    if not isinstance(sc, collections.Iterable):
        sc = [sc]

    for comp in sc:

        assert comp.shape == 'Point', "Cannot handle shape %s" % comp.shape

        assert_same_chan_pol(im, comp)

        if insert_method == "Lanczos":
            pixloc = skycoord_to_pixel(comp.direction, im.wcs, 0, 'wcs')
            _L2D(im.data, pixloc[1], pixloc[0], comp.flux)
        else:
            pixloc = numpy.round(
                skycoord_to_pixel(comp.direction, im.wcs, 1,
                                  'wcs')).astype('int')
            x, y = pixloc[0], pixloc[1]
            if x >= 0 and x < nx and y >= 0 and y < ny:
                im.data[:, :, y, x] += comp.flux

    return im
Example #2
0
def _pixel_scale_angle_at_skycoord(skycoord, wcs, offset=1.0 * u.arcsec):
    """
    Calculate the pixel scale and WCS rotation angle at the position of
    a SkyCoord coordinate.

    Parameters
    ----------
    skycoord : `~astropy.coordinates.SkyCoord`
        The SkyCoord coordinate.

    wcs : WCS object
        A world coordinate system (WCS) transformation that supports the
        `astropy shared interface for WCS
        <https://docs.astropy.org/en/stable/wcs/wcsapi.html>`_ (e.g.
        `astropy.wcs.WCS`, `gwcs.wcs.WCS`).

    offset : `~astropy.units.Quantity`
        A small angular offset to use to compute the pixel scale and
        position angle.

    Returns
    -------
    scale : `~astropy.units.Quantity`
        The pixel scale in arcsec/pixel.

    angle : `~astropy.units.Quantity`
        The angle (in degrees) measured counterclockwise from the
        positive x axis to the "North" axis of the celestial coordinate
        system.

    Notes
    -----
    If distortions are present in the image, the x and y pixel scales
    likely differ.  This function computes a single pixel scale along
    the North/South axis.
    """

    try:
        x, y = wcs.world_to_pixel(skycoord)

        # We take a point directly North (i.e. latitude offset) the input
        # sky coordinate and convert it to pixel coordinates, then we use the
        # pixel deltas between the input and offset sky coordinate to
        # calculate the pixel scale and angle.
        skycoord_offset = skycoord.directional_offset_by(0.0, offset)
        x_offset, y_offset = wcs.world_to_pixel(skycoord_offset)
    except AttributeError:
        # for Astropy < 3.1 WCS support
        x, y = skycoord_to_pixel(skycoord, wcs)
        coord = skycoord.represent_as('unitspherical')
        coord_new = UnitSphericalRepresentation(coord.lon, coord.lat + offset)
        coord_offset = skycoord.realize_frame(coord_new)
        x_offset, y_offset = skycoord_to_pixel(coord_offset, wcs)

    dx = x_offset - x
    dy = y_offset - y
    scale = offset.to(u.arcsec) / (np.hypot(dx, dy) * u.pixel)
    angle = (np.arctan2(dy, dx) * u.radian).to(u.deg)

    return scale, angle
Example #3
0
def test_skycoord_to_pixel_swapped():

    # Regression test for a bug that caused skycoord_to_pixel and
    # pixel_to_skycoord to not work correctly if the axes were swapped in the
    # WCS.

    # Import astropy.coordinates here to avoid circular imports
    from astropy.coordinates import SkyCoord

    header = get_pkg_data_contents('maps/1904-66_TAN.hdr', encoding='binary')
    wcs = WCS(header)

    wcs_swapped = wcs.sub([WCSSUB_LATITUDE, WCSSUB_LONGITUDE])

    ref = SkyCoord(0.1 * u.deg, -89. * u.deg, frame='icrs')

    xp1, yp1 = skycoord_to_pixel(ref, wcs)
    xp2, yp2 = skycoord_to_pixel(ref, wcs_swapped)

    assert_allclose(xp1, xp2)
    assert_allclose(yp1, yp2)

    # WCS is in FK5 so we need to transform back to ICRS
    new1 = pixel_to_skycoord(xp1, yp1, wcs).transform_to('icrs')
    new2 = pixel_to_skycoord(xp1, yp1, wcs_swapped).transform_to('icrs')

    assert_allclose(new1.ra.degree, new2.ra.degree)
    assert_allclose(new1.dec.degree, new2.dec.degree)
def show_components(im, comps, npixels=128, fig=None, vmax=None, vmin=None):
    """ Show components against an image

    :param im:
    :param comps:
    :param npixels:
    :param fig:
    :return:
    """
    import matplotlib.pyplot as plt
    
    if vmax is None:
        vmax = numpy.max(im.data[0, 0, ...])
    if vmin is None:
        vmin = numpy.min(im.data[0, 0, ...])
    
    if not fig:
        fig = plt.figure()
    plt.clf()
    
    for isc, sc in enumerate(comps):
        newim = copy_image(im)
        plt.subplot(111, projection=newim.wcs.sub([1, 2]))
        centre = numpy.round(skycoord_to_pixel(sc.direction, newim.wcs, 1, 'wcs')).astype('int')
        newim.data = newim.data[:, :,
                     (centre[1] - npixels // 2):(centre[1] + npixels // 2),
                     (centre[0] - npixels // 2):(centre[0] + npixels // 2)]
        newim.wcs.wcs.crpix[0] -= centre[0] - npixels // 2
        newim.wcs.wcs.crpix[1] -= centre[1] - npixels // 2
        plt.imshow(newim.data[0, 0, ...], origin='lower', cmap='Greys', vmax=vmax, vmin=vmin)
        x, y = skycoord_to_pixel(sc.direction, newim.wcs, 0, 'wcs')
        plt.plot(x, y, marker='+', color='red')
        plt.title('Name = %s, flux = %s' % (sc.name, sc.flux))
        plt.show()
Example #5
0
def test_skycoord_to_pixel_swapped():

    # Regression test for a bug that caused skycoord_to_pixel and
    # pixel_to_skycoord to not work correctly if the axes were swapped in the
    # WCS.

    # Import astropy.coordinates here to avoid circular imports
    from astropy.coordinates import SkyCoord

    header = get_pkg_data_contents('data/maps/1904-66_TAN.hdr',
                                   encoding='binary')
    wcs = WCS(header)

    wcs_swapped = wcs.sub([WCSSUB_LATITUDE, WCSSUB_LONGITUDE])

    ref = SkyCoord(0.1 * u.deg, -89. * u.deg, frame='icrs')

    xp1, yp1 = skycoord_to_pixel(ref, wcs)
    xp2, yp2 = skycoord_to_pixel(ref, wcs_swapped)

    assert_allclose(xp1, xp2)
    assert_allclose(yp1, yp2)

    # WCS is in FK5 so we need to transform back to ICRS
    new1 = pixel_to_skycoord(xp1, yp1, wcs).transform_to('icrs')
    new2 = pixel_to_skycoord(xp1, yp1, wcs_swapped).transform_to('icrs')

    assert_allclose(new1.ra.degree, new2.ra.degree)
    assert_allclose(new1.dec.degree, new2.dec.degree)
def crop_to_training_area(image_path, out_path, freq, pad_factor=1.0):
    """
    For a given SDC1 image, write a new FITS file containing only the training
    area.
    Training area defined by RA/Dec, which doesn't map perfectly to pixel values.

    Args:
        image_path (`str`): Path to input image
        out_path (`str`): Path to write sub-image to
        freq (`int`): [560, 1400, 9200] SDC1 image frequency (different training areas)
        pad_factor (`float`, optional): Area scaling factor to include edges
    """
    hdu = fits.open(image_path)[0]
    wcs = WCS(hdu.header)

    # Lookup training limits for given frequency
    ra_max = TRAIN_LIM[freq]["ra_max"]
    ra_min = TRAIN_LIM[freq]["ra_min"]
    dec_max = TRAIN_LIM[freq]["dec_max"]
    dec_min = TRAIN_LIM[freq]["dec_min"]

    # Centre of training area pixel coordinate:
    train_centre = SkyCoord(
        ra=(ra_max + ra_min) / 2,
        dec=(dec_max + dec_min) / 2,
        frame="fk5",
        unit="deg",
    )

    # Opposing corners of training area:
    train_min = SkyCoord(
        ra=ra_min,
        dec=dec_min,
        frame="fk5",
        unit="deg",
    )
    train_max = SkyCoord(
        ra=ra_max,
        dec=dec_max,
        frame="fk5",
        unit="deg",
    )

    # Training area approx width
    pixel_width = (abs(
        skycoord_to_pixel(train_max, wcs)[0] -
        skycoord_to_pixel(train_min, wcs)[0]) * pad_factor)

    # Training area approx height
    pixel_height = (abs(
        skycoord_to_pixel(train_max, wcs)[1] -
        skycoord_to_pixel(train_min, wcs)[1]) * pad_factor)

    save_subimage(
        image_path,
        out_path,
        skycoord_to_pixel(train_centre, wcs),
        (pixel_height, pixel_width),
    )
Example #7
0
def skycoord_to_pixel_scale_angle(skycoord, wcs, small_offset=1 * u.arcsec):
    """
    Convert a set of SkyCoord coordinates into pixel coordinates, pixel
    scales, and position angles.

    Parameters
    ----------
    skycoord : `~astropy.coordinates.SkyCoord`
        Sky coordinates
    wcs : `~astropy.wcs.WCS`
        The WCS transformation to use
    small_offset : `~astropy.units.Quantity`
        A small offset to use to compute the angle

    Returns
    -------
    pixcoord : `~regions.PixCoord`
        Pixel coordinates
    scale : float
        The pixel scale at each location, in degrees/pixel
    angle : `~astropy.units.Quantity`
        The position angle of the celestial coordinate system in pixel space.
    """

    # Convert to pixel coordinates
    x, y = skycoord_to_pixel(skycoord, wcs, mode=skycoord_to_pixel_mode)
    pixcoord = PixCoord(x=x, y=y)

    # We take a point directly 'above' (in latitude) the position requested
    # and convert it to pixel coordinates, then we use that to figure out the
    # scale and position angle of the coordinate system at the location of
    # the points.

    # Find the coordinates as a representation object
    r_old = skycoord.represent_as('unitspherical')

    # Add a a small perturbation in the latitude direction (since longitude
    # is more difficult because it is not directly an angle).
    dlat = small_offset
    r_new = UnitSphericalRepresentation(r_old.lon, r_old.lat + dlat)
    coords_offset = skycoord.realize_frame(r_new)

    # Find pixel coordinates of offset coordinates
    x_offset, y_offset = skycoord_to_pixel(coords_offset,
                                           wcs,
                                           mode=skycoord_to_pixel_mode)

    # Find vector
    dx = x_offset - x
    dy = y_offset - y

    # Find the length of the vector
    scale = np.hypot(dx, dy) / dlat.to('degree').value

    # Find the position angle
    angle = np.arctan2(dy, dx) * u.radian

    return pixcoord, scale, angle
Example #8
0
def skycoord_to_pixel_scale_angle(skycoord, wcs, small_offset=1 * u.arcsec):
    """
    Convert a set of SkyCoord coordinates into pixel coordinates, pixel
    scales, and position angles.

    Parameters
    ----------
    skycoord : `~astropy.coordinates.SkyCoord`
        Sky coordinates
    wcs : `~astropy.wcs.WCS`
        The WCS transformation to use
    small_offset : `~astropy.units.Quantity`
        A small offset to use to compute the angle

    Returns
    -------
    pixcoord : `~regions.PixCoord`
        Pixel coordinates
    scale : float
        The pixel scale at each location, in degrees/pixel
    angle : `~astropy.units.Quantity`
        The position angle of the celestial coordinate system in pixel space.
    """

    # Convert to pixel coordinates
    x, y = skycoord_to_pixel(skycoord, wcs, mode=skycoord_to_pixel_mode)
    pixcoord = PixCoord(x=x, y=y)

    # We take a point directly 'above' (in latitude) the position requested
    # and convert it to pixel coordinates, then we use that to figure out the
    # scale and position angle of the coordinate system at the location of
    # the points.

    # Find the coordinates as a representation object
    r_old = skycoord.represent_as('unitspherical')

    # Add a a small perturbation in the latitude direction (since longitude
    # is more difficult because it is not directly an angle).
    dlat = small_offset
    r_new = UnitSphericalRepresentation(r_old.lon, r_old.lat + dlat)
    coords_offset = skycoord.realize_frame(r_new)

    # Find pixel coordinates of offset coordinates
    x_offset, y_offset = skycoord_to_pixel(coords_offset, wcs,
                                           mode=skycoord_to_pixel_mode)

    # Find vector
    dx = x_offset - x
    dy = y_offset - y

    # Find the length of the vector
    scale = np.hypot(dx, dy) / dlat.to('degree').value

    # Find the position angle
    angle = np.arctan2(dy, dx) * u.radian

    return pixcoord, scale, angle
Example #9
0
def skycoord_to_pixel_scale_angle(coords, wcs):
    """
    Convert a set of SkyCoord coordinates into pixel coordinates, pixel
    scales, and position angles.

    Parameters
    ----------
    coords : `~astropy.coordinates.SkyCoord`
        The coordinates to convert
    wcs : `~astropy.wcs.WCS`
        The WCS transformation to use

    Returns
    -------
    x, y : `~numpy.ndarray`
        The x and y pixel coordinates corresponding to the input coordinates
    scale : `~astropy.units.Quantity`
        The pixel scale at each location, in degrees/pixel
    angle : `~astropy.units.Quantity`
        The position angle of the celestial coordinate system in pixel space.
    """

    # Convert to pixel coordinates
    x, y = skycoord_to_pixel(coords, wcs, mode=skycoord_to_pixel_mode)

    # We take a point directly 'above' (in latitude) the position requested
    # and convert it to pixel coordinates, then we use that to figure out the
    # scale and position angle of the coordinate system at the location of
    # the points.

    # Find the coordinates as a representation object
    r_old = coords.represent_as('unitspherical')

    # Add a a small perturbation in the latitude direction (since longitude
    # is more difficult because it is not directly an angle).
    dlat = 1 * u.arcsec
    r_new = UnitSphericalRepresentation(r_old.lon, r_old.lat + dlat)
    coords_offset = coords.realize_frame(r_new)

    # Find pixel coordinates of offset coordinates
    x_offset, y_offset = skycoord_to_pixel(coords_offset,
                                           wcs,
                                           mode=skycoord_to_pixel_mode)

    # Find vector
    dx = x_offset - x
    dy = y_offset - y

    # Find the length of the vector
    scale = np.hypot(dx, dy) * u.pixel / dlat

    # Find the position angle
    angle = np.arctan2(dy, dx) * u.radian

    return x, y, scale, angle
Example #10
0
def skycoord_to_pixel_scale_angle(coords, wcs):
    """
    Convert a set of SkyCoord coordinates into pixel coordinates, pixel
    scales, and position angles.

    Parameters
    ----------
    coords : `~astropy.coordinates.SkyCoord`
        The coordinates to convert
    wcs : `~astropy.wcs.WCS`
        The WCS transformation to use

    Returns
    -------
    x, y : `~numpy.ndarray`
        The x and y pixel coordinates corresponding to the input coordinates
    scale : `~astropy.units.Quantity`
        The pixel scale at each location, in degrees/pixel
    angle : `~astropy.units.Quantity`
        The position angle of the celestial coordinate system in pixel space.
    """

    # Convert to pixel coordinates
    x, y = skycoord_to_pixel(coords, wcs, mode=skycoord_to_pixel_mode)

    # We take a point directly 'above' (in latitude) the position requested
    # and convert it to pixel coordinates, then we use that to figure out the
    # scale and position angle of the coordinate system at the location of
    # the points.

    # Find the coordinates as a representation object
    r_old = coords.represent_as('unitspherical')

    # Add a a small perturbation in the latitude direction (since longitude
    # is more difficult because it is not directly an angle).
    dlat = 1 * u.arcsec
    r_new = UnitSphericalRepresentation(r_old.lon, r_old.lat + dlat)
    coords_offset = coords.realize_frame(r_new)

    # Find pixel coordinates of offset coordinates
    x_offset, y_offset = skycoord_to_pixel(coords_offset, wcs,
                                           mode=skycoord_to_pixel_mode)

    # Find vector
    dx = x_offset - x
    dy = y_offset - y

    # Find the length of the vector
    scale = np.hypot(dx, dy) * u.pixel / dlat

    # Find the position angle
    angle = np.arctan2(dy, dx) * u.radian

    return x, y, scale, angle
Example #11
0
def pixel_scale_angle_at_skycoord(skycoord, wcs, offset=1. * u.arcsec):
    """
    Calculate the pixel scale and WCS rotation angle at the position of
    a SkyCoord coordinate.

    Parameters
    ----------
    skycoord : `~astropy.coordinates.SkyCoord`
        The SkyCoord coordinate.
    wcs : `~astropy.wcs.WCS`
        The world coordinate system (WCS) transformation to use.
    offset : `~astropy.units.Quantity`
        A small angular offset to use to compute the pixel scale and
        position angle.

    Returns
    -------
    scale : `~astropy.units.Quantity`
        The pixel scale in arcsec/pixel.
    angle : `~astropy.units.Quantity`
        The angle (in degrees) measured counterclockwise from the
        positive x axis to the "North" axis of the celestial coordinate
        system.

    Notes
    -----
    If distortions are present in the image, the x and y pixel scales
    likely differ.  This function computes a single pixel scale along
    the North/South axis.
    """

    # We take a point directly "above" (in latitude) the input position
    # and convert it to pixel coordinates, then we use the pixel deltas
    # between the input and offset point to calculate the pixel scale and
    # angle.

    # Find the coordinates as a representation object
    coord = skycoord.represent_as('unitspherical')

    # Add a a small perturbation in the latitude direction (since longitude
    # is more difficult because it is not directly an angle)
    coord_new = UnitSphericalRepresentation(coord.lon, coord.lat + offset)
    coord_offset = skycoord.realize_frame(coord_new)

    # Find pixel coordinates of offset coordinates and pixel deltas
    x_offset, y_offset = skycoord_to_pixel(coord_offset, wcs, mode='all')
    x, y = skycoord_to_pixel(skycoord, wcs, mode='all')
    dx = x_offset - x
    dy = y_offset - y

    scale = offset.to(u.arcsec) / (np.hypot(dx, dy) * u.pixel)
    angle = (np.arctan2(dy, dx) * u.radian).to(u.deg)

    return scale, angle
Example #12
0
    def __wcs_skycoord_to_pixels(self) -> Tuple[np.ndarray, np.ndarray]:
        """Use the wcs.utils skycoord_to_pixel to derive the pixel positions
        
        Returns:
            Tuple[np.ndarray, np.ndarray] -- Pixels coordinate postions of nearby sources
        """
        pix = skycoord_to_pixel(self.coords["sky"], self.wcs) * u.pixel
        center_pix = skycoord_to_pixel(self.center_coord, self.wcs) * u.pixel

        pix = [p - c for p, c in zip(pix, center_pix)]

        return pix
Example #13
0
    def to_pixel(self, wcs, mode='all'):
        """
        Convert the aperture to a `CircularAperture` instance in pixel
        coordinates.

        Parameters
        ----------
        wcs : `~astropy.wcs.WCS`
            The WCS transformation to use.

        mode : {'all', 'wcs'}, optional
            Whether to do the transformation including distortions
            (``'all'``; default) or only including only the core WCS
            transformation (``'wcs'``).

        Returns
        -------
        aperture : `CircularAperture` object
            A `CircularAperture` object.
        """

        x, y = skycoord_to_pixel(self.positions, wcs, mode=mode)

        if self.r.unit.physical_type == 'angle':
            central_pos = SkyCoord([wcs.wcs.crval], frame=self.positions.name,
                                   unit=wcs.wcs.cunit)
            xc, yc, scale, angle = skycoord_to_pixel_scale_angle(central_pos,
                                                                 wcs)
            r = (scale * self.r).to(u.pixel).value
        else:    # pixels
            r = self.r.value

        pixel_positions = np.array([x, y]).transpose()

        return CircularAperture(pixel_positions, r)
Example #14
0
def show_image(im: Image, fig=None, title: str = '', pol=0, chan=0, cm='rainbow', components=None):
    """ Show an Image with coordinates using matplotlib

    :param im:
    :param fig:
    :param title:
    :param pol: Polarisation
    :param chan: Channel
    :param components: Optional components
    :return:
    """
    import matplotlib.pyplot as plt
    
    assert isinstance(im, Image), im
    if not fig:
        fig = plt.figure()
    plt.clf()
    fig.add_subplot(111, projection=im.wcs.sub(['longitude', 'latitude']))
    if len(im.data.shape) == 4:
        plt.imshow(numpy.real(im.data[chan, pol, :, :]), origin='lower', cmap=cm)
    elif len(im.data.shape) == 2:
        plt.imshow(numpy.real(im.data[:, :]), origin='lower', cmap=cm)
    plt.xlabel('RA---SIN')
    plt.ylabel('DEC--SIN')
    plt.title(title)
    plt.colorbar()
    
    if components is not None:
        for sc in components:
            x, y = skycoord_to_pixel(sc.direction, im.wcs, 1, 'wcs')
            plt.plot(x, y, marker='+')
    return fig
Example #15
0
def _world_to_pixel(skycoord, wcs):
    """
    Calculate the sky coordinates at the input pixel positions.

    Parameters
    ----------
    skycoord : `~astropy.coordinates.SkyCoord`
        The sky coordinate(s).

    wcs : WCS object or `None`
        A world coordinate system (WCS) transformation that supports the
        `astropy shared interface for WCS
        <https://docs.astropy.org/en/stable/wcs/wcsapi.html>`_ (e.g.
        `astropy.wcs.WCS`, `gwcs.wcs.WCS`).

    Returns
    -------
    xpos, ypos : float or array-like
        The x and y pixel position(s) at the input sky coordinate(s).
    """

    if wcs is None:
        return None

    try:
        return wcs.world_to_pixel(skycoord)
    except AttributeError:
        if isinstance(wcs, WCS):
            # for Astropy < 3.1 WCS support
            return skycoord_to_pixel(skycoord, wcs, origin=0)
        else:
            raise ValueError('Input wcs does not support the shared WCS '
                             'interface.')
def fit_skycomponent(im: Image, sc: SkyCoord, params={}):
    """ Find flux at a given direction, return SkyComponent

    :param im:
    :type Image:
    :param sc:
    :type SkyCoord:
    :returns: SkyComponent

    """
    log_parameters(params)
    log.debug(
        "find_flux_at_direction: Extracting flux at world coordinates %s" %
        str(sc))
    w = im.wcs.sub(['longitude', 'latitude'])
    pixloc = skycoord_to_pixel(sc, im.wcs, 0, 'wcs')
    log.debug(
        "find_flux_at_direction: Extracting flux at pixel coordinates %d %d" %
        (pixloc[0], pixloc[1]))
    flux = im.data[:, :, int(pixloc[1] + 0.5), int(pixloc[0] + 0.5)]
    log.debug("find_flux_at_direction: Flux is %s" % flux)

    # We also need the frequency values
    w = im.wcs.sub(['spectral'])
    frequency = w.wcs_pix2world(range(im.data.shape[0]), 0)

    return create_skycomponent(direction=sc,
                               flux=flux,
                               frequency=frequency,
                               shape='point')
    def test_auto_rotate_systematic(self, angle):

        # This is a test to make sure for a number of angles that the corners
        # of the image are inside the final WCS but the next pixels outwards are
        # not. We test the full 360 range of angles.

        angle = np.radians(angle)
        pc = np.array([[np.cos(angle), -np.sin(angle)],
                       [np.sin(angle), np.cos(angle)]])
        self.wcs.wcs.pc = pc

        wcs, shape = find_optimal_celestial_wcs([(self.array, self.wcs)],
                                                auto_rotate=True)

        ny, nx = self.array.shape

        xp = np.array([0, 0, nx - 1, nx - 1, -1, -1, nx, nx])
        yp = np.array([0, ny - 1, ny - 1, 0, -1, ny, ny, -1])

        c = pixel_to_skycoord(xp, yp, self.wcs, origin=0)
        xp_final, yp_final = skycoord_to_pixel(c, wcs, origin=0)

        ny_final, nx_final = shape

        inside = ((xp_final >= -0.5) & (xp_final <= nx_final - 0.5) &
                  (yp_final >= -0.5) & (yp_final <= ny_final - 0.5))

        assert_equal(inside, [1, 1, 1, 1, 0, 0, 0, 0])
Example #18
0
    def __init__(self, nddata, position, shape):
        if isinstance(position, SkyCoord):
            if nddata.wcs is None:
                raise ValueError('nddata must contain WCS if the input '
                                 'position is a SkyCoord')

            x, y = skycoord_to_pixel(position, nddata.wcs, mode='all')
            position = (y, x)

        data = np.asanyarray(nddata.data)
        print(data.shape, shape, position)
        slices_large, slices_small = overlap_slices(data.shape, shape,
                                                    position)
        self.slices_large = slices_large
        self.slices_small = slices_small

        data = nddata.data[slices_large]
        mask = None
        uncertainty = None
        if nddata.mask is not None:
            mask = nddata.mask[slices_large]
        if nddata.uncertainty is not None:
            uncertainty = nddata.uncertainty[slices_large]

        self.nddata = NDData(data, mask=mask, uncertainty=uncertainty)
Example #19
0
def generate_pv_line_coordinates(angle, box, wcs, n_points):
    """
    This function generates the PV pixel and sky position given
    the its PA in degrees.
    """
    angle_pvline = np.pi / 180 * (angle + 90)

    def y_pv(xp, m, x0, y0):
        return m * (xp - x0) + y0

    vla4b_sky = SkyCoord(*mf.default_params['vla4b_deg'], unit='deg')
    vla4b_pixel = skycoord_to_pixel(vla4b_sky, wcs)
    #   aframe = vla4b_sky.skyoffset_frame()
    #   vla4b_offset = vla4b_sky.transform_to(aframe)

    x_first, y_first = box[1]
    x_last, y_last = box[0]
    xs_pixel = np.array([x for x in np.linspace(x_first, x_last, n_points)])

    ys_pixel = np.array([
        y_pv(
            x,
            np.tan(angle_pvline),
            vla4b_pixel[0],
            vla4b_pixel[1],
        ) for x in xs_pixel
    ])

    xys_sky_PV = np.array(
        [pixel_to_skycoord(x, y, wcs) for x, y in zip(xs_pixel, ys_pixel)])

    return xys_sky_PV
Example #20
0
def make_proposal_boxes(wcs: WCS, catalogue: Table):
    """
    Create Faster RCNN proposal boxes for all sources in the image

    The sky_coords seems to be swapped x and y on the boxes, so should be swapped here too
    :param wcs: WCS of the Radio data, so catalog data can be translated correctly
    :param catalogue: Catalogue to query
    :return: A Numpy array that holds the information in the correct location
    """

    ra_array = np.array(catalogue["ra"], dtype=float)
    dec_array = np.array(catalogue["dec"], dtype=float)
    sky_coords = SkyCoord(ra_array, dec_array, unit="deg")

    # Now have the objects, need to convert those RA and Decs to pixel coordinates
    proposals = []
    coords = skycoord_to_pixel(sky_coords, wcs, 0)
    for index, x in enumerate(coords[0]):
        try:
            proposals.append(
                make_bounding_box(
                    ra_array[index],
                    dec_array[index],
                    wcs=wcs,
                    class_name="Proposal Box",
                )
            )
        except Exception as e:
            print(f"Failed Proposal: {e}")
    return proposals
Example #21
0
def getSourceVals(RA, DEC, w, hdu, allfreq):
    c = SkyCoord(RA, DEC, frame='fk5', unit='deg')
    x, y = wcs.skycoord_to_pixel(c, w)
    X = np.rint(x)
    Y = np.rint(y)

    #hdu=pf.open(cube, memmap=True, mode='denywrite')
    if Y < 0 or X < 0:  #Y > hdu[0].data.shape[1] or X > hdu[0].data.shape[2] or
        #print "Source not in image!"
        col = []
        return col, allfreq

    col = hdu[0].data[:, 0, int(Y), int(X)]
    #hdu.close()
    #col = cube[:,int(Y),int(X)]

    flag = np.zeros(col.size)
    flag[np.isfinite(col)] = 1
    flag[np.abs(col) > 10] = 0
    flag[col == 0] = 0
    #pdb.set_trace()
    col = np.where(is_outlier(col), np.nan, col)
    col = np.where(np.isfinite(col), col, np.nan)
    col = np.where(col == 0, np.nan, col)
    col = np.where(np.abs(col) > 1E15, np.nan, col)
    #col=col[flag==1]
    #allfreq=allfreq[flag==1]

    return col, allfreq
Example #22
0
def voronoi_decomposition(im, comps):
    """Construct a Voronoi decomposition of a set of components

    The array return contains the index into the Voronoi structure

    :param im:
    :param comps:
    :return: Voronoi structure, vertex image
    """
    
    def voronoi_vertex(vy, vx, vertex_y, vertex_x):
        """ Return the nearest Voronoi vertex

        :param vy:
        :param vx:
        :param vertex_y:
        :param vertex_x:
        :return:
        """
        return numpy.argmin(numpy.hypot(vy - vertex_y, vx - vertex_x))
    
    directions = SkyCoord([u.rad * c.direction.ra.rad for c in comps],
                          [u.rad * c.direction.dec.rad for c in comps])
    x, y = skycoord_to_pixel(directions, im.wcs, 0, 'wcs')
    points = [(x[i], y[i]) for i, _ in enumerate(x)]
    vor = Voronoi(points)
    
    nchan, npol, ny, nx = im.shape
    vertex_image = numpy.zeros([ny, nx]).astype('int')
    for j in range(ny):
        for i in range(nx):
            vertex_image[j, i] = voronoi_vertex(j, i, vor.points[:, 1], vor.points[:, 0])
    
    return vor, vertex_image
Example #23
0
def test_skycoord_to_pixel(mode):

    # Import astropy.coordinates here to avoid circular imports
    from astropy.coordinates import SkyCoord

    header = get_pkg_data_contents('maps/1904-66_TAN.hdr', encoding='binary')
    wcs = WCS(header)

    ref = SkyCoord(0.1 * u.deg, -89. * u.deg, frame='icrs')

    xp, yp = skycoord_to_pixel(ref, wcs, mode=mode)

    # WCS is in FK5 so we need to transform back to ICRS
    new = pixel_to_skycoord(xp, yp, wcs, mode=mode).transform_to('icrs')

    assert_allclose(new.ra.degree, ref.ra.degree)
    assert_allclose(new.dec.degree, ref.dec.degree)

    # Make sure you can specify a different class using ``cls`` keyword
    class SkyCoord2(SkyCoord):
        pass

    new2 = pixel_to_skycoord(xp, yp, wcs, mode=mode,
                             cls=SkyCoord2).transform_to('icrs')

    assert new2.__class__ is SkyCoord2
    assert_allclose(new2.ra.degree, ref.ra.degree)
    assert_allclose(new2.dec.degree, ref.dec.degree)
Example #24
0
    def test_auto_rotate_systematic(self, angle):

        # This is a test to make sure for a number of angles that the corners
        # of the image are inside the final WCS but the next pixels outwards are
        # not. We test the full 360 range of angles.

        angle = np.radians(angle)
        pc = np.array([[np.cos(angle), -np.sin(angle)],
                       [np.sin(angle), np.cos(angle)]])
        self.wcs.wcs.pc = pc

        wcs, shape = find_optimal_celestial_wcs([(self.array, self.wcs)], auto_rotate=True)

        ny, nx = self.array.shape

        xp = np.array([0, 0, nx - 1, nx - 1, -1, -1, nx, nx])
        yp = np.array([0, ny - 1, ny - 1, 0, -1, ny, ny, -1])

        c = pixel_to_skycoord(xp, yp, self.wcs, origin=0)
        xp_final, yp_final = skycoord_to_pixel(c, wcs, origin=0)

        ny_final, nx_final = shape

        inside = ((xp_final >= -0.5) & (xp_final <= nx_final - 0.5) &
                  (yp_final >= -0.5) & (yp_final <= ny_final - 0.5))

        assert_equal(inside, [1, 1, 1, 1, 0, 0, 0, 0])
Example #25
0
    def to_pixel(self, wcs, mode='all'):
        """
        Convert the aperture to a `CircularAperture` instance in pixel
        coordinates.

        Parameters
        ----------
        wcs : `~astropy.wcs.WCS`
            The WCS transformation to use.

        mode : {'all', 'wcs'}, optional
            Whether to do the transformation including distortions
            (``'all'``; default) or only including only the core WCS
            transformation (``'wcs'``).

        Returns
        -------
        aperture : `CircularAperture` object
            A `CircularAperture` object.
        """

        x, y = skycoord_to_pixel(self.positions, wcs, mode=mode)

        if self.r.unit.physical_type == 'angle':
            central_pos = SkyCoord([wcs.wcs.crval], frame=self.positions.name,
                                   unit=wcs.wcs.cunit)
            xc, yc, scale, angle = skycoord_to_pixel_scale_angle(central_pos,
                                                                 wcs)
            r = (scale * self.r).to(u.pixel).value
        else:    # pixels
            r = self.r.value

        pixel_positions = np.array([x, y]).transpose()

        return CircularAperture(pixel_positions, r)
Example #26
0
    def to_pixel(self, wcs):
        """
        Return a EllipticalAnnulus instance in pixel coordinates.
        """

        x, y = skycoord_to_pixel(self.positions, wcs,
                                 mode=skycoord_to_pixel_mode)
        central_pos = SkyCoord([wcs.wcs.crval], frame=self.positions.name,
                               unit=wcs.wcs.cunit)
        xc, yc, scale, angle = skycoord_to_pixel_scale_angle(central_pos, wcs)

        if self.a_in.unit.physical_type == 'angle':
            a_in = (scale * self.a_in).to(u.pixel).value
            a_out = (scale * self.a_out).to(u.pixel).value
            b_out = (scale * self.b_out).to(u.pixel).value
        else:
            a_in = self.a_in.value
            a_out = self.a_out.value
            b_out = self.b_out.value

        theta = (angle + self.theta).to(u.radian).value

        pixel_positions = np.array([x, y]).transpose()

        return EllipticalAnnulus(pixel_positions, a_in, a_out, b_out, theta)
Example #27
0
def extract_gaussian_parameters_from_component_catalogue(
    pandas_cat,
    wcs,
    arcsec_per_pixel=1.5,
    PA_offset_degree=90,
    maj_min_in_arcsec=True,
    peak_flux_is_in_mJy=True,
):
    # Create skycoords for the center locations of all gaussians
    c = SkyCoord(pandas_cat.RA, pandas_cat.DEC, unit="deg")

    # transform ra, decs to pixel coordinates
    if maj_min_in_arcsec:
        deg2arcsec = 1
    else:
        deg2arcsec = 3600
    if peak_flux_is_in_mJy:
        mJy2Jy = 1000
    else:
        mJy2Jy = 1
    pixel_locs = skycoord_to_pixel(c, wcs, origin=0, mode="all")
    gaussians = [
        models.Gaussian2D(
            row.Peak_flux / mJy2Jy,
            x,
            y,
            FWHM_to_sigma_for_gaussian(row.Maj * deg2arcsec /
                                       arcsec_per_pixel),
            FWHM_to_sigma_for_gaussian(row.Min * deg2arcsec /
                                       arcsec_per_pixel),
            theta=np.deg2rad(row.PA + PA_offset_degree),
        ) for ((irow, row), x,
               y) in zip(pandas_cat.iterrows(), pixel_locs[0], pixel_locs[1])
    ]
    return gaussians
Example #28
0
def test_skycoord_to_pixel(mode):

    # Import astropy.coordinates here to avoid circular imports
    from astropy.coordinates import SkyCoord

    header = get_pkg_data_contents('data/maps/1904-66_TAN.hdr',
                                   encoding='binary')
    wcs = WCS(header)

    ref = SkyCoord(0.1 * u.deg, -89. * u.deg, frame='icrs')

    xp, yp = skycoord_to_pixel(ref, wcs, mode=mode)

    # WCS is in FK5 so we need to transform back to ICRS
    new = pixel_to_skycoord(xp, yp, wcs, mode=mode).transform_to('icrs')

    assert_allclose(new.ra.degree, ref.ra.degree)
    assert_allclose(new.dec.degree, ref.dec.degree)

    # Make sure you can specify a different class using ``cls`` keyword
    class SkyCoord2(SkyCoord):
        pass

    new2 = pixel_to_skycoord(xp, yp, wcs, mode=mode,
                             cls=SkyCoord2).transform_to('icrs')

    assert new2.__class__ is SkyCoord2
    assert_allclose(new2.ra.degree, ref.ra.degree)
    assert_allclose(new2.dec.degree, ref.dec.degree)
Example #29
0
def mask_galaxy(image, wcs, Ra, Dec, name, radius):
    """Masks galaxy at Ra, Dec within a radius given in arcminutes

    Creates a circular mask centered at a given Ra, Dec. The radius
    is given in arcmins. The wcs object is used to convert these inputs
    to pixel locations. A pixel scale is also determined. If the object
    name is suppled, SESAME is used to find object center. If no active
    internet connection is available, center location must be manually
    entered, in degrees. If no center coordinates are supplied, (0, 0)
    is the default center.

        Args:
            image(array, required):      Image data
            wcs:                         World Coordinte System object
            name(str, optional):         Name of galaxy or object
            Ra(str):                     Right Ascention
            Dec(str):                    Declination
            Radius(float, required):     Radius to be masked, in arcminutes

        Returns:
            masked_img(array):           Image which has been masked
            mask(boolean array):         Mask of the given object"""
    # Radius must be given in arcminutes
    # Dimentions of the image
    dim = (image.shape)
    y, x = dim[0], dim[1]

    # Finds the center of an object by inputting its name into SESAME
    # This requires an active internet connection
    # a, b are the coordinates of the center given in pixels

    try:
        center = SkyCoord.from_name(name)
    except Exception:
        print("No active internet connection. Manually enter Ra, Dec.")
        Ra = Ra
        Dec = Dec
        center = SkyCoord(Ra, Dec, unit="deg")

    c_pix = skycoord_to_pixel(center, wcs)
    a, b = c_pix[0], c_pix[1]
    print(center)

    radius = radius * u.arcmin

    # Finds pixel scale using WSC object. The default units can be found by
    # unit = header['CUNIT1'], they are degrees by convention
    # degrees are converted to arcmins and radius in computed in pixels
    scale = proj_plane_pixel_scales(wcs)
    pix_scale = scale[0] * u.deg.to(u.arcmin)
    print('Image Scale: ' + str(pix_scale) + ' arcmin/pix')

    rad_pix = (radius / pix_scale).value

    # Indexes each pixel and checks if its is >= radius from center
    Y, X = np.ogrid[:y, :x]
    dist_from_center = np.sqrt((X - a)**2 + (Y - b)**2)
    mask = dist_from_center <= rad_pix
    return mask
def main():

    files = np.loadtxt("filenames_M8_wcs.txt", dtype='str')

    for infile in files:
        print infile
        ccmapfile = open('Lagoon_2MASS_xy_radec.dat', 'w')
        newfile = infile.replace('wcs', 'wcs2')
        copyfile(infile, newfile)

        coords = np.loadtxt('Lagoon_2MASS_radec_amended.dat', dtype=str)
        ra = coords[:, 0]
        ra = np.array([float(i) for i in ra])
        dec = coords[:, 1]
        dec = np.array([float(i) for i in dec])

        #   open image:
        instr = fits.open(infile, mode='readonly', memmap=True)
        pixels = instr[0].data[:]
        crval1p = instr[0].header['CRVAL1P']
        crval2p = instr[0].header['CRVAL2P']
        instr.close()

        for i in np.arange(len(ra)):
            skyposition = SkyCoord(ra[i],
                                   dec[i],
                                   unit=('deg', 'deg'),
                                   frame='icrs')
            wcs = WCS(infile)
            pixelpos = skycoord_to_pixel(skyposition, wcs=wcs)
            columns = str(int(round(pixelpos[0])))
            rows = str(int(round(pixelpos[1])))

            ## Guess at flux:
            fluxguess = str(pixels[int(rows), int(columns)])

            result = kepprf_AMC.kepprf_AMC(infile,'1',columns,rows,fluxguess,border=1,background='yes',focus='no', \
              prfdir='/Users/acody/Data/Kepler',xtol=0.0001,ftol=0.01,verbose=False,logfile='kepprf.log')

            newx = result[1] - crval1p + 1
            newy = result[2] - crval2p + 1

            print >> ccmapfile, newx, newy, ra[i], dec[i]

        ccmapfile.close()

        # Call ccmap to compute new wcs
        iraf.ccmap("Lagoon_2MASS_xy_radec.dat",
                   "Lagoon_coordfit.db",
                   images=newfile,
                   lngunit="degrees",
                   latunit="degrees",
                   update="yes",
                   verbose="no",
                   interactive="no")

        os.remove('Lagoon_2MASS_xy_radec.dat')
        os.remove('Lagoon_coordfit.db')
Example #31
0
def MakeTiffCut(tiledir, outdir, positions, xs, ys, df, maketiff, makepngs):
	logger = logging.getLogger(__name__)
	os.makedirs(outdir, exist_ok=True)
	
	imgname = glob.glob(tiledir + '*.tiff')
	try:
		im = Image.open(imgname[0])
	#except IOError as e:
	except IndexError as e:
		print('No TIFF file found for tile ' + df['TILENAME'][0] + '. Will not create true-color cutout.')
		logger.error('MakeTiffCut - No TIFF file found for tile ' + df['TILENAME'][0] + '. Will not create true-color cutout.')
		return
	
	# try opening I band FITS (fallback on G, R bands)
	hdul = None
	for _i in ['i','g','r','z','Y']:
		tilename = glob.glob(tiledir+'*_{}.fits.fz'.format(_i))
		try:
			hdul = fits.open(tilename[0])
		except IOError as e:
			hdul = None
			logger.warning('MakeTiffCut - Could not find master FITS file: ' + tilename)
			continue
		else:
			break
	if not hdul:
		print('Cannot find a master fits file for this tile.')
		logger.error('MakeTiffCut - Cannot find a master fits file for this tile.')
		return
	
	w = WCS(hdul['SCI'].header)
	
	pixelscale = utils.proj_plane_pixel_scales(w)
	dx = int(0.5 * xs * ARCMIN_TO_DEG / pixelscale[0])		# pixelscale is in degrees (CUNIT)
	dy = int(0.5 * ys * ARCMIN_TO_DEG / pixelscale[1])
	
	pixcoords = utils.skycoord_to_pixel(positions, w, origin=0, mode='wcs')
	
	for i in range(len(positions)):
		if 'COADD_OBJECT_ID' in df:
			filenm = outdir + str(df['COADD_OBJECT_ID'][i])
		else:
			filenm = outdir + 'x{0}y{1}'.format(df['RA'][i], df['DEC'][i])
			#filenm = outdir + 'DESJ' + _DecConverter(df['RA'][0], df['DEC'][0])
		left = max(0, pixcoords[0][i] - dx)
		upper = max(0, im.size[1] - pixcoords[1][i] - dy)
		right = min(pixcoords[0][i] + dx, 10000)
		lower = min(im.size[1] - pixcoords[1][i] + dy, 10000)
		newimg = im.crop((left, upper, right, lower))
		
		if newimg.size != (2*dx, 2*dy):
			logger.info('MakeTiffCut - {} is smaller than user requested. This is likely because the object/coordinate was in close proximity to the edge of a tile.'.format(filenm.split('/')[-1]))
		
		if maketiff:
			newimg.save(filenm+'.tiff', format='TIFF')
		if makepngs:
			newimg.save(filenm+'.png', format='PNG')
	logger.info('MakeTiffCut - Tile {} complete.'.format(df['TILENAME'][0]))
Example #32
0
def insert_skycomponent_para(im: image_for_para,
                             sc: Union[Skycomponent, List[Skycomponent]],
                             insert_method='',
                             bandwidth=1.0,
                             support=8) -> image_for_para:
    '''
    :param im: 被插入的image
    :param sc: 插入的skycomponent,可以有多个skycomponent
    :param insert_method: 插入方法,四种分别为: Lanczos Sinc PSWF 和 缺省方法
    :param bandwidth:
    :param support:
    :return: 新的image
    '''
    if type(im) == tuple:
        im = im[1]

    assert type(im) == image_for_para

    support = int(support / bandwidth)

    ny, nx = im.shape

    if not isinstance(sc, collections.Iterable):
        sc = [sc]

    for comp in sc:
        assert comp.shape == 'Point', "Cannot handle shape %s" % comp.shape
        pixloc = skycoord_to_pixel(comp.direction, im.wcs, 1, 'wcs')
        if insert_method == "Lanczos":
            insert_array_para(im.data,
                              pixloc[0],
                              pixloc[1],
                              comp.flux[im.channel, im.polarisation],
                              bandwidth,
                              support,
                              insert_function=insert_function_L)
        elif insert_method == "Sinc":
            insert_array_para(im.data,
                              pixloc[0],
                              pixloc[1],
                              comp.flux[im.channel, im.polarisation],
                              bandwidth,
                              support,
                              insert_function=insert_function_sinc)
        elif insert_method == "PSWF":
            insert_array_para(im.data,
                              pixloc[0],
                              pixloc[1],
                              comp.flux[im.channel, im.polarisation],
                              bandwidth,
                              support,
                              insert_function=insert_function_pswf)
        else:
            y, x = numpy.round(pixloc[1]).astype('int'), numpy.round(
                pixloc[0]).astype('int')
            if x >= 0 and x < nx and y >= 0 and y < ny:
                im.data[y, x] += comp.flux[im.channel, im.polarisation]
    return im
Example #33
0
    def to_pixel(self, wcs, mode='local', tolerance=None):
        if mode != 'local':
            raise NotImplementedError
        if tolerance is not None:
            raise NotImplementedError

        x, y = skycoord_to_pixel(self.vertices, wcs)
        vertices_pix = PixCoord(x, y)
        return PolygonPixelRegion(vertices_pix)
Example #34
0
def skytopix(self, sky):
    """
    Given a skycoord (or list of skycoords) returns the pixel locations
    """
    hdu = self.sci
    hdr = hdu.header
    wcs, frame = WCS(hdr), hdr['RADESYS'].lower()
    pixel = skycoord_to_pixel(sky, wcs)
    return pixel
Example #35
0
 def lm(self, ra, dec):
     coord = SkyCoord(ra=ra * u.rad, dec=dec * u.rad)
     coord_pixels = utils.skycoord_to_pixel(coords=coord, wcs=self.wcs, origin=0, mode='all')
     if np.isnan(np.sum(coord_pixels)):
         l, m = -0.0, 0.0
     else:
         l, m = coord_pixels[self.ra_axis], coord_pixels[self.dec_axis]
     l = (l - self._l0) * -self.xscale
     m = (m - self._m0) * self.yscale
     return l, m
def show_image(im: Image,
               fig=None,
               title: str = '',
               pol=0,
               chan=0,
               cm='Greys',
               components=None,
               vmin=None,
               vmax=None,
               vscale=1.0):
    """ Show an Image with coordinates using matplotlib, optionally with components

    :param im: Image
    :param fig: Matplotlib figure
    :param title: String for title of plot
    :param pol: Polarisation to show (index)
    :param chan: Channel to show (index)
    :param components: Optional components to be overlaid
    :param vmin: Clip to this minimum
    :param vmax: Clip to this maximum
    :param vscale: scale max, min by this amount
    :return:
    """
    import matplotlib.pyplot as plt

    assert isinstance(im, Image), im

    fig = plt.figure()
    ax = fig.add_subplot(1, 1, 1, projection=im.wcs.sub([1, 2]))

    if len(im.data.shape) == 4:
        data_array = numpy.real(im.data[chan, pol, :, :])
    else:
        data_array = numpy.real(im.data)

    if vmax is None:
        vmax = vscale * numpy.max(data_array)
    if vmin is None:
        vmin = vscale * numpy.min(data_array)

    cm = ax.imshow(data_array, origin='lower', cmap=cm, vmax=vmax, vmin=vmin)

    ax.set_xlabel(im.wcs.wcs.ctype[0])
    ax.set_ylabel(im.wcs.wcs.ctype[1])
    ax.set_title(title)

    fig.colorbar(cm, orientation='vertical', shrink=0.7)

    if components is not None:
        for sc in components:
            x, y = skycoord_to_pixel(sc.direction, im.wcs, 0, 'wcs')
            ax.plot(x, y, marker='+', color='red')

    return fig
Example #37
0
def show_skymodel(sms, psf_width=1.75, cm='Greys', vmax=None, vmin=None):
    """ Show a list of SkyModels

    :param sms: List of SkyModels
    :param psf_width: Width of PSF in pixels
    :param cm: matplotlib colormap
    :param vmax: Maximum in image display
    :param vmin: Minimum in image display
    :return:
    """
    sp = 1

    for ism, sm in enumerate(sms):
        plt.clf()
        plt.subplot(121, projection=sms[ism].image.wcs.sub([1, 2]))
        sp += 1

        smodel = copy_image(sms[ism].image)
        smodel = insert_skycomponent(smodel, sms[ism].components)
        smodel = smooth_image(smodel, psf_width)

        if vmax is None:
            vmax = numpy.max(smodel.data[0, 0, ...])
        if vmin is None:
            vmin = numpy.min(smodel.data[0, 0, ...])

        plt.imshow(smodel.data[0, 0, ...],
                   origin='lower',
                   cmap=cm,
                   vmax=vmax,
                   vmin=vmin)
        plt.xlabel(sms[ism].image.wcs.wcs.ctype[0])
        plt.ylabel(sms[ism].image.wcs.wcs.ctype[1])

        plt.title('SkyModel%d' % ism)

        components = sms[ism].components
        if components is not None:
            for sc in components:
                x, y = skycoord_to_pixel(sc.direction, sms[ism].image.wcs, 0,
                                         'wcs')
                plt.plot(x, y, marker='+', color='red')

        gaintable = sms[ism].gaintable
        if gaintable is not None:
            plt.subplot(122)
            sp += 1
            phase = numpy.angle(sm.gaintable.gain[:, :, 0, 0, 0])
            phase -= phase[:, 0][:, numpy.newaxis]
            plt.imshow(phase, origin='lower')
            plt.xlabel('Dish/Station')
            plt.ylabel('Integration')
            plt.show()
Example #38
0
    def plot_exclusion_mask(self, size=None, **kwargs):
        """Plot exclusion mask for this observation

        The plot will be centered at the pointing position

        Parameters
        ----------
        size : `~astropy.coordinates.Angle`
            Edge length of the plot
        """
        size = Angle('5 deg') if size is None else size
        ax = self.meta.exclusion.plot(**kwargs)
        self._set_ax_limits(ax, size)
        point = skycoord_to_pixel(self.meta.pointing, ax.wcs)
        ax.scatter(point[0], point[1], s=250, marker="+", color='black')
        return ax
Example #39
0
def skycoord_to_pixel(coords, wcs, unit='deg'):
    """Transform sky coordinates (ra, dec) to pixel coordinates (x, y) given a wcs.

    :param coords: Coordinates. Multiple formats accepted:

     - [ra, dec]
     - [[ra1, ra2], [dec1, dec2]]
     - or a SkyCoord object

    :param wcs: an astropy.wcs.WCS object
    :return: A list of (x, y) coordinates in pixel units
    """

    if not isinstance(coords, SkyCoord):
        coords = SkyCoord(coords[0], coords[1], unit=unit)
    return utils.skycoord_to_pixel(coords, wcs)
Example #40
0
    def _to_pixel_params(self, wcs, mode='all'):
        """
        Convert the sky aperture parameters to those for a pixel
        aperture.

        Parameters
        ----------
        wcs : `~astropy.wcs.WCS`
            The world coordinate system (WCS) transformation to use.

        mode : {'all', 'wcs'}, optional
            Whether to do the transformation including distortions
            (``'all'``; default) or only including only the core WCS
            transformation (``'wcs'``).

        Returns
        -------
        pixel_params : dict
            A dictionary of parameters for an equivalent pixel aperture.
        """

        pixel_params = {}
        x, y = skycoord_to_pixel(self.positions, wcs, mode=mode)
        pixel_params['positions'] = np.array([x, y]).transpose()

        # The aperture object must have a single value for each shape
        # parameter so we must use a single pixel scale for all positions.
        # Here, we define the scale at the WCS CRVAL position.
        crval = SkyCoord([wcs.wcs.crval], frame=wcs_to_celestial_frame(wcs),
                         unit=wcs.wcs.cunit)
        scale, angle = pixel_scale_angle_at_skycoord(crval, wcs)

        params = self._params[:]
        theta_key = 'theta'
        if theta_key in self._params:
            pixel_params[theta_key] = (self.theta + angle).to(u.radian).value
            params.remove(theta_key)

        param_vals = [getattr(self, param) for param in params]
        if param_vals[0].unit.physical_type == 'angle':
            for param, param_val in zip(params, param_vals):
                pixel_params[param] = (param_val / scale).to(u.pixel).value
        else:    # pixels
            for param, param_val in zip(params, param_vals):
                pixel_params[param] = param_val.value

        return pixel_params
Example #41
0
def test_skycoord_to_pixel_distortions(mode):

    # Import astropy.coordinates here to avoid circular imports
    from astropy.coordinates import SkyCoord

    header = get_pkg_data_filename('data/sip.fits')
    wcs = WCS(header)

    ref = SkyCoord(202.50 * u.deg, 47.19 * u.deg, frame='icrs')

    xp, yp = skycoord_to_pixel(ref, wcs, mode=mode)

    # WCS is in FK5 so we need to transform back to ICRS
    new = pixel_to_skycoord(xp, yp, wcs, mode=mode).transform_to('icrs')

    assert_allclose(new.ra.degree, ref.ra.degree)
    assert_allclose(new.dec.degree, ref.dec.degree)
Example #42
0
def from_moc(depth_ipix_d, wcs):
    # Create a new MOC that do not contain the HEALPix
    # cells that are backfacing the projection
    depths = [int(depth_str) for depth_str in depth_ipix_d.keys()]
    min_depth = min(depths)
    max_depth = max(depths)
    ipixels = np.asarray(depth_ipix_d[str(min_depth)])

    # Split the cells located at the border of the projection
    # until at least the depth 7
    max_split_depth = max(7, max_depth)

    ipix_d = {}
    for depth in range(min_depth, max_split_depth + 1):
        hp = HEALPix(nside=(1 << depth), order='nested', frame=ICRS())

        ipix_boundaries = hp.boundaries_skycoord(ipixels, step=1)
        # Projection on the given WCS
        xp, yp = skycoord_to_pixel(coords=ipix_boundaries, wcs=wcs)
        _, _, frontface_id = backface_culling(xp, yp)

        # Get the pixels which are backfacing the projection
        backfacing_ipix = ipixels[~frontface_id]
        frontface_ipix = ipixels[frontface_id]

        depth_str = str(depth)
        ipix_d.update({depth_str: frontface_ipix})

        next_depth = str(depth + 1)
        ipixels = []
        if next_depth in depth_ipix_d:
            ipixels = depth_ipix_d[next_depth]

        for bf_ipix in backfacing_ipix:
            child_bf_ipix = bf_ipix << 2
            ipixels.extend([child_bf_ipix,
                child_bf_ipix + 1,
                child_bf_ipix + 2,
                child_bf_ipix + 3])

        ipixels = np.asarray(ipixels)

    return ipix_d
Example #43
0
    def wcs_skycoord_to_pixel(self, coords):
        """
        Convert a set of SkyCoord coordinates into pixels.

        Calls `~astropy.wcs.utils.skycoord_to_pixel`, passing ``coords`` to it.

        Parameters
        ----------
        coords : `~astropy.coordinates.SkyCoord`
            The coordinates to convert.

        Returns
        -------
        xp, yp : `~numpy.ndarray`
            The pixel coordinates.
        """
        return skycoord_to_pixel(coords=coords, wcs=self.wcs,
                                 origin=_DEFAULT_WCS_ORIGIN,
                                 mode=_DEFAULT_WCS_MODE)
Example #44
0
    def to_pixel(self, wcs, mode='all'):
        """
        Convert the aperture to a `RectangularAnnulus` instance in pixel
        coordinates.

        Parameters
        ----------
        wcs : `~astropy.wcs.WCS`
            The WCS transformation to use.

        mode : {'all', 'wcs'}, optional
            Whether to do the transformation including distortions
            (``'all'``; default) or only including only the core WCS
            transformation (``'wcs'``).

        Returns
        -------
        aperture : `RectangularAnnulus` object
            A `RectangularAnnulus` object.
        """

        x, y = skycoord_to_pixel(self.positions, wcs, mode=mode)
        central_pos = SkyCoord([wcs.wcs.crval], frame=self.positions.name,
                               unit=wcs.wcs.cunit)
        xc, yc, scale, angle = skycoord_to_pixel_scale_angle(central_pos, wcs)

        if self.w_in.unit.physical_type == 'angle':
            w_in = (scale * self.w_in).to(u.pixel).value
            w_out = (scale * self.w_out).to(u.pixel).value
            h_out = (scale * self.h_out).to(u.pixel).value
        else:
            # pixels
            w_in = self.w_in.value
            w_out = self.w_out.value
            h_out = self.h_out.value

        theta = (angle + self.theta).to(u.radian).value

        pixel_positions = np.array([x, y]).transpose()

        return RectangularAnnulus(pixel_positions, w_in, w_out, h_out, theta)
Example #45
0
    def to_pixel(self, wcs):
        """
        Convert the aperture to a `CircularAperture` instance in
        pixel coordinates.
        """

        x, y = skycoord_to_pixel(self.positions, wcs,
                                 mode=skycoord_to_pixel_mode)

        if self.r.unit.physical_type == 'angle':
            central_pos = SkyCoord([wcs.wcs.crval], frame=self.positions.name,
                                   unit=wcs.wcs.cunit)
            xc, yc, scale, angle = skycoord_to_pixel_scale_angle(central_pos,
                                                                 wcs)
            r = (scale * self.r).to(u.pixel).value
        else:
            r = self.r.value    # pixels

        pixel_positions = np.array([x, y]).transpose()

        return CircularAperture(pixel_positions, r)
Example #46
0
    def to_pixel(self, wcs):
        """
        Return a CircularAnnulus instance in pixel coordinates.
        """

        x, y = skycoord_to_pixel(self.positions, wcs,
                                 mode=skycoord_to_pixel_mode)
        if self.r_in.unit.physical_type == 'angle':
            central_pos = SkyCoord([wcs.wcs.crval], frame=self.positions.name,
                                   unit=wcs.wcs.cunit)
            xc, yc, scale, angle = skycoord_to_pixel_scale_angle(central_pos,
                                                                 wcs)
            r_in = (scale * self.r_in).to(u.pixel).value
            r_out = (scale * self.r_out).to(u.pixel).value
        else:  # pixel
            r_in = self.r_in.value
            r_out = self.r_out.value

        pixel_positions = np.array([x, y]).transpose()

        return CircularAnnulus(pixel_positions, r_in, r_out)
Example #47
0
def linear_offset_coordinates(wcs, center):
    '''
    return a locally linear offset coordinate system

    does the simplest thing possible and assumes no projection distortions
    '''
    assert isinstance(center, coords.SkyCoord), \
        '`center` must by of type `SkyCoord`'
    assert center.isscalar, '`center` must have length 1'
    # Convert center to pixel coordinates
    xp, yp = skycoord_to_pixel(center, wcs)

    # Set up new WCS
    new_wcs = WCS(naxis=2)
    new_wcs.wcs.crpix = xp + 1, yp + 1
    new_wcs.wcs.crval = 0., 0.
    new_wcs.wcs.cdelt = proj_plane_pixel_scales(wcs)
    new_wcs.wcs.ctype = 'XOFFSET', 'YOFFSET'
    new_wcs.wcs.cunit = 'deg', 'deg'

    return new_wcs
Example #48
0
def gcentroid_wcs(im, wcs, guess, **kwargs):
    """Gaussian centroid given sky coordinates.

    Parameters
    ----------
    im : ndarray
        2D image for centroiding.

    wcs : astropy WCS
        World coordinate system object.

    guess : SkyCoord or tuple of Quantity
        Location on which to centroid.

    **kwargs
        Any ``gcentroid`` keyword arguments.


    Returns
    -------
    cyx : ndarray
        Pixel coordinates of the computed center.  The lower-left
        corner of a pixel is -0.5, -0.5.

    c : SkyCoord
        World coordinates of the computed center.

    """

    if isinstance(guess, coords.SkyCoord):
        g = guess
    else:
        g = coords.SkyCoord(*guess)

    gx, gy = np.array(skycoord_to_pixel(g, wcs))

    cyx = gcentroid(im, yx=(gy, gx), **kwargs)
    c = pixel_to_skycoord(cyx[1], cyx[0], wcs)

    return cyx, c
Example #49
0
    def to_pixel(self, wcs):
        """
        Return a `~gammapy.regions.PixCircleRegion`.

        Parameters
        ----------
        wcs : `~astropy.wcs.WCS`
            WCS object
        """

        x, y = skycoord_to_pixel(self.pos, wcs, mode='wcs', origin=1)
        pix_radius = self.radius.deg / np.abs(wcs.wcs.cdelt[0])

        # TODO understand what is going on here
        # from photutils.utils.wcs_helpers import skycoord_to_pixel_scale_angle
        # central_pos = SkyCoord([wcs.wcs.crval], frame=self.pos.name, unit=wcs.wcs.cunit)
        # xc, yc, scale, angle = skycoord_to_pixel_scale_angle(central_pos, wcs)
        # val = (scale * self.radius).to(u.pixel).value
        # pix_radius = np.round(val[0],4)
        # pix_position = np.array([x, y]).transpose()

        return PixCircleRegion((x, y), pix_radius)
Example #50
0
File: fill.py Project: tboch/mocpy
def compute_healpix_vertices(depth, ipix, wcs):
    path_vertices = np.array([])
    codes = np.array([])

    depth = int(depth)

    step = 1
    if depth < 3:
        step = 2

    hp = HEALPix(order="nested", nside=(1 << depth), frame=ICRS())
    ipix_boundaries = hp.boundaries_skycoord(ipix, step=step)
    # Projection on the given WCS
    xp, yp = skycoord_to_pixel(ipix_boundaries, wcs=wcs)

    c1 = np.vstack((xp[:, 0], yp[:, 0])).T
    c2 = np.vstack((xp[:, 1], yp[:, 1])).T
    c3 = np.vstack((xp[:, 2], yp[:, 2])).T
    c4 = np.vstack((xp[:, 3], yp[:, 3])).T

    if depth < 3:
        c5 = np.vstack((xp[:, 4], yp[:, 4])).T
        c6 = np.vstack((xp[:, 5], yp[:, 5])).T
        c7 = np.vstack((xp[:, 6], yp[:, 6])).T
        c8 = np.vstack((xp[:, 7], yp[:, 7])).T

        cells = np.hstack((c1, c2, c3, c4, c5, c6, c7, c8, np.zeros((c1.shape[0], 2))))

        path_vertices = cells.reshape((9*c1.shape[0], 2))
        single_code = np.array([Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY])
    else:
        cells = np.hstack((c1, c2, c3, c4, np.zeros((c1.shape[0], 2))))

        path_vertices = cells.reshape((5*c1.shape[0], 2))
        single_code = np.array([Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY])

    codes = np.tile(single_code, c1.shape[0])

    return path_vertices, codes
Example #51
0
    def to_pixel(self, wcs):
        """
        Return a EllipticalAperture instance in pixel coordinates.
        """

        x, y = skycoord_to_pixel(self.positions, wcs,
                                 mode=skycoord_to_pixel_mode)
        central_pos = SkyCoord([wcs.wcs.crval], frame=self.positions.name,
                               unit=wcs.wcs.cunit)
        xc, yc, scale, angle = skycoord_to_pixel_scale_angle(central_pos, wcs)

        if self.a.unit.physical_type == 'angle':
            a = (scale * self.a).to(u.pixel).value
            b = (scale * self.b).to(u.pixel).value
        else:  # pixel
            a = self.a.value
            b = self.b.value

        theta = (angle + self.theta).to(u.radian).value

        pixel_positions = np.array([x, y]).transpose()

        return EllipticalAperture(pixel_positions, a, b, theta)
Example #52
0
 def to_pixel(self, wcs):
     center_x, center_y = skycoord_to_pixel(self.center, wcs=wcs)
     center = PixCoord(center_x, center_y)
     return TextPixelRegion(center, self.text, self.meta, self.visual)
Example #53
0
def test_fill_acceptance_image():
    # create empty image
    # odd number of pixels needed for having the center in its own pixel
    n_pix_x = 101
    n_pix_y = 101
    bin_size = Angle(0.1, 'deg')
    image = make_empty_image(n_pix_x, n_pix_y, bin_size.degree,
                             xref=0, yref=0, fill=0,
                             proj='CAR', coordsys='GAL',
                             xrefpix=None, yrefpix=None, dtype='float32')

    # define center coordinate of the image in wolrd and pixel coordinates
    lon = image.header['CRVAL1']
    lat = image.header['CRVAL2']

    center = SkyCoord(lon, lat, unit='deg', frame='galactic')

    # initialize WCS to the header of the image
    w = WCS(image.header)

    x_center_pix, y_center_pix = skycoord_to_pixel(center, w, origin=0)

    # define pixel sizes
    # x_pix_size = Angle(abs(image.header['CDELT1']), 'deg')
    # y_pix_size = Angle(abs(image.header['CDELT2']), 'deg')

    # define radial acceptance and offset angles
    # using bin_size for the offset step makes the test comparison easier
    offset = Angle(np.arange(0., 30., bin_size.degree), 'deg')
    sigma = Angle(1.0, 'deg')
    amplitude = 1.
    mean = 0.
    stddev = sigma.radian
    gaus_model = models.Gaussian1D(amplitude, mean, stddev)
    acceptance = gaus_model(offset.radian)

    # fill acceptance in the image
    image = fill_acceptance_image(image.header, center, offset, acceptance)

    # test: check points at the offsets where the acceptance is defined
    # along the x axis

    # define grids of pixel coorinates
    xpix_coord_grid, ypix_coord_grid = coordinates(image, world=False)

    # calculate pixel offset from center (in world coordinates)
    coord = pixel_to_skycoord(xpix_coord_grid, ypix_coord_grid, w, origin=0)
    pix_off = coord.separation(center)

    # x axis defined in the array positions [y_center_pix,:]
    # only interested in semi axis, so [y_center_pix, x_center_pix:]
    ix_min = int(x_center_pix)
    iy = int(y_center_pix)
    pix_off_x_axis = pix_off[iy, ix_min:]
    image.data_x_axis = image.data[iy, ix_min:]

    # cut offset and acceptance arrays to match image size
    # this is only valid if the offset step matches the pixel size
    n = pix_off_x_axis.size
    acceptance_cut = acceptance[0:n]

    # check acceptance of the image:
    np.testing.assert_almost_equal(image.data_x_axis, acceptance_cut, decimal=4)
Example #54
0
def nddata_cutout2d(nddata, position, size, mode='trim', fill_value=np.nan):
    """
    Create a 2D cutout of a `~astropy.nddata.NDData` object.

    Specifically, cutouts will made for the ``nddata.data`` and
    ``nddata.mask`` (if present) arrays.  If ``nddata.wcs`` exists, then
    it will also be updated.

    Note that cutouts will not be made for ``nddata.uncertainty`` (if
    present) because they are general objects and not arrays.

    Parameters
    ----------
    nddata : `~astropy.nddata.NDData`
        The 2D `~astropy.nddata.NDData` from which the cutout is taken.

    position : tuple or `~astropy.coordinates.SkyCoord`
        The position of the cutout array's center with respect to the
        ``nddata.data`` array.  The position can be specified either as
        a ``(x, y)`` tuple of pixel coordinates or a
        `~astropy.coordinates.SkyCoord`, in which case ``nddata.wcs``
        must exist.

    size : int, array-like, `~astropy.units.Quantity`
        The size of the cutout array along each axis.  If ``size`` is a
        scalar number or a scalar `~astropy.units.Quantity`, then a
        square cutout of ``size`` will be created.  If ``size`` has two
        elements, they should be in ``(ny, nx)`` order.  Scalar numbers
        in ``size`` are assumed to be in units of pixels.  ``size`` can
        also be a `~astropy.units.Quantity` object or contain
        `~astropy.units.Quantity` objects.  Such
        `~astropy.units.Quantity` objects must be in pixel or angular
        units.  For all cases, ``size`` will be converted to an integer
        number of pixels, rounding the the nearest integer.  See the
        ``mode`` keyword for additional details on the final cutout
        size.

    mode : {'trim', 'partial', 'strict'}, optional
        The mode used for creating the cutout data array.  For the
        ``'partial'`` and ``'trim'`` modes, a partial overlap of the
        cutout array and the input ``nddata.data`` array is sufficient.
        For the ``'strict'`` mode, the cutout array has to be fully
        contained within the ``nddata.data`` array, otherwise an
        `~astropy.nddata.utils.PartialOverlapError` is raised.   In all
        modes, non-overlapping arrays will raise a
        `~astropy.nddata.utils.NoOverlapError`.  In ``'partial'`` mode,
        positions in the cutout array that do not overlap with the
        ``nddata.data`` array will be filled with ``fill_value``.  In
        ``'trim'`` mode only the overlapping elements are returned, thus
        the resulting cutout array may be smaller than the requested
        ``size``.

    fill_value : number, optional
        If ``mode='partial'``, the value to fill pixels in the cutout
        array that do not overlap with the input ``nddata.data``.
        ``fill_value`` must have the same ``dtype`` as the input
        ``nddata.data`` array.

    Returns
    -------
    result : `~astropy.nddata.NDData`
        A `~astropy.nddata.NDData` object with cutouts for the data and
        mask, if input.

    Examples
    --------
    >>> from astropy.nddata import NDData
    >>> import astropy.units as u
    >>> from astroimtools import nddata_cutout2d
    >>> data = np.random.random((500, 500))
    >>> unit = u.electron / u.s
    >>> mask = (data > 0.7)
    >>> meta = {'exptime': 1234 * u.s}
    >>> nddata = NDData(data, mask=mask, unit=unit, meta=meta)
    >>> cutout = nddata_cutout2d(nddata, (100, 100), (10, 10))
    >>> cutout.data.shape
    (10, 10)
    >>> cutout.mask.shape
    (10, 10)
    >>> cutout.unit
    Unit("electron / s")
    """

    from astropy.nddata.utils import Cutout2D

    if not isinstance(nddata, NDData):
        raise ValueError('nddata input must be an NDData object')

    if isinstance(position, SkyCoord):
        if nddata.wcs is None:
            raise ValueError('nddata must contain WCS if the input '
                             'position is a SkyCoord')
        position = skycoord_to_pixel(position, nddata.wcs, mode='all')

    data_cutout = Cutout2D(np.asanyarray(nddata.data), position, size,
                           wcs=nddata.wcs, mode=mode, fill_value=fill_value)
    # need to create a new NDData instead of copying/replacing
    nddata_out = NDData(data_cutout.data, unit=nddata.unit,
                        uncertainty=nddata.uncertainty, meta=nddata.meta)

    if nddata.wcs is not None:
        nddata_out.wcs = data_cutout.wcs

    if nddata.mask is not None:
        mask_cutout = Cutout2D(np.asanyarray(nddata.mask), position, size,
                               mode=mode, fill_value=fill_value)
        nddata_out.mask = mask_cutout.data

    return nddata_out
    # Todo:voir pour la normalisation normalement il le fait tout seul mais pas sur...
    psf_image_SgrA = fill_acceptance_image(header, on.center(), psf_file_SgrA["theta"].to("deg"),
                                           psf_file_SgrA["psf_value"].data, psf_file_SgrA["theta"].to("deg")[-1])
    source_center_SgrA = SkyCoord(359.9442, -0.0462, unit='deg', frame="galactic")
    # source_center_SgrA = SkyCoord.from_name("SgrA*")
    source_center_G0p9 = SkyCoord(0.868, 0.075, unit='deg', frame="galactic")
    psf_image_G0p9 = fill_acceptance_image(header, on.center(), psf_file_G0p9["theta"].to("deg"),
                                           psf_file_G0p9["psf_value"].data, psf_file_G0p9["theta"].to("deg")[-1])
    psf_image_SgrA.writeto("psf_image_SgrA_" + str(E1) + "_" + str(E2) + ".fits", clobber=True)
    psf_image_G0p9.writeto("psf_image_G0p9_" + str(E1) + "_" + str(E2) + ".fits", clobber=True)
    load_psf("psf_SgrA", "psf_image_SgrA_" + str(E1) + "_" + str(E2) + ".fits")
    load_psf("psf_G0p9", "psf_image_G0p9_" + str(E1) + "_" + str(E2) + ".fits")

    # modele gauss pour sgrA centre sur SgrA
    mygaus_SgrA = normgauss2dint("SgrA")
    mygaus_SgrA.xpos, mygaus_SgrA.ypos = skycoord_to_pixel(source_center_SgrA, on.wcs)
    mygaus_SgrA.xpos.val += 0.5
    mygaus_SgrA.ypos.val += 0.5
    # Modele marge gaussienne a multiplie avec CS centre sur SgrA
    large_gaus = Gauss2D("Gauss_to_CS")
    large_gaus.xpos, large_gaus.ypos = skycoord_to_pixel(source_center_SgrA, on.wcs)
    large_gaus.fwhm = 100
    central_gauss = Gauss2D("central_gauss")
    central_gauss.xpos, central_gauss.ypos = skycoord_to_pixel(source_center_SgrA, on.wcs)
    central_gauss.fwhm = 100
    # modele gauss pour G0p9 centre sur G0p9
    mygaus_G0p9 = normgauss2dint("G0p9")
    mygaus_G0p9.xpos, mygaus_G0p9.ypos = skycoord_to_pixel(source_center_G0p9, on.wcs)
    mygaus_G0p9.xpos.val += 0.5
    mygaus_G0p9.ypos.val += 0.5
Example #56
0
 def to_pixel(self, wcs):
     center_x, center_y = skycoord_to_pixel(self.center, wcs=wcs)
     center = PixCoord(center_x, center_y)
     return PointPixelRegion(center)
Example #57
0
File: utils.py Project: n0d/astropy
    def __init__(self, data, position, size, wcs=None, mode='trim',
                 fill_value=np.nan, copy=False):
        """
        Parameters
        ----------
        data : `~numpy.ndarray`
            The 2D data array from which to extract the cutout array.

        position : tuple or `~astropy.coordinates.SkyCoord`
            The position of the cutout array's center with respect to
            the ``data`` array.  The position can be specified either as
            a ``(x, y)`` tuple of pixel coordinates or a
            `~astropy.coordinates.SkyCoord`, in which case ``wcs`` is a
            required input.

        size : int, array-like, `~astropy.units.Quantity`
            The size of the cutout array along each axis.  If ``size``
            is a scalar number or a scalar `~astropy.units.Quantity`,
            then a square cutout of ``size`` will be created.  If
            ``size`` has two elements, they should be in ``(ny, nx)``
            order.  Scalar numbers in ``size`` are assumed to be in
            units of pixels.  ``size`` can also be a
            `~astropy.units.Quantity` object or contain
            `~astropy.units.Quantity` objects.  Such
            `~astropy.units.Quantity` objects must be in pixel or
            angular units.  For all cases, ``size`` will be converted to
            an integer number of pixels, rounding the the nearest
            integer.  See the ``mode`` keyword for additional details on
            the final cutout size.

            .. note::
                If ``size`` is in angular units, the cutout size is
                converted to pixels using the pixel scales along each
                axis of the image at the ``CRPIX`` location.  Projection
                and other non-linear distortions are not taken into
                account.

        wcs : `~astropy.wcs.WCS`, optional
            A WCS object associated with the input ``data`` array.  If
            ``wcs`` is not `None`, then the returned cutout object will
            contain a copy of the updated WCS for the cutout data array.

        mode : {'trim', 'partial', 'strict'}, optional
            The mode used for creating the cutout data array.  For the
            ``'partial'`` and ``'trim'`` modes, a partial overlap of the
            cutout array and the input ``data`` array is sufficient.
            For the ``'strict'`` mode, the cutout array has to be fully
            contained within the ``data`` array, otherwise an
            `~astropy.nddata.utils.PartialOverlapError` is raised.   In
            all modes, non-overlapping arrays will raise a
            `~astropy.nddata.utils.NoOverlapError`.  In ``'partial'``
            mode, positions in the cutout array that do not overlap with
            the ``data`` array will be filled with ``fill_value``.  In
            ``'trim'`` mode only the overlapping elements are returned,
            thus the resulting cutout array may be smaller than the
            requested ``shape``.

        fill_value : number, optional
            If ``mode='partial'``, the value to fill pixels in the
            cutout array that do not overlap with the input ``data``.
            ``fill_value`` must have the same ``dtype`` as the input
            ``data`` array.

        copy : bool, optional
            If `False` (default), then the cutout data will be a view
            into the original ``data`` array.  If `True`, then the
            cutout data will hold a copy of the original ``data`` array.

        Returns
        -------
        result : `~astropy.nddata.utils.Cutout2D`
            A cutout object containing the 2D cutout data array and the
            updated WCS, if ``wcs`` is input.

        Examples
        --------
        >>> import numpy as np
        >>> from astropy.nddata.utils import Cutout2D
        >>> from astropy import units as u
        >>> data = np.arange(20.).reshape(5, 4)
        >>> cutout1 = Cutout2D(data, (2, 2), (3, 3))
        >>> print(cutout1.data)
        [[  5.   6.   7.]
         [  9.  10.  11.]
         [ 13.  14.  15.]]

        >>> print(cutout1.center_original)
        (2.0, 2.0)
        >>> print(cutout1.center_cutout)
        (1.0, 1.0)
        >>> print(cutout1.origin_original)
        (1, 1)

        >>> cutout2 = Cutout2D(data, (2, 2), 3)
        >>> print(cutout2.data)
        [[  5.   6.   7.]
         [  9.  10.  11.]
         [ 13.  14.  15.]]

        >>> size = u.Quantity([3, 3], u.pixel)
        >>> cutout3 = Cutout2D(data, (0, 0), size)
        >>> print(cutout3.data)
        [[ 0.  1.]
         [ 4.  5.]]

        >>> cutout4 = Cutout2D(data, (0, 0), (3 * u.pixel, 3))
        >>> print(cutout4.data)
        [[ 0.  1.]
         [ 4.  5.]]

        >>> cutout5 = Cutout2D(data, (0, 0), (3, 3), mode='partial')
        >>> print(cutout5.data)
        [[ nan  nan  nan]
         [ nan   0.   1.]
         [ nan   4.   5.]]
        """

        if isinstance(position, SkyCoord):
            if wcs is None:
                raise ValueError('wcs must be input if position is a '
                                 'SkyCoord')
            position = skycoord_to_pixel(position, wcs, mode='all')  # (x, y)

        if np.isscalar(size):
            size = np.repeat(size, 2)

        # special handling for a scalar Quantity
        if isinstance(size, u.Quantity):
            size = np.atleast_1d(size)
            if len(size) == 1:
                size = np.repeat(size, 2)

        if len(size) > 2:
            raise ValueError('size must have at most two elements')

        shape = np.zeros(2).astype(int)
        pixel_scales = None
        # ``size`` can have a mixture of int and Quantity (and even units),
        # so evaluate each axis separately
        for axis, side in enumerate(size):
            if not isinstance(side, u.Quantity):
                shape[axis] = np.int(np.round(size[axis]))     # pixels
            else:
                if side.unit == u.pixel:
                    shape[axis] = np.int(np.round(side.value))
                elif side.unit.physical_type == 'angle':
                    if wcs is None:
                        raise ValueError('wcs must be input if any element '
                                         'of size has angular units')
                    if pixel_scales is None:
                        pixel_scales = u.Quantity(
                            proj_plane_pixel_scales(wcs), wcs.wcs.cunit[axis])
                    shape[axis] = np.int(np.round(
                        (side / pixel_scales[axis]).decompose()))
                else:
                    raise ValueError('shape can contain Quantities with only '
                                     'pixel or angular units')

        data = np.asanyarray(data)
        # reverse position because extract_array and overlap_slices
        # use (y, x), but keep the input position
        pos_yx = position[::-1]

        cutout_data, input_position_cutout = extract_array(
            data, tuple(shape), pos_yx, mode=mode, fill_value=fill_value,
            return_position=True)
        if copy:
            cutout_data = np.copy(cutout_data)
        self.data = cutout_data

        self.input_position_cutout = input_position_cutout[::-1]    # (x, y)
        slices_original, slices_cutout = overlap_slices(
            data.shape, shape, pos_yx, mode=mode)

        self.slices_original = slices_original
        self.slices_cutout = slices_cutout

        self.shape = self.data.shape
        self.input_position_original = position
        self.shape_input = shape

        ((self.xmin_original, self.xmax_original),
         (self.ymin_original, self.ymax_original)) = self.bbox_original

        ((self.xmin_cutout, self.xmax_cutout),
         (self.ymin_cutout, self.ymax_cutout)) = self.bbox_cutout

        # the true origin pixel of the cutout array, including any
        # filled cutout values
        self._origin_original_true = (
            self.origin_original[0] - self.slices_cutout[1].start,
            self.origin_original[1] - self.slices_cutout[0].start)

        if wcs is not None:
            self.wcs = deepcopy(wcs)
            self.wcs.wcs.crpix -= self._origin_original_true
        else:
            self.wcs = None
Example #58
0
def listpixels(data, position, shape, subarray_indices=False, wcs=None):
    """
    Return a `~astropy.table.Table` listing the ``(y, x)`` positions and
    ``data`` values for a subarray.

    Given a position of the center of the subarray, with respect to the
    large array, the array indices and values are returned.  This
    function takes care of the correct behavior at the boundaries, where
    the small array is appropriately trimmed.

    Parameters
    ----------
    data : array-like
        The input data.

    position : tuple (int) or `~astropy.coordinates.SkyCoord`
        The position of the subarray center with respect to the data
        array.  The position can be specified either as an integer ``(y,
        x)`` tuple of pixel coordinates or a
        `~astropy.coordinates.SkyCoord`, in which case ``wcs`` is a
        required input.

    shape : tuple (int)
        The integer shape (``(ny, nx)``) of the subarray.

    subarray_indices : bool, optional
        If `True` then the returned positions are relative to the small
        subarray.  If `False` (default) then the returned positions are
        relative to the ``data`` array.

    wcs : `~astropy.wcs.WCS`, optional
        The WCS transformation to use if ``position`` is a
        `~astropy.coordinates.SkyCoord`.

    Returns
    -------
    table : `~astropy.table.Table`
        A table containing the ``x`` and ``y`` positions and data
        values.

    Notes
    -----
    This function is decorated with `~astropy.nddata.support_nddata` and
    thus supports `~astropy.nddata.NDData` objects as input.

    Examples
    --------
    >>> import numpy as np
    >>> from astroimtools import listpixels
    >>> np.random.seed(12345)
    >>> data = np.random.random((25, 25))
    >>> tbl = listpixels(data, (8, 11), (3, 3))
    >>> for col in tbl.colnames:
    ...     tbl[col].info.format = '%.8g'  # for consistent table output
    >>> tbl.pprint(max_lines=-1)
     x   y     value
    --- --- -----------
     10   7  0.75857204
     11   7 0.069529666
     12   7  0.70547344
     10   8   0.8406625
     11   8  0.46931469
     12   8  0.56264343
     10   9 0.034131584
     11   9  0.23049655
     12   9  0.22835371
    """

    if isinstance(position, SkyCoord):
        if wcs is None:
            raise ValueError('wcs must be input if positions is a SkyCoord')

        x, y = skycoord_to_pixel(position, wcs, mode='all')
        position = (y, x)

    data = np.asanyarray(data)
    slices_large, slices_small = overlap_slices(data.shape, shape, position)
    slices = slices_large
    yy, xx = np.mgrid[slices]
    values = data[yy, xx]

    if subarray_indices:
        slices = slices_small
        yy, xx = np.mgrid[slices]

    tbl = Table()
    tbl['x'] = xx.ravel()
    tbl['y'] = yy.ravel()
    tbl['value'] = values.ravel()
    return tbl
Example #59
0
    def __init__(self, data, position, size, wcs=None, mode='trim',
                 fill_value=np.nan, copy=False):
        if isinstance(position, SkyCoord):
            if wcs is None:
                raise ValueError('wcs must be input if position is a '
                                 'SkyCoord')
            position = skycoord_to_pixel(position, wcs, mode='all')  # (x, y)

        if np.isscalar(size):
            size = np.repeat(size, 2)

        # special handling for a scalar Quantity
        if isinstance(size, u.Quantity):
            size = np.atleast_1d(size)
            if len(size) == 1:
                size = np.repeat(size, 2)

        if len(size) > 2:
            raise ValueError('size must have at most two elements')

        shape = np.zeros(2).astype(int)
        pixel_scales = None
        # ``size`` can have a mixture of int and Quantity (and even units),
        # so evaluate each axis separately
        for axis, side in enumerate(size):
            if not isinstance(side, u.Quantity):
                shape[axis] = int(np.round(size[axis]))     # pixels
            else:
                if side.unit == u.pixel:
                    shape[axis] = int(np.round(side.value))
                elif side.unit.physical_type == 'angle':
                    if wcs is None:
                        raise ValueError('wcs must be input if any element '
                                         'of size has angular units')
                    if pixel_scales is None:
                        pixel_scales = u.Quantity(
                            proj_plane_pixel_scales(wcs), wcs.wcs.cunit[axis])
                    shape[axis] = int(np.round(
                        (side / pixel_scales[axis]).decompose()))
                else:
                    raise ValueError('shape can contain Quantities with only '
                                     'pixel or angular units')

        data = np.asanyarray(data)
        # reverse position because extract_array and overlap_slices
        # use (y, x), but keep the input position
        pos_yx = position[::-1]

        cutout_data, input_position_cutout = extract_array(
            data, tuple(shape), pos_yx, mode=mode, fill_value=fill_value,
            return_position=True)
        if copy:
            cutout_data = np.copy(cutout_data)
        self.data = cutout_data

        self.input_position_cutout = input_position_cutout[::-1]    # (x, y)
        slices_original, slices_cutout = overlap_slices(
            data.shape, shape, pos_yx, mode=mode)

        self.slices_original = slices_original
        self.slices_cutout = slices_cutout

        self.shape = self.data.shape
        self.input_position_original = position
        self.shape_input = shape

        ((self.ymin_original, self.ymax_original),
         (self.xmin_original, self.xmax_original)) = self.bbox_original

        ((self.ymin_cutout, self.ymax_cutout),
         (self.xmin_cutout, self.xmax_cutout)) = self.bbox_cutout

        # the true origin pixel of the cutout array, including any
        # filled cutout values
        self._origin_original_true = (
            self.origin_original[0] - self.slices_cutout[1].start,
            self.origin_original[1] - self.slices_cutout[0].start)

        if wcs is not None:
            self.wcs = deepcopy(wcs)
            self.wcs.wcs.crpix -= self._origin_original_true
            self.wcs.array_shape = self.data.shape
            if wcs.sip is not None:
                self.wcs.sip = Sip(wcs.sip.a, wcs.sip.b,
                                   wcs.sip.ap, wcs.sip.bp,
                                   wcs.sip.crpix - self._origin_original_true)
        else:
            self.wcs = None