diff --git a/README.md b/README.md
index 4e9b97c5..248e48d1 100644
--- a/README.md
+++ b/README.md
@@ -99,17 +99,17 @@ from astropy_xarray.coordinates.sky_coord import (
)
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"]),
- }
+ 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
```
diff --git a/docs/examples/plotting.ipynb b/docs/examples/plotting.ipynb
index 57601e6b..509533c8 100644
--- a/docs/examples/plotting.ipynb
+++ b/docs/examples/plotting.ipynb
@@ -68,7 +68,7 @@
"metadata": {},
"source": [
"
\n",
- "
Note: this example uses the data provided by the
xarray.tutorial functions. As such, the
units attributes follow the CF conventions, which
astropy does not understand by default. To still be able to read them we are using the registry provided by
cf-xarray.\n",
+ "
Note: this example uses the data provided by the
xarray.tutorial functions. As such, the
units attributes follow the CF conventions, which
astropy does not understand by default. To still be able to read them, registry be aliases can be used. For more information, see
cf-xarray.\n",
"
"
]
},
@@ -107,7 +107,7 @@
"id": "9",
"metadata": {},
"source": [
- "Most operations will preserve the units but there are some which will drop them (see the [duck array integration status](https://xarray.pydata.org/en/stable/user-guide/duckarrays.html#missing-features) page). To work around that there are unit-aware versions on the `.pint` accessor. For example, to select data use `.astropy.sel` instead of `.sel`:"
+ "Most operations will preserve the units but there are some which will drop them (see the [duck array integration status](https://xarray.pydata.org/en/stable/user-guide/duckarrays.html#missing-features) page). To work around that there are unit-aware versions on the `.astropy` accessor. For example, to select data use `.astropy.sel` instead of `.sel`:"
]
},
{
@@ -142,127 +142,6 @@
"source": [
"monthly_means.astropy.dequantify(format=\"unicode\").plot.imshow(col=\"month\", col_wrap=4)"
]
- },
- {
- "cell_type": "markdown",
- "id": "13",
- "metadata": {},
- "source": [
- "## Time\n",
- "\n",
- "astropy-xarray patches Time and DeltaTime to be recognized xarray, capturing:\n",
- "* format\n",
- "* timescale\n",
- "* precision"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "14",
- "metadata": {},
- "outputs": [],
- "source": [
- "from astropy.time import Time, TimeDelta\n",
- "\n",
- "ds = xr.Dataset(\n",
- " data_vars={\n",
- " \"f_time\": (\"time_idx\", Time([0, 1, 2], format=\"unix\", scale=\"utc\")),\n",
- " \"i_time\": (\n",
- " \"time_idx\",\n",
- " Time([0, 1, 2], format=\"unix\", scale=\"utc\").copy(\"datetime64\"),\n",
- " ),\n",
- " \"s_time\": (\n",
- " \"time_idx\",\n",
- " Time([0, 1, 2], format=\"unix\", scale=\"utc\").copy(\"isot\"),\n",
- " ),\n",
- " \"interval\": (\"time_idx\", TimeDelta([0.9, 0.9, 0.9], format=\"sec\", scale=\"tai\")),\n",
- " \"temp\": (\"time_idx\", u.Quantity([0, 1, 2], \"K\")),\n",
- " },\n",
- " coords=xr.Coordinates(\n",
- " {\n",
- " \"time_idx\": [0, 1, 2],\n",
- " }\n",
- " ),\n",
- ")\n",
- "ds"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "15",
- "metadata": {},
- "outputs": [],
- "source": [
- "ds = ds.astropy.dequantify()\n",
- "ds.i_time"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "16",
- "metadata": {},
- "source": [
- "## SkyCoord, Frame and Angle\n",
- "\n",
- "SkyCoord and Frame fully support conversion to datasets preserving:\n",
- "* Representation\n",
- "* Differential\n",
- "* Frame\n",
- "* Angle, Longitude, Latitude containers\n",
- "\n",
- "Conversion optionally requires coords argument for applying named coordinates to data variable axes.\n",
- "\n",
- "Frame-specific mapped names for data variables coming soon."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "17",
- "metadata": {},
- "outputs": [],
- "source": [
- "from astropy.coordinates import SkyCoord\n",
- "\n",
- "from astropy_xarray.coordinates.sky_coord import (\n",
- " dataset_to_skycoord,\n",
- " skycoord_to_dataset,\n",
- ")\n",
- "\n",
- "sc = 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",
- "\n",
- "\n",
- "s = skycoord_to_dataset(sc, coords=[(\"field\", [0, 1, 2, 3])])\n",
- "\n",
- "display(s)\n",
- "s.astropy.dequantify()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "18",
- "metadata": {},
- "outputs": [],
- "source": [
- "display(dataset_to_skycoord(s))"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "19",
- "metadata": {},
- "outputs": [],
- "source": []
}
],
"metadata": {
diff --git a/docs/examples/skycoord.ipynb b/docs/examples/skycoord.ipynb
index 668ec671..2e38510e 100644
--- a/docs/examples/skycoord.ipynb
+++ b/docs/examples/skycoord.ipynb
@@ -304,36 +304,6 @@
"print(\"Dataset:\", ds.ra.data[1].value)"
]
},
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {},
- "outputs": [],
- "source": [
- "import astropy.units as u\n",
- "from astropy.coordinates import SkyCoord\n",
- "from astropy.time import Time\n",
- "\n",
- "from astropy_xarray.coordinates.sky_coord import (\n",
- " skycoord_to_dataset,\n",
- ")\n",
- "\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",
- "sc"
- ]
- },
{
"cell_type": "code",
"execution_count": null,
diff --git a/docs/examples/specialized_quantities.ipynb b/docs/examples/specialized_quantities.ipynb
new file mode 100644
index 00000000..e2733a13
--- /dev/null
+++ b/docs/examples/specialized_quantities.ipynb
@@ -0,0 +1,284 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "0",
+ "metadata": {},
+ "source": [
+ "# Specialized Quantities\n",
+ "\n",
+ "Beyond `astropy.units.Quantity`, astropy provides further specialized quantities. `astropy-xarray` captures this using the `units.class` attribute."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import xarray as xr\n",
+ "from astropy import units as u"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2",
+ "metadata": {},
+ "source": [
+ "## Time and TimeDelta\n",
+ "\n",
+ "`astropy_xarray` patches `astropy.time.Time` and `astropy.time.TimeDelta` to be recognized xarray, capturing:\n",
+ "* format\n",
+ "* timescale\n",
+ "* precision"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from astropy.time import Time, TimeDelta\n",
+ "\n",
+ "import astropy_xarray # noqa: F401\n",
+ "\n",
+ "ds = xr.Dataset(\n",
+ " data_vars={\n",
+ " \"d_time\": (\n",
+ " \"time\",\n",
+ " Time([0, 1, 2], format=\"unix\", scale=\"utc\").copy(\"datetime64\"),\n",
+ " ),\n",
+ " \"s_time\": (\n",
+ " \"time\",\n",
+ " Time([0, 1, 2], format=\"unix\", scale=\"utc\").copy(\"isot\"),\n",
+ " ),\n",
+ " \"interval\": (\"time\", TimeDelta([0.9, 0.9, 0.9], format=\"sec\", scale=\"tai\")),\n",
+ " },\n",
+ " coords=xr.Coordinates(\n",
+ " {\n",
+ " \"f_time\": (\"time\", Time([0, 1, 2], format=\"unix\", scale=\"utc\")),\n",
+ " }\n",
+ " ),\n",
+ ")\n",
+ "ds"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# dequantified attributes\n",
+ "ds.astropy.dequantify()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5",
+ "metadata": {},
+ "source": [
+ "## SkyCoord, Frame and Angle\n",
+ "\n",
+ "SkyCoord and Frame fully support conversion to datasets preserving:\n",
+ "* Representation\n",
+ "* Differential\n",
+ "* Frame\n",
+ "* Angle, Longitude, Latitude containers\n",
+ "\n",
+ "Conversion optionally requires coords argument for applying named coordinates to data variable axes.\n",
+ "\n",
+ "Frame-specific mapped names for data variables coming soon."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from astropy.coordinates import SkyCoord\n",
+ "\n",
+ "from astropy_xarray.coordinates.sky_coord import (\n",
+ " skycoord_to_dataset,\n",
+ ")\n",
+ "\n",
+ "sc = SkyCoord(\n",
+ " ra=[2, 6, 7, 4] * u.deg,\n",
+ " dec=[4, 7, 4, 3] * u.deg,\n",
+ ")\n",
+ "\n",
+ "\n",
+ "s = skycoord_to_dataset(sc, coords={\"field\": [\"a\", \"b\", \"c\", \"d\"]})\n",
+ "display(s)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7",
+ "metadata": {},
+ "source": [
+ "## Logarithmic Units and Quantities\n",
+ "\n",
+ "Astropy provides a generic `LogQuantity` and other various log scale specialized classes and units:\n",
+ "\n",
+ "$$scalar = A * log_{B}(\\frac{V}{V_0})$$\n",
+ "\n",
+ "\n",
+ "| Name | Equiv SI Unit | Scale Factor | Log Base | 0 Reference |\n",
+ "| --------------------| ------------- | -------------- | --------- | ---------------------------------------|\n",
+ "| Magnitude (absolute)| Unitless | -2.5 | 10 | Apparent brightness at 10pc away |\n",
+ "| Dex | Unitless | 1 | 10 | 1 |\n",
+ "| Decibels (power) | Unitless | 10 | 10 | Variable |\n",
+ "| Decibels (amplitude)| Unitless | 20 | 10 | Variable |\n",
+ "| Magnitude (apparent)| Unitless | -2.5 | 10 | Usually Vega or AB from Earth |\n",
+ "| Magnitude (AB) | Jy | -2.5 | 10 | 3631 Jy |"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import types\n",
+ "\n",
+ "import astropy.units\n",
+ "import astropy.units as u\n",
+ "import numpy as np\n",
+ "from astropy.units import Dex, Equivalency, Magnitude, Quantity\n",
+ "\n",
+ "import astropy_xarray # noqa: F401\n",
+ "\n",
+ "\n",
+ "# extend registry\n",
+ "def asplund():\n",
+ " asplund = types.ModuleType(\"asplund\")\n",
+ " astropy.units.def_unit(\n",
+ " [\"solH\", \"Xsun\"],\n",
+ " format={\"latex\": \"X_{\\\\odot}\", \"unicode\": \"X⊙\"},\n",
+ " namespace=asplund.__dict__,\n",
+ " )\n",
+ " astropy.units.def_unit(\n",
+ " [\"solHe\", \"Ysun\"],\n",
+ " format={\"latex\": \"Y_{\\\\odot}\", \"unicode\": \"Y⊙\"},\n",
+ " namespace=asplund.__dict__,\n",
+ " )\n",
+ " astropy.units.def_unit(\n",
+ " [\"solMetal\", \"Zsun\"],\n",
+ " format={\"latex\": \"Z_{\\\\odot}\", \"unicode\": \"Z⊙\"},\n",
+ " namespace=asplund.__dict__,\n",
+ " )\n",
+ "\n",
+ " return asplund\n",
+ "\n",
+ "\n",
+ "if not hasattr(u, \"asplund\"):\n",
+ " u.asplund = asplund()\n",
+ " u.add_enabled_units(u.asplund)\n",
+ " u.__dict__.update(u.get_current_unit_registry().registry)\n",
+ "\n",
+ "\n",
+ "def asplund_solar_relative_mass() -> Equivalency:\n",
+ " \"\"\"measurements from https://www.aanda.org/articles/aa/full_html/2021/09/aa40445-21/aa40445-21.html\"\"\"\n",
+ " return Equivalency(\n",
+ " [\n",
+ " (u.Xsun, u.Msun, lambda x: x * 0.7438),\n",
+ " (u.Ysun, u.Msun, lambda x: x * 0.2423),\n",
+ " (u.Zsun, u.Msun, lambda x: x * 0.0139),\n",
+ " ]\n",
+ " )\n",
+ "\n",
+ "\n",
+ "if not hasattr(u, \"asplund_solar_relative_mass\"):\n",
+ " u.asplund_solar_relative_mass = asplund_solar_relative_mass\n",
+ " # uncomment for implicit conversions\n",
+ " # u.add_enabled_equivalencies(u.asplund_solar_relative_mass())"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "ds = xr.Dataset(\n",
+ " coords=xr.Coordinates(\n",
+ " {\n",
+ " \"timestamp\": (\"time\", Time([1.7e9], format=\"unix\")),\n",
+ " \"body_label\": (\"body\", [\"sun\", \"proxima centauri\"]),\n",
+ " \"wavelength\": (\"frequency\", [565, 535, 445] * u.nm),\n",
+ " }\n",
+ " ),\n",
+ " data_vars={\n",
+ " \"mass\": ([\"time\", \"body\"], Dex([[0.0, 0.02]], unit=u.dex(u.Msun))),\n",
+ " \"distance\": ([\"time\", \"body\"], [[1.007, 12950]] * u.AU),\n",
+ " \"luminosity\": (\n",
+ " [\"time\", \"body\"],\n",
+ " Quantity([[1, 0.001]], unit=u.Lsun).to(u.dex(u.Lsun)),\n",
+ " ), # radiant flux\n",
+ " \"metallicity\": ([\"time\", \"body\"], Dex([[0.0, np.nan]], unit=u.dex(u.Zsun))),\n",
+ " \"apparent_magnitude\": (\n",
+ " [\"time\", \"body\"],\n",
+ " Magnitude([[-26.74, 10.67]]),\n",
+ " ), # to Vega\n",
+ " \"absolute_magnitude\": ([\"time\", \"body\"], Magnitude([[4.83, 15.60]])),\n",
+ " # \"irradiance\": ([\"time\", \"body\"], [[1361, 0]] * u.W / u.m**2),\n",
+ " # \"radiant_flux_density\": ([\"time\", \"body\"], [[1.0, 0.0]] * u.W / u.m**2),\n",
+ " # \"spectral_flux_density\": ([\"time\", \"body\", \"frequency\"], [[[68000, 0, 0], [0, 0, 0]]] * u.Jy),\n",
+ " },\n",
+ ")\n",
+ "ds"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "10",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "ds.astropy.sel(body=[0]).astropy.to(\n",
+ " {\n",
+ " \"mass\": u.kg,\n",
+ " \"distance\": u.km,\n",
+ " \"illuminance\": u.cd * u.sr / u.m**2,\n",
+ " \"luminosity\": u.kW,\n",
+ " \"metallicity\": u.kg,\n",
+ " },\n",
+ " equivalencies=asplund_solar_relative_mass(),\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "11",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/docs/requirements.txt b/docs/requirements.txt
index 2aa1e0ef..67f127a4 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -3,7 +3,7 @@ xarray>=2022.06.0
pooch
netCDF4
cf-xarray>=0.6
-sphinx
+sphinx>=8.0.0,<9.0.0
sphinx_rtd_theme>=1.0
ipython
ipykernel
diff --git a/docs/whats-new.rst b/docs/whats-new.rst
index 26a33bee..fb2b9e90 100644
--- a/docs/whats-new.rst
+++ b/docs/whats-new.rst
@@ -3,13 +3,13 @@
What's new
==========
-0.2.0 (30 Mar 2026)
+0.2.0 (31 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.time.TimeDelta`
- :py:class:`astropy.coordinates.Angle`
- :py:class:`astropy.coordinates.Longitude`
- :py:class:`astropy.coordinates.Latitude`
diff --git a/pyproject.toml b/pyproject.toml
index 08c9a738..281dc117 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -47,7 +47,7 @@ test = [
"bottleneck",
]
docs = [
- "sphinx>=8.0",
+ "sphinx==8.2.3",
"sphinx_auto_summary_accessors",
"nbsphinx",
"sphinx_rtd_theme",