Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add_markers #111

Merged
merged 4 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add selected sources export as `astropy.Table` list with property `selected_objects` (#100)
- Add function `get_view_as_fits` to export the view as a `astropy.io.fits.HDUList` (#98)
- Add function `save_view_as_image` to save the view as an image file (#108)
- Support for planetary objects for Aladin Lite target (#103)
- Support planetary objects for ipyaladin targets (#103)
- new method `add_marker` to add a marker to the view (#111)

### Deprecated

Expand Down
111 changes: 44 additions & 67 deletions examples/02_Base_Commands.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"metadata": {},
"outputs": [],
"source": [
"from ipyaladin import Aladin\n",
"from astropy.coordinates import Angle, SkyCoord\n",
"from ipyaladin import Aladin, Marker\n",
"from pathlib import Path"
]
},
Expand All @@ -23,24 +24,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"A list of all available commands can be displayed as such."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(dir(Aladin))"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"A few of them are illustrated in the next cells. Let's first, create the widget with a few initial parameters:"
"`ipyaladin`'s full list of methods can be found in the documentation [here](https://cds-astro.github.io/ipyaladin/autoapi/ipyaladin/widget/index.html). A few of them are illustrated in the next cells. Let's first, create the widget with a few initial parameters:"
]
},
{
Expand All @@ -64,22 +48,20 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": []
},
"metadata": {},
"outputs": [],
"source": [
"aladin.target = \"sgr a*\""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"aladin.target"
],
"outputs": [],
"execution_count": null
]
},
{
"cell_type": "markdown",
Expand All @@ -91,9 +73,7 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": []
},
"metadata": {},
"outputs": [],
"source": [
"aladin.fov = 2"
Expand All @@ -118,9 +98,7 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": []
},
"metadata": {},
"outputs": [],
"source": [
"aladin.overlay_survey = \"P/allWISE/color\"\n",
Expand All @@ -137,9 +115,7 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": []
},
"metadata": {},
"outputs": [],
"source": [
"aladin.coo_frame = \"ICRSd\" # ICRS, and angles expressed in degrees"
Expand All @@ -161,15 +137,6 @@
"The target and field of view can be set with astropy objects"
]
},
{
"cell_type": "code",
"metadata": {},
"source": [
"from astropy.coordinates import Angle, SkyCoord"
],
"outputs": [],
"execution_count": null
},
{
"cell_type": "code",
"execution_count": null,
Expand Down Expand Up @@ -204,32 +171,42 @@
"source": [
"aladin.add_fits(Path(\"images/m31.fits\"), name=\"M31\", opacity=0.5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can add markers to the view of the widget with custom popup title and description.\n",
"Here we will add markers for Messier objects M1 to M10."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"markers = []\n",
"for i in range(1, 11):\n",
" name = f\"M{i}\"\n",
" markers.append(\n",
" Marker(\n",
" position=name,\n",
" title=name,\n",
" description=(\n",
" '<a href=\"https://simbad.cds.unistra.fr/simbad/'\n",
" f'sim-basic?Ident={name}&submit=SIMBAD+search\"> '\n",
" \"Read more on SIMBAD</a>\"\n",
" ),\n",
" )\n",
" )\n",
"aladin.add_markers(markers, name=\"M1-M10\", color=\"pink\", shape=\"cross\", source_size=15)\n",
"aladin.target = \"M1\"\n",
"aladin.fov = 0.2"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.8"
},
"vscode": {
"interpreter": {
"hash": "916dbcbb3f70747c44a77c7bcd40155683ae19c65e1c03b4aa3499c5328201f1"
}
}
},
"metadata": {},
"nbformat": 4,
"nbformat_minor": 4
}
1 change: 1 addition & 0 deletions js/models/event_handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ export default class EventHandler {
});

this.eventHandlers = {
add_marker: this.messageHandler.handleAddMarker,
change_fov: this.messageHandler.handleChangeFoV,
goto_ra_dec: this.messageHandler.handleGotoRaDec,
save_view_as_image: this.messageHandler.handleSaveViewAsImage,
Expand Down
20 changes: 20 additions & 0 deletions js/models/message_handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,26 @@ export default class MessageHandler {
this.model = model;
}

handleAddMarker(msg) {
const options = convertOptionNamesToCamelCase(msg["options"] || {});
// default name
if (!options.name) options.name = "markers";
// create catalog
const catalog = A.catalog(options);
this.aladin.addCatalog(catalog);
const pythonMarkers = msg["markers"];
const markers = [];
for (const marker of pythonMarkers) {
markers.push(
A.marker(marker["lon"], marker["lat"], {
popupTitle: marker["title"],
popupDesc: marker["description"],
}),
);
}
catalog.addSources(markers);
}

handleChangeFoV(msg) {
this.aladin.setFoV(msg["fov"]);
}
Expand Down
1 change: 1 addition & 0 deletions src/ipyaladin/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Top-level package for ipyaladin."""

from .widget import Aladin # noqa: F401
from .elements.marker import Marker # noqa: F401
from .__about__ import __version__, __aladin_lite_version__ # noqa: F401
File renamed without changes.
31 changes: 31 additions & 0 deletions src/ipyaladin/elements/marker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from dataclasses import dataclass
from typing import Tuple, Union

from astropy.coordinates import SkyCoord, Longitude, Latitude
from ipyaladin.utils._coordinate_parser import _parse_coordinate_string


@dataclass
class Marker:
"""A class representing a marker in Aladin Lite."""

def __init__(
self,
position: Union[str, SkyCoord, Tuple[Longitude, Latitude]],
title: str,
description: str,
) -> None:
self.title = title
self.description = description
if isinstance(position, SkyCoord):
self.lon = position.ra.deg
self.lat = position.dec.deg
elif isinstance(position, str):
self.lon, self.lat = _parse_coordinate_string(position)
elif (
isinstance(position, Tuple)
and isinstance(position[0], Longitude)
and isinstance(position[1], Latitude)
):
self.lon = position[0].deg
self.lat = position[1].deg
38 changes: 37 additions & 1 deletion src/ipyaladin/widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"""

from collections.abc import Callable
from dataclasses import asdict
import io
import pathlib
from json import JSONDecodeError
Expand All @@ -27,6 +28,7 @@

from .utils.exceptions import WidgetReducedError, WidgetNotReadyError
from .utils._coordinate_parser import _parse_coordinate_string
from .elements.marker import Marker

try:
from regions import (
Expand Down Expand Up @@ -281,7 +283,7 @@ class Aladin(anywidget.AnyWidget):
"is reduced in size when hidden.",
).tag(sync=True)

init_options = traitlets.List(trait=Any()).tag(sync=True)
init_options = traitlets.List(trait=traitlets.Any()).tag(sync=True)

@default("init_options")
def _init_options(self) -> List[str]:
Expand Down Expand Up @@ -507,6 +509,36 @@ def target(self, target: Union[str, SkyCoord, Tuple[float, float]]) -> None:
}
)

def add_markers(
self, markers: Union[Marker, List[Marker]], **catalog_options: any
) -> None:
"""Add markers to the Aladin Lite widget.
Markers have a popup window that appear when they're clicked on.
Parameters
----------
markers : Marker or list[Marker]
The marker(s) to add to the widget. It can be given as a single `Marker`
object or as a list of `Marker` objects.
catalog_options : any
The options for the catalog. See the `Aladin Lite catalog options
<https://cds-astro.github.io/aladin-lite/global.html#CatalogOptions>`_
See Also
--------
add_table: also adds points, but without popup window.
"""
if not isinstance(markers, list):
markers = [markers]
self.send(
{
"event_name": "add_marker",
"markers": [asdict(marker) for marker in markers],
"options": catalog_options,
}
)

def _save_file(self, path: str, buffer: bytes) -> None:
"""Save a file from a buffer.
Expand Down Expand Up @@ -776,6 +808,10 @@ def add_table(self, table: Union[QTable, Table], **table_options: any) -> None:
table options
<https://cds-astro.github.io/aladin-lite/global.html#CatalogOptions>`_
See Also
--------
add_markers: adds markers with a popup window when clicked
"""
table_bytes = io.BytesIO()
table.write(table_bytes, format="votable")
Expand Down
Empty file added src/tests/__init__.py
Empty file.
File renamed without changes.
File renamed without changes.
Loading