Skip to content

Commit da81f44

Browse files
committed
Addressed comments from Albert
1 parent 1be344f commit da81f44

File tree

12 files changed

+74
-102
lines changed

12 files changed

+74
-102
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
repos:
22
- repo: https://github.com/PyCQA/docformatter
3-
rev: v1.7.5
3+
rev: master
44
hooks:
55
- id: docformatter
66
args: ["--in-place", "--pre-summary-newline", "--make-summary-multi"]

changelog/207.breaking.rst

Lines changed: 2 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,2 @@
1-
**New Coalignment API in sunkit_image.coalignment**
2-
3-
The new coalignment API, developed as part of GSoC 2024, addresses the need for a more precise and flexible approach to image coalignment within the `sunkit_image.coalignment` module.
4-
As solar imaging data continues to grow in complexity, the existing coalignment functions from ``sunpy.image.coalignment`` and ``sunpy.physics.solar_rotation`` were found to be scattered and lacked a unified interface, leading to confusion and redundant code.
5-
6-
**New Features:**
7-
8-
- **Coalignment Interface** (`sunkit_image.coalignment.interface`):
9-
10-
- ``coalign`` function: A high-level function for image coalignment with a specified method. Default method: :func:`~sunkit_image.coalignment.match_template.match_template_coalign`.
11-
- ``AffineParams`` NamedTuple: Stores and passes affine transformation parameters.
12-
13-
- **Template Matching Coalignment** (`sunkit_image.coalignment.match_template`):
14-
15-
- ``match_template_coalign`` function: A coalignment method that uses template matching.
16-
17-
- **Decorator Utility** (`sunkit_image.coalignment.decorators`):
18-
19-
- ``register_coalignment_method`` decorator: Enables easy registration of coalignment methods.
20-
- Global Registry: Maintains a dictionary of registered coalignment methods.
21-
22-
**Enhancements:**
23-
24-
- Improved Metadata Handling: Updates WCS metadata based on affine transformation parameters.
25-
- User Warnings: Alerts users to significant spatial or temporal separations between maps.
26-
27-
**Documentation:**
28-
29-
- All functions are well-documented in the API reference.
30-
31-
**Examples**
32-
33-
- Please find the examples related to the :ref:`adding of coalignment method <sunkit-image-how-to-guide-add-a-new-coalignment-method>` and using a coalignment method here :ref:`sphx_glr_generated_gallery_aligning_aia_with_eis_maps.py`
1+
The previous coalignment API has been deleted and replaced with a new set of imports and functions.
2+
Please see this example: :ref:`sphx_glr_generated_gallery_aligning_aia_with_eis_maps.py`.

docs/code_ref/coalignment.rst

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,10 @@ Coalignment Package
66
The main entry point is the `~sunkit_image.coalignment.coalign` function, which accepts a reference map, a target map, and a specified method for coalignment.
77
This method returns a new map with updated metadata reflecting the applied affine transformations, such as scaling, rotation, and translation.
88

9-
The module supports various transformation methods registered via the `~sunkit_image.coalignment.decorators.register_coalignment_method` decorator, allowing for flexible coalignment strategies based on the specific needs of the data.
9+
The module supports various transformation methods registered via the `~sunkit_image.coalignment.interface.register_coalignment_method` decorator, allowing for flexible coalignment strategies based on the specific needs of the data.
1010

1111
.. automodapi:: sunkit_image.coalignment
1212

1313
.. automodapi:: sunkit_image.coalignment.interface
1414

1515
.. automodapi:: sunkit_image.coalignment.match_template
16-
17-
.. automodapi:: sunkit_image.coalignment.decorators

docs/how_to_guide/adding_a_coalignment_method.rst

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@
44
Add a New Coalignment Method
55
****************************
66

7-
If you want to register a new coalignment method that can be used by :func:`~sunkit_image.coalignment.coalign`, you can use :func:`~sunkit_image.coalignment.decorators.register_coalignment_method`:
7+
If you want to register a new coalignment method that can be used by :func:`~sunkit_image.coalignment.coalign`, you can use :func:`~sunkit_image.coalignment.interface.register_coalignment_method`:
88

99
.. code-block:: python
1010
11-
from sunkit_image.coalignment.decorators import register_coalignment_method
12-
from sunkit_image.coalignment.interface import AffineParams
11+
from sunkit_image.coalignment.interface import AffineParams, register_coalignment_method
1312
1413
@register_coalignment_method("my_coalign")
15-
def my_coalignment_method(input_array, target_array):
14+
def my_coalignment_method(input_array, target_array, **kwargs):
1615
# Your coalignment code goes here
1716
# This should encompass calculating the shifts,
1817
# handling NaN values appropriately.
@@ -24,7 +23,7 @@ Decorator Parameters
2423

2524
Currently the decorator takes one parameter:
2625

27-
- ``name``: The name of your custom coalignment method, which in the above example is "my_coalign".
26+
- ``name`` : The name of your custom coalignment method, which in the above example is "my_coalign".
2827

2928
Function Requirements
3029
=====================
@@ -33,14 +32,15 @@ Your coalignment function should:
3332

3433
1. **Take Input Parameters**:
3534

36-
- ``input_array``: The 2D array to be coaligned.
37-
- ``target_array``: The 2D array to align to.
35+
- ``input_array`` : The 2D array to be coaligned.
36+
- ``target_array`` : The 2D array to align to.
37+
- ``**kwargs``: So extra arguments can be passed down the stack.
3838

39-
2. **Compute Shifts**: Calculate the shifts in the x and y directions needed to align ``input_array`` with ``target_array``.
39+
2. **Compute Shifts** : Calculate the shifts in the x and y directions needed to align ``input_array`` with ``target_array``.
4040

41-
3. **Determine Affine Parameters**: Decide the values of the affine parameters - translation, scale and rotation.
41+
3. **Determine Affine Parameters** : Decide the values of the affine parameters - translation, scale and rotation.
4242

43-
4. **Return**: Use the ``AffineParams`` named tuple included or provide your own that exposes the three parameters as attributes.
43+
4. **Return** : Use the ``AffineParams`` named tuple included or provide your own that exposes the three parameters as attributes.
4444

4545
Handling NaNs and Infs
4646
======================
@@ -55,5 +55,6 @@ To check if your method is registered, you can check if it is present in the reg
5555

5656
.. code-block:: python
5757
58-
from sunkit_image.coalignment.decorators import REGISTERED_METHODS
58+
from sunkit_image.coalignment.interface import REGISTERED_METHODS
59+
5960
print(REGISTERED_METHODS)

examples/aligning_aia_with_eis_maps.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
###################################################################################
2222
# Firstly, let us acquire the EIS and AIA data we need for this example.
2323
#
24-
# For this example, we will use the IS data from the sunpy data repository.
25-
# This is a preprocessed IS raster data.
24+
# For this example, we will use the EIS data from the sunpy data repository.
25+
# This is a preprocessed EIS raster data.
2626

2727

2828
eis_map = sunpy.map.Map("https://github.com/sunpy/data/raw/main/sunkit-image/eis_20140108_095727.fe_12_195_119.2c-0.int.fits")
@@ -35,30 +35,30 @@
3535

3636
###################################################################################
3737
# Lets find the AIA image that we want to use as a reference.
38-
# We want to be using an image near the "date_average" of the IS raster.
38+
# We want to be using an image near the "date_average" of the EIS raster.
3939

4040
query = Fido.search(a.Time(start=eis_map.meta["date_beg"], near=eis_map.meta["date_avg"], end=eis_map.meta["date_end"]), a.Instrument('aia'), a.Wavelength(193*u.angstrom))
4141
aia_file = Fido.fetch(query)
4242
aia_map = sunpy.map.Map(aia_file)
4343

4444
####################################################################################
4545
# Before coaligning the images, we first downsample the AIA image to the same plate
46-
# scale as the IS image. This is not done automatically.
46+
# scale as the EIS image. This is not done automatically.
4747

4848
nx = (aia_map.scale.axis1 * aia_map.dimensions.x) / eis_map.scale.axis1
4949
ny = (aia_map.scale.axis2 * aia_map.dimensions.y) / eis_map.scale.axis2
5050

5151
aia_downsampled = aia_map.resample(u.Quantity([nx, ny]))
5252

5353
####################################################################################
54-
# Now we can coalign IS to AIA using cross-correlation. For this we would be using the
54+
# Now we can coalign EIS to AIA using cross-correlation. For this we would be using the
5555
# "match_template" method. For details of the implementation refer to the
5656
# documentation of `~sunkit_image.coalignment.match_template.match_template_coalign`.
5757

5858
coaligned_eis_map = coalign(aia_downsampled, eis_map)
5959

6060
####################################################################################
61-
# To check now effective this has been, we will plot the IS data and
61+
# To check now effective this has been, we will plot the EIS data and
6262
# overlap the bright regions from AIA before and after the coalignment.
6363

6464
levels = [800] * aia_map.unit

sunkit_image/coalignment/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1+
# This will register the function
2+
import sunkit_image.coalignment_match_template # NOQA: F401
13
from sunkit_image.coalignment.interface import coalign
2-
from sunkit_image.coalignment.match_template import match_template_coalign as _ # NOQA: F401
34

45
__all__ = ["coalign"]

sunkit_image/coalignment/decorators.py

Lines changed: 0 additions & 21 deletions
This file was deleted.

sunkit_image/coalignment/interface.py

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@
1010
from sunpy.sun.models import differential_rotation
1111
from sunpy.util.exceptions import SunpyUserWarning
1212

13-
from sunkit_image.coalignment.decorators import REGISTERED_METHODS
13+
__all__ = ["AffineParams", "register_coalignment_method", "REGISTERED_METHODS"]
1414

15-
__all__ = ["AffineParams"]
15+
# Global Dictionary to store the registered methods and their names
16+
REGISTERED_METHODS = {}
1617

1718

1819
class AffineParams(NamedTuple):
@@ -32,6 +33,23 @@ class AffineParams(NamedTuple):
3233
translation: tuple[float, float]
3334

3435

36+
def register_coalignment_method(name):
37+
"""
38+
Registers a coalignment method to be used by the coalignment interface.
39+
40+
Parameters
41+
----------
42+
name : str
43+
The name of the coalignment method.
44+
"""
45+
46+
def decorator(func):
47+
REGISTERED_METHODS[name] = func
48+
return func
49+
50+
return decorator
51+
52+
3553
def _update_fits_wcs_metadata(reference_map, target_map, affine_params):
3654
"""
3755
Update the metadata of a sunpy.map.Map` based on affine transformation
@@ -115,7 +133,7 @@ def _warn_user_of_separation(reference_map, target_map):
115133
)
116134

117135

118-
def coalign(reference_map, target_map, method='match_template'):
136+
def coalign(reference_map, target_map, method='match_template', **kwargs):
119137
"""
120138
Performs image coalignment using the specified method.
121139
@@ -134,8 +152,11 @@ def coalign(reference_map, target_map, method='match_template'):
134152
The reference map to which the target map is to be coaligned.
135153
target_map : `sunpy.map.Map`
136154
The target map to be coaligned to the reference map.
137-
method : `str`
155+
method : {{{coalignment_function_names}}}, optional
138156
The name of the registered coalignment method to use.
157+
Defaults to 'match_template'.
158+
kwargs : `dict`
159+
Additional keyword arguments to pass to the registered method.
139160
140161
Returns
141162
-------
@@ -154,5 +175,12 @@ def coalign(reference_map, target_map, method='match_template'):
154175
target_array = target_map.data
155176
reference_array = reference_map.data
156177
_warn_user_of_separation(reference_map, target_map)
157-
affine_params = REGISTERED_METHODS[method](reference_array, target_array)
178+
affine_params = REGISTERED_METHODS[method](reference_array, target_array, **kwargs)
158179
return _update_fits_wcs_metadata(reference_map, target_map, affine_params)
180+
181+
182+
# Generate the string with allowable coalignment-function names for use in docstrings
183+
_coalignment_function_names = ", ".join([f"``'{name}'``" for name in REGISTERED_METHODS])
184+
# Insert into the docstring for coalign. We cannot use the add_common_docstring decorator
185+
# due to what would be a circular loop in definitions.
186+
coalign.__doc__ = coalign.__doc__.format(coalignment_function_names=_coalignment_function_names) # type: ignore

sunkit_image/coalignment/match_template.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import numpy as np
22
from skimage.feature import match_template
33

4-
from sunkit_image.coalignment.decorators import register_coalignment_method
5-
from sunkit_image.coalignment.interface import AffineParams
4+
from sunkit_image.coalignment.interface import AffineParams, register_coalignment_method
65

76
__all__ = ["match_template_coalign"]
87

@@ -88,7 +87,7 @@ def _find_best_match_location(corr):
8887

8988

9089
@register_coalignment_method("match_template")
91-
def match_template_coalign(reference_array, target_array):
90+
def match_template_coalign(input_array, target_array, **kwargs):
9291
"""
9392
Perform coalignment by matching the template array to the input array.
9493
@@ -111,11 +110,11 @@ def match_template_coalign(reference_array, target_array):
111110
- translation : `tuple`
112111
A tuple containing the x and y translation values.
113112
"""
114-
corr = match_template(np.float64(reference_array), np.float64(target_array))
113+
corr = match_template(np.float64(input_array), np.float64(target_array))
115114
# Find the best match location
116115
y_shift, x_shift = _find_best_match_location(corr)
117116
# Particularly for this method, there is no change in the rotation or scaling,
118117
# hence the hardcoded values of scale to 1.0 & rotation to identity matrix
119118
scale = np.array([1.0, 1.0])
120119
rotation_matrix = np.eye(2)
121-
return AffineParams(scale=scale, rotation_matrix=rotation_matrix, translation=(x_shift , y_shift ))
120+
return AffineParams(scale=scale, rotation_matrix=rotation_matrix, translation=(x_shift, y_shift))

sunkit_image/coalignment/tests/test_coalignment.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
from sunpy.net import attrs as a
1313

1414
from sunkit_image.coalignment import coalign
15-
from sunkit_image.coalignment.decorators import register_coalignment_method
16-
from sunkit_image.coalignment.interface import AffineParams
15+
from sunkit_image.coalignment.interface import REGISTERED_METHODS, AffineParams, register_coalignment_method
1716
from sunkit_image.tests.helpers import figure_test
1817

1918

@@ -41,8 +40,7 @@ def cutout_map(aia171_test_map):
4140
aia_map = sunpy.map.Map(aia171_test_map)
4241
bottom_left = SkyCoord(-300 * u.arcsec, -300 * u.arcsec, frame = aia_map.coordinate_frame)
4342
top_right = SkyCoord(800 * u.arcsec, 600 * u.arcsec, frame = aia_map.coordinate_frame)
44-
cutout_map = aia_map.submap(bottom_left, top_right=top_right)
45-
return cutout_map
43+
return aia_map.submap(bottom_left, top_right=top_right)
4644

4745

4846
def test_coalignment_reflects_pixel_shifts(cutout_map, aia171_test_map):
@@ -108,3 +106,13 @@ def test_coalignment_reflects_rotation(cutout_map, aia171_test_map):
108106
fixed_cutout_map = coalign(aia171_test_map, rotated_map, method="rotation")
109107
assert_allclose(fixed_cutout_map.rotation_matrix[0, 0], cutout_map.rotation_matrix[0, 0], rtol=1e-4, atol=0)
110108
assert_allclose(fixed_cutout_map.rotation_matrix[1, 1], cutout_map.rotation_matrix[1, 1], rtol=1e-4, atol=0)
109+
110+
111+
def test_register_coalignment_method():
112+
@register_coalignment_method("test_method")
113+
def test_func():
114+
return "Test function"
115+
116+
assert "test_method" in REGISTERED_METHODS
117+
assert REGISTERED_METHODS["test_method"] == test_func
118+
assert test_func() == "Test function"

0 commit comments

Comments
 (0)