Source code for colour.algebra.extrapolation

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Extrapolation
=============

Defines classes for extrapolating variables:

-   :class:`Extrapolator1d`: 1-D function extrapolation.
"""

from __future__ import division, unicode_literals

import numpy as np

from colour.algebra import is_numeric, to_ndarray

__author__ = 'Colour Developers'
__copyright__ = 'Copyright (C) 2013 - 2014 - Colour Developers'
__license__ = 'New BSD License - http://opensource.org/licenses/BSD-3-Clause'
__maintainer__ = 'Colour Developers'
__email__ = 'colour-science@googlegroups.com'
__status__ = 'Production'

__all__ = ['Extrapolator1d']


[docs]class Extrapolator1d(object): """ Extrapolates the 1-D function of given interpolator. The Extrapolator1d acts as a wrapper around a given *Colour* or *scipy* interpolator class instance with compatible signature. Two extrapolation methods are available: - *Linear*: Linearly extrapolates given points using the slope defined by the interpolator boundaries (xi[0], xi[1]) if x < xi[0] and (xi[-1], xi[-2]) if x > xi[-1]. - *Constant*: Extrapolates given points by assigning the interpolator boundaries values xi[0] if x < xi[0] and xi[-1] if x > xi[-1]. Specifying the *left* and *right* arguments takes precedence on the chosen extrapolation method and will assign the respective *left* and *right* values to the given points. Parameters ---------- interpolator : object Interpolator object. method : unicode, optional ('Linear', 'Constant'), Extrapolation method. left : numeric, optional Value to return for x < xi[0]. right : numeric, optional Value to return for x > xi[-1]. Methods ------- __class__ Notes ----- The interpolator must define *x* and *y* attributes. References ---------- .. [1] http://stackoverflow.com/a/2745496/931625 (Last accessed 8 August 2014) Examples -------- Extrapolating a single numeric variable: >>> from colour.algebra import LinearInterpolator1d >>> x = np.array([3, 4, 5]) >>> y = np.array([1, 2, 3]) >>> interpolator = LinearInterpolator1d(x, y) >>> extrapolator = Extrapolator1d(interpolator) >>> extrapolator(1) -1.0 Extrapolating an *array_like* variable: >>> extrapolator(np.array([6, 7 , 8])) array([ 4., 5., 6.]) Using the *Constant* extrapolation method: >>> x = np.array([3, 4, 5]) >>> y = np.array([1, 2, 3]) >>> interpolator = LinearInterpolator1d(x, y) >>> extrapolator = Extrapolator1d(interpolator, method='Constant') >>> extrapolator(np.array([0.1, 0.2, 8, 9])) array([ 1., 1., 3., 3.]) Using defined *left* boundary and *Constant* extrapolation method: >>> x = np.array([3, 4, 5]) >>> y = np.array([1, 2, 3]) >>> interpolator = LinearInterpolator1d(x, y) >>> extrapolator = Extrapolator1d(interpolator, method='Constant', left=0) >>> extrapolator(np.array([0.1, 0.2, 8, 9])) array([ 0., 0., 3., 3.]) """ def __init__(self, interpolator=None, method='Linear', left=None, right=None): self.__interpolator = None self.interpolator = interpolator self.__method = None self.method = method self.__right = None self.right = right self.__left = None self.left = left @property def interpolator(self): """ Property for **self.__interpolator** private attribute. Returns ------- object self.__interpolator """ return self.__interpolator @interpolator.setter
[docs] def interpolator(self, value): """ Setter for **self.__interpolator** private attribute. Parameters ---------- value : object Attribute value. """ if value is not None: assert hasattr(value, 'x'), ( '"{0}" interpolator has no "x" attribute!'.format(value)) assert hasattr(value, 'y'), ( '"{0}" interpolator has no "y" attribute!'.format(value)) self.__interpolator = value
@property def method(self): """ Property for **self.__method** private attribute. Returns ------- unicode self.__method """ return self.__method @method.setter
[docs] def method(self, value): """ Setter for **self.__method** private attribute. Parameters ---------- value : unicode Attribute value. """ if value is not None: assert type(value) in (str, unicode), ( ('"{0}" attribute: "{1}" type is not ' '"str" or "unicode"!').format('method', value)) value = value.lower() self.__method = value
@property def left(self): """ Property for **self.__left** private attribute. Returns ------- numeric self.__left """ return self.__left @left.setter
[docs] def left(self, value): """ Setter for **self.__left** private attribute. Parameters ---------- value : numeric Attribute value. """ if value is not None: assert is_numeric(value), ( '"{0}" attribute: "{1}" type is not "numeric"!').format( 'left', value) self.__left = value
@property def right(self): """ Property for **self.__right** private attribute. Returns ------- numeric self.__right """ return self.__right @right.setter
[docs] def right(self, value): """ Setter for **self.__right** private attribute. Parameters ---------- value : numeric Attribute value. """ if value is not None: assert is_numeric(value), ( '"{0}" attribute: "{1}" type is not "numeric"!').format( 'right', value) self.__right = value
[docs] def __call__(self, x): """ Evaluates the Extrapolator1d at given point(s). Parameters ---------- x : numeric or array_like Point(s) to evaluate the Extrapolator1d at. Returns ------- float or ndarray Extrapolated points value(s). """ xe = self.__evaluate(to_ndarray(x)) if is_numeric(x): return float(xe) else: return xe
def __evaluate(self, x): """ Performs the extrapolating evaluation at given points. Parameters ---------- x : ndarray Points to evaluate the Extrapolator1d at. Returns ------- ndarray Extrapolated points values. """ xi = self.__interpolator.x yi = self.__interpolator.y y = np.empty_like(x) if self.__method == 'linear': y[x < xi[0]] = (yi[0] + (x[x < xi[0]] - xi[0]) * (yi[1] - yi[0]) / (xi[1] - xi[0])) y[x > xi[-1]] = (yi[-1] + (x[x > xi[-1]] - xi[-1]) * (yi[-1] - yi[-2]) / (xi[-1] - xi[-2])) elif self.__method == 'constant': y[x < xi[0]] = yi[0] y[x > xi[-1]] = yi[-1] if self.__left is not None: y[x < xi[0]] = self.__left if self.__right is not None: y[x > xi[-1]] = self.__right in_range = np.logical_and(x >= xi[0], x <= xi[-1]) y[in_range] = self.__interpolator(x[in_range]) return y