#!/usr/bin/env python
#
# naninfrange.py - The naninfrange function.
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
"""This module provides the :func:`naninfrange` function, which calculates
the range of a numpy array, ignoring infinite and nan values.
"""
import warnings
import numpy as np
[docs]
def naninfrange(data):
"""Returns the minimum and maximum values in the given ``numpy`` array,
ignoring ``nan`` and ``inf`` values.
The ``numpy.nanmin``/``numpy.nanmax`` functions do not handle
positive/negative infinity, so if such values are in the data, we need to
use an alternate approach to calculating the minimum/maximum.
"""
# For structured arrays, we assume that
# all fields have the same dtype, and we
# simply take the range across all fields
if len(data.dtype) > 0:
# Avoid inducing a data copy if
# at all possible. np.ndarray
# doesn't preserve the underlying
# order, so let's set that. Also,
# we're forced to make a copy if
# the array is not contiguous,
# otherwise ndarray will complain
if data.flags['C_CONTIGUOUS']: order = 'C'
elif data.flags['F_CONTIGUOUS']: order = 'F'
else:
data = np.ascontiguousarray(data)
order = 'C'
shape = [len(data.dtype)] + list(data.shape)
data = np.ndarray(buffer=data.data,
shape=shape,
order=order,
dtype=data.dtype[0])
if not np.issubdtype(data.dtype, np.floating):
return data.min(), data.max()
# But np.nanmin/nanmax are substantially
# faster than the alternate, so we try it
# first.
with warnings.catch_warnings():
warnings.filterwarnings('ignore')
dmin = np.nanmin(data)
dmax = np.nanmax(data)
# If there are no nans/infs in the data,
# we can just use nanmin/nanmax
if np.isfinite(dmin) and np.isfinite(dmax):
return dmin, dmax
# The entire array contains nans
if np.isnan(dmin):
return dmin, dmin
# Otherwise we need to calculate min/max
# only on finite values. This is the slow
# option.
# Find all finite values
finite = np.isfinite(data)
# Try to calculate min/max on those values.
# An error will be raised if there are no
# finite values in the array
try:
return data[finite].min(), data[finite].max()
except Exception:
return np.nan, np.nan