Skip to content
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

[map_branch] Moved data methods on mapbase to deprecated mixins #7592

Merged
merged 17 commits into from
Apr 27, 2024
1 change: 1 addition & 0 deletions changelog/7592.removal.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Deprecated several data methods on map in favour of ``sunpy.map.GenericMap.data.<method_name>``.
22 changes: 11 additions & 11 deletions docs/how_to/create_custom_map.rst
Original file line number Diff line number Diff line change
Expand Up @@ -157,18 +157,18 @@ From these header MetaDict's that are generated, we can now create a custom map:
<sunpy.map.mapbase.GenericMap object at ...>
SunPy Map
---------
Observatory: Test case
Instrument: UV detector
Observatory: Test case
Instrument: UV detector
Detector:
Measurement: 1000.0 Angstrom
Wavelength: 1000.0 Angstrom
Observation Date: 2013-10-28 00:00:00
Exposure Time: Unknown
Dimension: [10. 10.] pix
Coordinate System: helioprojective
Scale: [2. 2.] arcsec / pix
Reference Pixel: [5. 5.] pix
Reference Coord: [0. 0.] arcsec
Measurement: 1000.0 Angstrom
Wavelength: 1000.0 Angstrom
Observation Date: 2013-10-28 00:00:00
Exposure Time: Unknown
Pixel Dimensions: [10. 10.]
Coordinate System: helioprojective
Scale: [2. 2.] arcsec / pix
Reference Pixel: [5. 5.] pix
Reference Coord: [0. 0.] arcsec
array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
[20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
Expand Down
65 changes: 8 additions & 57 deletions sunpy/map/mapbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,14 @@
from sunpy.image.resample import resample as sunpy_image_resample
from sunpy.image.resample import reshape_image_to_4d_superpixel
from sunpy.image.transform import _get_transform_method, _rotation_function_names, affine_transform
from sunpy.map.mixins.mapdeprecate import MapDeprecateMixin
from sunpy.map.mixins.mapmeta import MapMetaMixin
from sunpy.util import MetaDict
from sunpy.util.decorators import add_common_docstring, cached_property_based_on
from sunpy.util.exceptions import warn_user
from sunpy.util.functools import seconddispatch
from sunpy.util.util import _figure_to_base64, fix_duplicate_notes
from sunpy.visualization.plotter.mpl_plotter import MapPlotter
from .mixins.mapmeta import MapMetaMixin, PixelPair

TIME_FORMAT = config.get("general", "time_format")
_NUMPY_COPY_IF_NEEDED = False if np.__version__.startswith("1.") else None
Expand Down Expand Up @@ -96,7 +97,7 @@
__all__ = ['GenericMap']


class GenericMap(MapMetaMixin, NDCube):
class GenericMap(MapDeprecateMixin, MapMetaMixin, NDCube):
"""
A Generic spatially-aware 2D data array

Expand Down Expand Up @@ -217,14 +218,9 @@ def __init__(self, data, *, wcs=None, uncertainty=None, mask=None, meta,

params = list(inspect.signature(NDCube).parameters)
ndcube_kwargs = {x: kwargs.pop(x) for x in params & kwargs.keys()}
super().__init__(data, wcs=None, uncertainty=uncertainty, mask=mask,
super().__init__(data, wcs=wcs, uncertainty=uncertainty, mask=mask,
meta=MetaDict(meta), unit=unit, copy=copy,
**ndcube_kwargs)
# NDData.__init__ sets self.wcs before it sets self.meta as our wcs
# setter needs self.meta to exist we call the parent __init__ with
# wcs=None and then set self.wcs so that meta is already set before the
# wcs setter is run with the "real" wcs.
self.wcs = wcs

# Validate header
# TODO: This should be a function of the header, not of the map
Expand Down Expand Up @@ -284,7 +280,7 @@ def _text_summary(self):
Wavelength:\t\t {wave}
Observation Date:\t {date}
Exposure Time:\t\t {dt}
Dimension:\t\t {dim}
Pixel Dimensions:\t\t {dim}
Coordinate System:\t {coord}
Scale:\t\t\t {scale}
Reference Pixel:\t {refpix}
Expand All @@ -293,7 +289,7 @@ def _text_summary(self):
meas=measurement, wave=wave,
date=self.date.strftime(TIME_FORMAT),
dt=dt,
dim=u.Quantity(self.dimensions),
dim=u.Quantity(self.shape[::-1]),
scale=u.Quantity(self.scale),
coord=self._coordinate_frame_name,
refpix=u.Quantity(self.reference_pixel),
Expand Down Expand Up @@ -555,51 +551,6 @@ def _as_mpl_axes(self):
# This code is reused from Astropy
return WCSAxes, {'wcs': self.wcs}

# Some numpy extraction
@property
def dimensions(self):
"""
The dimensions of the array (x axis first, y axis second).
"""
return PixelPair(*u.Quantity(np.flipud(self.data.shape), 'pixel'))

@property
def dtype(self):
"""
The `numpy.dtype` of the array of the map.
"""
return self.data.dtype

@property
def ndim(self):
"""
The value of `numpy.ndarray.ndim` of the data array of the map.
"""
return self.data.ndim

def std(self, *args, **kwargs):
"""
Calculate the standard deviation of the data array, ignoring NaNs.
"""
return np.nanstd(self.data, *args, **kwargs)

def mean(self, *args, **kwargs):
"""
Calculate the mean of the data array, ignoring NaNs.
"""
return np.nanmean(self.data, *args, **kwargs)

def min(self, *args, **kwargs):
"""
Calculate the minimum value of the data array, ignoring NaNs.
"""
return np.nanmin(self.data, *args, **kwargs)

def max(self, *args, **kwargs):
"""
Calculate the maximum value of the data array, ignoring NaNs.
"""
return np.nanmax(self.data, *args, **kwargs)

@u.quantity_input
def shift_reference_coord(self, axis1: u.deg, axis2: u.deg):
Expand Down Expand Up @@ -794,8 +745,8 @@ def resample(self, dimensions: u.pixel, method='linear'):
method, center=True)
new_data = new_data.T

scale_factor_x = float(self.dimensions[0] / dimensions[0])
scale_factor_y = float(self.dimensions[1] / dimensions[1])
scale_factor_x = float(self.shape[1] / dimensions[0].value)
scale_factor_y = float(self.shape[0] / dimensions[1].value)

# Update image scale and number of pixels
new_meta = self.meta.copy()
Expand Down
4 changes: 2 additions & 2 deletions sunpy/map/mapsequence.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@

if resample:
if self.all_maps_same_shape():
resample = u.Quantity(self.maps[0].dimensions) * np.array(resample)
resample = u.Quantity(self.maps[0].shape) * np.array(resample)

Check warning on line 350 in sunpy/map/mapsequence.py

View check run for this annotation

Codecov / codecov/patch

sunpy/map/mapsequence.py#L350

Added line #L350 was not covered by tests
ani_data = [amap.resample(resample) for amap in self.maps]
else:
raise ValueError('Maps in mapsequence do not all have the same shape.')
Expand Down Expand Up @@ -465,7 +465,7 @@
if resample:
if self.all_maps_same_shape():
plot_sequence = MapSequence()
resample = u.Quantity(self.maps[0].dimensions) * np.array(resample)
resample = u.Quantity(self.maps[0].shape) * np.array(resample)

Check warning on line 468 in sunpy/map/mapsequence.py

View check run for this annotation

Codecov / codecov/patch

sunpy/map/mapsequence.py#L468

Added line #L468 was not covered by tests
for amap in self.maps:
plot_sequence.maps.append(amap.resample(resample))
else:
Expand Down
2 changes: 1 addition & 1 deletion sunpy/map/maputils.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def map_edges(smap):
hand side pixel locations respectively of the input map.
"""
# Calculate all the edge pixels
nx, ny = smap.dimensions.x.value, smap.dimensions.y.value
ny, nx = smap.shape
top = list(product(np.arange(nx), [ny - 1])) * u.pix
bottom = list(product(np.arange(nx), [0])) * u.pix
left_hand_side = list(product([0], np.arange(ny))) * u.pix
Expand Down
3 changes: 2 additions & 1 deletion sunpy/map/mixins/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .mapdeprecate import MapDeprecateMixin
from .mapmeta import MapMetaMixin, MapMetaValidationError

__all__ = ['MapMetaValidationError', 'MapMetaMixin']
__all__ = ['MapMetaValidationError', 'MapMetaMixin', 'MapDeprecateMixin']
67 changes: 67 additions & 0 deletions sunpy/map/mixins/mapdeprecate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import numpy as np

from astropy import units as u

from sunpy.util.decorators import deprecated
from .mapmeta import PixelPair

__all__ = ['MapDeprecateMixin']

class MapDeprecateMixin:
"""
This class contains the deprecated attributes on map.
"""

@property
@deprecated(since="6.1", message=".dimensions will be removed in 6.1. Use sunpy.map.GenericMap.shape instead")
def dimensions(self):
"""
The dimensions of the array (x axis first, y axis second).
"""
return PixelPair(*u.Quantity(np.flipud(self.data.shape), 'pixel'))

Check warning on line 21 in sunpy/map/mixins/mapdeprecate.py

View check run for this annotation

Codecov / codecov/patch

sunpy/map/mixins/mapdeprecate.py#L21

Added line #L21 was not covered by tests


@property
@deprecated(since="6.1", message="sunpy.map.GenericMap.dtype will be removed in 6.1, use sunpy.map.GenericMap.data.dtype instead")
def dtype(self):
"""
The `numpy.dtype` of the array of the map.
"""
return self.data.dtype

@property
@deprecated(since="6.1", message="sunpy.map.GenericMap.ndim will be removed in 6.1, use sunpy.map.GenericMap.data.ndim() instead")
def ndim(self):
"""
The value of `numpy.ndarray.ndim` of the data array of the map.
"""
return self.data.ndim

Check warning on line 38 in sunpy/map/mixins/mapdeprecate.py

View check run for this annotation

Codecov / codecov/patch

sunpy/map/mixins/mapdeprecate.py#L38

Added line #L38 was not covered by tests


@deprecated(since="6.1", message="sunpy.map.GenericMap.std() will be removed in 6.1, use sunpy.map.GenericMap.data.std() instead")
def std(self, *args, **kwargs):
"""
Calculate the standard deviation of the data array, ignoring NaNs.
"""
return np.nanstd(self.data, *args, **kwargs)

Check warning on line 46 in sunpy/map/mixins/mapdeprecate.py

View check run for this annotation

Codecov / codecov/patch

sunpy/map/mixins/mapdeprecate.py#L46

Added line #L46 was not covered by tests

@deprecated(since="6.1", message="sunpy.map.GenericMap.mean() will be removed in 6.1, use sunpy.map.GenericMap.data.mean() instead")
def mean(self, *args, **kwargs):
"""
Calculate the mean of the data array, ignoring NaNs.
"""
return np.nanmean(self.data, *args, **kwargs)

Check warning on line 53 in sunpy/map/mixins/mapdeprecate.py

View check run for this annotation

Codecov / codecov/patch

sunpy/map/mixins/mapdeprecate.py#L53

Added line #L53 was not covered by tests

@deprecated(since="6.1", message="sunpy.map.GenericMap.min() will be removed in 6.1, use sunpy.map.GenericMap.data.min() instead")
def min(self, *args, **kwargs):
"""
Calculate the minimum value of the data array, ignoring NaNs.
"""
return np.nanmin(self.data, *args, **kwargs)

Check warning on line 60 in sunpy/map/mixins/mapdeprecate.py

View check run for this annotation

Codecov / codecov/patch

sunpy/map/mixins/mapdeprecate.py#L60

Added line #L60 was not covered by tests

@deprecated(since="6.1", message="sunpy.map.GenericMap.max() will be removed in 6.1, use sunpy.map.GenericMap.data.max() instead")
def max(self, *args, **kwargs):
"""
Calculate the maximum value of the data array, ignoring NaNs.
"""
return np.nanmax(self.data, *args, **kwargs)

Check warning on line 67 in sunpy/map/mixins/mapdeprecate.py

View check run for this annotation

Codecov / codecov/patch

sunpy/map/mixins/mapdeprecate.py#L67

Added line #L67 was not covered by tests
4 changes: 2 additions & 2 deletions sunpy/map/mixins/mapmeta.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ def top_right_coord(self):
"""
The physical coordinate at the center of the the top right ([-1, -1]) pixel.
"""
top_right = np.array([self.dimensions.x.value, self.dimensions.y.value]) - 1
top_right = np.array([self.shape[1], self.shape[0]]) - 1
return self.wcs.pixel_to_world(*top_right)

@property
Expand All @@ -312,7 +312,7 @@ def center(self):
If the array has an even number of pixels in a given dimension,
the coordinate returned lies on the edge between the two central pixels.
"""
center = (np.array([self.dimensions.x.value, self.dimensions.y.value]) - 1) / 2.
center = (np.array([self.shape[1], self.shape[0]]) - 1) / 2.
return self.wcs.pixel_to_world(*center)

def _rsun_meters(self, dsun=None):
Expand Down