-
-
Notifications
You must be signed in to change notification settings - Fork 53
Simplify NDCube.to_nddata #892
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
`~ndcube.NDCube` now accepts ``global_coords=`` and ``extra_coords=`` in the constructor of the class. |
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -48,8 +48,6 @@ | |||||||||||||
except ImportError: | ||||||||||||||
pass | ||||||||||||||
|
||||||||||||||
COPY = object() | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
class NDCubeABC(astropy.nddata.NDDataBase): | ||||||||||||||
|
||||||||||||||
|
@@ -381,25 +379,27 @@ class NDCubeBase(NDCubeABC, astropy.nddata.NDData, NDCubeSlicingMixin): | |||||||||||||
_global_coords = NDCubeLinkedDescriptor(GlobalCoords) | ||||||||||||||
|
||||||||||||||
def __init__(self, data, wcs=None, uncertainty=None, mask=None, meta=None, | ||||||||||||||
unit=None, copy=False, **kwargs): | ||||||||||||||
unit=None, copy=False, psf=None, *, extra_coords=None, global_coords=None, **kwargs): | ||||||||||||||
|
||||||||||||||
super().__init__(data, wcs=wcs, uncertainty=uncertainty, mask=mask, | ||||||||||||||
meta=meta, unit=unit, copy=copy, **kwargs) | ||||||||||||||
meta=meta, unit=unit, copy=copy, psf=psf, **kwargs) | ||||||||||||||
|
||||||||||||||
# Enforce that the WCS object is not None | ||||||||||||||
if self.wcs is None: | ||||||||||||||
raise TypeError("The WCS argument can not be None.") | ||||||||||||||
|
||||||||||||||
# Get existing extra_coords if initializing from an NDCube | ||||||||||||||
if hasattr(data, "extra_coords"): | ||||||||||||||
if extra_coords is None and getattr(data, "extra_coords", None) is not None: | ||||||||||||||
extra_coords = data.extra_coords | ||||||||||||||
if extra_coords is not None: | ||||||||||||||
if copy: | ||||||||||||||
extra_coords = deepcopy(extra_coords) | ||||||||||||||
self._extra_coords = extra_coords | ||||||||||||||
|
||||||||||||||
# Get existing global_coords if initializing from an NDCube | ||||||||||||||
if hasattr(data, "global_coords"): | ||||||||||||||
if global_coords is None and getattr(data, "global_coords", None) is not None: | ||||||||||||||
global_coords = data._global_coords | ||||||||||||||
if global_coords is not None: | ||||||||||||||
if copy: | ||||||||||||||
global_coords = deepcopy(global_coords) | ||||||||||||||
self._global_coords = global_coords | ||||||||||||||
|
@@ -1465,24 +1465,28 @@ def fill_masked(self, fill_value, uncertainty_fill_value=None, unmask=False, fil | |||||||||||||
|
||||||||||||||
def to_nddata(self, | ||||||||||||||
*, | ||||||||||||||
data=COPY, | ||||||||||||||
wcs=COPY, | ||||||||||||||
uncertainty=COPY, | ||||||||||||||
mask=COPY, | ||||||||||||||
unit=COPY, | ||||||||||||||
meta=COPY, | ||||||||||||||
psf=COPY, | ||||||||||||||
extra_coords=COPY, | ||||||||||||||
global_coords=COPY, | ||||||||||||||
data=True, | ||||||||||||||
wcs=True, | ||||||||||||||
uncertainty=True, | ||||||||||||||
mask=True, | ||||||||||||||
unit=True, | ||||||||||||||
meta=True, | ||||||||||||||
psf=True, | ||||||||||||||
nddata_type=NDData, | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My only remaining question is if we want to add a |
||||||||||||||
**kwargs, | ||||||||||||||
): | ||||||||||||||
""" | ||||||||||||||
Constructs new type instance with the same attribute values as this `~ndcube.NDCube`. | ||||||||||||||
|
||||||||||||||
Attribute values can be altered on the output object by setting a kwarg with the new | ||||||||||||||
value, e.g. ``data=new_data``. | ||||||||||||||
Any attributes not supported by the new class (``nddata_type``), will be discarded. | ||||||||||||||
Constructs a new `~astropy.nddata.NDData` instance from this object. | ||||||||||||||
|
||||||||||||||
By default all known ``NDData`` attributes are copied (by reference) from | ||||||||||||||
this object, values can be altered on the output object by | ||||||||||||||
setting a kwarg with the new value, e.g. ``data=new_data``. | ||||||||||||||
Custom attributes on this class can be passed by setting that | ||||||||||||||
keyword to `True`, for example ``mycube.to_nddata(spam=True)`` | ||||||||||||||
is the equivalent of setting | ||||||||||||||
``mycube.to_nddata(spam=mycube.spam)``. | ||||||||||||||
Any attributes not supported by the new class | ||||||||||||||
(``nddata_type``), will be discarded. | ||||||||||||||
|
||||||||||||||
Parameters | ||||||||||||||
---------- | ||||||||||||||
|
@@ -1500,16 +1504,11 @@ def to_nddata(self, | |||||||||||||
Metadata object of new instance. Default is to use data of this instance. | ||||||||||||||
psf: Any, optional | ||||||||||||||
PSF object of new instance. Default is to use data of this instance. | ||||||||||||||
extra_coords: `ndcube.ExtraCoordsABC`, optional | ||||||||||||||
Extra coords object of new instance. Default is to use data of this instance. | ||||||||||||||
global_coords: `ndcube.GlobalCoordsABC`, optional | ||||||||||||||
WCS object of new instance. Default is to use data of this instance. | ||||||||||||||
nddata_type: Any, optional | ||||||||||||||
The type of the returned object. Must be a subclass of `~astropy.nddata.NDData` | ||||||||||||||
or a class that behaves like one. Default=`~astropy.nddata.NDData`. | ||||||||||||||
kwargs: | ||||||||||||||
Additional inputs to the ``nddata_type`` constructor that should differ from, | ||||||||||||||
or are not represented by, the attributes of this instance. For example, to | ||||||||||||||
Additional inputs to the ``nddata_type`` constructor. For example, to | ||||||||||||||
set different data values on the returned object, set a kwarg ``data=new_data``, | ||||||||||||||
where ``new_data`` is an array of compatible shape and dtype. Note that kwargs | ||||||||||||||
given by the user and attributes on this instance that are not supported by the | ||||||||||||||
|
@@ -1525,39 +1524,29 @@ def to_nddata(self, | |||||||||||||
Examples | ||||||||||||||
-------- | ||||||||||||||
To create an `~astropy.nddata.NDData` instance which is a copy of an `~ndcube.NDCube` | ||||||||||||||
(called ``cube``) without a WCS, do: | ||||||||||||||
(called ``cube``) without a WCS, do:: | ||||||||||||||
|
||||||||||||||
>>> nddata_without_coords = cube.to_nddata(wcs=None) # doctest: +SKIP | ||||||||||||||
|
||||||||||||||
To create a new `~ndcube.NDCube` instance which is a copy of | ||||||||||||||
an `~ndcube.NDCube` (called ``cube``) without an uncertainty, | ||||||||||||||
but with ``global_coords`` and ``extra_coords`` do:: | ||||||||||||||
|
||||||||||||||
>>> nddata_without_coords = cube.to_nddata(uncertainty=None, global_coords=True, extra_coords=True) # doctest: +SKIP | ||||||||||||||
""" | ||||||||||||||
# Build dictionary of new attribute values from this NDCube instance | ||||||||||||||
# and update with user-defined kwargs. Remove any kwargs not set by user. | ||||||||||||||
# Put all NDData kwargs in a dict | ||||||||||||||
user_kwargs = {"data": data, | ||||||||||||||
"wcs": wcs, | ||||||||||||||
"uncertainty": uncertainty, | ||||||||||||||
"mask": mask, | ||||||||||||||
"unit": unit, | ||||||||||||||
"meta": meta, | ||||||||||||||
"psf": psf, | ||||||||||||||
"extra_coords": extra_coords, | ||||||||||||||
"global_coords": global_coords} | ||||||||||||||
user_kwargs = {key: value for key, value in user_kwargs.items() if value is not COPY} | ||||||||||||||
user_kwargs.update(kwargs) | ||||||||||||||
all_kwargs = {key.strip("_"): value for key, value in self.__dict__.items()} | ||||||||||||||
all_kwargs.update(user_kwargs) | ||||||||||||||
# Inspect call signature of new_nddata class and | ||||||||||||||
# remove unsupported items from new_kwargs. | ||||||||||||||
all_kwargs = {key: value for key, value in all_kwargs.items() | ||||||||||||||
if key in inspect.signature(nddata_type).parameters.keys()} | ||||||||||||||
**kwargs} | ||||||||||||||
# If any are True then copy by reference | ||||||||||||||
user_kwargs = {key: getattr(self, key) if value is True else value for key, value in user_kwargs.items()} | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
# Construct and return new instance. | ||||||||||||||
new_nddata = nddata_type(**all_kwargs) | ||||||||||||||
if isinstance(new_nddata, NDCubeBase): | ||||||||||||||
if extra_coords is COPY: | ||||||||||||||
extra_coords = copy.copy(self._extra_coords) | ||||||||||||||
extra_coords._ndcube = new_nddata | ||||||||||||||
new_nddata._extra_coords = extra_coords | ||||||||||||||
if global_coords is COPY: | ||||||||||||||
new_nddata._global_coords = copy.copy(self._global_coords) | ||||||||||||||
return new_nddata | ||||||||||||||
return nddata_type(**user_kwargs) | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
def _create_masked_array_for_rebinning(data, mask, operation_ignores_mask): | ||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't use
mask=True
here asTrue
is a valid user input formask
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, that's so freaking stupid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The solution to this is that the one user who wants to do this uses
np.True_
rather thanTrue
to set the whole mask to be a single boolean.