Skip to content

Commit

Permalink
Merge pull request #1232 from larrybradley/bkg2d-refactor
Browse files Browse the repository at this point in the history
Refactor background classes
  • Loading branch information
larrybradley committed Sep 3, 2021
2 parents 7b58316 + 5065e86 commit 8bbe2c1
Show file tree
Hide file tree
Showing 8 changed files with 1,043 additions and 718 deletions.
31 changes: 31 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ General
New Features
^^^^^^^^^^^^

- ``photutils.background``

- Improved the performance of ``Background2D`` by up to 10-50% when
the optional ``bottleneck`` package is installed. [#1232]

- Added a ``masked`` keyword to the background
classes ``MeanBackground``, ``MedianBackground``,
``ModeEstimatorBackground``, ``MMMBackground``,
``SExtractorBackground``, ``BiweightLocationBackground``,
``StdBackgroundRMS``, ``MADStdBackgroundRMS``, and
``BiweightScaleBackgroundRMS``. [#1232]

Bug Fixes
^^^^^^^^^

Expand Down Expand Up @@ -55,6 +67,25 @@ API changes
- Removed the deprecated ``BoundingBox.slices`` and
``PixelAperture.bounding_boxes`` attributes. [#1215]

- ``photutils.background``

- Invalid data values (i.e., NaN or inf) are now automatically masked
in ``Background2D``. [#1232]

- The background classes ``MeanBackground``, ``MedianBackground``,
``ModeEstimatorBackground``, ``MMMBackground``,
``SExtractorBackground``, ``BiweightLocationBackground``,
``StdBackgroundRMS``, ``MADStdBackgroundRMS``, and
``BiweightScaleBackgroundRMS`` now return by default a
``numpy.ndarray`` with ``np.nan`` values representing masked pixels
instead of a masked array. A masked array can be returned by setting
``masked=True``. [#1232]

- Deprecated the ``Background2D`` attributes ``background_mesh_ma``
and ``background_rms_mesh_ma``. They have been renamed to
``background_mesh_masked`` and ``background_rms_mesh_masked``.
[#1232]


1.1.0 (2021-03-20)
------------------
Expand Down
1 change: 1 addition & 0 deletions photutils/background/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@

from .background_2d import * # noqa
from .core import * # noqa
from .interpolators import * # noqa
77 changes: 77 additions & 0 deletions photutils/background/_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
"""
This module defines nan-ignoring statistical functions, using bottleneck
for performance if available.
"""

import numpy as np

from ..utils._optional_deps import HAS_BOTTLENECK

if HAS_BOTTLENECK:
import bottleneck


def move_tuple_axes_first(array, axis):
"""
Bottleneck can only take integer axis, not tuple, so this function
takes all the axes to be operated on and combines them into the
first dimension of the array so that we can then use axis=0.
"""
# Figure out how many axes we are operating over
naxis = len(axis)

# Add remaining axes to the axis tuple
axis += tuple(i for i in range(array.ndim) if i not in axis)

# The new position of each axis is just in order
destination = tuple(range(array.ndim))

# Reorder the array so that the axes being operated on are at the
# beginning
array_new = np.moveaxis(array, axis, destination)

# Collapse the dimensions being operated on into a single dimension
# so that we can then use axis=0 with the bottleneck functions
array_new = array_new.reshape((-1,) + array_new.shape[naxis:])

return array_new


def nanmean(array, axis=None):
"""
A nanmean function that uses bottleneck if available.
"""
if HAS_BOTTLENECK:
if isinstance(axis, tuple):
array = move_tuple_axes_first(array, axis=axis)
axis = 0
return bottleneck.nanmean(array, axis=axis)
else:
return np.nanmean(array, axis=axis)


def nanmedian(array, axis=None):
"""
A nanmedian function that uses bottleneck if available.
"""
if HAS_BOTTLENECK:
if isinstance(axis, tuple):
array = move_tuple_axes_first(array, axis=axis)
axis = 0
return bottleneck.nanmedian(array, axis=axis)
else:
return np.nanmedian(array, axis=axis)


def nanstd(array, axis=None, ddof=0):
"""
A nanstd function that uses bottleneck if available.
"""
if HAS_BOTTLENECK:
if isinstance(axis, tuple):
array = move_tuple_axes_first(array, axis=axis)
axis = 0
return bottleneck.nanstd(array, axis=axis, ddof=ddof)
else:
return np.nanstd(array, axis=axis, ddof=ddof)

0 comments on commit 8bbe2c1

Please sign in to comment.