|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | + |
| 3 | +""" |
| 4 | +The module provised `csaps` shortcut function for smoothing data |
| 5 | +
|
| 6 | +""" |
| 7 | + |
| 8 | +from collections import abc as c_abc |
| 9 | +from typing import Optional, Union, Sequence, NamedTuple |
| 10 | + |
| 11 | +import numpy as np |
| 12 | + |
| 13 | +from csaps._base import ISmoothingSpline |
| 14 | +from csaps._sspumv import UnivariateCubicSmoothingSpline |
| 15 | +from csaps._sspndg import ndgrid_prepare_data_sites, NdGridCubicSmoothingSpline |
| 16 | +from csaps._types import ( |
| 17 | + UnivariateDataType, |
| 18 | + UnivariateVectorizedDataType, |
| 19 | + NdGridDataType, |
| 20 | +) |
| 21 | + |
| 22 | +_XDataType = Union[UnivariateDataType, NdGridDataType] |
| 23 | +_YDataType = Union[UnivariateVectorizedDataType, np.ndarray] |
| 24 | +_XiDataType = Optional[Union[UnivariateDataType, NdGridDataType]] |
| 25 | +_WeightsDataType = Optional[Union[UnivariateDataType, NdGridDataType]] |
| 26 | +_SmoothDataType = Optional[Union[float, Sequence[Optional[float]]]] |
| 27 | + |
| 28 | +SmoothingResult = NamedTuple('SmoothingResult', [ |
| 29 | + ('values', _YDataType), |
| 30 | + ('smooth', _SmoothDataType), |
| 31 | +]) |
| 32 | + |
| 33 | +_ReturnType = Union[ |
| 34 | + _YDataType, |
| 35 | + SmoothingResult, |
| 36 | + ISmoothingSpline, |
| 37 | +] |
| 38 | + |
| 39 | + |
| 40 | +def csaps(xdata: _XDataType, |
| 41 | + ydata: _YDataType, |
| 42 | + xidata: _XiDataType = None, |
| 43 | + weights: _WeightsDataType = None, |
| 44 | + smooth: _SmoothDataType = None, |
| 45 | + axis: Optional[int] = None) -> _ReturnType: |
| 46 | + """Smooths the univariate/multivariate/gridded data or computes the corresponding splines |
| 47 | +
|
| 48 | + This function might be used in procedural code. |
| 49 | +
|
| 50 | + Parameters |
| 51 | + ---------- |
| 52 | + xdata : np.ndarray, array-like |
| 53 | + [required] The data sites ``x1 < x2 < ... < xN``: |
| 54 | + - 1-D data vector/sequence (array-like) for univariate/multivariate ydata case |
| 55 | + - The sequence of 1-D data vectors for nd-gridded ydata case |
| 56 | +
|
| 57 | + ydata : np.ndarray, array-like |
| 58 | + [required] The data values: |
| 59 | + - 1-D data vector/sequence (array-like) for univariate data case |
| 60 | + - N-D array/array-like for multivariate data case |
| 61 | + - N-D array for nd-gridded data case |
| 62 | +
|
| 63 | + xidata : np.ndarray, array-like, sequence[array-like] |
| 64 | + [optional] The data sites for output smoothed data: |
| 65 | + - 1-D data vector/sequence (array-like) for univariate/multivariate ydata case |
| 66 | + - The sequence of 1-D data vectors for nd-gridded ydata case |
| 67 | + If this argument was not set, the function will return computed spline for given data |
| 68 | + in `ISmoothingSpline` object. |
| 69 | +
|
| 70 | + weights : np.ndarray, array-like, sequence[array-like] |
| 71 | + [optional] The weights data vectors: |
| 72 | + - 1-D data vector/sequence (array-like) for univariate/multivariate ydata case |
| 73 | + - The sequence of 1-D data vectors for nd-gridded ydata case |
| 74 | +
|
| 75 | + smooth : float, sequence[float] |
| 76 | + [optional] The smoothing factor value(s): |
| 77 | + - float value in the range ``[0, 1]`` for univariate/multivariate ydata case |
| 78 | + - the sequence of float in the range ``[0, 1]`` or None for nd-gridded ydata case |
| 79 | + If this argument was not set or None or sequence with None-items, the function will return |
| 80 | + named tuple `SmoothingResult` with computed smoothed data values and smoothing factor value(s). |
| 81 | +
|
| 82 | + axis : int |
| 83 | + [optional] The ydata axis. Axis along which "ydata" is assumed to be varying. |
| 84 | + If this argument was not set the last axis will be used. |
| 85 | + Currently, `axis` will be ignored for nd-gridded ydata case. |
| 86 | +
|
| 87 | + Returns |
| 88 | + ------- |
| 89 | + yidata : np.ndarray |
| 90 | + Smoothed data values if `xidata` and `smooth` were set. |
| 91 | + smoothed_data : SmoothingResult |
| 92 | + The named tuple with two fileds: |
| 93 | + - 'values' -- smoothed data values |
| 94 | + - 'smooth' -- computed smoothing factor |
| 95 | + This result will be returned if `xidata` was set and `smooth` was not set. |
| 96 | + sspobj : ISmoothingSpline |
| 97 | + Smoothing spline object if `xidata` was not set: |
| 98 | + - `UnivariateCubicSmoothingSpline` instance for univariate/multivariate data |
| 99 | + - `NdGridCubicSmoothingSpline` instance for nd-gridded data |
| 100 | +
|
| 101 | + Examples |
| 102 | + -------- |
| 103 | +
|
| 104 | + Univariate data smoothing |
| 105 | +
|
| 106 | + .. code-block:: python |
| 107 | +
|
| 108 | + import numpy as np |
| 109 | + from csaps import csaps |
| 110 | +
|
| 111 | + x = np.linspace(-5., 5., 25) |
| 112 | + y = np.exp(-(x/2.5)**2) + (np.random.rand(25) - 0.2) * 0.3 |
| 113 | + xi = np.linspace(-5., 5., 150) |
| 114 | +
|
| 115 | + # Smooth data with smoothing factor 0.85 |
| 116 | + yi = csaps(x, y, xi, smooth=0.85) |
| 117 | +
|
| 118 | + # Smooth data and compute smoothing factor automatically |
| 119 | + yi, smooth = csaps(x, y, xi) |
| 120 | +
|
| 121 | + # Do not evaluate the spline, only compute it |
| 122 | + sp = csaps(x, y, smooth=0.98) |
| 123 | +
|
| 124 | + See Also |
| 125 | + -------- |
| 126 | +
|
| 127 | + `UnivariateCubicSmoothingSpline` |
| 128 | + `NdGridCubicSmoothingSpline` |
| 129 | +
|
| 130 | + """ |
| 131 | + |
| 132 | + if isinstance(xdata, c_abc.Sequence): |
| 133 | + try: |
| 134 | + ndgrid_prepare_data_sites(xdata, 'xdata') |
| 135 | + except ValueError: |
| 136 | + umv = True |
| 137 | + else: |
| 138 | + umv = False |
| 139 | + else: |
| 140 | + umv = True |
| 141 | + |
| 142 | + if umv: |
| 143 | + axis = -1 if axis is None else axis |
| 144 | + sp = UnivariateCubicSmoothingSpline(xdata, ydata, weights, smooth, axis) |
| 145 | + else: |
| 146 | + sp = NdGridCubicSmoothingSpline(xdata, ydata, weights, smooth) |
| 147 | + |
| 148 | + if xidata is None: |
| 149 | + return sp |
| 150 | + |
| 151 | + yidata = sp(xidata) |
| 152 | + |
| 153 | + auto_smooth = smooth is None |
| 154 | + if isinstance(smooth, Sequence): |
| 155 | + auto_smooth = any(sm is None for sm in smooth) |
| 156 | + |
| 157 | + if auto_smooth: |
| 158 | + return SmoothingResult(yidata, sp.smooth) |
| 159 | + else: |
| 160 | + return yidata |
0 commit comments