Skip to content

Commit

Permalink
✨ Add support for pixel regions
Browse files Browse the repository at this point in the history
  • Loading branch information
Xen0Xys committed May 15, 2024
1 parent 3876ce3 commit c0b218c
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 28 deletions.
52 changes: 48 additions & 4 deletions js/models/message_handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,37 @@ export default class MessageHandler {
case "stcs":
overlay.add(A.footprintsFromSTCS(infos.stcs, options));
break;
case "circle":
case "circle_pixel":
[infos.ra, infos.dec] = this.aladin.pix2world(infos.x, infos.y, "ICRS");
infos.radius = this.aladin.angularDist(
infos.x,
infos.y,
infos.x + infos.radius,
infos.y,
"ICRS",
);
// Voluntary fallthrough
case "circle_sky":
overlay.add(A.circle(infos.ra, infos.dec, infos.radius, options));
break;
case "ellipse":
case "ellipse_pixel":
[infos.ra, infos.dec] = this.aladin.pix2world(infos.x, infos.y, "ICRS");
infos.a = this.aladin.angularDist(
infos.x,
infos.y,
infos.x + infos.a,
infos.y,
"ICRS",
);
infos.b = this.aladin.angularDist(
infos.x,
infos.y,
infos.x,
infos.y + infos.b,
"ICRS",
);
// Voluntary fallthrough
case "ellipse_sky":
overlay.add(
A.ellipse(
infos.ra,
Expand All @@ -55,12 +82,29 @@ export default class MessageHandler {
),
);
break;
case "line":
case "line_pixel":
[infos.ra1, infos.dec1] = this.aladin.pix2world(
infos.x1,
infos.y1,
"ICRS",
);
[infos.ra2, infos.dec2] = this.aladin.pix2world(
infos.x2,
infos.y2,
"ICRS",
);
// Voluntary fallthrough
case "line_sky":
overlay.add(
A.line(infos.ra1, infos.dec1, infos.ra2, infos.dec2, options),
);
break;
case "polygon":
case "polygon_pixel":
infos.vertices = infos.vertices.map(([x, y]) =>
this.aladin.pix2world(x, y, "ICRS"),
);
// Voluntary fallthrough
case "polygon_sky":
overlay.add(A.polygon(infos.vertices, options));
break;
}
Expand Down
24 changes: 4 additions & 20 deletions src/ipyaladin/aladin.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,9 @@

try:
from regions import (
CircleSkyRegion,
EllipseSkyRegion,
LineSkyRegion,
PolygonSkyRegion,
RectangleSkyRegion,
Region,
)
except ImportError:
CircleSkyRegion = None
EllipseSkyRegion = None
LineSkyRegion = None
PolygonSkyRegion = None
RectangleSkyRegion = None
Region = None
from traitlets import (
Float,
Expand Down Expand Up @@ -357,29 +347,23 @@ def add_overlay(
self,
region: Union[
str,
CircleSkyRegion,
EllipseSkyRegion,
LineSkyRegion,
PolygonSkyRegion,
RectangleSkyRegion,
Region,
],
**overlay_options: any,
) -> None:
"""Add an overlay layer to the Aladin Lite widget.
Parameters
----------
region: str, CircleSkyRegion, EllipseSkyRegion, LineSkyRegion
The region to overlay. It can be a string, a CircleSkyRegion,
an EllipseSkyRegion, a LineSkyRegion or a RectangleSkyRegion.
region: str or regions object
overlay_options: keyword arguments
"""
# Check if the regions library is installed and raise an error if not
if (
not isinstance(region, str) and CircleSkyRegion is None
not isinstance(region, str) and Region is None
): # Only need to check one of the imports
raise ValueError(
raise ImportError(
"A region can be given as an STC-S string or a regions "
"object. To read regions objects, you need to install the regions "
"library with 'pip install regions'."
Expand Down
96 changes: 92 additions & 4 deletions src/ipyaladin/region_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
CircleSkyRegion,
EllipseSkyRegion,
LineSkyRegion,
CirclePixelRegion,
EllipsePixelRegion,
LinePixelRegion,
PolygonPixelRegion,
RectanglePixelRegion,
PixCoord,
)
from astropy.coordinates import SkyCoord
from typing import Union
Expand Down Expand Up @@ -184,6 +190,47 @@ def rectangle_to_polygon_region(region: RectangleSkyRegion) -> PolygonSkyRegion:
)


def rectangle_pixel_to_polygon_pixel(
region: RectanglePixelRegion,
) -> PolygonPixelRegion:
"""Convert a RectanglePixelRegion to a PolygonPixelRegion.
Parameters
----------
region : RectanglePixelRegion
The region to convert.
Returns
-------
PolygonPixelRegion
The converted region.
"""
center = region.center
vertices = [
[center.x - region.width / 2, center.y - region.height / 2],
[center.x + region.width / 2, center.y - region.height / 2],
[center.x + region.width / 2, center.y + region.height / 2],
[center.x - region.width / 2, center.y + region.height / 2],
]
rotation = region.angle.deg
if rotation != 0:
rotation = math.radians(rotation)
cos_rot = math.cos(rotation)
sin_rot = math.sin(rotation)
for vertex in vertices:
x = vertex[0] - center.x
y = vertex[1] - center.y
vertex[0] = x * cos_rot - y * sin_rot + center.x
vertex[1] = x * sin_rot + y * cos_rot + center.y
vertices = {
"x": [vertex[0] for vertex in vertices],
"y": [vertex[1] for vertex in vertices],
}
vertices = PixCoord(x=vertices["x"], y=vertices["y"])
return PolygonPixelRegion(vertices=vertices, visual=region.visual, meta=region.meta)


class RegionInfos:
"""Extract information from a region.
Expand All @@ -200,10 +247,15 @@ def __init__(self, region: Union[str, Region]) -> None:
self._region_parsers = {
"str": self._from_stcs,
"CircleSkyRegion": self._from_circle_sky_region,
"CirclePixelRegion": self._from_circle_pixel_region,
"EllipseSkyRegion": self._from_ellipse_sky_region,
"EllipsePixelRegion": self._from_ellipse_pixel_region,
"LineSkyRegion": self._from_line_sky_region,
"LinePixelRegion": self._from_line_pixel_region,
"PolygonSkyRegion": self._from_polygon_sky_region,
"PolygonPixelRegion": self._from_polygon_pixel_region,
"RectangleSkyRegion": self._from_rectangle_sky_region,
"RectanglePixelRegion": self._from_rectangle_pixel_region,
}
self.from_region(region)

Expand All @@ -226,15 +278,23 @@ def _from_stcs(self, stcs: str) -> None:
self.infos = {"stcs": stcs}

def _from_circle_sky_region(self, region: CircleSkyRegion) -> None:
self.region_type = "circle"
self.region_type = "circle_sky"
self.infos = {
"ra": region.center.ra.deg,
"dec": region.center.dec.deg,
"radius": region.radius.deg,
}

def _from_circle_pixel_region(self, region: CirclePixelRegion) -> None:
self.region_type = "circle_pixel"
self.infos = {
"x": region.center.x,
"y": region.center.y,
"radius": region.radius,
}

def _from_ellipse_sky_region(self, region: EllipseSkyRegion) -> None:
self.region_type = "ellipse"
self.region_type = "ellipse_sky"
self.infos = {
"ra": region.center.ra.deg,
"dec": region.center.dec.deg,
Expand All @@ -243,20 +303,48 @@ def _from_ellipse_sky_region(self, region: EllipseSkyRegion) -> None:
"theta": region.angle.deg,
}

def _from_ellipse_pixel_region(self, region: EllipsePixelRegion) -> None:
self.region_type = "ellipse_pixel"
self.infos = {
"x": region.center.x,
"y": region.center.y,
"a": region.width,
"b": region.height,
"theta": region.angle.deg,
}

def _from_line_sky_region(self, region: LineSkyRegion) -> None:
self.region_type = "line"
self.region_type = "line_sky"
self.infos = {
"ra1": region.start.ra.deg,
"dec1": region.start.dec.deg,
"ra2": region.end.ra.deg,
"dec2": region.end.dec.deg,
}

def _from_line_pixel_region(self, region: LinePixelRegion) -> None:
self.region_type = "line_pixel"
self.infos = {
"x1": region.start.x,
"y1": region.start.y,
"x2": region.end.x,
"y2": region.end.y,
}

def _from_polygon_sky_region(self, region: PolygonSkyRegion) -> None:
self.region_type = "polygon"
self.region_type = "polygon_sky"
vertices = [[coord.ra.deg, coord.dec.deg] for coord in region.vertices]
self.infos = {"vertices": vertices}

def _from_polygon_pixel_region(self, region: PolygonPixelRegion) -> None:
self.region_type = "polygon_pixel"
vertices = [[coord.x, coord.y] for coord in region.vertices]
self.infos = {"vertices": vertices}

def _from_rectangle_sky_region(self, region: RectangleSkyRegion) -> None:
# Rectangle is interpreted as a polygon in Aladin Lite
self._from_polygon_sky_region(rectangle_to_polygon_region(region))

def _from_rectangle_pixel_region(self, region: RectanglePixelRegion) -> None:
# Rectangle is interpreted as a polygon in Aladin Lite
self._from_polygon_pixel_region(rectangle_pixel_to_polygon_pixel(region))

0 comments on commit c0b218c

Please sign in to comment.