Description
wcs's cdelt, crval and cd setters pass their argument through set_double_array, which converts any array-like to doubles. A Quantity therefore has its unit silently discarded and its magnitude reinterpreted in whatever cunit currently is.
This isn't new and isn't specific to the preserve_units kwarg, but preserve_units makes it much easier to hit, because it changes which unit is the "right" one. On the default path a WCS built from an arcsec header has been normalised to degrees, so cdelt = 1 * u.arcsec means one degree; with preserve_units=True the same WCS reports arcsec, so cdelt = 1 * u.deg means one arcsecond.
Expected behavior
I expected that, since the setter happily accepts a u.Quantity that it would also be using the unit in the calculation to set the cdelt. It should either reject quantities as input or convert them in a unit-aware fashion.
How to Reproduce
import astropy.units as u
from astropy.wcs import WCS
header = {"CTYPE1": "HPLN-TAN", "CTYPE2": "HPLT-TAN",
"CUNIT1": "arcsec", "CUNIT2": "arcsec",
"CDELT1": 2.0, "CDELT2": 2.0,
"CRPIX1": 1.0, "CRPIX2": 1.0, "CRVAL1": 0.0, "CRVAL2": 0.0}
# Default: astropy normalises the WCS to degrees
w = WCS(header)
w.wcs.cdelt = [1, 1] * u.arcsec
print(w.wcs.cdelt[0], w.wcs.cunit[0]) # 1.0 deg <- but asked for arcsec
# preserve_units=True: the WCS stays in arcsec
w = WCS(header, preserve_units=True)
w.wcs.cdelt = [1, 1] * u.deg
print(w.wcs.cdelt[0], w.wcs.cunit[0]) # 1.0 arcsec <- asked for degrees
Versions
platform
--------
platform.platform() = 'Linux-6.6.87.2-microsoft-standard-WSL2-x86_64-with-glibc2.35'
platform.version() = '#1 SMP PREEMPT_DYNAMIC Thu Jun 5 18:30:46 UTC 2025'
platform.python_version() = '3.13.8'
packages
--------
astropy 8.1.0.dev663+g1f930be7c.d20260928
numpy 2.5.3
scipy 1.17.1
matplotlib 3.10.9
pandas 3.0.5
pyerfa 2.0.1.5
Description
wcs's cdelt, crval and cd setters pass their argument through set_double_array, which converts any array-like to doubles. A Quantity therefore has its unit silently discarded and its magnitude reinterpreted in whatever cunit currently is.
This isn't new and isn't specific to the preserve_units kwarg, but preserve_units makes it much easier to hit, because it changes which unit is the "right" one. On the default path a WCS built from an arcsec header has been normalised to degrees, so cdelt = 1 * u.arcsec means one degree; with preserve_units=True the same WCS reports arcsec, so cdelt = 1 * u.deg means one arcsecond.
Expected behavior
I expected that, since the setter happily accepts a u.Quantity that it would also be using the unit in the calculation to set the cdelt. It should either reject quantities as input or convert them in a unit-aware fashion.
How to Reproduce
Versions