Source code for hats.search.region_search
from __future__ import annotations
import nested_pandas as npd
import numpy as np
import hats.pixel_math.healpix_shim as hp
from hats.catalog import TableProperties
from hats.pixel_math.region_to_moc import wrap_ra_angles
[docs]
def box_filter(
data_frame: npd.NestedFrame,
ra: tuple[float, float],
dec: tuple[float, float],
metadata: TableProperties,
) -> npd.NestedFrame:
"""Filters a dataframe to only include points within the specified box region.
Parameters
----------
data_frame : npd.NestedFrame
DataFrame containing points in the sky
ra : tuple[float,float]
Right ascension range, in degrees
dec : tuple[float,float]
Declination range, in degrees
metadata : TableProperties
hats `Catalog` with catalog_info that matches `data_frame`
Returns
-------
NestedFrame
A new DataFrame with the rows from `data_frame` filtered to only the points inside the box region.
"""
ra_values = data_frame[metadata.ra_column].to_numpy()
dec_values = data_frame[metadata.dec_column].to_numpy()
wrapped_ra = wrap_ra_angles(ra_values)
mask_ra = _create_ra_mask(ra, wrapped_ra)
mask_dec = (dec[0] <= dec_values) & (dec_values <= dec[1])
data_frame = data_frame.iloc[mask_ra & mask_dec]
return data_frame
def _create_ra_mask(ra: tuple[float, float], values: np.ndarray) -> np.ndarray:
"""Creates the mask to filter right ascension values. If this range crosses
the discontinuity line (0 degrees), we have a branched logical operation.
Parameters
----------
ra: tuple[float, float]
Right ascension range, in degrees
values: np.ndarray
values to mask
Returns
-------
ndarray
array mask of values within ra range
"""
if ra[0] == ra[1]:
return np.ones(len(values), dtype=bool)
if ra[0] < ra[1]:
mask = (values >= ra[0]) & (values <= ra[1])
else:
mask = ((values >= ra[0]) & (values <= 360)) | ((values >= 0) & (values <= ra[1]))
return mask
[docs]
def cone_filter(data_frame: npd.NestedFrame, ra, dec, radius_arcsec, metadata: TableProperties):
"""Filters a dataframe to only include points within the specified cone
Parameters
----------
data_frame : npd.NestedFrame
DataFrame containing points in the sky
ra : float
Right Ascension of the center of the cone in degrees
dec : float
Declination of the center of the cone in degrees
radius_arcsec : float
Radius of the cone in arcseconds
metadata : hc.TableProperties
hats `TableProperties` with metadata that matches `data_frame`
Returns
-------
NestedFrame
A new DataFrame with the rows from `data_frame` filtered to only the points inside the cone
"""
ra_rad = np.radians(data_frame[metadata.ra_column].to_numpy())
dec_rad = np.radians(data_frame[metadata.dec_column].to_numpy())
ra0 = np.radians(ra)
dec0 = np.radians(dec)
cos_angle = np.sin(dec_rad) * np.sin(dec0) + np.cos(dec_rad) * np.cos(dec0) * np.cos(ra_rad - ra0)
# Clamp to valid range to avoid numerical issues
cos_separation = np.clip(cos_angle, -1.0, 1.0)
cos_radius = np.cos(np.radians(radius_arcsec / 3600))
data_frame = data_frame[cos_separation >= cos_radius]
return data_frame
[docs]
def polygon_filter(data_frame: npd.NestedFrame, polygon, metadata: TableProperties) -> npd.NestedFrame:
"""Filters a dataframe to only include points within the specified polygon.
Parameters
----------
data_frame : npd.NestedFrame
DataFrame containing points in the sky
polygon : ConvexPolygon
Convex spherical polygon of interest, used to filter points
metadata : TableProperties
hats `Catalog` with catalog_info that matches `dataframe`
Returns
-------
NestedFrame
A new DataFrame with the rows from `dataframe` filtered to only the pixels inside the polygon.
"""
ra_values = np.radians(data_frame[metadata.ra_column].to_numpy())
dec_values = np.radians(data_frame[metadata.dec_column].to_numpy())
inside_polygon = polygon.contains(ra_values, dec_values)
data_frame = data_frame.iloc[inside_polygon]
return data_frame
# pylint: disable=import-outside-toplevel
[docs]
def get_cartesian_polygon(vertices: list[tuple[float, float]]):
"""Creates the convex polygon to filter pixels with. It transforms the
vertices, provided in sky coordinates of ra and dec, to their respective
cartesian representation on the unit sphere.
Parameters
----------
vertices : list[tuple[float, float]]
The list of vertices of the polygon to filter pixels with,
as a list of (ra,dec) coordinates, in degrees.
Returns
-------
sphgeom.ConvexPolygon
The convex polygon object.
"""
try:
from lsst.sphgeom import ConvexPolygon, UnitVector3d # pylint: disable=import-error
except ImportError as exc:
raise ImportError("lsst.sphgeom is required to use this method. Install with pip or conda.") from exc
vertices_xyz = hp.ang2vec(*np.array(vertices).T)
edge_vectors = [UnitVector3d(x, y, z) for x, y, z in vertices_xyz]
return ConvexPolygon(edge_vectors)