Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
3df55bd
Initial commit of spherical sky regions
sedonaprice Jul 28, 2025
8e2f4a7
Add spherical polygon, boundary discretization
sedonaprice Jul 28, 2025
4e75922
Add bounding lonlat
sedonaprice Jul 28, 2025
1fbf3cd
Add spherical circle annulus
sedonaprice Jul 28, 2025
3b6905c
Add spherical lune
sedonaprice Jul 28, 2025
4b5a7f7
Add spherical range region
sedonaprice Jul 28, 2025
1234550
Add `to_spherical_sky()` to PixelRegion, SkyRegion classes
sedonaprice Aug 20, 2025
2d46536
Codestyle fixes
sedonaprice Aug 21, 2025
24b5594
Implement test suite for spherical regions
sedonaprice Sep 8, 2025
ed146c4
Correct docstring syntax for sphinx docs
sedonaprice Oct 1, 2025
09ebbfb
Initial docs edits
sedonaprice Oct 2, 2025
d48f851
Landing page example
sedonaprice Oct 2, 2025
0e585e2
Changes to shapes doc page
sedonaprice Oct 2, 2025
0010883
Edited contains docs to include spherical regions
sedonaprice Oct 2, 2025
f0fefae
Updated compound docs to add spherical regions
sedonaprice Oct 2, 2025
d19becb
Added spherical example to plotting doc page
sedonaprice Oct 2, 2025
55e820a
Spherical region frame transformation doc
sedonaprice Oct 3, 2025
52ec2b4
Spherical region bounding info docs
sedonaprice Oct 6, 2025
3ff3c0d
Bugfixes, update tests
sedonaprice Oct 6, 2025
7a162f4
Add FLOAT_CMP to docs for testing
sedonaprice Oct 6, 2025
9481dd3
Apply changes from #628 to CompoundSphericalSkyRegion
sedonaprice Nov 3, 2025
3b8acbf
Correct in-line comments
sedonaprice Nov 6, 2025
b859b48
Rename test to spherical sky
sedonaprice Nov 6, 2025
accfb96
Remove unused function in test_polygon.py
sedonaprice Nov 6, 2025
6a60879
Fix typo
sedonaprice Nov 6, 2025
3d2727e
Split compound examples for smaller code chunks
sedonaprice Nov 6, 2025
168c9af
Change test expected failure handling
sedonaprice Nov 6, 2025
3c69f72
Change lon/lat derivation handling in range
sedonaprice Nov 6, 2025
65013fb
Validate range lon/lat range & bound inputs
sedonaprice Nov 6, 2025
7ec488b
Update spherical <-> planar transform errors
sedonaprice Nov 6, 2025
e66b3df
Added changelog entry
sedonaprice Nov 6, 2025
fbb7f1b
Fix assert vs error messages in range validation
sedonaprice Nov 6, 2025
0739232
Remove unnecessary comment from whole_sky.py
sedonaprice Nov 6, 2025
5118868
Fix typo in plotting.rst
sedonaprice Dec 18, 2025
1004600
Resolve conflict with main in test_api.py
larrybradley Nov 24, 2025
1c7fb95
Fix deprecation in coord concatenation
sedonaprice Dec 22, 2025
53e7fa1
Bugfix polygon vertices ordering
sedonaprice Jan 3, 2026
a39f67f
Simplify/speed up with patthern `.to_value(UNIT)`
sedonaprice Mar 9, 2026
b7b1797
Swap to use `np.minimum` directly on quantities
sedonaprice Mar 9, 2026
435b6a3
Correct discretization to use `circ_center`
sedonaprice Mar 9, 2026
8b6385a
Correct spelling of "latitude"
sedonaprice Mar 9, 2026
624e441
Correct `latitude_range` description
sedonaprice Mar 9, 2026
227e15d
Correct docstring: second `lons_arr` -> `lats_arr`
sedonaprice Mar 9, 2026
a36be9a
Remove commented lines
sedonaprice Mar 9, 2026
66cec61
Add `merge_attributes` kwarg to inheriting `transform_to`
sedonaprice Mar 9, 2026
487e1e5
Add tildes for links to package classes
sedonaprice Mar 10, 2026
e345b6d
Simplify discretization boundary SkyCoord creation
sedonaprice Mar 10, 2026
bbd76b8
Remove unnecessary if statement in lune.py
sedonaprice Mar 12, 2026
7a4674c
Remove other unnecessary if statements from lune,range
sedonaprice Mar 12, 2026
904ed05
Change include_bound_dist + no WCS error msg format
sedonaprice Mar 12, 2026
4509a47
Simplify range bound transformation method
sedonaprice Mar 12, 2026
0084a34
Common _validate_planar_spherical_transform() method
sedonaprice Mar 12, 2026
bb7e227
Document convex-only spherical polygon limitation
sedonaprice Apr 6, 2026
7b6d639
Update test: improved pixel <-> sky conversion
sedonaprice Apr 6, 2026
dfd448f
Update shapes.rst for repr, wcs sky<->pix changes
sedonaprice Apr 6, 2026
9b2f4e2
Run pre-commit for linting
sedonaprice Apr 6, 2026
639a0b1
Fix docs, docstring typos
sedonaprice May 4, 2026
295b100
Add missing import
sedonaprice May 4, 2026
9fe2e96
Change default to `n_points=100` everywhere
sedonaprice May 4, 2026
6c662db
Add lune GC center invert test
sedonaprice May 4, 2026
faca545
Fix lune boundary discretization
sedonaprice May 4, 2026
426cd94
Discretize to total n_points, not per-edge
sedonaprice May 4, 2026
1dc56d9
Apply meta, visual to polygon in `discretize_boundary()`
sedonaprice May 4, 2026
94eed79
Whole sky discretization not implemented test
sedonaprice May 4, 2026
cd14f83
Implement `to_polygon()` method
sedonaprice May 4, 2026
2c998a5
Docs: more explicitly note "WCS distortion"
sedonaprice May 4, 2026
cbc312f
Remove `discretize_kwargs` for `n_points=None`
sedonaprice May 5, 2026
e93ce74
Change WholeSky errors for undefined methods
sedonaprice May 5, 2026
92fa60b
Implement lune distorted sph->planar
sedonaprice May 5, 2026
b8d8f14
Add docs demo of spherical vs planar circle
sedonaprice May 6, 2026
c7c02b4
Validate same frame for spherical compound regions
sedonaprice May 6, 2026
2817097
Improve _validate_frame()
sedonaprice May 6, 2026
510e9f1
Update to_pixel() docstring
sedonaprice May 6, 2026
7de267a
Update n_points descriptions
sedonaprice May 6, 2026
6d6c663
Remove `discretize_kwargs` from line.py
sedonaprice May 6, 2026
6d3df5f
Fix typo in getting_started.rst
sedonaprice May 6, 2026
7a71ca0
Implement stand-alone port _get_frame_class
sedonaprice May 6, 2026
3f0f3e6
Rename to _validate_frame_transformation
sedonaprice May 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,28 @@ New Features
- Improved the string representations of all ``Regions`` and ``Region``
objects. [#653]

- Regions now includes ``SphericalSkyRegion`` ("region-on-celestial-sphere"),
complementing the implicitly planar ``SkyRegion`` ("region-on-images").
``SphericalSkyRegion`` does not require a WCS to determine whether points
are contained within the region or not (unlike ``SkyRegion``).
Additionally, ``SphericalSkyRegion`` classes include the method
``transform_to`` to transform the regions between different
celestial coordinate reference frames.
It is also possible to transform between spherical and planar
(sky or pixel) regions (with ``to_sky``, ``to_pixel``, and ``to_spherical_sky``,
as appropriate), with the option to capture boundary distortions due to
WCS projection effects between spherical and planar geometries
or to ignore them (e.g., assuming a circle stays a perfect circle).
Current spherical shapes supported include: ``CircleSphericalSkyRegion``,
``CircleAnnulusSphericalSkyRegion``,
``PolygonSphericalSkyRegion`` (currently only supports convex polygons),
``RangeSphericalSkyRegion`` (i.e., bounded by ranges of longitude and/or latitude), and
``LuneSphericalSkyRegion`` (a slice between two great circles,
such as between two lines of longitude).
Support for additional spherical shapes, and for all cases of
planar <-> spherical transformation (where well defined) may be added
at a future date. [#618]

Bug Fixes
---------

Expand Down
89 changes: 87 additions & 2 deletions docs/compound.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ Combining Regions
=================

There are a few ways to combine any two `~regions.Region` objects
into a compound region, i.e., a `~regions.CompoundPixelRegion` or
`~regions.CompoundSkyRegion` object.
into a compound region, i.e., a `~regions.CompoundPixelRegion`,
`~regions.CompoundSkyRegion`, or `~regions.CompoundSphericalSkyRegion` object.

Let's start by defining two sky regions::

Expand Down Expand Up @@ -120,9 +120,14 @@ operator or the :meth:`~regions.Region.symmetric_difference` method::
Example Illustrating Compound Regions
-------------------------------------

The following examples demonstrate how to combine planar sky regions
and spherical sky regions, with the same circle centers and radii.

.. plot::
:include-source: false

# planar

import matplotlib.pyplot as plt
import numpy as np
from astropy.coordinates import Angle, SkyCoord
Expand All @@ -141,6 +146,7 @@ Example Illustrating Compound Regions
# remove sources
dataset.image.data = np.zeros_like(dataset.image.data)

#----------------------------------------
# define 2 sky circles
circle1 = CircleSkyRegion(
center=SkyCoord(20, 0, unit='deg', frame='galactic'),
Expand All @@ -156,6 +162,7 @@ Example Illustrating Compound Regions
coords = np.array(np.meshgrid(lon, lat)).T.reshape(-1, 2)
skycoords = SkyCoord(coords, unit='deg', frame='galactic')

#----------------------------------------
# get events in AND and XOR
compound_and = circle1 & circle2
compound_xor = circle1 ^ circle2
Expand All @@ -167,6 +174,7 @@ Example Illustrating Compound Regions

# plot
fig = plt.figure()
fig.set_size_inches(7,3.5)
ax = fig.add_axes([0.15, 0.1, 0.8, 0.8], projection=wcs, aspect='equal')

ax.scatter(skycoords.l.value, skycoords.b.value, label='all',
Expand All @@ -185,3 +193,80 @@ Example Illustrating Compound Regions

ax.set_xlim(-0.5, dataset.config['shape'][1] - 0.5)
ax.set_ylim(-0.5, dataset.config['shape'][0] - 0.5)
ax.set_title("Planar SkyRegions")


.. plot::
:include-source: false

# spherical

import matplotlib.pyplot as plt
import numpy as np
from astropy.coordinates import Angle, SkyCoord

from regions import CircleSphericalSkyRegion, make_example_dataset

# load example dataset to get skymap
config = dict(crval=(0, 0),
crpix=(180, 90),
cdelt=(-1, 1),
shape=(180, 360))

dataset = make_example_dataset(data='simulated', config=config)
wcs = dataset.wcs

# remove sources
dataset.image.data = np.zeros_like(dataset.image.data)

#----------------------------------------
# define 2 spherical sky circles
sph_circle1 = CircleSphericalSkyRegion(
center=SkyCoord(20, 0, unit='deg', frame='galactic'),
radius=Angle('30 deg'))

sph_circle2 = CircleSphericalSkyRegion(
center=SkyCoord(50, 45, unit='deg', frame='galactic'),
radius=Angle('30 deg'))

# define skycoords
lon = np.arange(-180, 181, 10)
lat = np.arange(-90, 91, 10)
coords = np.array(np.meshgrid(lon, lat)).T.reshape(-1, 2)
skycoords = SkyCoord(coords, unit='deg', frame='galactic')

#----------------------------------------
# get events in AND and XOR
sph_compound_and = sph_circle1 & sph_circle2
sph_compound_xor = sph_circle1 ^ sph_circle2

sph_mask_and = sph_compound_and.contains(skycoords)
sph_skycoords_and = skycoords[sph_mask_and]
sph_mask_xor = sph_compound_xor.contains(skycoords)
sph_skycoords_xor = skycoords[sph_mask_xor]

# plot
fig = plt.figure()
fig.set_size_inches(7,3.5)
ax = fig.add_axes([0.15, 0.1, 0.8, 0.8], projection=wcs, aspect='equal')

ax.scatter(skycoords.l.value, skycoords.b.value, label='all',
transform=ax.get_transform('galactic'))
ax.scatter(sph_skycoords_xor.l.value, sph_skycoords_xor.b.value, color='orange',
label='xor', transform=ax.get_transform('galactic'))
ax.scatter(sph_skycoords_and.l.value, sph_skycoords_and.b.value, color='magenta',
label='and', transform=ax.get_transform('galactic'))

boundary_kwargs = dict(
include_boundary_distortions=True, n_points=1000
)
sph_circle1.to_pixel(wcs=wcs,**boundary_kwargs).plot(ax=ax, edgecolor='green', facecolor='none',
alpha=0.8, lw=3)
sph_circle2.to_pixel(wcs=wcs,**boundary_kwargs).plot(ax=ax, edgecolor='red', facecolor='none',
alpha=0.8, lw=3)

ax.legend(loc='lower right')

ax.set_xlim(-0.5, dataset.config['shape'][1] - 0.5)
ax.set_ylim(-0.5, dataset.config['shape'][0] - 0.5)
ax.set_title("Spherical SkyRegions")
36 changes: 35 additions & 1 deletion docs/contains.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
Checking for Points Inside Regions
==================================

Let's start by defining both a sky and pixel region::
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
Expand Down Expand Up @@ -60,3 +63,34 @@ 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 `~regions.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
`~regions.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])
Loading
Loading