Checking for Points Inside Regions#
Points Inside Planar Regions#
Let’s start by defining both a planar sky and pixel region:
>>> from astropy.coordinates import Angle, SkyCoord
>>> from regions import CircleSkyRegion, PixCoord, CirclePixelRegion
>>> sky_center = SkyCoord(42, 43, unit='deg')
>>> sky_radius = Angle(25, 'deg')
>>> sky_region = CircleSkyRegion(sky_center, sky_radius)
>>> print(sky_region)
Region: CircleSkyRegion
center: <SkyCoord (ICRS): (ra, dec) in deg
(42., 43.)>
radius: 25.0 deg
>>> pixel_center = PixCoord(x=42, y=43)
>>> pixel_radius = 42
>>> pixel_region = CirclePixelRegion(pixel_center, pixel_radius)
>>> print(pixel_region)
Region: CirclePixelRegion
center: PixCoord(x=42, y=43)
radius: 42
Let’s also define a WCS object using our example dataset:
>>> from regions import make_example_dataset
>>> dataset = make_example_dataset(data='simulated')
>>> wcs = dataset.wcs
To test if a given point is inside or outside the region, the Python
in operator can be called:
>>> from regions import PixCoord
>>> PixCoord(55, 40) in pixel_region
True
>>> PixCoord(55, 200) in pixel_region
False
The in operator works only for scalar coordinates and pixel regions.
If you try to use in for non-scalar coordinates, you’ll get a
ValueError:
>>> pixcoord = PixCoord([50, 50], [10, 60])
>>> pixcoord in pixel_region
Traceback (most recent call last):
...
ValueError: coord must be scalar. coord=PixCoord(x=[50 50], y=[10 60])
If you have arrays of coordinates, use the regions.SkyRegion.contains
or regions.PixelRegion.contains methods:
>>> pixcoords = PixCoord.from_sky(sky_center, wcs)
>>> pixel_region.contains(pixcoords)
np.True_
Note that regions.SkyRegion.contains requires a WCS to be passed:
>>> skycoord = SkyCoord([50, 50], [10, 60], unit='deg')
>>> sky_region.contains(skycoord, wcs)
array([False, True])
Points Inside Spherical Regions#
For SphericalSkyRegion objects, checking whether point(s) are
contained inside that region requires no other input — since these
regions are defined with a spherical geometry, and not a projected geometry
(as captured through the projection encoded in a WCS) as in
SkyRegion.
Let’s define a spherical sky region:
>>> from regions import CircleSphericalSkyRegion
>>> sph_sky_center = SkyCoord(42, 43, unit='deg')
>>> sph_sky_radius = Angle(25, 'deg')
>>> sph_sky_region = CircleSphericalSkyRegion(sph_sky_center,
... sph_sky_radius)
>>> print(sph_sky_region)
Region: CircleSphericalSkyRegion
center: <SkyCoord (ICRS): (ra, dec) in deg
(42., 43.)>
radius: 25.0 deg
Use the regions.SphericalSkyRegion.contains method to determine which
point(s) lie inside or outside the region:
>>> skycoord = SkyCoord([50, 50], [10, 60], unit='deg')
>>> sph_sky_region.contains(skycoord)
array([False, True])
Boundary Behavior: contains versus covers#
The contains method excludes the region boundary: a point that lies
exactly on an edge or vertex is considered to be outside the region.
This is consistent with Shapely’s contains predicate and the
DE-9IM semantics used by most
GIS tools.
If you instead want boundary points to be treated as inside the
region, use the covers method. It is available on pixel regions
(regions.PixelRegion.covers), planar sky regions
(regions.SkyRegion.covers), and spherical sky regions
(regions.SphericalSkyRegion.covers), and takes the same arguments as
the corresponding contains method.
For example, the point (84, 43) lies exactly on the boundary of our
circular pixel region (centered at (42, 43) with a radius of
42), so it is excluded by contains but included by covers:
>>> boundary_point = PixCoord(84, 43)
>>> pixel_region.contains(boundary_point)
np.False_
>>> pixel_region.covers(boundary_point)
np.True_
For points strictly inside or strictly outside the region, the two methods return identical results:
>>> pixel_region.contains(PixCoord(42, 43))
np.True_
>>> pixel_region.covers(PixCoord(42, 43))
np.True_
Note
The covers method is currently implemented for circle, ellipse,
rectangle, polygon, and annulus regions (and their sky and
spherical-sky equivalents); calling it on a region type that does
not support it raises a NotImplementedError.