Skip to content

Commit

Permalink
feat: homogenize the complement argument in from_polygons methods
Browse files Browse the repository at this point in the history
  • Loading branch information
ManonMarchand committed Jul 2, 2024
1 parent 89a8334 commit 29163f4
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 20 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ and radii. This is multi-threaded.
* new method `MOC.from_boxes` allows to create lists of MOCs from boxes. This is multi-threaded.
* the `mocpy.WCS` class can now accept a sequence of angles as its fov argument rather than always
representing square areas of the sky.
* `MOC.from_polygons` and `MOC.from_polygons` now accept a boolean `complement` that allows to chose
between the small MOC described by the polygon or the bigger one (its complement)

### Changed

Expand Down
4 changes: 2 additions & 2 deletions docs/api.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
API
===
Detailed list of all methods
============================

Auto-generated API documentation for MOCpy.

Expand Down
5 changes: 1 addition & 4 deletions docs/examples/polygon_coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,7 @@
],
)
skycoord = SkyCoord(vertices, unit="deg", frame="icrs")
# A point that we say it belongs to the inside of the MOC
inside = SkyCoord(ra=10, dec=5, unit="deg", frame="icrs")
moc = MOC.from_polygon_skycoord(skycoord, max_depth=9)
moc.save("polygon_moc.fits", format="fits", overwrite=True)
moc = MOC.from_polygon_skycoord(skycoord, complement=False, max_depth=9)

# Plot the MOC using matplotlib
fig = plt.figure(111, figsize=(10, 10))
Expand Down
12 changes: 8 additions & 4 deletions docs/examples/user_documentation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ Gallery of notebooks examples using SMOCs

.. nbgallery::
../_collections/notebooks/00-MOCpy_introduction
../_collections/notebooks/compute_moc_borders.ipynb
../_collections/notebooks/compute_moc_borders
../_collections/notebooks/filtering_astropy_table
../_collections/notebooks/FITS-image-pixels-intersecting-MOC
../_collections/notebooks/from_astropy_table.ipynb
../_collections/notebooks/01-Creating_MOCs_from_shapes.ipynb
../_collections/notebooks/01-Creating_MOCs_from_shapes
../_collections/notebooks/02-Creating_MOCs_from_astropy_regions
../_collections/notebooks/from_fits_and_intersection
../_collections/notebooks/from_image_with_mask
Expand Down Expand Up @@ -59,14 +59,18 @@ This example:
.. plot:: examples/logical_operations.py
:include-source:

Create a MOC from a concave polygon
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Create a MOC from a polygon
~~~~~~~~~~~~~~~~~~~~~~~~~~~

This example shows how to call :py:meth:`mocpy.moc.MOC.from_polygon` or :py:meth:`mocpy.moc.MOC.from_polygon_skycoord`.

.. plot:: examples/polygon_coverage.py
:include-source:

For a more extended description on how to create MOCs from shapes, you can check the example notebooks
:doc:`../_collections/notebooks/01-Creating_MOCs_from_shapes` and
:doc:`../_collections/notebooks/02-Creating_MOCs_from_astropy_regions`.

Get the border(s) of a MOC
~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
33 changes: 25 additions & 8 deletions python/mocpy/moc/moc.py
Original file line number Diff line number Diff line change
Expand Up @@ -815,8 +815,7 @@ def probability_in_multiordermap(self, multiordermap):
See Also
--------
probabilities_in_multiordermap: makes this calculation for a list of MOCs in a
parallelized way.
probabilities_in_multiordermap: makes this calculation for a list of MOCs
"""
index = self.store_index
Expand Down Expand Up @@ -1358,7 +1357,7 @@ def from_ring(
return cls(index)

@classmethod
def from_polygon_skycoord(cls, skycoord, max_depth=10):
def from_polygon_skycoord(cls, skycoord, complement=False, max_depth=10):
"""
Create a MOC from a polygon.
Expand All @@ -1369,6 +1368,8 @@ def from_polygon_skycoord(cls, skycoord, max_depth=10):
----------
skycoord : `astropy.coordinates.SkyCoord`
The sky coordinates defining the vertices of a polygon.
complement : return the complement of the polygon. Set to False by default.
The default polygon is the smallest one.
max_depth : int, optional
The resolution of the MOC. Set to 10 by default.
Expand All @@ -1394,24 +1395,33 @@ def from_polygon_skycoord(cls, skycoord, max_depth=10):
return cls.from_polygon(
lon=skycoord.icrs.ra,
lat=skycoord.icrs.dec,
complement=complement,
max_depth=np.uint8(max_depth),
)

@classmethod
def from_polygons(cls, list_vertices, max_depth=10, n_threads=None):
def from_polygons(
cls,
list_vertices,
complement=False,
max_depth=10,
n_threads=None,
):
"""
Create a list of MOCs list from a list of polygons.
Parameters
----------
list_vertices : list[`~astropy.coordinates.SkyCoord`] OR numpy.ndarray
- If list_vertices is a list of `~astropy.coordinates.SkyCoord` objects, each
If list_vertices is a list of `~astropy.coordinates.SkyCoord` objects, each
SkyCoord object should contain more than three vertices and they should each
describe a polygon.
- If list_vertices is a numpy.ndarray, it should be in the form
If list_vertices is a numpy.ndarray, it should be in the form
[lon_array1, lat_array1, lon_array2, lat_array2, lon_array3, lat_array3, ...].
They should be valid longitudes and latitudes in degrees in ICRS.
max_depth : int, optional
complement : return the complement of the polygon. Set to False by default.
The default polygon is the smallest one.
max_depth : int, optional
The resolution of the MOC. Set to 10 by default.
n_threads : int, optional
The number of threads to be used. If this is set to None (default value),
Expand Down Expand Up @@ -1449,12 +1459,18 @@ def from_polygons(cls, list_vertices, max_depth=10, n_threads=None):
for x in list_vertices
for f in (lambda x: x.icrs.ra.deg, lambda x: x.icrs.dec.deg)
]
indices = mocpy.from_polygons(lon_lat_list, np.uint8(max_depth), n_threads)
indices = mocpy.from_polygons(
lon_lat_list,
complement,
np.uint8(max_depth),
n_threads,
)
else:
# This is the unsafe version where the users should provide correct coordinates
# without checks on our side
indices = mocpy.from_polygons(
np.array(list_vertices, dtype=np.float64),
complement,
np.uint8(max_depth),
n_threads,
)
Expand All @@ -1477,6 +1493,7 @@ def from_polygon(cls, lon, lat, complement=False, max_depth=10):
The latitudes defining the polygon. Can describe convex and concave
polygons but not self-intersecting ones.
complement : return the complement of the polygon. Set to False by default.
The default polygon is the smallest one.
max_depth : int, optional
The resolution of the MOC. Set to 10 by default.
Expand Down
3 changes: 3 additions & 0 deletions python/mocpy/tests/test_moc.py
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,10 @@ def test_moc_contains_2d_parameters():
lat2 = Angle(np.array([[20, 25, 10, 22], [-60, 80, 0, 10]]), unit=u.deg)
moc = MOC.from_polygon(lon=lon, lat=lat, max_depth=12)
should_be_inside = moc.contains_lonlat(lon=lon, lat=lat)
complement_moc = MOC.from_polygon(lon=lon, lat=lat, max_depth=12, complement=True)
assert complement_moc.sky_fraction > moc.sky_fraction
assert should_be_inside.all()

# test mismatched
with pytest.raises(
ValueError,
Expand Down
7 changes: 5 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -601,11 +601,14 @@ fn mocpy(_py: Python, m: &PyModule) -> PyResult<()> {
/// # Params
/// * `lon_lat_deg` list of polygons vertices coordinates, of the form
/// `lon_array_1, lat_array_1, lon_array_2, lat_array_2, ..., lon_array_b, lat_array_n`
/// * `is_complement` should the method return the complement of the polygon (false returns
/// the smallest polygon)
/// * `depth`: MOC depth
/// * `n_threads`: number of threads to use (max number of threads if `n_threads=None`.
#[pyfn(m)]
pub fn from_polygons(
lon_lat_deg: Vec<PyReadonlyArrayDyn<f64>>,
complement: bool,
depth: u8,
n_threads: Option<u16>,
) -> PyResult<Vec<usize>> {
Expand Down Expand Up @@ -640,7 +643,7 @@ fn mocpy(_py: Python, m: &PyModule) -> PyResult<()> {
.map(|(lon, lat)| {
U64MocStore::get_global_store().from_polygon(
lon.iter().cloned().zip(lat.iter().cloned()),
false,
complement,
depth,
CellSelection::All,
)
Expand All @@ -656,7 +659,7 @@ fn mocpy(_py: Python, m: &PyModule) -> PyResult<()> {
.map(|(lon, lat)| {
U64MocStore::get_global_store().from_polygon(
lon.iter().cloned().zip(lat.iter().cloned()),
false,
complement,
depth,
CellSelection::All,
)
Expand Down

0 comments on commit 29163f4

Please sign in to comment.