Skip to content

Commit

Permalink
feat: WCS and 2 axis FoV export
Browse files Browse the repository at this point in the history
* ✨ Implement WCS and 2 axis FoV recovery

* 📝 Add new notebook example for wcs and ov recovery

* 📝 Update changelog

* ✨ Add support for cooFrameChanged event to update the WCS

* ✏️ Fix typo

Co-authored-by: Manon Marchand <[email protected]>

* 🎨 Add error raising when recovering the WSC in the same cell that an update

* 🚑 Fix wrong _wcs traitlets assignation

* 🎨 Rename example 11

* ⬆️ Update Aladin Lite from 3.4.1-beta to 3.4.4-beta

* ✨ Add missing events that impact WCS and FoV

* maint: prepare release 0.4.0

fix: A.line was removed from public AL API in favor of A.vector

* ✨ Add layerChanged listener for future AL version

* maint: prepare release 0.4.0

fix: A.line was removed from public AL API in favor of A.vector

* ⬆️ Bump Aladin Lite to 3.4.5-beta

* ✨ Convert height to property to change the WCS on height updates

* 🥅 Add custom WidgetCommunicationError

* refactor: create a utils submodule

* ✨ Add support for multiple Aladin Lite instances
Data will be exported from the last created one

* maint: sort imports

* fix: avoid most getElementById calls

* fix: don't empty fov_xy if fov does not change

* docs: edit info extractions

* fix: only parse string once

* docs: add paragraph on limitations

---------

Co-authored-by: Manon Marchand <[email protected]>
  • Loading branch information
Xen0Xys and ManonMarchand authored Jul 22, 2024
1 parent a68bde6 commit 75925c3
Show file tree
Hide file tree
Showing 15 changed files with 548 additions and 32 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Allow WCS and 2 axis FoV recovery from `wcs` and `fov_xy` properties (#96)
- monochromatic FITS images can be added to the view with `ipyaladin.Aladin.add_fits`.
The method accepts `astropy.io.fits.HDUList`, `pathlib.Path`, or `string` representing paths (#86)

### Changed

- Upgrade Aladin Lite version to 3.4.5-beta (#96)

## [0.4.0]

### Added
Expand All @@ -40,7 +45,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Change the jslink target trait from `target` to `shared_target` (#80)
- Change the jslink fov trait from `fov` to `shared_fov` (#83)
- Upgrade Aladin Lite version to 3.4.1-beta (#88)
- Upgrade Aladin Lite version to 3.4.4-beta (#88)
- Add support for list of strings in `add_overlay_from_stcs` (#88)

### Deprecated
Expand Down
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,11 @@ Ipyaladin brings [Aladin Lite](https://github.com/cds-astro/aladin-lite) into no

Correspondence table between ipyaladin versions and Aladin Lite versions:

| ipyaladin | Aladin-Lite |
| --------- | ----------- |
| 0.3.0 | 3.3.3-dev |
| 0.4.0 | 3.4.4-beta |
| ipyaladin | Aladin-Lite |
| ---------- | ----------- |
| Unreleased | 3.4.5-beta |
| 0.4.0 | 3.4.4-beta |
| 0.3.0 | 3.3.3-dev |

> [!TIP]
> This can always be read like so
Expand Down
340 changes: 340 additions & 0 deletions examples/11_Extracting_information_from_the_view.ipynb

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion js/aladin_lite.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import A from "https://esm.sh/[email protected].4-beta";
import A from "https://esm.sh/[email protected].5-beta";

export default A;
83 changes: 78 additions & 5 deletions js/models/event_handler.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import MessageHandler from "./message_handler";
import { Lock } from "../utils";
import { divNumber, setDivNumber, Lock } from "../utils";

export default class EventHandler {
/**
Expand All @@ -12,7 +12,51 @@ export default class EventHandler {
this.aladin = aladin;
this.aladinDiv = aladinDiv;
this.model = model;
this.messageHandler = new MessageHandler(aladin);
this.messageHandler = new MessageHandler(aladin, model);
this.currentDivNumber = parseInt(aladinDiv.id.split("-").pop());
}

/**
* Checks if the current div is the last active div.
* @returns {boolean}
*/
isLastDiv() {
if (this.currentDivNumber === divNumber) {
return true;
}
let maxDiv = divNumber;
for (let i = maxDiv; i >= 0; i--) {
const alDiv = document.getElementById(`aladin-lite-div-${i}`);
if (!alDiv) continue;
if (alDiv.style.display !== "none") {
maxDiv = i;
break;
}
}
setDivNumber(maxDiv);
return this.currentDivNumber === maxDiv;
}

/**
* Updates the WCS coordinates in the model.
* WARNING: This method don't call model.save_changes()!
*/
updateWCS() {
if (!this.isLastDiv()) return;
this.model.set("_wcs", this.aladin.getViewWCS());
}

/**
* Updates the 2-axis FoV in the model.
* WARNING: This method don't call model.save_changes()!
*/
update2AxisFoV() {
if (!this.isLastDiv()) return;
const twoAxisFoV = this.aladin.getFov();
this.model.set("_fov_xy", {
x: twoAxisFoV[0],
y: twoAxisFoV[1],
});
}

/**
Expand Down Expand Up @@ -42,6 +86,7 @@ export default class EventHandler {
}
jsTargetLock.lock();
const raDec = [position.ra, position.dec];
this.updateWCS();
this.model.set("_target", `${raDec[0]} ${raDec[1]}`);
this.model.save_changes();
});
Expand All @@ -68,6 +113,8 @@ export default class EventHandler {
}
jsFovLock.lock();
// fov MUST be cast into float in order to be sent to the model
this.updateWCS();
this.update2AxisFoV();
this.model.set("_fov", parseFloat(fov.toFixed(5)));
this.model.save_changes();
});
Expand All @@ -83,13 +130,39 @@ export default class EventHandler {
});

/* Div control */
this.model.on("change:height", () => {
let height = this.model.get("height");
this.model.on("change:_height", () => {
let height = this.model.get("_height");
this.aladinDiv.style.height = `${height}px`;
// Update WCS and FoV only if this is the last div
this.updateWCS();
this.update2AxisFoV();
this.model.save_changes();
});

/* Aladin callbacks */

this.aladin.on("cooFrameChanged", () => {
this.updateWCS();
this.model.save_changes();
});

this.aladin.on("projectionChanged", () => {
this.updateWCS();
this.model.save_changes();
});

this.aladin.on("layerChanged", (_, layerName, state) => {
if (layerName !== "base" || state !== "ADDED") return;
this.updateWCS();
this.model.save_changes();
});

this.aladin.on("resizeChanged", () => {
this.updateWCS();
this.update2AxisFoV();
this.model.save_changes();
});

this.aladin.on("objectHovered", (object) => {
if (object["data"] !== undefined) {
this.model.send({
Expand Down Expand Up @@ -200,7 +273,7 @@ export default class EventHandler {
unsubscribeAll() {
this.model.off("change:_target");
this.model.off("change:_fov");
this.model.off("change:height");
this.model.off("change:_height");
this.model.off("change:coo_frame");
this.model.off("change:survey");
this.model.off("change:overlay_survey");
Expand Down
3 changes: 2 additions & 1 deletion js/models/message_handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import A from "../aladin_lite";
let imageCount = 0;

export default class MessageHandler {
constructor(aladin) {
constructor(aladin, model) {
this.aladin = aladin;
this.model = model;
}

handleChangeFoV(msg) {
Expand Down
13 changes: 12 additions & 1 deletion js/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,15 @@ class Lock {
}
}

export { snakeCaseToCamelCase, convertOptionNamesToCamelCase, Lock };
let divNumber = -1;
function setDivNumber(num) {
divNumber = num;
}

export {
snakeCaseToCamelCase,
convertOptionNamesToCamelCase,
Lock,
divNumber,
setDivNumber,
};
17 changes: 12 additions & 5 deletions js/widget.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import "./widget.css";
import EventHandler from "./models/event_handler";
import { snakeCaseToCamelCase } from "./utils";
import { divNumber, setDivNumber, snakeCaseToCamelCase } from "./utils";
import A from "./aladin_lite";

let idxView = 0;

function initAladinLite(model, el) {
setDivNumber(divNumber + 1);
let initOptions = {};
model.get("init_options").forEach((option_name) => {
initOptions[snakeCaseToCamelCase(option_name)] = model.get(option_name);
Expand All @@ -15,15 +14,23 @@ function initAladinLite(model, el) {
aladinDiv.classList.add("aladin-widget");
aladinDiv.style.height = `${initOptions["height"]}px`;

aladinDiv.id = `aladin-lite-div-${idxView}`;
aladinDiv.id = `aladin-lite-div-${divNumber}`;
let aladin = new A.aladin(aladinDiv, initOptions);
idxView += 1;

// Set the target again after the initialization to be sure that the target is set
// from icrs coordinates because of the use of gotoObject in the Aladin Lite API
const raDec = initOptions["target"].split(" ");
aladin.gotoRaDec(raDec[0], raDec[1]);

// Set current FoV and WCS
const twoAxisFoV = aladin.getFov();
model.set("_fov_xy", {
x: twoAxisFoV[0],
y: twoAxisFoV[1],
});
model.set("_wcs", aladin.getViewWCS());
model.save_changes();

el.appendChild(aladinDiv);
return { aladin, aladinDiv };
}
Expand Down
Empty file added src/ipyaladin/utils/__init__.py
Empty file.
File renamed without changes.
6 changes: 6 additions & 0 deletions src/ipyaladin/utils/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class WidgetCommunicationError(OSError):
"""Error raised when there is a communication error with the widget."""

def __init__(self, message: str) -> None:
self.message = message
super(WidgetCommunicationError, self).__init__(message)
File renamed without changes.
Loading

0 comments on commit 75925c3

Please sign in to comment.