Skip to content

Commit 8e65d49

Browse files
authored
Merge pull request #276 from Cadair/wcs-_naxis
Fix two WCS bugs
2 parents 12a97de + 97556cc commit 8e65d49

File tree

7 files changed

+160
-5
lines changed

7 files changed

+160
-5
lines changed

CHANGES.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
- Add support for asdf-transform-schemas 0.6 and asdf-coordinates-schemas 0.4. [#279]
1414
- Ignore UnitsWarnings emitted by astropy when converting units to VO format. [#281]
1515
- Add support for new astronomy-1.1.0 manifest. [#282]
16+
- Serialize ``pixel_shape`` on ``astropy.wcs.WCS``. [#276]
17+
- Accept a gwcs object when serializing ``SlicedLowLevelWCS``. [#276]
1618

1719
0.7.1 (2025-02-12)
1820
------------------

asdf_astropy/converters/wcs/tests/test_wcs.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@
66
from astropy.utils.data import get_pkg_data_filename, get_pkg_data_filenames
77
from astropy.wcs import WCS, DistortionLookupTable, FITSFixedWarning, Sip
88

9+
from asdf_astropy.exceptions import InconsistentWCSError
910
from asdf_astropy.testing.helpers import assert_wcs_roundtrip
1011

11-
_astropy_test_header_filenames = list(get_pkg_data_filenames("tests/data/maps", "astropy.wcs", "*.hdr")) + list(
12-
get_pkg_data_filenames("tests/data/spectra", "astropy.wcs", "*.hdr"),
13-
)
12+
_astropy_test_header_filenames = list(get_pkg_data_filenames("tests/data/maps", "astropy.wcs", "*.hdr"))
1413

1514
_astropy_test_fits_filenames = [
1615
get_pkg_data_filename(f"tests/data/{fn}", "astropy.wcs")
@@ -118,3 +117,11 @@ def test_astropy_data_fits_roundtrip(fn, tmp_path, version):
118117
wcs = WCS(ff[0].header, ff)
119118

120119
assert_wcs_roundtrip(wcs, tmp_path, version)
120+
121+
122+
@pytest.mark.parametrize("attr", ["pixel_shape", "pixel_bounds"])
123+
def test_failure_to_convert_inconsistent(tmp_path, attr):
124+
wcs = create_wcs_with_attrs()
125+
wcs.naxis -= 1
126+
with pytest.raises(InconsistentWCSError, match="does not match naxis"):
127+
assert_wcs_roundtrip(wcs, tmp_path)

asdf_astropy/converters/wcs/wcs.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
from asdf.extension import Converter
22

3+
from asdf_astropy.exceptions import InconsistentWCSError
4+
35
# These attributes don't end up in the hdulist and
46
# instead will be stored in "attrs"
5-
_WCS_ATTRS = ("naxis", "colsel", "keysel", "key", "pixel_bounds")
7+
_WCS_ATTRS = ("naxis", "colsel", "keysel", "key", "pixel_bounds", "pixel_shape")
68

79

810
class WCSConverter(Converter):
@@ -18,20 +20,34 @@ def from_yaml_tree(self, node, tag, ctx):
1820
if naxis := attrs.pop("naxis"):
1921
hdulist[0].header["naxis"] = naxis
2022

23+
# pop attrs that are not valid kwargs
24+
pixel_shape = attrs.pop("pixel_shape")
2125
pixel_bounds = attrs.pop("pixel_bounds")
2226

2327
wcs = WCS(hdulist[0].header, fobj=hdulist, **attrs)
2428

29+
wcs.pixel_shape = pixel_shape
30+
wcs.pixel_bounds = pixel_bounds
31+
2532
if wcs.sip is not None:
2633
# work around a bug in astropy where sip headers lose precision
2734
# see https://github.com/astropy/astropy/issues/17334
2835
wcs.sip = wcs._read_sip_kw(hdulist[0].header, attrs.get("key", " "))
2936
wcs.wcs.set()
3037

31-
wcs.pixel_bounds = pixel_bounds
3238
return wcs
3339

3440
def to_yaml_tree(self, wcs, tag, ctx):
41+
# Check that wcs is consistent. Astropy inconsistently checks
42+
# that certain expected attributes match. We need to check this
43+
# here to prevent writing inconsistent files that would be problematic
44+
# to open.
45+
if naxis := wcs.naxis:
46+
for attr in ("pixel_shape", "pixel_bounds"):
47+
if value := getattr(wcs, attr):
48+
if len(value) != naxis:
49+
msg = f"{attr} shape ({len(value)}) does not match naxis ({naxis})"
50+
raise InconsistentWCSError(msg)
3551
hdulist = wcs.to_fits(relax=True)
3652
attrs = {a: getattr(wcs, a) for a in _WCS_ATTRS if hasattr(wcs, a)}
3753
return {"hdulist": hdulist, "attrs": attrs}

asdf_astropy/exceptions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
class InconsistentWCSError(ValueError):
2+
"""
3+
An error for a WCS with inconsistent attributes.
4+
"""

asdf_astropy/extensions.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,7 @@
540540

541541

542542
_ASTROPY_EXTENSION_MANIFEST_URIS = [
543+
"asdf://astropy.org/astropy/manifests/astropy-1.4.0",
543544
"asdf://astropy.org/astropy/manifests/astropy-1.3.0",
544545
"asdf://astropy.org/astropy/manifests/astropy-1.2.0",
545546
"asdf://astropy.org/astropy/manifests/astropy-1.1.0",
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
id: asdf://astropy.org/astropy/manifests/astropy-1.4.0
2+
extension_uri: asdf://astropy.org/astropy/extensions/astropy-1.4.0
3+
title: Astropy extension 1.4.0
4+
description: |-
5+
A set of tags for serializing astropy objects. This does not include most
6+
model classes, which are handled by an implementation of the ASDF
7+
transform extension.
8+
asdf_standard_requirement:
9+
gte: 1.6.0
10+
tags:
11+
- tag_uri: tag:astropy.org:astropy/time/timedelta-1.1.0
12+
schema_uri: http://astropy.org/schemas/astropy/time/timedelta-1.1.0
13+
title: Represents an instance of TimeDelta from astropy
14+
description: |-
15+
Represents the time difference between two times.
16+
- tag_uri: tag:astropy.org:astropy/fits/fits-1.1.0
17+
schema_uri: http://astropy.org/schemas/astropy/fits/fits-1.1.0
18+
title: A FITS file inside of an ASDF file.
19+
description: |-
20+
This schema is useful for distributing ASDF files that can
21+
automatically be converted to FITS files by specifying the exact
22+
content of the resulting FITS file.
23+
24+
Not all kinds of data in FITS are directly representable in ASDF.
25+
For example, applying an offset and scale to the data using the
26+
`BZERO` and `BSCALE` keywords. In these cases, it will not be
27+
possible to store the data in the native format from FITS and also
28+
be accessible in its proper form in the ASDF file.
29+
30+
Only image and binary table extensions are supported.
31+
- tag_uri: tag:astropy.org:astropy/table/table-1.2.0
32+
schema_uri: http://astropy.org/schemas/astropy/table/table-1.2.0
33+
title: A table.
34+
description: |-
35+
A table is represented as a list of columns, where each entry is a
36+
[column](ref:http://stsci.edu/schemas/asdf/table/column-1.1.0)
37+
object, containing the data and some additional information.
38+
39+
The data itself may be stored inline as text, or in binary in either
40+
row- or column-major order by use of the `strides` property on the
41+
individual column arrays.
42+
43+
Each column in the table must have the same first (slowest moving)
44+
dimension.
45+
- tag_uri: tag:astropy.org:astropy/transform/units_mapping-1.1.0
46+
schema_uri: http://astropy.org/schemas/astropy/transform/units_mapping-1.1.0
47+
title: Mapper that operates on the units of the input.
48+
description: |-
49+
This transform operates on the units of the input, first converting to
50+
the expected input units, then assigning replacement output units without
51+
further conversion.
52+
- tag_uri: tag:astropy.org:astropy/table/ndarraymixin-1.0.0
53+
schema_uri: http://astropy.org/schemas/astropy/table/ndarraymixin-1.0.0
54+
title: NdarrayMixin column.
55+
description: |-
56+
Represents an astropy.table.NdarrayMixin instance.
57+
- tag_uri: tag:astropy.org:astropy/wcs/slicedwcs-1.1.0
58+
schema_uri: http://astropy.org/schemas/astropy/wcs/slicedwcs-1.1.0
59+
title: Represents an instance of SlicedLowLevelWCS
60+
description: |-
61+
The SlicedLowLevelWCS class is a wrapper class for WCS that applies slices
62+
to the WCS, allowing certain pixel and world dimensions to be retained or
63+
dropped.
64+
65+
It manages the slicing and coordinate transformations while preserving
66+
the underlying WCS object.
67+
- tag_uri: tag:astropy.org:astropy/wcs/wcs-1.0.0
68+
schema_uri: http://astropy.org/schemas/astropy/wcs/wcs-1.0.0
69+
title: FITS WCS (World Coordinate System) Converter
70+
description: |-
71+
Represents the FITS WCS object, the HDUlist of the FITS header is preserved
72+
during serialization and during deserialization the WCS object is recreated
73+
from the HDUlist.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
%YAML 1.1
2+
---
3+
$schema: "http://stsci.edu/schemas/yaml-schema/draft-01"
4+
id: "http://astropy.org/schemas/astropy/wcs/slicedwcs-1.1.0"
5+
6+
title: Represents the SlicedLowLevelWCS object
7+
8+
description: >-
9+
The SlicedLowLevelWCS class is a wrapper class for WCS that applies slices
10+
to the WCS, allowing certain pixel and world dimensions to be retained or
11+
dropped.
12+
It manages the slicing and coordinate transformations while preserving
13+
the underlying WCS object.
14+
15+
allOf:
16+
- type: object
17+
properties:
18+
wcs:
19+
anyOf:
20+
# Known WCS objects
21+
- tag: "tag:astropy.org:astropy/wcs/wcs-1*"
22+
- tag: "tag:stsci.edu:gwcs/wcs-*"
23+
- tag: "tag:astropy.org:astropy/wcs/slicedwcs-*"
24+
- tag: "tag:sunpy.org:ndcube/resampledwcs-*"
25+
- tag: "tag:sunpy.org:ndcube/ndcubesequence-*"
26+
- tag: "tag:sunpy.org:ndcube/reorderedwcs-*"
27+
- tag: "tag:sunpy.org:ndcube/compoundwcs-*"
28+
# Allow anything else because any APE-14 compliant object is valid
29+
- {}
30+
31+
slices_array:
32+
type: array
33+
items:
34+
- oneOf:
35+
- type: integer
36+
- type: object
37+
properties:
38+
start:
39+
anyOf:
40+
- type: integer
41+
- type: "null"
42+
stop:
43+
anyOf:
44+
- type: integer
45+
- type: "null"
46+
step:
47+
anyOf:
48+
- type: integer
49+
- type: "null"
50+
51+
52+
required: ["wcs", "slices_array"]

0 commit comments

Comments
 (0)