|
""" |
|
fitpack (dierckx in netlib) --- A Python-C wrapper to FITPACK (by P. Dierckx). |
|
FITPACK is a collection of FORTRAN programs for curve and surface |
|
fitting with splines and tensor product splines. |
|
|
|
See |
|
https://web.archive.org/web/20010524124604/http://www.cs.kuleuven.ac.be:80/cwis/research/nalag/research/topics/fitpack.html |
|
or |
|
http://www.netlib.org/dierckx/ |
|
|
|
Copyright 2002 Pearu Peterson all rights reserved, |
|
Pearu Peterson <[email protected]> |
|
Permission to use, modify, and distribute this software is given under the |
|
terms of the SciPy (BSD style) license. See LICENSE.txt that came with |
|
this distribution for specifics. |
|
|
|
NO WARRANTY IS EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. |
|
|
|
TODO: Make interfaces to the following fitpack functions: |
|
For univariate splines: cocosp, concon, fourco, insert |
|
For bivariate splines: profil, regrid, parsur, surev |
|
""" |
|
|
|
__all__ = ['splrep', 'splprep', 'splev', 'splint', 'sproot', 'spalde', |
|
'bisplrep', 'bisplev', 'insert', 'splder', 'splantider'] |
|
|
|
import warnings |
|
import numpy as np |
|
from . import _fitpack |
|
from numpy import (atleast_1d, array, ones, zeros, sqrt, ravel, transpose, |
|
empty, iinfo, asarray) |
|
|
|
|
|
|
|
from . import _dfitpack as dfitpack |
|
|
|
|
|
dfitpack_int = dfitpack.types.intvar.dtype |
|
|
|
|
|
def _int_overflow(x, exception, msg=None): |
|
"""Cast the value to an dfitpack_int and raise an OverflowError if the value |
|
cannot fit. |
|
""" |
|
if x > iinfo(dfitpack_int).max: |
|
if msg is None: |
|
msg = f'{x!r} cannot fit into an {dfitpack_int!r}' |
|
raise exception(msg) |
|
return dfitpack_int.type(x) |
|
|
|
|
|
_iermess = { |
|
0: ["The spline has a residual sum of squares fp such that " |
|
"abs(fp-s)/s<=0.001", None], |
|
-1: ["The spline is an interpolating spline (fp=0)", None], |
|
-2: ["The spline is weighted least-squares polynomial of degree k.\n" |
|
"fp gives the upper bound fp0 for the smoothing factor s", None], |
|
1: ["The required storage space exceeds the available storage space.\n" |
|
"Probable causes: data (x,y) size is too small or smoothing parameter" |
|
"\ns is too small (fp>s).", ValueError], |
|
2: ["A theoretically impossible result when finding a smoothing spline\n" |
|
"with fp = s. Probable cause: s too small. (abs(fp-s)/s>0.001)", |
|
ValueError], |
|
3: ["The maximal number of iterations (20) allowed for finding smoothing\n" |
|
"spline with fp=s has been reached. Probable cause: s too small.\n" |
|
"(abs(fp-s)/s>0.001)", ValueError], |
|
10: ["Error on input data", ValueError], |
|
'unknown': ["An error occurred", TypeError] |
|
} |
|
|
|
_iermess2 = { |
|
0: ["The spline has a residual sum of squares fp such that " |
|
"abs(fp-s)/s<=0.001", None], |
|
-1: ["The spline is an interpolating spline (fp=0)", None], |
|
-2: ["The spline is weighted least-squares polynomial of degree kx and ky." |
|
"\nfp gives the upper bound fp0 for the smoothing factor s", None], |
|
-3: ["Warning. The coefficients of the spline have been computed as the\n" |
|
"minimal norm least-squares solution of a rank deficient system.", |
|
None], |
|
1: ["The required storage space exceeds the available storage space.\n" |
|
"Probable causes: nxest or nyest too small or s is too small. (fp>s)", |
|
ValueError], |
|
2: ["A theoretically impossible result when finding a smoothing spline\n" |
|
"with fp = s. Probable causes: s too small or badly chosen eps.\n" |
|
"(abs(fp-s)/s>0.001)", ValueError], |
|
3: ["The maximal number of iterations (20) allowed for finding smoothing\n" |
|
"spline with fp=s has been reached. Probable cause: s too small.\n" |
|
"(abs(fp-s)/s>0.001)", ValueError], |
|
4: ["No more knots can be added because the number of B-spline\n" |
|
"coefficients already exceeds the number of data points m.\n" |
|
"Probable causes: either s or m too small. (fp>s)", ValueError], |
|
5: ["No more knots can be added because the additional knot would\n" |
|
"coincide with an old one. Probable cause: s too small or too large\n" |
|
"a weight to an inaccurate data point. (fp>s)", ValueError], |
|
10: ["Error on input data", ValueError], |
|
11: ["rwrk2 too small, i.e., there is not enough workspace for computing\n" |
|
"the minimal least-squares solution of a rank deficient system of\n" |
|
"linear equations.", ValueError], |
|
'unknown': ["An error occurred", TypeError] |
|
} |
|
|
|
_parcur_cache = {'t': array([], float), 'wrk': array([], float), |
|
'iwrk': array([], dfitpack_int), 'u': array([], float), |
|
'ub': 0, 'ue': 1} |
|
|
|
|
|
def splprep(x, w=None, u=None, ub=None, ue=None, k=3, task=0, s=None, t=None, |
|
full_output=0, nest=None, per=0, quiet=1): |
|
|
|
if task <= 0: |
|
_parcur_cache = {'t': array([], float), 'wrk': array([], float), |
|
'iwrk': array([], dfitpack_int), 'u': array([], float), |
|
'ub': 0, 'ue': 1} |
|
x = atleast_1d(x) |
|
idim, m = x.shape |
|
if per: |
|
for i in range(idim): |
|
if x[i][0] != x[i][-1]: |
|
if not quiet: |
|
warnings.warn(RuntimeWarning('Setting x[%d][%d]=x[%d][0]' % |
|
(i, m, i)), |
|
stacklevel=2) |
|
x[i][-1] = x[i][0] |
|
if not 0 < idim < 11: |
|
raise TypeError('0 < idim < 11 must hold') |
|
if w is None: |
|
w = ones(m, float) |
|
else: |
|
w = atleast_1d(w) |
|
ipar = (u is not None) |
|
if ipar: |
|
_parcur_cache['u'] = u |
|
if ub is None: |
|
_parcur_cache['ub'] = u[0] |
|
else: |
|
_parcur_cache['ub'] = ub |
|
if ue is None: |
|
_parcur_cache['ue'] = u[-1] |
|
else: |
|
_parcur_cache['ue'] = ue |
|
else: |
|
_parcur_cache['u'] = zeros(m, float) |
|
if not (1 <= k <= 5): |
|
raise TypeError('1 <= k= %d <=5 must hold' % k) |
|
if not (-1 <= task <= 1): |
|
raise TypeError('task must be -1, 0 or 1') |
|
if (not len(w) == m) or (ipar == 1 and (not len(u) == m)): |
|
raise TypeError('Mismatch of input dimensions') |
|
if s is None: |
|
s = m - sqrt(2*m) |
|
if t is None and task == -1: |
|
raise TypeError('Knots must be given for task=-1') |
|
if t is not None: |
|
_parcur_cache['t'] = atleast_1d(t) |
|
n = len(_parcur_cache['t']) |
|
if task == -1 and n < 2*k + 2: |
|
raise TypeError('There must be at least 2*k+2 knots for task=-1') |
|
if m <= k: |
|
raise TypeError('m > k must hold') |
|
if nest is None: |
|
nest = m + 2*k |
|
|
|
if (task >= 0 and s == 0) or (nest < 0): |
|
if per: |
|
nest = m + 2*k |
|
else: |
|
nest = m + k + 1 |
|
nest = max(nest, 2*k + 3) |
|
u = _parcur_cache['u'] |
|
ub = _parcur_cache['ub'] |
|
ue = _parcur_cache['ue'] |
|
t = _parcur_cache['t'] |
|
wrk = _parcur_cache['wrk'] |
|
iwrk = _parcur_cache['iwrk'] |
|
t, c, o = _fitpack._parcur(ravel(transpose(x)), w, u, ub, ue, k, |
|
task, ipar, s, t, nest, wrk, iwrk, per) |
|
_parcur_cache['u'] = o['u'] |
|
_parcur_cache['ub'] = o['ub'] |
|
_parcur_cache['ue'] = o['ue'] |
|
_parcur_cache['t'] = t |
|
_parcur_cache['wrk'] = o['wrk'] |
|
_parcur_cache['iwrk'] = o['iwrk'] |
|
ier = o['ier'] |
|
fp = o['fp'] |
|
n = len(t) |
|
u = o['u'] |
|
c.shape = idim, n - k - 1 |
|
tcku = [t, list(c), k], u |
|
if ier <= 0 and not quiet: |
|
warnings.warn(RuntimeWarning(_iermess[ier][0] + |
|
"\tk=%d n=%d m=%d fp=%f s=%f" % |
|
(k, len(t), m, fp, s)), |
|
stacklevel=2) |
|
if ier > 0 and not full_output: |
|
if ier in [1, 2, 3]: |
|
warnings.warn(RuntimeWarning(_iermess[ier][0]), stacklevel=2) |
|
else: |
|
try: |
|
raise _iermess[ier][1](_iermess[ier][0]) |
|
except KeyError as e: |
|
raise _iermess['unknown'][1](_iermess['unknown'][0]) from e |
|
if full_output: |
|
try: |
|
return tcku, fp, ier, _iermess[ier][0] |
|
except KeyError: |
|
return tcku, fp, ier, _iermess['unknown'][0] |
|
else: |
|
return tcku |
|
|
|
|
|
_curfit_cache = {'t': array([], float), 'wrk': array([], float), |
|
'iwrk': array([], dfitpack_int)} |
|
|
|
|
|
def splrep(x, y, w=None, xb=None, xe=None, k=3, task=0, s=None, t=None, |
|
full_output=0, per=0, quiet=1): |
|
|
|
if task <= 0: |
|
_curfit_cache = {} |
|
x, y = map(atleast_1d, [x, y]) |
|
m = len(x) |
|
if w is None: |
|
w = ones(m, float) |
|
if s is None: |
|
s = 0.0 |
|
else: |
|
w = atleast_1d(w) |
|
if s is None: |
|
s = m - sqrt(2*m) |
|
if not len(w) == m: |
|
raise TypeError('len(w)=%d is not equal to m=%d' % (len(w), m)) |
|
if (m != len(y)) or (m != len(w)): |
|
raise TypeError('Lengths of the first three arguments (x,y,w) must ' |
|
'be equal') |
|
if not (1 <= k <= 5): |
|
raise TypeError('Given degree of the spline (k=%d) is not supported. ' |
|
'(1<=k<=5)' % k) |
|
if m <= k: |
|
raise TypeError('m > k must hold') |
|
if xb is None: |
|
xb = x[0] |
|
if xe is None: |
|
xe = x[-1] |
|
if not (-1 <= task <= 1): |
|
raise TypeError('task must be -1, 0 or 1') |
|
if t is not None: |
|
task = -1 |
|
if task == -1: |
|
if t is None: |
|
raise TypeError('Knots must be given for task=-1') |
|
numknots = len(t) |
|
_curfit_cache['t'] = empty((numknots + 2*k + 2,), float) |
|
_curfit_cache['t'][k+1:-k-1] = t |
|
nest = len(_curfit_cache['t']) |
|
elif task == 0: |
|
if per: |
|
nest = max(m + 2*k, 2*k + 3) |
|
else: |
|
nest = max(m + k + 1, 2*k + 3) |
|
t = empty((nest,), float) |
|
_curfit_cache['t'] = t |
|
if task <= 0: |
|
if per: |
|
_curfit_cache['wrk'] = empty((m*(k + 1) + nest*(8 + 5*k),), float) |
|
else: |
|
_curfit_cache['wrk'] = empty((m*(k + 1) + nest*(7 + 3*k),), float) |
|
_curfit_cache['iwrk'] = empty((nest,), dfitpack_int) |
|
try: |
|
t = _curfit_cache['t'] |
|
wrk = _curfit_cache['wrk'] |
|
iwrk = _curfit_cache['iwrk'] |
|
except KeyError as e: |
|
raise TypeError("must call with task=1 only after" |
|
" call with task=0,-1") from e |
|
if not per: |
|
n, c, fp, ier = dfitpack.curfit(task, x, y, w, t, wrk, iwrk, |
|
xb, xe, k, s) |
|
else: |
|
n, c, fp, ier = dfitpack.percur(task, x, y, w, t, wrk, iwrk, k, s) |
|
tck = (t[:n], c[:n], k) |
|
if ier <= 0 and not quiet: |
|
_mess = (_iermess[ier][0] + "\tk=%d n=%d m=%d fp=%f s=%f" % |
|
(k, len(t), m, fp, s)) |
|
warnings.warn(RuntimeWarning(_mess), stacklevel=2) |
|
if ier > 0 and not full_output: |
|
if ier in [1, 2, 3]: |
|
warnings.warn(RuntimeWarning(_iermess[ier][0]), stacklevel=2) |
|
else: |
|
try: |
|
raise _iermess[ier][1](_iermess[ier][0]) |
|
except KeyError as e: |
|
raise _iermess['unknown'][1](_iermess['unknown'][0]) from e |
|
if full_output: |
|
try: |
|
return tck, fp, ier, _iermess[ier][0] |
|
except KeyError: |
|
return tck, fp, ier, _iermess['unknown'][0] |
|
else: |
|
return tck |
|
|
|
|
|
def splev(x, tck, der=0, ext=0): |
|
|
|
t, c, k = tck |
|
try: |
|
c[0][0] |
|
parametric = True |
|
except Exception: |
|
parametric = False |
|
if parametric: |
|
return list(map(lambda c, x=x, t=t, k=k, der=der: |
|
splev(x, [t, c, k], der, ext), c)) |
|
else: |
|
if not (0 <= der <= k): |
|
raise ValueError("0<=der=%d<=k=%d must hold" % (der, k)) |
|
if ext not in (0, 1, 2, 3): |
|
raise ValueError(f"ext = {ext} not in (0, 1, 2, 3) ") |
|
|
|
x = asarray(x) |
|
shape = x.shape |
|
x = atleast_1d(x).ravel() |
|
if der == 0: |
|
y, ier = dfitpack.splev(t, c, k, x, ext) |
|
else: |
|
y, ier = dfitpack.splder(t, c, k, x, der, ext) |
|
|
|
if ier == 10: |
|
raise ValueError("Invalid input data") |
|
if ier == 1: |
|
raise ValueError("Found x value not in the domain") |
|
if ier: |
|
raise TypeError("An error occurred") |
|
|
|
return y.reshape(shape) |
|
|
|
|
|
def splint(a, b, tck, full_output=0): |
|
|
|
t, c, k = tck |
|
try: |
|
c[0][0] |
|
parametric = True |
|
except Exception: |
|
parametric = False |
|
if parametric: |
|
return list(map(lambda c, a=a, b=b, t=t, k=k: |
|
splint(a, b, [t, c, k]), c)) |
|
else: |
|
aint, wrk = dfitpack.splint(t, c, k, a, b) |
|
if full_output: |
|
return aint, wrk |
|
else: |
|
return aint |
|
|
|
|
|
def sproot(tck, mest=10): |
|
|
|
t, c, k = tck |
|
if k != 3: |
|
raise ValueError("sproot works only for cubic (k=3) splines") |
|
try: |
|
c[0][0] |
|
parametric = True |
|
except Exception: |
|
parametric = False |
|
if parametric: |
|
return list(map(lambda c, t=t, k=k, mest=mest: |
|
sproot([t, c, k], mest), c)) |
|
else: |
|
if len(t) < 8: |
|
raise TypeError(f"The number of knots {len(t)}>=8") |
|
z, m, ier = dfitpack.sproot(t, c, mest) |
|
if ier == 10: |
|
raise TypeError("Invalid input data. " |
|
"t1<=..<=t4<t5<..<tn-3<=..<=tn must hold.") |
|
if ier == 0: |
|
return z[:m] |
|
if ier == 1: |
|
warnings.warn(RuntimeWarning("The number of zeros exceeds mest"), |
|
stacklevel=2) |
|
return z[:m] |
|
raise TypeError("Unknown error") |
|
|
|
|
|
def spalde(x, tck): |
|
|
|
t, c, k = tck |
|
try: |
|
c[0][0] |
|
parametric = True |
|
except Exception: |
|
parametric = False |
|
if parametric: |
|
return list(map(lambda c, x=x, t=t, k=k: |
|
spalde(x, [t, c, k]), c)) |
|
else: |
|
x = atleast_1d(x) |
|
if len(x) > 1: |
|
return list(map(lambda x, tck=tck: spalde(x, tck), x)) |
|
d, ier = dfitpack.spalde(t, c, k+1, x[0]) |
|
if ier == 0: |
|
return d |
|
if ier == 10: |
|
raise TypeError("Invalid input data. t(k)<=x<=t(n-k+1) must hold.") |
|
raise TypeError("Unknown error") |
|
|
|
|
|
|
|
|
|
|
|
_surfit_cache = {'tx': array([], float), 'ty': array([], float), |
|
'wrk': array([], float), 'iwrk': array([], dfitpack_int)} |
|
|
|
|
|
def bisplrep(x, y, z, w=None, xb=None, xe=None, yb=None, ye=None, |
|
kx=3, ky=3, task=0, s=None, eps=1e-16, tx=None, ty=None, |
|
full_output=0, nxest=None, nyest=None, quiet=1): |
|
""" |
|
Find a bivariate B-spline representation of a surface. |
|
|
|
Given a set of data points (x[i], y[i], z[i]) representing a surface |
|
z=f(x,y), compute a B-spline representation of the surface. Based on |
|
the routine SURFIT from FITPACK. |
|
|
|
Parameters |
|
---------- |
|
x, y, z : ndarray |
|
Rank-1 arrays of data points. |
|
w : ndarray, optional |
|
Rank-1 array of weights. By default ``w=np.ones(len(x))``. |
|
xb, xe : float, optional |
|
End points of approximation interval in `x`. |
|
By default ``xb = x.min(), xe=x.max()``. |
|
yb, ye : float, optional |
|
End points of approximation interval in `y`. |
|
By default ``yb=y.min(), ye = y.max()``. |
|
kx, ky : int, optional |
|
The degrees of the spline (1 <= kx, ky <= 5). |
|
Third order (kx=ky=3) is recommended. |
|
task : int, optional |
|
If task=0, find knots in x and y and coefficients for a given |
|
smoothing factor, s. |
|
If task=1, find knots and coefficients for another value of the |
|
smoothing factor, s. bisplrep must have been previously called |
|
with task=0 or task=1. |
|
If task=-1, find coefficients for a given set of knots tx, ty. |
|
s : float, optional |
|
A non-negative smoothing factor. If weights correspond |
|
to the inverse of the standard-deviation of the errors in z, |
|
then a good s-value should be found in the range |
|
``(m-sqrt(2*m),m+sqrt(2*m))`` where m=len(x). |
|
eps : float, optional |
|
A threshold for determining the effective rank of an |
|
over-determined linear system of equations (0 < eps < 1). |
|
`eps` is not likely to need changing. |
|
tx, ty : ndarray, optional |
|
Rank-1 arrays of the knots of the spline for task=-1 |
|
full_output : int, optional |
|
Non-zero to return optional outputs. |
|
nxest, nyest : int, optional |
|
Over-estimates of the total number of knots. If None then |
|
``nxest = max(kx+sqrt(m/2),2*kx+3)``, |
|
``nyest = max(ky+sqrt(m/2),2*ky+3)``. |
|
quiet : int, optional |
|
Non-zero to suppress printing of messages. |
|
|
|
Returns |
|
------- |
|
tck : array_like |
|
A list [tx, ty, c, kx, ky] containing the knots (tx, ty) and |
|
coefficients (c) of the bivariate B-spline representation of the |
|
surface along with the degree of the spline. |
|
fp : ndarray |
|
The weighted sum of squared residuals of the spline approximation. |
|
ier : int |
|
An integer flag about splrep success. Success is indicated if |
|
ier<=0. If ier in [1,2,3] an error occurred but was not raised. |
|
Otherwise an error is raised. |
|
msg : str |
|
A message corresponding to the integer flag, ier. |
|
|
|
See Also |
|
-------- |
|
splprep, splrep, splint, sproot, splev |
|
UnivariateSpline, BivariateSpline |
|
|
|
Notes |
|
----- |
|
See `bisplev` to evaluate the value of the B-spline given its tck |
|
representation. |
|
|
|
If the input data is such that input dimensions have incommensurate |
|
units and differ by many orders of magnitude, the interpolant may have |
|
numerical artifacts. Consider rescaling the data before interpolation. |
|
|
|
References |
|
---------- |
|
.. [1] Dierckx P.:An algorithm for surface fitting with spline functions |
|
Ima J. Numer. Anal. 1 (1981) 267-283. |
|
.. [2] Dierckx P.:An algorithm for surface fitting with spline functions |
|
report tw50, Dept. Computer Science,K.U.Leuven, 1980. |
|
.. [3] Dierckx P.:Curve and surface fitting with splines, Monographs on |
|
Numerical Analysis, Oxford University Press, 1993. |
|
|
|
Examples |
|
-------- |
|
Examples are given :ref:`in the tutorial <tutorial-interpolate_2d_spline>`. |
|
|
|
""" |
|
x, y, z = map(ravel, [x, y, z]) |
|
m = len(x) |
|
if not (m == len(y) == len(z)): |
|
raise TypeError('len(x)==len(y)==len(z) must hold.') |
|
if w is None: |
|
w = ones(m, float) |
|
else: |
|
w = atleast_1d(w) |
|
if not len(w) == m: |
|
raise TypeError('len(w)=%d is not equal to m=%d' % (len(w), m)) |
|
if xb is None: |
|
xb = x.min() |
|
if xe is None: |
|
xe = x.max() |
|
if yb is None: |
|
yb = y.min() |
|
if ye is None: |
|
ye = y.max() |
|
if not (-1 <= task <= 1): |
|
raise TypeError('task must be -1, 0 or 1') |
|
if s is None: |
|
s = m - sqrt(2*m) |
|
if tx is None and task == -1: |
|
raise TypeError('Knots_x must be given for task=-1') |
|
if tx is not None: |
|
_surfit_cache['tx'] = atleast_1d(tx) |
|
nx = len(_surfit_cache['tx']) |
|
if ty is None and task == -1: |
|
raise TypeError('Knots_y must be given for task=-1') |
|
if ty is not None: |
|
_surfit_cache['ty'] = atleast_1d(ty) |
|
ny = len(_surfit_cache['ty']) |
|
if task == -1 and nx < 2*kx+2: |
|
raise TypeError('There must be at least 2*kx+2 knots_x for task=-1') |
|
if task == -1 and ny < 2*ky+2: |
|
raise TypeError('There must be at least 2*ky+2 knots_x for task=-1') |
|
if not ((1 <= kx <= 5) and (1 <= ky <= 5)): |
|
raise TypeError('Given degree of the spline (kx,ky=%d,%d) is not ' |
|
'supported. (1<=k<=5)' % (kx, ky)) |
|
if m < (kx + 1)*(ky + 1): |
|
raise TypeError('m >= (kx+1)(ky+1) must hold') |
|
if nxest is None: |
|
nxest = int(kx + sqrt(m/2)) |
|
if nyest is None: |
|
nyest = int(ky + sqrt(m/2)) |
|
nxest, nyest = max(nxest, 2*kx + 3), max(nyest, 2*ky + 3) |
|
if task >= 0 and s == 0: |
|
nxest = int(kx + sqrt(3*m)) |
|
nyest = int(ky + sqrt(3*m)) |
|
if task == -1: |
|
_surfit_cache['tx'] = atleast_1d(tx) |
|
_surfit_cache['ty'] = atleast_1d(ty) |
|
tx, ty = _surfit_cache['tx'], _surfit_cache['ty'] |
|
wrk = _surfit_cache['wrk'] |
|
u = nxest - kx - 1 |
|
v = nyest - ky - 1 |
|
km = max(kx, ky) + 1 |
|
ne = max(nxest, nyest) |
|
bx, by = kx*v + ky + 1, ky*u + kx + 1 |
|
b1, b2 = bx, bx + v - ky |
|
if bx > by: |
|
b1, b2 = by, by + u - kx |
|
msg = "Too many data points to interpolate" |
|
lwrk1 = _int_overflow(u*v*(2 + b1 + b2) + |
|
2*(u + v + km*(m + ne) + ne - kx - ky) + b2 + 1, |
|
OverflowError, |
|
msg=msg) |
|
lwrk2 = _int_overflow(u*v*(b2 + 1) + b2, OverflowError, msg=msg) |
|
tx, ty, c, o = _fitpack._surfit(x, y, z, w, xb, xe, yb, ye, kx, ky, |
|
task, s, eps, tx, ty, nxest, nyest, |
|
wrk, lwrk1, lwrk2) |
|
_curfit_cache['tx'] = tx |
|
_curfit_cache['ty'] = ty |
|
_curfit_cache['wrk'] = o['wrk'] |
|
ier, fp = o['ier'], o['fp'] |
|
tck = [tx, ty, c, kx, ky] |
|
|
|
ierm = min(11, max(-3, ier)) |
|
if ierm <= 0 and not quiet: |
|
_mess = (_iermess2[ierm][0] + |
|
"\tkx,ky=%d,%d nx,ny=%d,%d m=%d fp=%f s=%f" % |
|
(kx, ky, len(tx), len(ty), m, fp, s)) |
|
warnings.warn(RuntimeWarning(_mess), stacklevel=2) |
|
if ierm > 0 and not full_output: |
|
if ier in [1, 2, 3, 4, 5]: |
|
_mess = ("\n\tkx,ky=%d,%d nx,ny=%d,%d m=%d fp=%f s=%f" % |
|
(kx, ky, len(tx), len(ty), m, fp, s)) |
|
warnings.warn(RuntimeWarning(_iermess2[ierm][0] + _mess), stacklevel=2) |
|
else: |
|
try: |
|
raise _iermess2[ierm][1](_iermess2[ierm][0]) |
|
except KeyError as e: |
|
raise _iermess2['unknown'][1](_iermess2['unknown'][0]) from e |
|
if full_output: |
|
try: |
|
return tck, fp, ier, _iermess2[ierm][0] |
|
except KeyError: |
|
return tck, fp, ier, _iermess2['unknown'][0] |
|
else: |
|
return tck |
|
|
|
|
|
def bisplev(x, y, tck, dx=0, dy=0): |
|
""" |
|
Evaluate a bivariate B-spline and its derivatives. |
|
|
|
Return a rank-2 array of spline function values (or spline derivative |
|
values) at points given by the cross-product of the rank-1 arrays `x` and |
|
`y`. In special cases, return an array or just a float if either `x` or |
|
`y` or both are floats. Based on BISPEV and PARDER from FITPACK. |
|
|
|
Parameters |
|
---------- |
|
x, y : ndarray |
|
Rank-1 arrays specifying the domain over which to evaluate the |
|
spline or its derivative. |
|
tck : tuple |
|
A sequence of length 5 returned by `bisplrep` containing the knot |
|
locations, the coefficients, and the degree of the spline: |
|
[tx, ty, c, kx, ky]. |
|
dx, dy : int, optional |
|
The orders of the partial derivatives in `x` and `y` respectively. |
|
|
|
Returns |
|
------- |
|
vals : ndarray |
|
The B-spline or its derivative evaluated over the set formed by |
|
the cross-product of `x` and `y`. |
|
|
|
See Also |
|
-------- |
|
splprep, splrep, splint, sproot, splev |
|
UnivariateSpline, BivariateSpline |
|
|
|
Notes |
|
----- |
|
See `bisplrep` to generate the `tck` representation. |
|
|
|
References |
|
---------- |
|
.. [1] Dierckx P. : An algorithm for surface fitting |
|
with spline functions |
|
Ima J. Numer. Anal. 1 (1981) 267-283. |
|
.. [2] Dierckx P. : An algorithm for surface fitting |
|
with spline functions |
|
report tw50, Dept. Computer Science,K.U.Leuven, 1980. |
|
.. [3] Dierckx P. : Curve and surface fitting with splines, |
|
Monographs on Numerical Analysis, Oxford University Press, 1993. |
|
|
|
Examples |
|
-------- |
|
Examples are given :ref:`in the tutorial <tutorial-interpolate_2d_spline>`. |
|
|
|
""" |
|
tx, ty, c, kx, ky = tck |
|
if not (0 <= dx < kx): |
|
raise ValueError("0 <= dx = %d < kx = %d must hold" % (dx, kx)) |
|
if not (0 <= dy < ky): |
|
raise ValueError("0 <= dy = %d < ky = %d must hold" % (dy, ky)) |
|
x, y = map(atleast_1d, [x, y]) |
|
if (len(x.shape) != 1) or (len(y.shape) != 1): |
|
raise ValueError("First two entries should be rank-1 arrays.") |
|
|
|
msg = "Too many data points to interpolate." |
|
|
|
_int_overflow(x.size * y.size, MemoryError, msg=msg) |
|
|
|
if dx != 0 or dy != 0: |
|
_int_overflow((tx.size - kx - 1)*(ty.size - ky - 1), |
|
MemoryError, msg=msg) |
|
z, ier = dfitpack.parder(tx, ty, c, kx, ky, dx, dy, x, y) |
|
else: |
|
z, ier = dfitpack.bispev(tx, ty, c, kx, ky, x, y) |
|
|
|
if ier == 10: |
|
raise ValueError("Invalid input data") |
|
if ier: |
|
raise TypeError("An error occurred") |
|
z.shape = len(x), len(y) |
|
if len(z) > 1: |
|
return z |
|
if len(z[0]) > 1: |
|
return z[0] |
|
return z[0][0] |
|
|
|
|
|
def dblint(xa, xb, ya, yb, tck): |
|
"""Evaluate the integral of a spline over area [xa,xb] x [ya,yb]. |
|
|
|
Parameters |
|
---------- |
|
xa, xb : float |
|
The end-points of the x integration interval. |
|
ya, yb : float |
|
The end-points of the y integration interval. |
|
tck : list [tx, ty, c, kx, ky] |
|
A sequence of length 5 returned by bisplrep containing the knot |
|
locations tx, ty, the coefficients c, and the degrees kx, ky |
|
of the spline. |
|
|
|
Returns |
|
------- |
|
integ : float |
|
The value of the resulting integral. |
|
""" |
|
tx, ty, c, kx, ky = tck |
|
return dfitpack.dblint(tx, ty, c, kx, ky, xa, xb, ya, yb) |
|
|
|
|
|
def insert(x, tck, m=1, per=0): |
|
|
|
t, c, k = tck |
|
try: |
|
c[0][0] |
|
parametric = True |
|
except Exception: |
|
parametric = False |
|
if parametric: |
|
cc = [] |
|
for c_vals in c: |
|
tt, cc_val, kk = insert(x, [t, c_vals, k], m) |
|
cc.append(cc_val) |
|
return (tt, cc, kk) |
|
else: |
|
tt, cc, ier = _fitpack._insert(per, t, c, k, x, m) |
|
if ier == 10: |
|
raise ValueError("Invalid input data") |
|
if ier: |
|
raise TypeError("An error occurred") |
|
return (tt, cc, k) |
|
|
|
|
|
def splder(tck, n=1): |
|
|
|
if n < 0: |
|
return splantider(tck, -n) |
|
|
|
t, c, k = tck |
|
|
|
if n > k: |
|
raise ValueError(f"Order of derivative (n = {n!r}) must be <= " |
|
f"order of spline (k = {tck[2]!r})") |
|
|
|
|
|
sh = (slice(None),) + ((None,)*len(c.shape[1:])) |
|
|
|
with np.errstate(invalid='raise', divide='raise'): |
|
try: |
|
for j in range(n): |
|
|
|
|
|
|
|
|
|
dt = t[k+1:-1] - t[1:-k-1] |
|
dt = dt[sh] |
|
|
|
c = (c[1:-1-k] - c[:-2-k]) * k / dt |
|
|
|
|
|
c = np.r_[c, np.zeros((k,) + c.shape[1:])] |
|
|
|
t = t[1:-1] |
|
k -= 1 |
|
except FloatingPointError as e: |
|
raise ValueError(("The spline has internal repeated knots " |
|
"and is not differentiable %d times") % n) from e |
|
|
|
return t, c, k |
|
|
|
|
|
def splantider(tck, n=1): |
|
|
|
if n < 0: |
|
return splder(tck, -n) |
|
|
|
t, c, k = tck |
|
|
|
|
|
sh = (slice(None),) + (None,)*len(c.shape[1:]) |
|
|
|
for j in range(n): |
|
|
|
|
|
|
|
dt = t[k+1:] - t[:-k-1] |
|
dt = dt[sh] |
|
|
|
c = np.cumsum(c[:-k-1] * dt, axis=0) / (k + 1) |
|
c = np.r_[np.zeros((1,) + c.shape[1:]), |
|
c, |
|
[c[-1]] * (k+2)] |
|
|
|
t = np.r_[t[0], t, t[-1]] |
|
k += 1 |
|
|
|
return t, c, k |
|
|