diff --git a/README.md b/README.md index bd8a9310..65fa1ea0 100644 --- a/README.md +++ b/README.md @@ -10,17 +10,21 @@ A convenience wrapper for using [astropy](https://www.astropy.org) with [xarray](https://xarray.pydata.org). -## Usage +## Simple Usage -To convert the variables of a `Dataset` to quantities: +To convert the variables of a `Dataset` to quantities, use accessor `.astropy.quantify()`: -```python -In [1]: import astropy_xarray - ...: import xarray as xr +```{code-block} python +import astropy_xarray +import xarray as xr + +ds = xr.Dataset({"a": ("x", [0, 1, 2]), "b": ("y", [-3, 5, 1], {"units": "m"})}) +ds +``` + +output: -In [2]: ds = xr.Dataset({"a": ("x", [0, 1, 2]), "b": ("y", [-3, 5, 1], {"units": "m"})}) - ...: ds -Out[2]: +``` Size: 48B Dimensions: (x: 3, y: 3) Dimensions without coordinates: x, y @@ -39,12 +43,16 @@ Data variables: b (y) float64 24B [m] -3.0 5.0 1.0 ``` -to convert to different units: +to convert to different units, use accessor `.astropy.to()`: -```python -In [4]: c = q.astropy.to({"a": "ms", "b": "km"}) - ...: c -Out[4]: +```{code-block} python +c = q.astropy.to({"a": "ms", "b": "km"}) +c +``` + +output: + +``` Size: 48B Dimensions: (x: 3, y: 3) Dimensions without coordinates: x, y @@ -53,7 +61,7 @@ Data variables: b (y) float64 24B [km] -0.003 0.005 0.001 ``` -to convert back to non-quantities: +to convert back to non-quantities for portability, use accessor `.astropy.dequantify()`: ```python In [5]: d = c.astropy.dequantify() @@ -67,4 +75,66 @@ Data variables: b (y) float64 24B -0.003 0.005 0.001 ``` +## SkyCoord Usage + +To convert a `astropy.skyCoord` to a `Dataset`, use `skycoord_to_dataset()`. + +```{code-block} python +import astropy.units as u +from astropy.coordinates import ICRS, SkyCoord +from astropy.time import Time + +from astropy_xarray.coordinates.sky_coord import ( + skycoord_to_dataset, +) + +sc = skycoord_to_dataset( + SkyCoord( + ra=[[2, 6, 7, 4]] * u.deg, + dec=[[4, 7, 4, 3]] * u.deg, + pm_ra_cosdec=[[1, 1, 1, 1]] * u.mas / u.yr, + pm_dec=[[1, 1, 1, 1]] * u.mas / u.yr, + frame="icrs", + ), + coords={ + "timestamp": ("time", Time([1.7e9], format='unix')), + "field_label": ("field", ["a", "b", "c", "d"]), + } +) +sc +``` + +output: + +```{code-block} python + Size: 152B +Dimensions: (time: 1, field: 4) +Coordinates: + timestamp (time) float64 8B [utc unix] 2023-11-14T22:13:20.000000000 + field_label (field) +``` + For more, see the [documentation](https://astropy-xarray.readthedocs.io/en/latest/) diff --git a/astropy_xarray/accessors.py b/astropy_xarray/accessors.py index 7b58ff18..84ad9f9e 100644 --- a/astropy_xarray/accessors.py +++ b/astropy_xarray/accessors.py @@ -1726,8 +1726,8 @@ def interpolate_na( return conversion.attach_units(interpolated, units) - def to_sky_coord(self): - """TODO""" + def to_skycoord(self): + """Convert a SkyCoord-based Dataset with metadata attributes to a SkyCoord.""" return dataset_to_skycoord(self.ds) diff --git a/astropy_xarray/coordinates/frame.py b/astropy_xarray/coordinates/frame.py index 54f3436e..210d6735 100644 --- a/astropy_xarray/coordinates/frame.py +++ b/astropy_xarray/coordinates/frame.py @@ -1,3 +1,4 @@ +from importlib.metadata import version from types import NoneType import astropy.units as u @@ -36,6 +37,7 @@ Supergalactic, ) from astropy.time import Time +from packaging.version import Version from astropy_xarray.coordinates.core import ( dump_quantity, @@ -53,17 +55,29 @@ load_optional_earthlocation, ) +if Version(version("astropy")) < Version("7.0.0"): + + def get_name_compat(representation): + return representation.get_name() + +else: + # 7.0.0 and above raises deprecation warnings when using get_name() + def get_name_compat(representation): + return representation.name + def dump_frame(frame: BaseCoordinateFrame, with_data: bool = False) -> dict: ser = { "name": frame.name, - "representation_type": frame.representation_type.get_name(), - "differential_type": frame.differential_type.get_name(), + "representation_type": get_name_compat(frame.representation_type), + "differential_type": get_name_compat(frame.differential_type), } if frame.has_data: - ser["data"] = {"representation_type": frame.data.get_name()} + ser["data"] = {"representation_type": get_name_compat(frame.data)} if "s" in frame.data.differentials: - ser["data"]["differential_type"] = frame.data.differentials["s"].get_name() + ser["data"]["differential_type"] = get_name_compat( + frame.data.differentials["s"] + ) if with_data: for component in frame.data.components: quantity: u.Quantity = getattr(frame.data, component) diff --git a/astropy_xarray/coordinates/sky_coord.py b/astropy_xarray/coordinates/sky_coord.py index 6a1c2472..2369e3cf 100644 --- a/astropy_xarray/coordinates/sky_coord.py +++ b/astropy_xarray/coordinates/sky_coord.py @@ -5,9 +5,12 @@ import numpy as np import xarray as xr from astropy.coordinates import SkyCoord +from astropy.utils import ShapedLikeNDArray from astropy_xarray.coordinates.frame import dump_frame, load_frame, load_representation +_ArrayLike = list | np.ndarray | ShapedLikeNDArray + def _skycoord_representation_component_names( skycoord: SkyCoord, @@ -68,19 +71,26 @@ def _skycoord_components(skycoord: SkyCoord) -> dict[str, u.Quantity]: def _skycoord_to_dataarrays( skycoord: SkyCoord, - coords: list[tuple[str, list]] | None = None, + coords: dict[str, tuple[str, _ArrayLike] | _ArrayLike] | None = None, ) -> dict[str, xr.DataArray]: + + dims = ( + [ + coords[key][0] if isinstance(coords[key], tuple) else key + for key in coords.keys() + ] + if coords is not None + else None + ) return { - name: xr.DataArray( - data=component, coords=dict(coords) if coords is not None else None - ) + name: xr.DataArray(data=component, coords=coords, dims=dims) for name, component in _skycoord_components(skycoord).items() } def skycoord_to_dataset( skycoord: SkyCoord, - coords: list[tuple[str, np.ndarray]] | None = None, + coords: dict[str, tuple[str, _ArrayLike] | _ArrayLike] | None = None, ) -> xr.Dataset: """Convert a SkyCoord object to an xarray Dataset. @@ -92,7 +102,7 @@ def skycoord_to_dataset( quantified dataset. """ return xr.Dataset( - coords=dict(coords) if coords is not None else None, + coords=coords if coords is not None else None, data_vars=_skycoord_to_dataarrays(skycoord, coords), attrs=dict( frame=dump_frame(skycoord.frame), @@ -105,7 +115,6 @@ def dataset_to_skycoord(ds: xr.Dataset) -> SkyCoord: Args: ds: skycoord dataset. - use_frame_names: True if frame component names are used a data_vars. Defaults to True. Returns: SkyCoord object. diff --git a/astropy_xarray/tests/test_sky_coord.py b/astropy_xarray/tests/test_sky_coord.py index b0c9d42f..35bbb362 100644 --- a/astropy_xarray/tests/test_sky_coord.py +++ b/astropy_xarray/tests/test_sky_coord.py @@ -308,10 +308,10 @@ def test_skycoord_roundtrip( == expected_frame_data_diff_name ) - coords = [ - ("calibrator_name", ["a1", "a2"]), - ("time_polynomial", [0]), - ] + coords = { + "calibrator_name": ["a1", "a2"], + "time_polynomial": [0], + } ds = skycoord_to_dataset(expected, coords=coords) # data_var keys diff --git a/astropy_xarray/tests/test_time.py b/astropy_xarray/tests/test_time.py index ee690753..d3986a67 100644 --- a/astropy_xarray/tests/test_time.py +++ b/astropy_xarray/tests/test_time.py @@ -73,19 +73,19 @@ def test_array_ufunc(self, time, dtype): np.array([1.0, 2.0, 3.0, 4.0]), "unix", "utc", - "[unix utc] 1970-01-01T00:00:01.000000000 ... 1970-01-01T0...", + "[utc unix] 1970-01-01T00:00:01.000000000 ... 1970-01-01T0...", ), ( np.array([1.0, 2.0, 3.0, 4.0]), "unix_tai", "utc", - "[unix_tai utc] 1969-12-31T23:59:52.999918210 ... 1969-12-...", + "[utc unix_tai] 1969-12-31T23:59:52.999918210 ... 1969-12-...", ), ( np.array([1.0, 2.0, 3.0, 4.0]), "mjd", "utc", - "[mjd utc] 1858-11-18T00:00:00.000000000 ... 1858-11-21T00...", + "[utc mjd] 1858-11-18T00:00:00.000000000 ... 1858-11-21T00...", ), ( np.array( @@ -97,7 +97,7 @@ def test_array_ufunc(self, time, dtype): ), "datetime64", "utc", - "[datetime64 utc] 1970-01-01T00:00:09.000082030 ... 1970-0...", + "[utc datetime64] 1970-01-01T00:00:09.000082030 ... 1970-0...", ), ( np.array( @@ -109,7 +109,7 @@ def test_array_ufunc(self, time, dtype): ), "iso", "utc", - "[iso utc] 1970-01-01T00:00:09.000082030 ... 1970-01-01T00...", + "[utc iso] 1970-01-01T00:00:09.000082030 ... 1970-01-01T00...", ), ], ) diff --git a/astropy_xarray/tests/test_visibility_serialization.py b/astropy_xarray/tests/test_visibility_serialization.py index 0ba96cb0..6d4567ea 100644 --- a/astropy_xarray/tests/test_visibility_serialization.py +++ b/astropy_xarray/tests/test_visibility_serialization.py @@ -191,9 +191,9 @@ def test_simple_visibility_dataset(): field_phase_center=xr.DataTree( skycoord_to_dataset( SkyCoord(ra=[0.1] * u.deg, dec=[0.5] * u.deg, frame=ICRS()), - coords=[ - ("time_poly", [0]), - ], + coords={ + "time_poly": [0], + }, ) ), # extensions @@ -203,10 +203,10 @@ def test_simple_visibility_dataset(): ra=[[0.5], [1.5], [0.2], [0.9], [1.1]] * u.deg, dec=[[1.2], [0.8], [0.6], [1.0], [1.5]] * u.deg, ), - coords=[ - ("calibrator_label", ["A", "B", "C", "D", "E"]), - ("time_poly", [0]), - ], + coords={ + "calibrator_label": ["A", "B", "C", "D", "E"], + "time_poly": [0], + }, ) ), ), @@ -310,10 +310,10 @@ def test_visibility_dataset(skycoords: list[SkyCoord], frame, unit): radial_velocity=[[1, 1]] * u.pc / u.yr, frame=ICRS(), ), - coords=[ - ("phase_center_label", np.array([0])), - ("time_poly", np.array([0, 1])), - ], + coords={ + "phase_center_label": np.array([0]), + "time_poly": np.array([0, 1]), + }, ) ), # extensions @@ -323,10 +323,10 @@ def test_visibility_dataset(skycoords: list[SkyCoord], frame, unit): ra=[[0.5], [1.5], [0.2], [0.9], [1.1]] * u.deg, dec=[[1.2], [0.8], [0.6], [1.0], [1.5]] * u.deg, ), - coords=[ - ("calibrator_label", ["A", "B", "C", "D", "E"]), - ("time_poly", np.array([0])), - ], + coords={ + "calibrator_label": ["A", "B", "C", "D", "E"], + "time_poly": np.array([0]), + }, ) ), ), diff --git a/astropy_xarray/time_compat.py b/astropy_xarray/time_compat.py index ade4f0ce..1b4b3825 100644 --- a/astropy_xarray/time_compat.py +++ b/astropy_xarray/time_compat.py @@ -7,7 +7,7 @@ def time_inline_repr(time: Time, max_width: int): value = time.datetime64 - scale_repr = f"{time.format} {time.scale}" + scale_repr = f"{time.scale} {time.format}" if isinstance(value, np.ndarray): data_repr = astropy_xarray.formatting.format_array_flat( value, max_width - len(scale_repr) - 3 @@ -22,7 +22,7 @@ def time_inline_repr(time: Time, max_width: int): def time_delta_inline_repr(time: TimeDelta, max_width: int): value = time.value - scale_repr = f"{time.format} {time.scale}" + scale_repr = f"{time.scale} {time.format}" if isinstance(value, np.ndarray): data_repr = astropy_xarray.formatting.format_array_flat( value, max_width - len(scale_repr) - 3 diff --git a/docs/api.rst b/docs/api.rst index 4b36f83d..00206146 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -35,6 +35,7 @@ Dataset xarray.Dataset.astropy.ffill xarray.Dataset.astropy.bfill xarray.Dataset.astropy.interpolate_na + xarray.Dataset.astropy.to_skycoord DataArray --------- diff --git a/docs/examples/plotting.ipynb b/docs/examples/plotting.ipynb index 25d95db6..57601e6b 100644 --- a/docs/examples/plotting.ipynb +++ b/docs/examples/plotting.ipynb @@ -21,7 +21,7 @@ "import astropy_xarray # noqa: F401\n", "\n", "# to be able to read unit attributes following the CF conventions\n", - "# import cf_xarray.units # must be imported before pint_xarray\n", + "# import cf_xarray.units # must be imported before astropy_xarray\n", "u.set_enabled_aliases(\n", " {\n", " \"degK\": u.Kelvin,\n", @@ -242,8 +242,7 @@ "\n", "s = skycoord_to_dataset(sc, coords=[(\"field\", [0, 1, 2, 3])])\n", "\n", - "# display(s1)\n", - "# display(s2)\n", + "display(s)\n", "s.astropy.dequantify()" ] }, diff --git a/docs/examples/skycoord.ipynb b/docs/examples/skycoord.ipynb index 120e37a4..668ec671 100644 --- a/docs/examples/skycoord.ipynb +++ b/docs/examples/skycoord.ipynb @@ -25,25 +25,32 @@ "import numpy as np\n", "import xarray as xr\n", "from astropy.coordinates import ICRS, SkyCoord\n", + "from astropy.time import Time\n", "\n", "from astropy_xarray.coordinates.sky_coord import (\n", " skycoord_to_dataset,\n", ")\n", "\n", "sky_direction = SkyCoord(\n", - " ra=[2, 6, 7, 4] * u.deg,\n", - " dec=[4, 7, 4, 3] * u.deg,\n", - " pm_ra_cosdec=[1, 1, 1, 1] * u.mas / u.yr,\n", - " pm_dec=[1, 1, 1, 1] * u.mas / u.yr,\n", + " ra=[[2, 6, 7, 4]] * u.deg,\n", + " dec=[[4, 7, 4, 3]] * u.deg,\n", + " pm_ra_cosdec=[[1, 1, 1, 1]] * u.mas / u.yr,\n", + " pm_dec=[[1, 1, 1, 1]] * u.mas / u.yr,\n", " frame=\"icrs\",\n", - " # NOTE: to explicity be a direction, use:\n", + " # NOTE: for explicit direction, consider using:\n", " # frame=ICRS(\n", " # representation_type='unitspherical',\n", " # differential_type='unitsphericalcoslat',\n", " # ),\n", ")\n", "display(sky_direction)\n", - "skycoord_to_dataset(sky_direction, coords=[(\"field\", [\"a\", \"b\", \"c\", \"d\"])])" + "skycoord_to_dataset(\n", + " sky_direction,\n", + " coords={\n", + " \"timestamp\": (\"time\", Time([1.7e9], format=\"unix\")),\n", + " \"field_label\": (\"field\", [\"a\", \"b\", \"c\", \"d\"]),\n", + " },\n", + ")" ] }, { @@ -71,7 +78,11 @@ " frame=\"icrs\",\n", ")\n", "display(sky_position)\n", - "display(skycoord_to_dataset(sky_position, coords=[(\"field\", [\"a\", \"b\", \"c\", \"d\"])]))" + "display(\n", + " skycoord_to_dataset(\n", + " sky_position, coords={\"field_label\": (\"field\", [\"a\", \"b\", \"c\", \"d\"])}\n", + " )\n", + ")" ] }, { @@ -85,7 +96,11 @@ "display(sky_position.radial_velocity)\n", "\n", "# skycoord_to_dataset will then subsequently include these radial velocity values when this occurs\n", - "display(skycoord_to_dataset(sky_position, coords=[(\"field\", [\"a\", \"b\", \"c\", \"d\"])]))" + "display(\n", + " skycoord_to_dataset(\n", + " sky_position, coords={\"field_label\": (\"field\", [\"a\", \"b\", \"c\", \"d\"])}\n", + " )\n", + ")" ] }, { @@ -105,18 +120,29 @@ "source": [ "from astropy_xarray.coordinates import dataset_to_skycoord, load_frame\n", "\n", - "ds = skycoord_to_dataset(sky_position, coords=[(\"field\", [\"a\", \"b\", \"c\", \"d\"])])\n", + "ds = skycoord_to_dataset(\n", + " sky_position, coords={\"field_label\": (\"field\", [\"a\", \"b\", \"c\", \"d\"])}\n", + ")\n", "\n", "# frame specific info stored as dataset attribute\n", "assert load_frame(ds.attrs[\"frame\"]) == sky_position.replicate_without_data()\n", "\n", "# dataset\n", "result = dataset_to_skycoord(ds)\n", + "display(result)\n", "np.testing.assert_array_equal(result.ra, sky_position.ra)\n", "np.testing.assert_array_equal(result.dec, sky_position.dec)\n", - "np.testing.assert_array_equal(result.distance, sky_position.distance)\n", - "\n", - "result" + "np.testing.assert_array_equal(result.distance, sky_position.distance)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# accessor available\n", + "ds.astropy.to_skycoord()" ] }, { @@ -136,7 +162,7 @@ "source": [ "# serializable layout\n", "dds = skycoord_to_dataset(\n", - " sky_direction, coords=[(\"field\", [0, 1, 2, 3])]\n", + " sky_direction, coords={\"field_label\": (\"field\", [0, 1, 2, 3])}\n", ").astropy.dequantify()\n", "dds" ] @@ -262,6 +288,8 @@ "metadata": {}, "outputs": [], "source": [ + "# astropy skycoord frame type casting between directional and positional\n", + "# representation may alias data\n", "sky_direction = SkyCoord(\n", " ra=[2, 6, 7, 4] * u.deg,\n", " dec=[4, 7, 4, 3] * u.deg,\n", @@ -269,37 +297,11 @@ " pm_dec=[1, 1, 1, 1] * u.mas / u.yr,\n", " frame=\"icrs\",\n", ")\n", - "\n", - "# NOTE: astropy skycoord frame casts to default non-unit representation and may alias data\n", "print(\"SkyCoord:\", sky_direction.ra.data[1])\n", "\n", - "# dataset serialization in FRAME mode avoids unit conversions where possible\n", - "ds = skycoord_to_dataset(sky_direction, coords=[(\"field\", [\"a\", \"b\", \"c\", \"d\"])])\n", - "print(\"Dataset:\", ds.ra.data[1].value)\n", - "\n", - "\n", - "sky_position = SkyCoord(\n", - " ra=[2, 6, 7, 4] * u.deg,\n", - " dec=[4, 7, 4, 3] * u.deg,\n", - " distance=[1, 1, 1, 1] * u.dimensionless_unscaled,\n", - " pm_ra_cosdec=[1, 1, 1, 1] * u.mas / u.yr,\n", - " pm_dec=[1, 1, 1, 1] * u.mas / u.yr,\n", - " frame=\"icrs\",\n", - ")\n", - "\n", - "display(sky_position)\n", - "ds = skycoord_to_dataset(sky_position, coords=[(\"field\", [\"a\", \"b\", \"c\", \"d\"])])\n", - "display(ds)\n", - "\n", - "# NOTE: positional representation avoids aliasing\n", - "assert sky_position.ra.data[1] == ds.ra.data[1].value" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# TODO" + "# dataset serialization avoids unit conversions where possible\n", + "ds = skycoord_to_dataset(sky_direction, coords={\"field\": [\"a\", \"b\", \"c\", \"d\"]})\n", + "print(\"Dataset:\", ds.ra.data[1].value)" ] }, { @@ -309,167 +311,27 @@ "outputs": [], "source": [ "import astropy.units as u\n", - "import numpy as np\n", - "import xarray as xr\n", - "from astropy.coordinates import ICRS, SkyCoord\n", + "from astropy.coordinates import SkyCoord\n", + "from astropy.time import Time\n", "\n", "from astropy_xarray.coordinates.sky_coord import (\n", - " DatasetRepresentation,\n", - " dataset_to_skycoord,\n", " skycoord_to_dataset,\n", ")\n", "\n", - "sky_direction = SkyCoord(\n", - " ra=[2, 6, 7, 4] * u.deg,\n", - " dec=[4, 7, 4, 3] * u.deg,\n", - " pm_ra_cosdec=[1, 1, 1, 1] * u.mas / u.yr,\n", - " pm_dec=[1, 1, 1, 1] * u.mas / u.yr,\n", - " frame=\"icrs\",\n", - ")\n", - "assert sky_direction.representation_type.name == \"spherical\"\n", - "assert sky_direction.differential_type.name == \"sphericalcoslat\"\n", - "\n", - "\n", - "# display(sky_direction.distance)\n", - "# display(sky_direction.radial_velocity)\n", - "\n", - "# sky_direction.data.distance\n", - "# sky_direction.data.differentials.get(\"s\").d_distance\n", - "# display(skycoord_to_dataset(sky_direction, coords=[(\"field\", [0, 1, 2, 3])], representation=DatasetRepresentation.FRAME))\n", - "\n", - "# TODO support different dim and coord name\n", - "# ds = skycoord_to_dataset(sky_direction, coords=[(\"field\", [0, 1, 2, 3])], representation=DatasetRepresentation.FRAME)\n", - "ds = skycoord_to_dataset(\n", - " sky_direction,\n", - " coords=[(\"field\", [0, 1, 2, 3])],\n", - " representation=DatasetRepresentation.FRAME_DATA,\n", - ")\n", - "display(ds)\n", - "res = dataset_to_skycoord(ds)\n", - "display(res)\n", - "assert res.representation_type.name == \"spherical\"\n", - "assert res.differential_type.name == \"sphericalcoslat\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sky_direction = SkyCoord(\n", - " ra=[2, 6, 7, 4] * u.deg,\n", - " dec=[4, 7, 4, 3] * u.deg,\n", - " distance=[2, 3, 4, 5] * u.pc,\n", - " pm_ra_cosdec=[1, 1, 1, 1] * u.mas / u.yr,\n", - " pm_dec=[1, 1, 1, 1] * u.mas / u.yr,\n", - " frame=\"icrs\",\n", - ")\n", - "assert sky_direction.frame.representation_type.name == \"spherical\"\n", - "assert sky_direction.frame.differential_type.name == \"sphericalcoslat\"\n", - "\n", - "sky_direction.frame.representation_type = \"cartesian\"\n", - "display(sky_direction)\n", - "assert sky_direction.frame.representation_type.name == \"cartesian\"\n", - "assert sky_direction.frame.differential_type.name == \"cartesian\"\n", - "\n", - "display(sky_direction.represent_as(\"cartesian\"))\n", - "assert type(sky_direction.frame.data).name == \"spherical\"\n", - "\n", - "assert hasattr(sky_direction, \"x\")\n", - "assert hasattr(sky_direction, \"y\")\n", - "assert hasattr(sky_direction, \"z\")\n", - "\n", - "# desired\n", - "# display(sky_direction.frame.data, sky_direction.frame.data.differentials)\n", - "# display(sky_direction.frame.get_representation_component_names())\n", - "# display(sky_direction.frame.represent_as(sky_direction.representation_type))\n", - "\n", - "# failure\n", - "ds = skycoord_to_dataset(\n", - " sky_direction,\n", - " coords=[(\"field\", [0, 1, 2, 3])],\n", - " representation=DatasetRepresentation.FRAME_DATA,\n", - ")\n", - "display(ds)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "ds = skycoord_to_dataset(\n", - " sky_direction,\n", - " coords=[(\"field\", [0, 1, 2, 3])],\n", - " representation=DatasetRepresentation.DATA,\n", - ")\n", - "display(ds)\n", - "\n", - "# # TODO handle mismatch (fallback to data?)\n", - "# ds = skycoord_to_dataset(sky_direction, coords=[(\"field\", [0, 1, 2, 3])], representation=DatasetRepresentation.FRAME_DEFAULT)\n", - "# display(ds)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sky_direction = SkyCoord(\n", - " ra=[2, 6, 7, 4] * u.deg,\n", - " dec=[4, 7, 4, 3] * u.deg,\n", - " distance=[2, 3, 4, 5] * u.pc,\n", - " pm_ra_cosdec=[1, 1, 1, 1] * u.mas / u.yr,\n", - " pm_dec=[1, 1, 1, 1] * u.mas / u.yr,\n", - " # radial_velocity=[1, 1, 1, 1] * u.mas / u.yr,\n", - " frame=\"icrs\",\n", - ")\n", - "assert sky_direction.representation_type.name == \"spherical\"\n", - "assert sky_direction.differential_type.name == \"sphericalcoslat\"\n", - "\n", - "sky_direction.representation_type = \"cartesian\"\n", - "# sky_direction.differential_type = \"cartesian\"\n", - "display(sky_direction)\n", - "assert sky_direction.differential_type.name == \"cartesian\"\n", - "\n", - "sky_direction.represent_as(\"cartesian\", \"cartesian\")\n", - "# TODO fallback to data for missing\n", - "ds = skycoord_to_dataset(\n", - " sky_direction,\n", - " coords=[(\"field\", [0, 1, 2, 3])],\n", - " representation=DatasetRepresentation.FRAME_DATA,\n", - ")\n", - "display(ds)\n", - "assert ds.attrs[\"frame\"][\"data\"][\"representation_type\"] == \"cartesian\", ds.attrs[\n", - " \"frame\"\n", - "][\"data\"][\"representation_type\"]\n", - "\n", - "ds = skycoord_to_dataset(\n", - " sky_direction,\n", - " coords=[(\"field\", [0, 1, 2, 3])],\n", - " representation=DatasetRepresentation.FRAME_DEFAULT,\n", - ")\n", - "display(ds)\n", - "\n", - "ds = skycoord_to_dataset(\n", - " sky_direction,\n", - " coords=[(\"field\", [0, 1, 2, 3])],\n", - " representation=DatasetRepresentation.DATA,\n", + "sc = skycoord_to_dataset(\n", + " SkyCoord(\n", + " ra=[[2, 6, 7, 4]] * u.deg,\n", + " dec=[[4, 7, 4, 3]] * u.deg,\n", + " pm_ra_cosdec=[[1, 1, 1, 1]] * u.mas / u.yr,\n", + " pm_dec=[[1, 1, 1, 1]] * u.mas / u.yr,\n", + " frame=\"icrs\",\n", + " ),\n", + " coords={\n", + " \"timestamp\": (\"time\", Time([1.7e9], format=\"unix\")),\n", + " \"field_label\": (\"field\", [\"a\", \"b\", \"c\", \"d\"]),\n", + " },\n", ")\n", - "display(ds)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "type(sky_direction.frame.data)\n", - "type(sky_direction.frame.data.differentials.get(\"s\"))" + "sc" ] }, { diff --git a/docs/whats-new.rst b/docs/whats-new.rst index 7ce8622c..26a33bee 100644 --- a/docs/whats-new.rst +++ b/docs/whats-new.rst @@ -3,13 +3,24 @@ What's new ========== -0.2 (TBD) ---------- - -- Added `coordinates` submodule with `dataset_to_skycoord` and `skycoord_to_dataset` excplit conversion functions for working with :py:class:`astropy.coordinates.SkyCoord`. - -0.1 (17 Jul 2025) ------------------ +0.2.0 (30 Mar 2026) +------------------- + +- Added `coordinates` submodule with `dataset_to_skycoord` and `skycoord_to_dataset` explicit conversion functions for working with :py:class:`astropy.coordinates.SkyCoord`. +- Added support for specialized quantities: + - :py:class:`astropy.time.Time` + - :py:class:`astropy.time.DeltaTime` + - :py:class:`astropy.coordinates.Angle` + - :py:class:`astropy.coordinates.Longitude` + - :py:class:`astropy.coordinates.Latitude` + - :py:class:`astropy.coordinates.Distance` + - :py:class:`astropy.units.LogQuantity` +- Added :py:meth:`Dataset.astropy.to_skycoord` accessor. + +By `Callan Gray `_. + +0.1.0 (17 Jul 2025) +------------------- - Added `equivalencies` parameter to :py:meth:`DataArray.astropy.to` and :py:meth:`Dataset.astropy.to`. - Removed `registry` parameter from :py:meth:`DataArray.astropy.quantify` and :py:meth:`Dataset.astropy.quantify`.