Improved mapping with BodyXY.map_img when using spline interpolation for images containing NaN pixels. The spline interpolator does not accept NaN values, so any NaN pixels must be replaced with finite values before performing the interpolation.
Although we propagate NaN values to the map (by default at least), the replacement values can still affect the interpolated values elsewhere if the replacement values are very different to the surrounding values. Previously, we just used np.nan_to_num to replaced any NaNs with 0, which could introduce large artefacts when the data values were large, due to the jump between 0 and the data (see below).
In the updated code, we now replace NaN (or infinite) values with the mean of surrounding non-NaN pixels (with a 3x3 footprint). All other NaN pixels (which don't have neighbouring non-NaN pixels) are replaced with the median of all the pixels in the original image. This generally minimises the delta between replaced NaN pixels, and the surrounding pixels, massively reducing (or even preventing) any artefacts around the NaN regions.
Other minor mapping changes:
For spline interpolations, areas outside the convex hull of pixel centres are automatically set to NaN, for consistency with the handling of NaN pixels. This can be controlled with the propagate_nan parameter.
propagate_nan can now be controlled from other Observation methods, and its value is recorded in mapped FITS headers.
It is now possible to directly pass a cube to map_img, where each slice will be automatically mapped and a mapped cube is returned. This saves having to manually iterate with np.array([body.map_img(img) for img in cube]).
Closes #382
Example
This is a very extreme example of the artefacts that could be introduced around NaN regions with the old behaviour with cubic interpolation. The circles show the locations and values for the image pixels. The old behaviour had artefacts introduced along the top edge of the mapped area and the NaN pixel on the left, caused by the large jump from the filled-in 0 values and the data values. The new behaviour prevents any large jumps between the pixels, preventing any artefacts.
Pull request checklist
[x] Add a clear description of the change
[x] Add any new tests needed
[x] Run spell check on new text visible to user (documentation, GUI etc.)
[x] Check any changes to requirements.txt are reflected in setup.py and conda-forge feedstock
[x] Check code passes CI checks (run run_ci.sh or check GitHub Actions)
Improved mapping with
BodyXY.map_img
when using spline interpolation for images containing NaN pixels. The spline interpolator does not accept NaN values, so any NaN pixels must be replaced with finite values before performing the interpolation.Although we propagate NaN values to the map (by default at least), the replacement values can still affect the interpolated values elsewhere if the replacement values are very different to the surrounding values. Previously, we just used
np.nan_to_num
to replaced any NaNs with 0, which could introduce large artefacts when the data values were large, due to the jump between 0 and the data (see below).In the updated code, we now replace NaN (or infinite) values with the mean of surrounding non-NaN pixels (with a 3x3 footprint). All other NaN pixels (which don't have neighbouring non-NaN pixels) are replaced with the median of all the pixels in the original image. This generally minimises the delta between replaced NaN pixels, and the surrounding pixels, massively reducing (or even preventing) any artefacts around the NaN regions.
Other minor mapping changes:
propagate_nan
parameter.propagate_nan
can now be controlled from otherObservation
methods, and its value is recorded in mapped FITS headers.map_img
, where each slice will be automatically mapped and a mapped cube is returned. This saves having to manually iterate withnp.array([body.map_img(img) for img in cube])
.Closes #382
Example
This is a very extreme example of the artefacts that could be introduced around NaN regions with the old behaviour with cubic interpolation. The circles show the locations and values for the image pixels. The old behaviour had artefacts introduced along the top edge of the mapped area and the NaN pixel on the left, caused by the large jump from the filled-in 0 values and the data values. The new behaviour prevents any large jumps between the pixels, preventing any artefacts.
Pull request checklist
requirements.txt
are reflected insetup.py
and conda-forge feedstockrun_ci.sh
or check GitHub Actions)See CONTRIBUTING.md for more details.