Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/893.doc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added an example (:ref:`sphx_glr_generated_gallery_upscaling_resolution_via_reproject.py`) showing how to change resolution of an NDCube using `~ndcube.NDCube.reproject`.
58 changes: 58 additions & 0 deletions examples/upscaling_resolution_via_reproject.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"""
=====================================
Upscaling the resolution of an NDCube
=====================================

This example shows how to increase the resolution of an NDCube by reprojecting to a finer grid.
"""

import matplotlib.pyplot as plt

from astropy.io import fits
from astropy.wcs import WCS

from sunpy.data.sample import AIA_171_IMAGE
from sunpy.visualization.colormaps import cm

from ndcube import NDCube

##############################################################################
# We start by creating an NDCube from sample solar data provided by SunPy.
# Here we use an AIA 171 image, but the same approach can be applied to other datasets, including those with non celestial axes.

hdul = fits.open(AIA_171_IMAGE)
cube = NDCube(hdul[1].data, WCS(hdul[1].header))

###########################################################################
# Next, we define a new WCS with a finer pixel scale, note that while it is obvious that the CDELT values are changed to reflect the finer scale,
# the CRPIX values also need to be adjusted as the reference pixel position changes with the new scale.
# You can use any value for the scale factor, including non-integer values, greater or less than 1.
# You can also scale each axis independently.

scale_factor = 1.5
new_wcs = cube.wcs.deepcopy()
new_wcs.wcs.cdelt /= scale_factor
new_wcs.wcs.crpix *= scale_factor

###########################################################################
# Now we can reproject the original cube to the new WCS with higher resolution.
new_shape = tuple(int(s * scale_factor) for s in cube.data.shape)
reprojected_cube = cube.reproject_to(new_wcs, shape_out=new_shape)

###########################################################################
# Our new NDCube now has a higher resolution.
# We can compare the shapes of the original and reprojected cubes with new pixel axes.
print(cube.data.shape, reprojected_cube.data.shape)

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 8))

ax1.imshow(cube.data, origin='lower', cmap=cm.sdoaia171, vmin=10, vmax=10000)
ax1.set_title('Original')
ax1.set_xlabel('X [pixel]')
ax1.set_ylabel('Y [pixel]')
ax2.imshow(reprojected_cube.data, origin='lower', cmap=cm.sdoaia171, vmin=10, vmax=10000)
ax2.set_title('Reprojected (Upscaled)')
ax2.set_xlabel('X [pixel]')
ax2.set_ylabel('Y [pixel]')
plt.tight_layout()
plt.show()
4 changes: 3 additions & 1 deletion ndcube/ndcube.py
Original file line number Diff line number Diff line change
Expand Up @@ -1267,9 +1267,11 @@ def my_propagate(uncertainty, data, mask, **kwargs):
bin_shape[bin_shape == -1] = np.array(data_shape)[bin_shape == -1]
if (bin_shape < 0).any():
raise ValueError("bin_shape should not be less than -1.")
if np.any(bin_shape > data_shape):
raise ValueError("bin_shape cannot be larger than data shape in any dimension.")
if (np.mod(data_shape, bin_shape) != 0).any():
raise ValueError(
"bin shape must be an integer fraction of the data shape in each dimension. "
"bin_shape must be an integer fraction of the data shape in each dimension. "
f"data shape: {data_shape}; bin shape: {bin_shape}"
)

Expand Down
11 changes: 9 additions & 2 deletions ndcube/tests/test_ndcube_reproject_and_rebin.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,13 +263,20 @@ def test_rebin_some_masked_uncerts_exclude_masked_values(ndcube_2d_ln_lt_mask_un
def test_rebin_errors(ndcube_3d_l_ln_lt_ectime):
cube = ndcube_3d_l_ln_lt_ectime
# Wrong number of axes in bin_shape)
with pytest.raises(ValueError):
with pytest.raises(ValueError, match="bin_shape must have an entry for each"):
cube.rebin((2,))

# bin shape shouldn't have any negatives
with pytest.raises(ValueError, match="bin_shape should not be less than -1"):
cube.rebin((2, -2, 1))
# bin_shape not integer multiple of data shape.
with pytest.raises(ValueError):
with pytest.raises(ValueError, match="bin_shape must be an integer fraction"):
cube.rebin((9, 2, 1))

# bin_shape larger than data shape.
with pytest.raises(ValueError, match="bin_shape cannot be larger than data shape"):
cube.rebin((20, 2, 1))


def test_rebin_no_propagate(ndcube_2d_ln_lt_mask_uncert):
# Execute rebin.
Expand Down
Loading