Coverage for /usr/lib/python3/dist-packages/scipy/interpolate/_fitpack2.py: 16%

472 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-14 15:55 +0200

1""" 

2fitpack --- curve and surface fitting with splines 

3 

4fitpack is based on a collection of Fortran routines DIERCKX 

5by P. Dierckx (see http://www.netlib.org/dierckx/) transformed 

6to double routines by Pearu Peterson. 

7""" 

8# Created by Pearu Peterson, June,August 2003 

9__all__ = [ 

10 'UnivariateSpline', 

11 'InterpolatedUnivariateSpline', 

12 'LSQUnivariateSpline', 

13 'BivariateSpline', 

14 'LSQBivariateSpline', 

15 'SmoothBivariateSpline', 

16 'LSQSphereBivariateSpline', 

17 'SmoothSphereBivariateSpline', 

18 'RectBivariateSpline', 

19 'RectSphereBivariateSpline'] 

20 

21 

22import warnings 

23 

24from numpy import zeros, concatenate, ravel, diff, array, ones 

25import numpy as np 

26 

27from . import _fitpack_impl 

28from . import dfitpack 

29 

30 

31dfitpack_int = dfitpack.types.intvar.dtype 

32 

33 

34# ############### Univariate spline #################### 

35 

36_curfit_messages = {1: """ 

37The required storage space exceeds the available storage space, as 

38specified by the parameter nest: nest too small. If nest is already 

39large (say nest > m/2), it may also indicate that s is too small. 

40The approximation returned is the weighted least-squares spline 

41according to the knots t[0],t[1],...,t[n-1]. (n=nest) the parameter fp 

42gives the corresponding weighted sum of squared residuals (fp>s). 

43""", 

44 2: """ 

45A theoretically impossible result was found during the iteration 

46process for finding a smoothing spline with fp = s: s too small. 

47There is an approximation returned but the corresponding weighted sum 

48of squared residuals does not satisfy the condition abs(fp-s)/s < tol.""", 

49 3: """ 

50The maximal number of iterations maxit (set to 20 by the program) 

51allowed for finding a smoothing spline with fp=s has been reached: s 

52too small. 

53There is an approximation returned but the corresponding weighted sum 

54of squared residuals does not satisfy the condition abs(fp-s)/s < tol.""", 

55 10: """ 

56Error on entry, no approximation returned. The following conditions 

57must hold: 

58xb<=x[0]<x[1]<...<x[m-1]<=xe, w[i]>0, i=0..m-1 

59if iopt=-1: 

60 xb<t[k+1]<t[k+2]<...<t[n-k-2]<xe""" 

61 } 

62 

63 

64# UnivariateSpline, ext parameter can be an int or a string 

65_extrap_modes = {0: 0, 'extrapolate': 0, 

66 1: 1, 'zeros': 1, 

67 2: 2, 'raise': 2, 

68 3: 3, 'const': 3} 

69 

70 

71class UnivariateSpline: 

72 """ 

73 1-D smoothing spline fit to a given set of data points. 

74 

75 Fits a spline y = spl(x) of degree `k` to the provided `x`, `y` data. `s` 

76 specifies the number of knots by specifying a smoothing condition. 

77 

78 Parameters 

79 ---------- 

80 x : (N,) array_like 

81 1-D array of independent input data. Must be increasing; 

82 must be strictly increasing if `s` is 0. 

83 y : (N,) array_like 

84 1-D array of dependent input data, of the same length as `x`. 

85 w : (N,) array_like, optional 

86 Weights for spline fitting. Must be positive. If `w` is None, 

87 weights are all 1. Default is None. 

88 bbox : (2,) array_like, optional 

89 2-sequence specifying the boundary of the approximation interval. If 

90 `bbox` is None, ``bbox=[x[0], x[-1]]``. Default is None. 

91 k : int, optional 

92 Degree of the smoothing spline. Must be 1 <= `k` <= 5. 

93 ``k = 3`` is a cubic spline. Default is 3. 

94 s : float or None, optional 

95 Positive smoothing factor used to choose the number of knots. Number 

96 of knots will be increased until the smoothing condition is satisfied:: 

97 

98 sum((w[i] * (y[i]-spl(x[i])))**2, axis=0) <= s 

99 

100 However, because of numerical issues, the actual condition is:: 

101 

102 abs(sum((w[i] * (y[i]-spl(x[i])))**2, axis=0) - s) < 0.001 * s 

103 

104 If `s` is None, `s` will be set as `len(w)` for a smoothing spline 

105 that uses all data points. 

106 If 0, spline will interpolate through all data points. This is 

107 equivalent to `InterpolatedUnivariateSpline`. 

108 Default is None. 

109 The user can use the `s` to control the tradeoff between closeness 

110 and smoothness of fit. Larger `s` means more smoothing while smaller 

111 values of `s` indicate less smoothing. 

112 Recommended values of `s` depend on the weights, `w`. If the weights 

113 represent the inverse of the standard-deviation of `y`, then a good 

114 `s` value should be found in the range (m-sqrt(2*m),m+sqrt(2*m)) 

115 where m is the number of datapoints in `x`, `y`, and `w`. This means 

116 ``s = len(w)`` should be a good value if ``1/w[i]`` is an 

117 estimate of the standard deviation of ``y[i]``. 

118 ext : int or str, optional 

119 Controls the extrapolation mode for elements 

120 not in the interval defined by the knot sequence. 

121 

122 * if ext=0 or 'extrapolate', return the extrapolated value. 

123 * if ext=1 or 'zeros', return 0 

124 * if ext=2 or 'raise', raise a ValueError 

125 * if ext=3 of 'const', return the boundary value. 

126 

127 Default is 0. 

128 

129 check_finite : bool, optional 

130 Whether to check that the input arrays contain only finite numbers. 

131 Disabling may give a performance gain, but may result in problems 

132 (crashes, non-termination or non-sensical results) if the inputs 

133 do contain infinities or NaNs. 

134 Default is False. 

135 

136 See Also 

137 -------- 

138 BivariateSpline : 

139 a base class for bivariate splines. 

140 SmoothBivariateSpline : 

141 a smoothing bivariate spline through the given points 

142 LSQBivariateSpline : 

143 a bivariate spline using weighted least-squares fitting 

144 RectSphereBivariateSpline : 

145 a bivariate spline over a rectangular mesh on a sphere 

146 SmoothSphereBivariateSpline : 

147 a smoothing bivariate spline in spherical coordinates 

148 LSQSphereBivariateSpline : 

149 a bivariate spline in spherical coordinates using weighted 

150 least-squares fitting 

151 RectBivariateSpline : 

152 a bivariate spline over a rectangular mesh 

153 InterpolatedUnivariateSpline : 

154 a interpolating univariate spline for a given set of data points. 

155 bisplrep : 

156 a function to find a bivariate B-spline representation of a surface 

157 bisplev : 

158 a function to evaluate a bivariate B-spline and its derivatives 

159 splrep : 

160 a function to find the B-spline representation of a 1-D curve 

161 splev : 

162 a function to evaluate a B-spline or its derivatives 

163 sproot : 

164 a function to find the roots of a cubic B-spline 

165 splint : 

166 a function to evaluate the definite integral of a B-spline between two 

167 given points 

168 spalde : 

169 a function to evaluate all derivatives of a B-spline 

170 

171 Notes 

172 ----- 

173 The number of data points must be larger than the spline degree `k`. 

174 

175 **NaN handling**: If the input arrays contain ``nan`` values, the result 

176 is not useful, since the underlying spline fitting routines cannot deal 

177 with ``nan``. A workaround is to use zero weights for not-a-number 

178 data points: 

179 

180 >>> import numpy as np 

181 >>> from scipy.interpolate import UnivariateSpline 

182 >>> x, y = np.array([1, 2, 3, 4]), np.array([1, np.nan, 3, 4]) 

183 >>> w = np.isnan(y) 

184 >>> y[w] = 0. 

185 >>> spl = UnivariateSpline(x, y, w=~w) 

186 

187 Notice the need to replace a ``nan`` by a numerical value (precise value 

188 does not matter as long as the corresponding weight is zero.) 

189 

190 References 

191 ---------- 

192 Based on algorithms described in [1]_, [2]_, [3]_, and [4]_: 

193 

194 .. [1] P. Dierckx, "An algorithm for smoothing, differentiation and 

195 integration of experimental data using spline functions", 

196 J.Comp.Appl.Maths 1 (1975) 165-184. 

197 .. [2] P. Dierckx, "A fast algorithm for smoothing data on a rectangular 

198 grid while using spline functions", SIAM J.Numer.Anal. 19 (1982) 

199 1286-1304. 

200 .. [3] P. Dierckx, "An improved algorithm for curve fitting with spline 

201 functions", report tw54, Dept. Computer Science,K.U. Leuven, 1981. 

202 .. [4] P. Dierckx, "Curve and surface fitting with splines", Monographs on 

203 Numerical Analysis, Oxford University Press, 1993. 

204 

205 Examples 

206 -------- 

207 >>> import numpy as np 

208 >>> import matplotlib.pyplot as plt 

209 >>> from scipy.interpolate import UnivariateSpline 

210 >>> rng = np.random.default_rng() 

211 >>> x = np.linspace(-3, 3, 50) 

212 >>> y = np.exp(-x**2) + 0.1 * rng.standard_normal(50) 

213 >>> plt.plot(x, y, 'ro', ms=5) 

214 

215 Use the default value for the smoothing parameter: 

216 

217 >>> spl = UnivariateSpline(x, y) 

218 >>> xs = np.linspace(-3, 3, 1000) 

219 >>> plt.plot(xs, spl(xs), 'g', lw=3) 

220 

221 Manually change the amount of smoothing: 

222 

223 >>> spl.set_smoothing_factor(0.5) 

224 >>> plt.plot(xs, spl(xs), 'b', lw=3) 

225 >>> plt.show() 

226 

227 """ 

228 

229 def __init__(self, x, y, w=None, bbox=[None]*2, k=3, s=None, 

230 ext=0, check_finite=False): 

231 

232 x, y, w, bbox, self.ext = self.validate_input(x, y, w, bbox, k, s, ext, 

233 check_finite) 

234 

235 # _data == x,y,w,xb,xe,k,s,n,t,c,fp,fpint,nrdata,ier 

236 data = dfitpack.fpcurf0(x, y, k, w=w, xb=bbox[0], 

237 xe=bbox[1], s=s) 

238 if data[-1] == 1: 

239 # nest too small, setting to maximum bound 

240 data = self._reset_nest(data) 

241 self._data = data 

242 self._reset_class() 

243 

244 @staticmethod 

245 def validate_input(x, y, w, bbox, k, s, ext, check_finite): 

246 x, y, bbox = np.asarray(x), np.asarray(y), np.asarray(bbox) 

247 if w is not None: 

248 w = np.asarray(w) 

249 if check_finite: 

250 w_finite = np.isfinite(w).all() if w is not None else True 

251 if (not np.isfinite(x).all() or not np.isfinite(y).all() or 

252 not w_finite): 

253 raise ValueError("x and y array must not contain " 

254 "NaNs or infs.") 

255 if s is None or s > 0: 

256 if not np.all(diff(x) >= 0.0): 

257 raise ValueError("x must be increasing if s > 0") 

258 else: 

259 if not np.all(diff(x) > 0.0): 

260 raise ValueError("x must be strictly increasing if s = 0") 

261 if x.size != y.size: 

262 raise ValueError("x and y should have a same length") 

263 elif w is not None and not x.size == y.size == w.size: 

264 raise ValueError("x, y, and w should have a same length") 

265 elif bbox.shape != (2,): 

266 raise ValueError("bbox shape should be (2,)") 

267 elif not (1 <= k <= 5): 

268 raise ValueError("k should be 1 <= k <= 5") 

269 elif s is not None and not s >= 0.0: 

270 raise ValueError("s should be s >= 0.0") 

271 

272 try: 

273 ext = _extrap_modes[ext] 

274 except KeyError as e: 

275 raise ValueError("Unknown extrapolation mode %s." % ext) from e 

276 

277 return x, y, w, bbox, ext 

278 

279 @classmethod 

280 def _from_tck(cls, tck, ext=0): 

281 """Construct a spline object from given tck""" 

282 self = cls.__new__(cls) 

283 t, c, k = tck 

284 self._eval_args = tck 

285 # _data == x,y,w,xb,xe,k,s,n,t,c,fp,fpint,nrdata,ier 

286 self._data = (None, None, None, None, None, k, None, len(t), t, 

287 c, None, None, None, None) 

288 self.ext = ext 

289 return self 

290 

291 def _reset_class(self): 

292 data = self._data 

293 n, t, c, k, ier = data[7], data[8], data[9], data[5], data[-1] 

294 self._eval_args = t[:n], c[:n], k 

295 if ier == 0: 

296 # the spline returned has a residual sum of squares fp 

297 # such that abs(fp-s)/s <= tol with tol a relative 

298 # tolerance set to 0.001 by the program 

299 pass 

300 elif ier == -1: 

301 # the spline returned is an interpolating spline 

302 self._set_class(InterpolatedUnivariateSpline) 

303 elif ier == -2: 

304 # the spline returned is the weighted least-squares 

305 # polynomial of degree k. In this extreme case fp gives 

306 # the upper bound fp0 for the smoothing factor s. 

307 self._set_class(LSQUnivariateSpline) 

308 else: 

309 # error 

310 if ier == 1: 

311 self._set_class(LSQUnivariateSpline) 

312 message = _curfit_messages.get(ier, 'ier=%s' % (ier)) 

313 warnings.warn(message) 

314 

315 def _set_class(self, cls): 

316 self._spline_class = cls 

317 if self.__class__ in (UnivariateSpline, InterpolatedUnivariateSpline, 

318 LSQUnivariateSpline): 

319 self.__class__ = cls 

320 else: 

321 # It's an unknown subclass -- don't change class. cf. #731 

322 pass 

323 

324 def _reset_nest(self, data, nest=None): 

325 n = data[10] 

326 if nest is None: 

327 k, m = data[5], len(data[0]) 

328 nest = m+k+1 # this is the maximum bound for nest 

329 else: 

330 if not n <= nest: 

331 raise ValueError("`nest` can only be increased") 

332 t, c, fpint, nrdata = (np.resize(data[j], nest) for j in 

333 [8, 9, 11, 12]) 

334 

335 args = data[:8] + (t, c, n, fpint, nrdata, data[13]) 

336 data = dfitpack.fpcurf1(*args) 

337 return data 

338 

339 def set_smoothing_factor(self, s): 

340 """ Continue spline computation with the given smoothing 

341 factor s and with the knots found at the last call. 

342 

343 This routine modifies the spline in place. 

344 

345 """ 

346 data = self._data 

347 if data[6] == -1: 

348 warnings.warn('smoothing factor unchanged for' 

349 'LSQ spline with fixed knots') 

350 return 

351 args = data[:6] + (s,) + data[7:] 

352 data = dfitpack.fpcurf1(*args) 

353 if data[-1] == 1: 

354 # nest too small, setting to maximum bound 

355 data = self._reset_nest(data) 

356 self._data = data 

357 self._reset_class() 

358 

359 def __call__(self, x, nu=0, ext=None): 

360 """ 

361 Evaluate spline (or its nu-th derivative) at positions x. 

362 

363 Parameters 

364 ---------- 

365 x : array_like 

366 A 1-D array of points at which to return the value of the smoothed 

367 spline or its derivatives. Note: `x` can be unordered but the 

368 evaluation is more efficient if `x` is (partially) ordered. 

369 nu : int 

370 The order of derivative of the spline to compute. 

371 ext : int 

372 Controls the value returned for elements of `x` not in the 

373 interval defined by the knot sequence. 

374 

375 * if ext=0 or 'extrapolate', return the extrapolated value. 

376 * if ext=1 or 'zeros', return 0 

377 * if ext=2 or 'raise', raise a ValueError 

378 * if ext=3 or 'const', return the boundary value. 

379 

380 The default value is 0, passed from the initialization of 

381 UnivariateSpline. 

382 

383 """ 

384 x = np.asarray(x) 

385 # empty input yields empty output 

386 if x.size == 0: 

387 return array([]) 

388 if ext is None: 

389 ext = self.ext 

390 else: 

391 try: 

392 ext = _extrap_modes[ext] 

393 except KeyError as e: 

394 raise ValueError("Unknown extrapolation mode %s." % ext) from e 

395 return _fitpack_impl.splev(x, self._eval_args, der=nu, ext=ext) 

396 

397 def get_knots(self): 

398 """ Return positions of interior knots of the spline. 

399 

400 Internally, the knot vector contains ``2*k`` additional boundary knots. 

401 """ 

402 data = self._data 

403 k, n = data[5], data[7] 

404 return data[8][k:n-k] 

405 

406 def get_coeffs(self): 

407 """Return spline coefficients.""" 

408 data = self._data 

409 k, n = data[5], data[7] 

410 return data[9][:n-k-1] 

411 

412 def get_residual(self): 

413 """Return weighted sum of squared residuals of the spline approximation. 

414 

415 This is equivalent to:: 

416 

417 sum((w[i] * (y[i]-spl(x[i])))**2, axis=0) 

418 

419 """ 

420 return self._data[10] 

421 

422 def integral(self, a, b): 

423 """ Return definite integral of the spline between two given points. 

424 

425 Parameters 

426 ---------- 

427 a : float 

428 Lower limit of integration. 

429 b : float 

430 Upper limit of integration. 

431 

432 Returns 

433 ------- 

434 integral : float 

435 The value of the definite integral of the spline between limits. 

436 

437 Examples 

438 -------- 

439 >>> import numpy as np 

440 >>> from scipy.interpolate import UnivariateSpline 

441 >>> x = np.linspace(0, 3, 11) 

442 >>> y = x**2 

443 >>> spl = UnivariateSpline(x, y) 

444 >>> spl.integral(0, 3) 

445 9.0 

446 

447 which agrees with :math:`\\int x^2 dx = x^3 / 3` between the limits 

448 of 0 and 3. 

449 

450 A caveat is that this routine assumes the spline to be zero outside of 

451 the data limits: 

452 

453 >>> spl.integral(-1, 4) 

454 9.0 

455 >>> spl.integral(-1, 0) 

456 0.0 

457 

458 """ 

459 return _fitpack_impl.splint(a, b, self._eval_args) 

460 

461 def derivatives(self, x): 

462 """ Return all derivatives of the spline at the point x. 

463 

464 Parameters 

465 ---------- 

466 x : float 

467 The point to evaluate the derivatives at. 

468 

469 Returns 

470 ------- 

471 der : ndarray, shape(k+1,) 

472 Derivatives of the orders 0 to k. 

473 

474 Examples 

475 -------- 

476 >>> import numpy as np 

477 >>> from scipy.interpolate import UnivariateSpline 

478 >>> x = np.linspace(0, 3, 11) 

479 >>> y = x**2 

480 >>> spl = UnivariateSpline(x, y) 

481 >>> spl.derivatives(1.5) 

482 array([2.25, 3.0, 2.0, 0]) 

483 

484 """ 

485 return _fitpack_impl.spalde(x, self._eval_args) 

486 

487 def roots(self): 

488 """ Return the zeros of the spline. 

489 

490 Notes 

491 ----- 

492 Restriction: only cubic splines are supported by FITPACK. For non-cubic 

493 splines, use `PPoly.root` (see below for an example). 

494 

495 Examples 

496 -------- 

497 

498 For some data, this method may miss a root. This happens when one of 

499 the spline knots (which FITPACK places automatically) happens to 

500 coincide with the true root. A workaround is to convert to `PPoly`, 

501 which uses a different root-finding algorithm. 

502 

503 For example, 

504 

505 >>> x = [1.96, 1.97, 1.98, 1.99, 2.00, 2.01, 2.02, 2.03, 2.04, 2.05] 

506 >>> y = [-6.365470e-03, -4.790580e-03, -3.204320e-03, -1.607270e-03, 

507 ... 4.440892e-16, 1.616930e-03, 3.243000e-03, 4.877670e-03, 

508 ... 6.520430e-03, 8.170770e-03] 

509 >>> from scipy.interpolate import UnivariateSpline 

510 >>> spl = UnivariateSpline(x, y, s=0) 

511 >>> spl.roots() 

512 array([], dtype=float64) 

513 

514 Converting to a PPoly object does find the roots at `x=2`: 

515 

516 >>> from scipy.interpolate import splrep, PPoly 

517 >>> tck = splrep(x, y, s=0) 

518 >>> ppoly = PPoly.from_spline(tck) 

519 >>> ppoly.roots(extrapolate=False) 

520 array([2.]) 

521 

522 See Also 

523 -------- 

524 sproot 

525 PPoly.roots 

526 

527 """ 

528 k = self._data[5] 

529 if k == 3: 

530 t = self._eval_args[0] 

531 mest = 3 * (len(t) - 7) 

532 return _fitpack_impl.sproot(self._eval_args, mest=mest) 

533 raise NotImplementedError('finding roots unsupported for ' 

534 'non-cubic splines') 

535 

536 def derivative(self, n=1): 

537 """ 

538 Construct a new spline representing the derivative of this spline. 

539 

540 Parameters 

541 ---------- 

542 n : int, optional 

543 Order of derivative to evaluate. Default: 1 

544 

545 Returns 

546 ------- 

547 spline : UnivariateSpline 

548 Spline of order k2=k-n representing the derivative of this 

549 spline. 

550 

551 See Also 

552 -------- 

553 splder, antiderivative 

554 

555 Notes 

556 ----- 

557 

558 .. versionadded:: 0.13.0 

559 

560 Examples 

561 -------- 

562 This can be used for finding maxima of a curve: 

563 

564 >>> import numpy as np 

565 >>> from scipy.interpolate import UnivariateSpline 

566 >>> x = np.linspace(0, 10, 70) 

567 >>> y = np.sin(x) 

568 >>> spl = UnivariateSpline(x, y, k=4, s=0) 

569 

570 Now, differentiate the spline and find the zeros of the 

571 derivative. (NB: `sproot` only works for order 3 splines, so we 

572 fit an order 4 spline): 

573 

574 >>> spl.derivative().roots() / np.pi 

575 array([ 0.50000001, 1.5 , 2.49999998]) 

576 

577 This agrees well with roots :math:`\\pi/2 + n\\pi` of 

578 :math:`\\cos(x) = \\sin'(x)`. 

579 

580 """ 

581 tck = _fitpack_impl.splder(self._eval_args, n) 

582 # if self.ext is 'const', derivative.ext will be 'zeros' 

583 ext = 1 if self.ext == 3 else self.ext 

584 return UnivariateSpline._from_tck(tck, ext=ext) 

585 

586 def antiderivative(self, n=1): 

587 """ 

588 Construct a new spline representing the antiderivative of this spline. 

589 

590 Parameters 

591 ---------- 

592 n : int, optional 

593 Order of antiderivative to evaluate. Default: 1 

594 

595 Returns 

596 ------- 

597 spline : UnivariateSpline 

598 Spline of order k2=k+n representing the antiderivative of this 

599 spline. 

600 

601 Notes 

602 ----- 

603 

604 .. versionadded:: 0.13.0 

605 

606 See Also 

607 -------- 

608 splantider, derivative 

609 

610 Examples 

611 -------- 

612 >>> import numpy as np 

613 >>> from scipy.interpolate import UnivariateSpline 

614 >>> x = np.linspace(0, np.pi/2, 70) 

615 >>> y = 1 / np.sqrt(1 - 0.8*np.sin(x)**2) 

616 >>> spl = UnivariateSpline(x, y, s=0) 

617 

618 The derivative is the inverse operation of the antiderivative, 

619 although some floating point error accumulates: 

620 

621 >>> spl(1.7), spl.antiderivative().derivative()(1.7) 

622 (array(2.1565429877197317), array(2.1565429877201865)) 

623 

624 Antiderivative can be used to evaluate definite integrals: 

625 

626 >>> ispl = spl.antiderivative() 

627 >>> ispl(np.pi/2) - ispl(0) 

628 2.2572053588768486 

629 

630 This is indeed an approximation to the complete elliptic integral 

631 :math:`K(m) = \\int_0^{\\pi/2} [1 - m\\sin^2 x]^{-1/2} dx`: 

632 

633 >>> from scipy.special import ellipk 

634 >>> ellipk(0.8) 

635 2.2572053268208538 

636 

637 """ 

638 tck = _fitpack_impl.splantider(self._eval_args, n) 

639 return UnivariateSpline._from_tck(tck, self.ext) 

640 

641 

642class InterpolatedUnivariateSpline(UnivariateSpline): 

643 """ 

644 1-D interpolating spline for a given set of data points. 

645 

646 Fits a spline y = spl(x) of degree `k` to the provided `x`, `y` data. 

647 Spline function passes through all provided points. Equivalent to 

648 `UnivariateSpline` with `s` = 0. 

649 

650 Parameters 

651 ---------- 

652 x : (N,) array_like 

653 Input dimension of data points -- must be strictly increasing 

654 y : (N,) array_like 

655 input dimension of data points 

656 w : (N,) array_like, optional 

657 Weights for spline fitting. Must be positive. If None (default), 

658 weights are all 1. 

659 bbox : (2,) array_like, optional 

660 2-sequence specifying the boundary of the approximation interval. If 

661 None (default), ``bbox=[x[0], x[-1]]``. 

662 k : int, optional 

663 Degree of the smoothing spline. Must be ``1 <= k <= 5``. Default is 

664 ``k = 3``, a cubic spline. 

665 ext : int or str, optional 

666 Controls the extrapolation mode for elements 

667 not in the interval defined by the knot sequence. 

668 

669 * if ext=0 or 'extrapolate', return the extrapolated value. 

670 * if ext=1 or 'zeros', return 0 

671 * if ext=2 or 'raise', raise a ValueError 

672 * if ext=3 of 'const', return the boundary value. 

673 

674 The default value is 0. 

675 

676 check_finite : bool, optional 

677 Whether to check that the input arrays contain only finite numbers. 

678 Disabling may give a performance gain, but may result in problems 

679 (crashes, non-termination or non-sensical results) if the inputs 

680 do contain infinities or NaNs. 

681 Default is False. 

682 

683 See Also 

684 -------- 

685 UnivariateSpline : 

686 a smooth univariate spline to fit a given set of data points. 

687 LSQUnivariateSpline : 

688 a spline for which knots are user-selected 

689 SmoothBivariateSpline : 

690 a smoothing bivariate spline through the given points 

691 LSQBivariateSpline : 

692 a bivariate spline using weighted least-squares fitting 

693 splrep : 

694 a function to find the B-spline representation of a 1-D curve 

695 splev : 

696 a function to evaluate a B-spline or its derivatives 

697 sproot : 

698 a function to find the roots of a cubic B-spline 

699 splint : 

700 a function to evaluate the definite integral of a B-spline between two 

701 given points 

702 spalde : 

703 a function to evaluate all derivatives of a B-spline 

704 

705 Notes 

706 ----- 

707 The number of data points must be larger than the spline degree `k`. 

708 

709 Examples 

710 -------- 

711 >>> import numpy as np 

712 >>> import matplotlib.pyplot as plt 

713 >>> from scipy.interpolate import InterpolatedUnivariateSpline 

714 >>> rng = np.random.default_rng() 

715 >>> x = np.linspace(-3, 3, 50) 

716 >>> y = np.exp(-x**2) + 0.1 * rng.standard_normal(50) 

717 >>> spl = InterpolatedUnivariateSpline(x, y) 

718 >>> plt.plot(x, y, 'ro', ms=5) 

719 >>> xs = np.linspace(-3, 3, 1000) 

720 >>> plt.plot(xs, spl(xs), 'g', lw=3, alpha=0.7) 

721 >>> plt.show() 

722 

723 Notice that the ``spl(x)`` interpolates `y`: 

724 

725 >>> spl.get_residual() 

726 0.0 

727 

728 """ 

729 

730 def __init__(self, x, y, w=None, bbox=[None]*2, k=3, 

731 ext=0, check_finite=False): 

732 

733 x, y, w, bbox, self.ext = self.validate_input(x, y, w, bbox, k, None, 

734 ext, check_finite) 

735 if not np.all(diff(x) > 0.0): 

736 raise ValueError('x must be strictly increasing') 

737 

738 # _data == x,y,w,xb,xe,k,s,n,t,c,fp,fpint,nrdata,ier 

739 self._data = dfitpack.fpcurf0(x, y, k, w=w, xb=bbox[0], 

740 xe=bbox[1], s=0) 

741 self._reset_class() 

742 

743 

744_fpchec_error_string = """The input parameters have been rejected by fpchec. \ 

745This means that at least one of the following conditions is violated: 

746 

7471) k+1 <= n-k-1 <= m 

7482) t(1) <= t(2) <= ... <= t(k+1) 

749 t(n-k) <= t(n-k+1) <= ... <= t(n) 

7503) t(k+1) < t(k+2) < ... < t(n-k) 

7514) t(k+1) <= x(i) <= t(n-k) 

7525) The conditions specified by Schoenberg and Whitney must hold 

753 for at least one subset of data points, i.e., there must be a 

754 subset of data points y(j) such that 

755 t(j) < y(j) < t(j+k+1), j=1,2,...,n-k-1 

756""" 

757 

758 

759class LSQUnivariateSpline(UnivariateSpline): 

760 """ 

761 1-D spline with explicit internal knots. 

762 

763 Fits a spline y = spl(x) of degree `k` to the provided `x`, `y` data. `t` 

764 specifies the internal knots of the spline 

765 

766 Parameters 

767 ---------- 

768 x : (N,) array_like 

769 Input dimension of data points -- must be increasing 

770 y : (N,) array_like 

771 Input dimension of data points 

772 t : (M,) array_like 

773 interior knots of the spline. Must be in ascending order and:: 

774 

775 bbox[0] < t[0] < ... < t[-1] < bbox[-1] 

776 

777 w : (N,) array_like, optional 

778 weights for spline fitting. Must be positive. If None (default), 

779 weights are all 1. 

780 bbox : (2,) array_like, optional 

781 2-sequence specifying the boundary of the approximation interval. If 

782 None (default), ``bbox = [x[0], x[-1]]``. 

783 k : int, optional 

784 Degree of the smoothing spline. Must be 1 <= `k` <= 5. 

785 Default is `k` = 3, a cubic spline. 

786 ext : int or str, optional 

787 Controls the extrapolation mode for elements 

788 not in the interval defined by the knot sequence. 

789 

790 * if ext=0 or 'extrapolate', return the extrapolated value. 

791 * if ext=1 or 'zeros', return 0 

792 * if ext=2 or 'raise', raise a ValueError 

793 * if ext=3 of 'const', return the boundary value. 

794 

795 The default value is 0. 

796 

797 check_finite : bool, optional 

798 Whether to check that the input arrays contain only finite numbers. 

799 Disabling may give a performance gain, but may result in problems 

800 (crashes, non-termination or non-sensical results) if the inputs 

801 do contain infinities or NaNs. 

802 Default is False. 

803 

804 Raises 

805 ------ 

806 ValueError 

807 If the interior knots do not satisfy the Schoenberg-Whitney conditions 

808 

809 See Also 

810 -------- 

811 UnivariateSpline : 

812 a smooth univariate spline to fit a given set of data points. 

813 InterpolatedUnivariateSpline : 

814 a interpolating univariate spline for a given set of data points. 

815 splrep : 

816 a function to find the B-spline representation of a 1-D curve 

817 splev : 

818 a function to evaluate a B-spline or its derivatives 

819 sproot : 

820 a function to find the roots of a cubic B-spline 

821 splint : 

822 a function to evaluate the definite integral of a B-spline between two 

823 given points 

824 spalde : 

825 a function to evaluate all derivatives of a B-spline 

826 

827 Notes 

828 ----- 

829 The number of data points must be larger than the spline degree `k`. 

830 

831 Knots `t` must satisfy the Schoenberg-Whitney conditions, 

832 i.e., there must be a subset of data points ``x[j]`` such that 

833 ``t[j] < x[j] < t[j+k+1]``, for ``j=0, 1,...,n-k-2``. 

834 

835 Examples 

836 -------- 

837 >>> import numpy as np 

838 >>> from scipy.interpolate import LSQUnivariateSpline, UnivariateSpline 

839 >>> import matplotlib.pyplot as plt 

840 >>> rng = np.random.default_rng() 

841 >>> x = np.linspace(-3, 3, 50) 

842 >>> y = np.exp(-x**2) + 0.1 * rng.standard_normal(50) 

843 

844 Fit a smoothing spline with a pre-defined internal knots: 

845 

846 >>> t = [-1, 0, 1] 

847 >>> spl = LSQUnivariateSpline(x, y, t) 

848 

849 >>> xs = np.linspace(-3, 3, 1000) 

850 >>> plt.plot(x, y, 'ro', ms=5) 

851 >>> plt.plot(xs, spl(xs), 'g-', lw=3) 

852 >>> plt.show() 

853 

854 Check the knot vector: 

855 

856 >>> spl.get_knots() 

857 array([-3., -1., 0., 1., 3.]) 

858 

859 Constructing lsq spline using the knots from another spline: 

860 

861 >>> x = np.arange(10) 

862 >>> s = UnivariateSpline(x, x, s=0) 

863 >>> s.get_knots() 

864 array([ 0., 2., 3., 4., 5., 6., 7., 9.]) 

865 >>> knt = s.get_knots() 

866 >>> s1 = LSQUnivariateSpline(x, x, knt[1:-1]) # Chop 1st and last knot 

867 >>> s1.get_knots() 

868 array([ 0., 2., 3., 4., 5., 6., 7., 9.]) 

869 

870 """ 

871 

872 def __init__(self, x, y, t, w=None, bbox=[None]*2, k=3, 

873 ext=0, check_finite=False): 

874 

875 x, y, w, bbox, self.ext = self.validate_input(x, y, w, bbox, k, None, 

876 ext, check_finite) 

877 if not np.all(diff(x) >= 0.0): 

878 raise ValueError('x must be increasing') 

879 

880 # _data == x,y,w,xb,xe,k,s,n,t,c,fp,fpint,nrdata,ier 

881 xb = bbox[0] 

882 xe = bbox[1] 

883 if xb is None: 

884 xb = x[0] 

885 if xe is None: 

886 xe = x[-1] 

887 t = concatenate(([xb]*(k+1), t, [xe]*(k+1))) 

888 n = len(t) 

889 if not np.all(t[k+1:n-k]-t[k:n-k-1] > 0, axis=0): 

890 raise ValueError('Interior knots t must satisfy ' 

891 'Schoenberg-Whitney conditions') 

892 if not dfitpack.fpchec(x, t, k) == 0: 

893 raise ValueError(_fpchec_error_string) 

894 data = dfitpack.fpcurfm1(x, y, k, t, w=w, xb=xb, xe=xe) 

895 self._data = data[:-3] + (None, None, data[-1]) 

896 self._reset_class() 

897 

898 

899# ############### Bivariate spline #################### 

900 

901class _BivariateSplineBase: 

902 """ Base class for Bivariate spline s(x,y) interpolation on the rectangle 

903 [xb,xe] x [yb, ye] calculated from a given set of data points 

904 (x,y,z). 

905 

906 See Also 

907 -------- 

908 bisplrep : 

909 a function to find a bivariate B-spline representation of a surface 

910 bisplev : 

911 a function to evaluate a bivariate B-spline and its derivatives 

912 BivariateSpline : 

913 a base class for bivariate splines. 

914 SphereBivariateSpline : 

915 a bivariate spline on a spherical grid 

916 """ 

917 

918 @classmethod 

919 def _from_tck(cls, tck): 

920 """Construct a spline object from given tck and degree""" 

921 self = cls.__new__(cls) 

922 if len(tck) != 5: 

923 raise ValueError("tck should be a 5 element tuple of tx," 

924 " ty, c, kx, ky") 

925 self.tck = tck[:3] 

926 self.degrees = tck[3:] 

927 return self 

928 

929 def get_residual(self): 

930 """ Return weighted sum of squared residuals of the spline 

931 approximation: sum ((w[i]*(z[i]-s(x[i],y[i])))**2,axis=0) 

932 """ 

933 return self.fp 

934 

935 def get_knots(self): 

936 """ Return a tuple (tx,ty) where tx,ty contain knots positions 

937 of the spline with respect to x-, y-variable, respectively. 

938 The position of interior and additional knots are given as 

939 t[k+1:-k-1] and t[:k+1]=b, t[-k-1:]=e, respectively. 

940 """ 

941 return self.tck[:2] 

942 

943 def get_coeffs(self): 

944 """ Return spline coefficients.""" 

945 return self.tck[2] 

946 

947 def __call__(self, x, y, dx=0, dy=0, grid=True): 

948 """ 

949 Evaluate the spline or its derivatives at given positions. 

950 

951 Parameters 

952 ---------- 

953 x, y : array_like 

954 Input coordinates. 

955 

956 If `grid` is False, evaluate the spline at points ``(x[i], 

957 y[i]), i=0, ..., len(x)-1``. Standard Numpy broadcasting 

958 is obeyed. 

959 

960 If `grid` is True: evaluate spline at the grid points 

961 defined by the coordinate arrays x, y. The arrays must be 

962 sorted to increasing order. 

963 

964 The ordering of axes is consistent with 

965 ``np.meshgrid(..., indexing="ij")`` and inconsistent with the 

966 default ordering ``np.meshgrid(..., indexing="xy")``. 

967 dx : int 

968 Order of x-derivative 

969 

970 .. versionadded:: 0.14.0 

971 dy : int 

972 Order of y-derivative 

973 

974 .. versionadded:: 0.14.0 

975 grid : bool 

976 Whether to evaluate the results on a grid spanned by the 

977 input arrays, or at points specified by the input arrays. 

978 

979 .. versionadded:: 0.14.0 

980 

981 Examples 

982 -------- 

983 Suppose that we want to bilinearly interpolate an exponentially decaying 

984 function in 2 dimensions. 

985 

986 >>> import numpy as np 

987 >>> from scipy.interpolate import RectBivariateSpline 

988 

989 We sample the function on a coarse grid. Note that the default indexing="xy" 

990 of meshgrid would result in an unexpected (transposed) result after 

991 interpolation. 

992 

993 >>> xarr = np.linspace(-3, 3, 100) 

994 >>> yarr = np.linspace(-3, 3, 100) 

995 >>> xgrid, ygrid = np.meshgrid(xarr, yarr, indexing="ij") 

996 

997 The function to interpolate decays faster along one axis than the other. 

998 

999 >>> zdata = np.exp(-np.sqrt((xgrid / 2) ** 2 + ygrid**2)) 

1000 

1001 Next we sample on a finer grid using interpolation (kx=ky=1 for bilinear). 

1002 

1003 >>> rbs = RectBivariateSpline(xarr, yarr, zdata, kx=1, ky=1) 

1004 >>> xarr_fine = np.linspace(-3, 3, 200) 

1005 >>> yarr_fine = np.linspace(-3, 3, 200) 

1006 >>> xgrid_fine, ygrid_fine = np.meshgrid(xarr_fine, yarr_fine, indexing="ij") 

1007 >>> zdata_interp = rbs(xgrid_fine, ygrid_fine, grid=False) 

1008 

1009 And check that the result agrees with the input by plotting both. 

1010 

1011 >>> import matplotlib.pyplot as plt 

1012 >>> fig = plt.figure() 

1013 >>> ax1 = fig.add_subplot(1, 2, 1, aspect="equal") 

1014 >>> ax2 = fig.add_subplot(1, 2, 2, aspect="equal") 

1015 >>> ax1.imshow(zdata) 

1016 >>> ax2.imshow(zdata_interp) 

1017 >>> plt.show() 

1018 """ 

1019 x = np.asarray(x) 

1020 y = np.asarray(y) 

1021 

1022 tx, ty, c = self.tck[:3] 

1023 kx, ky = self.degrees 

1024 if grid: 

1025 if x.size == 0 or y.size == 0: 

1026 return np.zeros((x.size, y.size), dtype=self.tck[2].dtype) 

1027 

1028 if (x.size >= 2) and (not np.all(np.diff(x) >= 0.0)): 

1029 raise ValueError("x must be strictly increasing when `grid` is True") 

1030 if (y.size >= 2) and (not np.all(np.diff(y) >= 0.0)): 

1031 raise ValueError("y must be strictly increasing when `grid` is True") 

1032 

1033 if dx or dy: 

1034 z, ier = dfitpack.parder(tx, ty, c, kx, ky, dx, dy, x, y) 

1035 if not ier == 0: 

1036 raise ValueError("Error code returned by parder: %s" % ier) 

1037 else: 

1038 z, ier = dfitpack.bispev(tx, ty, c, kx, ky, x, y) 

1039 if not ier == 0: 

1040 raise ValueError("Error code returned by bispev: %s" % ier) 

1041 else: 

1042 # standard Numpy broadcasting 

1043 if x.shape != y.shape: 

1044 x, y = np.broadcast_arrays(x, y) 

1045 

1046 shape = x.shape 

1047 x = x.ravel() 

1048 y = y.ravel() 

1049 

1050 if x.size == 0 or y.size == 0: 

1051 return np.zeros(shape, dtype=self.tck[2].dtype) 

1052 

1053 if dx or dy: 

1054 z, ier = dfitpack.pardeu(tx, ty, c, kx, ky, dx, dy, x, y) 

1055 if not ier == 0: 

1056 raise ValueError("Error code returned by pardeu: %s" % ier) 

1057 else: 

1058 z, ier = dfitpack.bispeu(tx, ty, c, kx, ky, x, y) 

1059 if not ier == 0: 

1060 raise ValueError("Error code returned by bispeu: %s" % ier) 

1061 

1062 z = z.reshape(shape) 

1063 return z 

1064 

1065 def partial_derivative(self, dx, dy): 

1066 """Construct a new spline representing a partial derivative of this 

1067 spline. 

1068 

1069 Parameters 

1070 ---------- 

1071 dx, dy : int 

1072 Orders of the derivative in x and y respectively. They must be 

1073 non-negative integers and less than the respective degree of the 

1074 original spline (self) in that direction (``kx``, ``ky``). 

1075 

1076 Returns 

1077 ------- 

1078 spline : 

1079 A new spline of degrees (``kx - dx``, ``ky - dy``) representing the 

1080 derivative of this spline. 

1081 

1082 Notes 

1083 ----- 

1084 

1085 .. versionadded:: 1.9.0 

1086 

1087 """ 

1088 if dx == 0 and dy == 0: 

1089 return self 

1090 else: 

1091 kx, ky = self.degrees 

1092 if not (dx >= 0 and dy >= 0): 

1093 raise ValueError("order of derivative must be positive or" 

1094 " zero") 

1095 if not (dx < kx and dy < ky): 

1096 raise ValueError("order of derivative must be less than" 

1097 " degree of spline") 

1098 tx, ty, c = self.tck[:3] 

1099 newc, ier = dfitpack.pardtc(tx, ty, c, kx, ky, dx, dy) 

1100 if ier != 0: 

1101 # This should not happen under normal conditions. 

1102 raise ValueError("Unexpected error code returned by" 

1103 " pardtc: %d" % ier) 

1104 nx = len(tx) 

1105 ny = len(ty) 

1106 newtx = tx[dx:nx - dx] 

1107 newty = ty[dy:ny - dy] 

1108 newkx, newky = kx - dx, ky - dy 

1109 newclen = (nx - dx - kx - 1) * (ny - dy - ky - 1) 

1110 return _DerivedBivariateSpline._from_tck((newtx, newty, 

1111 newc[:newclen], 

1112 newkx, newky)) 

1113 

1114 

1115_surfit_messages = {1: """ 

1116The required storage space exceeds the available storage space: nxest 

1117or nyest too small, or s too small. 

1118The weighted least-squares spline corresponds to the current set of 

1119knots.""", 

1120 2: """ 

1121A theoretically impossible result was found during the iteration 

1122process for finding a smoothing spline with fp = s: s too small or 

1123badly chosen eps. 

1124Weighted sum of squared residuals does not satisfy abs(fp-s)/s < tol.""", 

1125 3: """ 

1126the maximal number of iterations maxit (set to 20 by the program) 

1127allowed for finding a smoothing spline with fp=s has been reached: 

1128s too small. 

1129Weighted sum of squared residuals does not satisfy abs(fp-s)/s < tol.""", 

1130 4: """ 

1131No more knots can be added because the number of b-spline coefficients 

1132(nx-kx-1)*(ny-ky-1) already exceeds the number of data points m: 

1133either s or m too small. 

1134The weighted least-squares spline corresponds to the current set of 

1135knots.""", 

1136 5: """ 

1137No more knots can be added because the additional knot would (quasi) 

1138coincide with an old one: s too small or too large a weight to an 

1139inaccurate data point. 

1140The weighted least-squares spline corresponds to the current set of 

1141knots.""", 

1142 10: """ 

1143Error on entry, no approximation returned. The following conditions 

1144must hold: 

1145xb<=x[i]<=xe, yb<=y[i]<=ye, w[i]>0, i=0..m-1 

1146If iopt==-1, then 

1147 xb<tx[kx+1]<tx[kx+2]<...<tx[nx-kx-2]<xe 

1148 yb<ty[ky+1]<ty[ky+2]<...<ty[ny-ky-2]<ye""", 

1149 -3: """ 

1150The coefficients of the spline returned have been computed as the 

1151minimal norm least-squares solution of a (numerically) rank deficient 

1152system (deficiency=%i). If deficiency is large, the results may be 

1153inaccurate. Deficiency may strongly depend on the value of eps.""" 

1154 } 

1155 

1156 

1157class BivariateSpline(_BivariateSplineBase): 

1158 """ 

1159 Base class for bivariate splines. 

1160 

1161 This describes a spline ``s(x, y)`` of degrees ``kx`` and ``ky`` on 

1162 the rectangle ``[xb, xe] * [yb, ye]`` calculated from a given set 

1163 of data points ``(x, y, z)``. 

1164 

1165 This class is meant to be subclassed, not instantiated directly. 

1166 To construct these splines, call either `SmoothBivariateSpline` or 

1167 `LSQBivariateSpline` or `RectBivariateSpline`. 

1168 

1169 See Also 

1170 -------- 

1171 UnivariateSpline : 

1172 a smooth univariate spline to fit a given set of data points. 

1173 SmoothBivariateSpline : 

1174 a smoothing bivariate spline through the given points 

1175 LSQBivariateSpline : 

1176 a bivariate spline using weighted least-squares fitting 

1177 RectSphereBivariateSpline : 

1178 a bivariate spline over a rectangular mesh on a sphere 

1179 SmoothSphereBivariateSpline : 

1180 a smoothing bivariate spline in spherical coordinates 

1181 LSQSphereBivariateSpline : 

1182 a bivariate spline in spherical coordinates using weighted 

1183 least-squares fitting 

1184 RectBivariateSpline : 

1185 a bivariate spline over a rectangular mesh. 

1186 bisplrep : 

1187 a function to find a bivariate B-spline representation of a surface 

1188 bisplev : 

1189 a function to evaluate a bivariate B-spline and its derivatives 

1190 """ 

1191 

1192 def ev(self, xi, yi, dx=0, dy=0): 

1193 """ 

1194 Evaluate the spline at points 

1195 

1196 Returns the interpolated value at ``(xi[i], yi[i]), 

1197 i=0,...,len(xi)-1``. 

1198 

1199 Parameters 

1200 ---------- 

1201 xi, yi : array_like 

1202 Input coordinates. Standard Numpy broadcasting is obeyed. 

1203 The ordering of axes is consistent with 

1204 ``np.meshgrid(..., indexing="ij")`` and inconsistent with the 

1205 default ordering ``np.meshgrid(..., indexing="xy")``. 

1206 dx : int, optional 

1207 Order of x-derivative 

1208 

1209 .. versionadded:: 0.14.0 

1210 dy : int, optional 

1211 Order of y-derivative 

1212 

1213 .. versionadded:: 0.14.0 

1214 

1215 Examples 

1216 -------- 

1217 Suppose that we want to bilinearly interpolate an exponentially decaying 

1218 function in 2 dimensions. 

1219 

1220 >>> import numpy as np 

1221 >>> from scipy.interpolate import RectBivariateSpline 

1222 >>> def f(x, y): 

1223 ... return np.exp(-np.sqrt((x / 2) ** 2 + y**2)) 

1224 

1225 We sample the function on a coarse grid and set up the interpolator. Note that 

1226 the default ``indexing="xy"`` of meshgrid would result in an unexpected (transposed) 

1227 result after interpolation. 

1228 

1229 >>> xarr = np.linspace(-3, 3, 21) 

1230 >>> yarr = np.linspace(-3, 3, 21) 

1231 >>> xgrid, ygrid = np.meshgrid(xarr, yarr, indexing="ij") 

1232 >>> zdata = f(xgrid, ygrid) 

1233 >>> rbs = RectBivariateSpline(xarr, yarr, zdata, kx=1, ky=1) 

1234 

1235 Next we sample the function along a diagonal slice through the coordinate space 

1236 on a finer grid using interpolation. 

1237 

1238 >>> xinterp = np.linspace(-3, 3, 201) 

1239 >>> yinterp = np.linspace(3, -3, 201) 

1240 >>> zinterp = rbs.ev(xinterp, yinterp) 

1241 

1242 And check that the interpolation passes through the function evaluations as a 

1243 function of the distance from the origin along the slice. 

1244 

1245 >>> import matplotlib.pyplot as plt 

1246 >>> fig = plt.figure() 

1247 >>> ax1 = fig.add_subplot(1, 1, 1) 

1248 >>> ax1.plot(np.sqrt(xarr**2 + yarr**2), np.diag(zdata), "or") 

1249 >>> ax1.plot(np.sqrt(xinterp**2 + yinterp**2), zinterp, "-b") 

1250 >>> plt.show() 

1251 """ 

1252 return self.__call__(xi, yi, dx=dx, dy=dy, grid=False) 

1253 

1254 def integral(self, xa, xb, ya, yb): 

1255 """ 

1256 Evaluate the integral of the spline over area [xa,xb] x [ya,yb]. 

1257 

1258 Parameters 

1259 ---------- 

1260 xa, xb : float 

1261 The end-points of the x integration interval. 

1262 ya, yb : float 

1263 The end-points of the y integration interval. 

1264 

1265 Returns 

1266 ------- 

1267 integ : float 

1268 The value of the resulting integral. 

1269 

1270 """ 

1271 tx, ty, c = self.tck[:3] 

1272 kx, ky = self.degrees 

1273 return dfitpack.dblint(tx, ty, c, kx, ky, xa, xb, ya, yb) 

1274 

1275 @staticmethod 

1276 def _validate_input(x, y, z, w, kx, ky, eps): 

1277 x, y, z = np.asarray(x), np.asarray(y), np.asarray(z) 

1278 if not x.size == y.size == z.size: 

1279 raise ValueError('x, y, and z should have a same length') 

1280 

1281 if w is not None: 

1282 w = np.asarray(w) 

1283 if x.size != w.size: 

1284 raise ValueError('x, y, z, and w should have a same length') 

1285 elif not np.all(w >= 0.0): 

1286 raise ValueError('w should be positive') 

1287 if (eps is not None) and (not 0.0 < eps < 1.0): 

1288 raise ValueError('eps should be between (0, 1)') 

1289 if not x.size >= (kx + 1) * (ky + 1): 

1290 raise ValueError('The length of x, y and z should be at least' 

1291 ' (kx+1) * (ky+1)') 

1292 return x, y, z, w 

1293 

1294 

1295class _DerivedBivariateSpline(_BivariateSplineBase): 

1296 """Bivariate spline constructed from the coefficients and knots of another 

1297 spline. 

1298 

1299 Notes 

1300 ----- 

1301 The class is not meant to be instantiated directly from the data to be 

1302 interpolated or smoothed. As a result, its ``fp`` attribute and 

1303 ``get_residual`` method are inherited but overriden; ``AttributeError`` is 

1304 raised when they are accessed. 

1305 

1306 The other inherited attributes can be used as usual. 

1307 """ 

1308 _invalid_why = ("is unavailable, because _DerivedBivariateSpline" 

1309 " instance is not constructed from data that are to be" 

1310 " interpolated or smoothed, but derived from the" 

1311 " underlying knots and coefficients of another spline" 

1312 " object") 

1313 

1314 @property 

1315 def fp(self): 

1316 raise AttributeError("attribute \"fp\" %s" % self._invalid_why) 

1317 

1318 def get_residual(self): 

1319 raise AttributeError("method \"get_residual\" %s" % self._invalid_why) 

1320 

1321 

1322class SmoothBivariateSpline(BivariateSpline): 

1323 """ 

1324 Smooth bivariate spline approximation. 

1325 

1326 Parameters 

1327 ---------- 

1328 x, y, z : array_like 

1329 1-D sequences of data points (order is not important). 

1330 w : array_like, optional 

1331 Positive 1-D sequence of weights, of same length as `x`, `y` and `z`. 

1332 bbox : array_like, optional 

1333 Sequence of length 4 specifying the boundary of the rectangular 

1334 approximation domain. By default, 

1335 ``bbox=[min(x), max(x), min(y), max(y)]``. 

1336 kx, ky : ints, optional 

1337 Degrees of the bivariate spline. Default is 3. 

1338 s : float, optional 

1339 Positive smoothing factor defined for estimation condition: 

1340 ``sum((w[i]*(z[i]-s(x[i], y[i])))**2, axis=0) <= s`` 

1341 Default ``s=len(w)`` which should be a good value if ``1/w[i]`` is an 

1342 estimate of the standard deviation of ``z[i]``. 

1343 eps : float, optional 

1344 A threshold for determining the effective rank of an over-determined 

1345 linear system of equations. `eps` should have a value within the open 

1346 interval ``(0, 1)``, the default is 1e-16. 

1347 

1348 See Also 

1349 -------- 

1350 BivariateSpline : 

1351 a base class for bivariate splines. 

1352 UnivariateSpline : 

1353 a smooth univariate spline to fit a given set of data points. 

1354 LSQBivariateSpline : 

1355 a bivariate spline using weighted least-squares fitting 

1356 RectSphereBivariateSpline : 

1357 a bivariate spline over a rectangular mesh on a sphere 

1358 SmoothSphereBivariateSpline : 

1359 a smoothing bivariate spline in spherical coordinates 

1360 LSQSphereBivariateSpline : 

1361 a bivariate spline in spherical coordinates using weighted 

1362 least-squares fitting 

1363 RectBivariateSpline : 

1364 a bivariate spline over a rectangular mesh 

1365 bisplrep : 

1366 a function to find a bivariate B-spline representation of a surface 

1367 bisplev : 

1368 a function to evaluate a bivariate B-spline and its derivatives 

1369 

1370 Notes 

1371 ----- 

1372 The length of `x`, `y` and `z` should be at least ``(kx+1) * (ky+1)``. 

1373 

1374 If the input data is such that input dimensions have incommensurate 

1375 units and differ by many orders of magnitude, the interpolant may have 

1376 numerical artifacts. Consider rescaling the data before interpolating. 

1377 

1378 This routine constructs spline knot vectors automatically via the FITPACK 

1379 algorithm. The spline knots may be placed away from the data points. For 

1380 some data sets, this routine may fail to construct an interpolating spline, 

1381 even if one is requested via ``s=0`` parameter. In such situations, it is 

1382 recommended to use `bisplrep` / `bisplev` directly instead of this routine 

1383 and, if needed, increase the values of ``nxest`` and ``nyest`` parameters 

1384 of `bisplrep`. 

1385 

1386 For linear interpolation, prefer `LinearNDInterpolator`. 

1387 See ``https://gist.github.com/ev-br/8544371b40f414b7eaf3fe6217209bff`` 

1388 for discussion. 

1389 

1390 """ 

1391 

1392 def __init__(self, x, y, z, w=None, bbox=[None] * 4, kx=3, ky=3, s=None, 

1393 eps=1e-16): 

1394 

1395 x, y, z, w = self._validate_input(x, y, z, w, kx, ky, eps) 

1396 bbox = ravel(bbox) 

1397 if not bbox.shape == (4,): 

1398 raise ValueError('bbox shape should be (4,)') 

1399 if s is not None and not s >= 0.0: 

1400 raise ValueError("s should be s >= 0.0") 

1401 

1402 xb, xe, yb, ye = bbox 

1403 nx, tx, ny, ty, c, fp, wrk1, ier = dfitpack.surfit_smth(x, y, z, w, 

1404 xb, xe, yb, 

1405 ye, kx, ky, 

1406 s=s, eps=eps, 

1407 lwrk2=1) 

1408 if ier > 10: # lwrk2 was to small, re-run 

1409 nx, tx, ny, ty, c, fp, wrk1, ier = dfitpack.surfit_smth(x, y, z, w, 

1410 xb, xe, yb, 

1411 ye, kx, ky, 

1412 s=s, 

1413 eps=eps, 

1414 lwrk2=ier) 

1415 if ier in [0, -1, -2]: # normal return 

1416 pass 

1417 else: 

1418 message = _surfit_messages.get(ier, 'ier=%s' % (ier)) 

1419 warnings.warn(message) 

1420 

1421 self.fp = fp 

1422 self.tck = tx[:nx], ty[:ny], c[:(nx-kx-1)*(ny-ky-1)] 

1423 self.degrees = kx, ky 

1424 

1425 

1426class LSQBivariateSpline(BivariateSpline): 

1427 """ 

1428 Weighted least-squares bivariate spline approximation. 

1429 

1430 Parameters 

1431 ---------- 

1432 x, y, z : array_like 

1433 1-D sequences of data points (order is not important). 

1434 tx, ty : array_like 

1435 Strictly ordered 1-D sequences of knots coordinates. 

1436 w : array_like, optional 

1437 Positive 1-D array of weights, of the same length as `x`, `y` and `z`. 

1438 bbox : (4,) array_like, optional 

1439 Sequence of length 4 specifying the boundary of the rectangular 

1440 approximation domain. By default, 

1441 ``bbox=[min(x,tx),max(x,tx), min(y,ty),max(y,ty)]``. 

1442 kx, ky : ints, optional 

1443 Degrees of the bivariate spline. Default is 3. 

1444 eps : float, optional 

1445 A threshold for determining the effective rank of an over-determined 

1446 linear system of equations. `eps` should have a value within the open 

1447 interval ``(0, 1)``, the default is 1e-16. 

1448 

1449 See Also 

1450 -------- 

1451 BivariateSpline : 

1452 a base class for bivariate splines. 

1453 UnivariateSpline : 

1454 a smooth univariate spline to fit a given set of data points. 

1455 SmoothBivariateSpline : 

1456 a smoothing bivariate spline through the given points 

1457 RectSphereBivariateSpline : 

1458 a bivariate spline over a rectangular mesh on a sphere 

1459 SmoothSphereBivariateSpline : 

1460 a smoothing bivariate spline in spherical coordinates 

1461 LSQSphereBivariateSpline : 

1462 a bivariate spline in spherical coordinates using weighted 

1463 least-squares fitting 

1464 RectBivariateSpline : 

1465 a bivariate spline over a rectangular mesh. 

1466 bisplrep : 

1467 a function to find a bivariate B-spline representation of a surface 

1468 bisplev : 

1469 a function to evaluate a bivariate B-spline and its derivatives 

1470 

1471 Notes 

1472 ----- 

1473 The length of `x`, `y` and `z` should be at least ``(kx+1) * (ky+1)``. 

1474 

1475 If the input data is such that input dimensions have incommensurate 

1476 units and differ by many orders of magnitude, the interpolant may have 

1477 numerical artifacts. Consider rescaling the data before interpolating. 

1478 

1479 """ 

1480 

1481 def __init__(self, x, y, z, tx, ty, w=None, bbox=[None]*4, kx=3, ky=3, 

1482 eps=None): 

1483 

1484 x, y, z, w = self._validate_input(x, y, z, w, kx, ky, eps) 

1485 bbox = ravel(bbox) 

1486 if not bbox.shape == (4,): 

1487 raise ValueError('bbox shape should be (4,)') 

1488 

1489 nx = 2*kx+2+len(tx) 

1490 ny = 2*ky+2+len(ty) 

1491 # The Fortran subroutine "surfit" (called as dfitpack.surfit_lsq) 

1492 # requires that the knot arrays passed as input should be "real 

1493 # array(s) of dimension nmax" where "nmax" refers to the greater of nx 

1494 # and ny. We pad the tx1/ty1 arrays here so that this is satisfied, and 

1495 # slice them to the desired sizes upon return. 

1496 nmax = max(nx, ny) 

1497 tx1 = zeros((nmax,), float) 

1498 ty1 = zeros((nmax,), float) 

1499 tx1[kx+1:nx-kx-1] = tx 

1500 ty1[ky+1:ny-ky-1] = ty 

1501 

1502 xb, xe, yb, ye = bbox 

1503 tx1, ty1, c, fp, ier = dfitpack.surfit_lsq(x, y, z, nx, tx1, ny, ty1, 

1504 w, xb, xe, yb, ye, 

1505 kx, ky, eps, lwrk2=1) 

1506 if ier > 10: 

1507 tx1, ty1, c, fp, ier = dfitpack.surfit_lsq(x, y, z, 

1508 nx, tx1, ny, ty1, w, 

1509 xb, xe, yb, ye, 

1510 kx, ky, eps, lwrk2=ier) 

1511 if ier in [0, -1, -2]: # normal return 

1512 pass 

1513 else: 

1514 if ier < -2: 

1515 deficiency = (nx-kx-1)*(ny-ky-1)+ier 

1516 message = _surfit_messages.get(-3) % (deficiency) 

1517 else: 

1518 message = _surfit_messages.get(ier, 'ier=%s' % (ier)) 

1519 warnings.warn(message) 

1520 self.fp = fp 

1521 self.tck = tx1[:nx], ty1[:ny], c 

1522 self.degrees = kx, ky 

1523 

1524 

1525class RectBivariateSpline(BivariateSpline): 

1526 """ 

1527 Bivariate spline approximation over a rectangular mesh. 

1528 

1529 Can be used for both smoothing and interpolating data. 

1530 

1531 Parameters 

1532 ---------- 

1533 x,y : array_like 

1534 1-D arrays of coordinates in strictly ascending order. 

1535 Evaluated points outside the data range will be extrapolated. 

1536 z : array_like 

1537 2-D array of data with shape (x.size,y.size). 

1538 bbox : array_like, optional 

1539 Sequence of length 4 specifying the boundary of the rectangular 

1540 approximation domain, which means the start and end spline knots of 

1541 each dimension are set by these values. By default, 

1542 ``bbox=[min(x), max(x), min(y), max(y)]``. 

1543 kx, ky : ints, optional 

1544 Degrees of the bivariate spline. Default is 3. 

1545 s : float, optional 

1546 Positive smoothing factor defined for estimation condition: 

1547 ``sum((z[i]-f(x[i], y[i]))**2, axis=0) <= s`` where f is a spline 

1548 function. Default is ``s=0``, which is for interpolation. 

1549 

1550 See Also 

1551 -------- 

1552 BivariateSpline : 

1553 a base class for bivariate splines. 

1554 UnivariateSpline : 

1555 a smooth univariate spline to fit a given set of data points. 

1556 SmoothBivariateSpline : 

1557 a smoothing bivariate spline through the given points 

1558 LSQBivariateSpline : 

1559 a bivariate spline using weighted least-squares fitting 

1560 RectSphereBivariateSpline : 

1561 a bivariate spline over a rectangular mesh on a sphere 

1562 SmoothSphereBivariateSpline : 

1563 a smoothing bivariate spline in spherical coordinates 

1564 LSQSphereBivariateSpline : 

1565 a bivariate spline in spherical coordinates using weighted 

1566 least-squares fitting 

1567 bisplrep : 

1568 a function to find a bivariate B-spline representation of a surface 

1569 bisplev : 

1570 a function to evaluate a bivariate B-spline and its derivatives 

1571 

1572 Notes 

1573 ----- 

1574 

1575 If the input data is such that input dimensions have incommensurate 

1576 units and differ by many orders of magnitude, the interpolant may have 

1577 numerical artifacts. Consider rescaling the data before interpolating. 

1578 

1579 """ 

1580 

1581 def __init__(self, x, y, z, bbox=[None] * 4, kx=3, ky=3, s=0): 

1582 x, y, bbox = ravel(x), ravel(y), ravel(bbox) 

1583 z = np.asarray(z) 

1584 if not np.all(diff(x) > 0.0): 

1585 raise ValueError('x must be strictly increasing') 

1586 if not np.all(diff(y) > 0.0): 

1587 raise ValueError('y must be strictly increasing') 

1588 if not x.size == z.shape[0]: 

1589 raise ValueError('x dimension of z must have same number of ' 

1590 'elements as x') 

1591 if not y.size == z.shape[1]: 

1592 raise ValueError('y dimension of z must have same number of ' 

1593 'elements as y') 

1594 if not bbox.shape == (4,): 

1595 raise ValueError('bbox shape should be (4,)') 

1596 if s is not None and not s >= 0.0: 

1597 raise ValueError("s should be s >= 0.0") 

1598 

1599 z = ravel(z) 

1600 xb, xe, yb, ye = bbox 

1601 nx, tx, ny, ty, c, fp, ier = dfitpack.regrid_smth(x, y, z, xb, xe, yb, 

1602 ye, kx, ky, s) 

1603 

1604 if ier not in [0, -1, -2]: 

1605 msg = _surfit_messages.get(ier, 'ier=%s' % (ier)) 

1606 raise ValueError(msg) 

1607 

1608 self.fp = fp 

1609 self.tck = tx[:nx], ty[:ny], c[:(nx - kx - 1) * (ny - ky - 1)] 

1610 self.degrees = kx, ky 

1611 

1612 

1613_spherefit_messages = _surfit_messages.copy() 

1614_spherefit_messages[10] = """ 

1615ERROR. On entry, the input data are controlled on validity. The following 

1616 restrictions must be satisfied: 

1617 -1<=iopt<=1, m>=2, ntest>=8 ,npest >=8, 0<eps<1, 

1618 0<=teta(i)<=pi, 0<=phi(i)<=2*pi, w(i)>0, i=1,...,m 

1619 lwrk1 >= 185+52*v+10*u+14*u*v+8*(u-1)*v**2+8*m 

1620 kwrk >= m+(ntest-7)*(npest-7) 

1621 if iopt=-1: 8<=nt<=ntest , 9<=np<=npest 

1622 0<tt(5)<tt(6)<...<tt(nt-4)<pi 

1623 0<tp(5)<tp(6)<...<tp(np-4)<2*pi 

1624 if iopt>=0: s>=0 

1625 if one of these conditions is found to be violated,control 

1626 is immediately repassed to the calling program. in that 

1627 case there is no approximation returned.""" 

1628_spherefit_messages[-3] = """ 

1629WARNING. The coefficients of the spline returned have been computed as the 

1630 minimal norm least-squares solution of a (numerically) rank 

1631 deficient system (deficiency=%i, rank=%i). Especially if the rank 

1632 deficiency, which is computed by 6+(nt-8)*(np-7)+ier, is large, 

1633 the results may be inaccurate. They could also seriously depend on 

1634 the value of eps.""" 

1635 

1636 

1637class SphereBivariateSpline(_BivariateSplineBase): 

1638 """ 

1639 Bivariate spline s(x,y) of degrees 3 on a sphere, calculated from a 

1640 given set of data points (theta,phi,r). 

1641 

1642 .. versionadded:: 0.11.0 

1643 

1644 See Also 

1645 -------- 

1646 bisplrep : 

1647 a function to find a bivariate B-spline representation of a surface 

1648 bisplev : 

1649 a function to evaluate a bivariate B-spline and its derivatives 

1650 UnivariateSpline : 

1651 a smooth univariate spline to fit a given set of data points. 

1652 SmoothBivariateSpline : 

1653 a smoothing bivariate spline through the given points 

1654 LSQUnivariateSpline : 

1655 a univariate spline using weighted least-squares fitting 

1656 """ 

1657 

1658 def __call__(self, theta, phi, dtheta=0, dphi=0, grid=True): 

1659 """ 

1660 Evaluate the spline or its derivatives at given positions. 

1661 

1662 Parameters 

1663 ---------- 

1664 theta, phi : array_like 

1665 Input coordinates. 

1666 

1667 If `grid` is False, evaluate the spline at points 

1668 ``(theta[i], phi[i]), i=0, ..., len(x)-1``. Standard 

1669 Numpy broadcasting is obeyed. 

1670 

1671 If `grid` is True: evaluate spline at the grid points 

1672 defined by the coordinate arrays theta, phi. The arrays 

1673 must be sorted to increasing order. 

1674 The ordering of axes is consistent with 

1675 ``np.meshgrid(..., indexing="ij")`` and inconsistent with the 

1676 default ordering ``np.meshgrid(..., indexing="xy")``. 

1677 dtheta : int, optional 

1678 Order of theta-derivative 

1679 

1680 .. versionadded:: 0.14.0 

1681 dphi : int 

1682 Order of phi-derivative 

1683 

1684 .. versionadded:: 0.14.0 

1685 grid : bool 

1686 Whether to evaluate the results on a grid spanned by the 

1687 input arrays, or at points specified by the input arrays. 

1688 

1689 .. versionadded:: 0.14.0 

1690 

1691 Examples 

1692 -------- 

1693 

1694 Suppose that we want to use splines to interpolate a bivariate function on a sphere. 

1695 The value of the function is known on a grid of longitudes and colatitudes. 

1696 

1697 >>> import numpy as np 

1698 >>> from scipy.interpolate import RectSphereBivariateSpline 

1699 >>> def f(theta, phi): 

1700 ... return np.sin(theta) * np.cos(phi) 

1701 

1702 We evaluate the function on the grid. Note that the default indexing="xy" 

1703 of meshgrid would result in an unexpected (transposed) result after 

1704 interpolation. 

1705 

1706 >>> thetaarr = np.linspace(0, np.pi, 22)[1:-1] 

1707 >>> phiarr = np.linspace(0, 2 * np.pi, 21)[:-1] 

1708 >>> thetagrid, phigrid = np.meshgrid(thetaarr, phiarr, indexing="ij") 

1709 >>> zdata = f(thetagrid, phigrid) 

1710 

1711 We next set up the interpolator and use it to evaluate the function 

1712 on a finer grid. 

1713 

1714 >>> rsbs = RectSphereBivariateSpline(thetaarr, phiarr, zdata) 

1715 >>> thetaarr_fine = np.linspace(0, np.pi, 200) 

1716 >>> phiarr_fine = np.linspace(0, 2 * np.pi, 200) 

1717 >>> zdata_fine = rsbs(thetaarr_fine, phiarr_fine) 

1718 

1719 Finally we plot the coarsly-sampled input data alongside the 

1720 finely-sampled interpolated data to check that they agree. 

1721 

1722 >>> import matplotlib.pyplot as plt 

1723 >>> fig = plt.figure() 

1724 >>> ax1 = fig.add_subplot(1, 2, 1) 

1725 >>> ax2 = fig.add_subplot(1, 2, 2) 

1726 >>> ax1.imshow(zdata) 

1727 >>> ax2.imshow(zdata_fine) 

1728 >>> plt.show() 

1729 """ 

1730 theta = np.asarray(theta) 

1731 phi = np.asarray(phi) 

1732 

1733 if theta.size > 0 and (theta.min() < 0. or theta.max() > np.pi): 

1734 raise ValueError("requested theta out of bounds.") 

1735 

1736 return _BivariateSplineBase.__call__(self, theta, phi, 

1737 dx=dtheta, dy=dphi, grid=grid) 

1738 

1739 def ev(self, theta, phi, dtheta=0, dphi=0): 

1740 """ 

1741 Evaluate the spline at points 

1742 

1743 Returns the interpolated value at ``(theta[i], phi[i]), 

1744 i=0,...,len(theta)-1``. 

1745 

1746 Parameters 

1747 ---------- 

1748 theta, phi : array_like 

1749 Input coordinates. Standard Numpy broadcasting is obeyed. 

1750 The ordering of axes is consistent with 

1751 np.meshgrid(..., indexing="ij") and inconsistent with the 

1752 default ordering np.meshgrid(..., indexing="xy"). 

1753 dtheta : int, optional 

1754 Order of theta-derivative 

1755 

1756 .. versionadded:: 0.14.0 

1757 dphi : int, optional 

1758 Order of phi-derivative 

1759 

1760 .. versionadded:: 0.14.0 

1761 

1762 Examples 

1763 -------- 

1764 Suppose that we want to use splines to interpolate a bivariate function on a sphere. 

1765 The value of the function is known on a grid of longitudes and colatitudes. 

1766 

1767 >>> import numpy as np 

1768 >>> from scipy.interpolate import RectSphereBivariateSpline 

1769 >>> def f(theta, phi): 

1770 ... return np.sin(theta) * np.cos(phi) 

1771 

1772 We evaluate the function on the grid. Note that the default indexing="xy" 

1773 of meshgrid would result in an unexpected (transposed) result after 

1774 interpolation. 

1775 

1776 >>> thetaarr = np.linspace(0, np.pi, 22)[1:-1] 

1777 >>> phiarr = np.linspace(0, 2 * np.pi, 21)[:-1] 

1778 >>> thetagrid, phigrid = np.meshgrid(thetaarr, phiarr, indexing="ij") 

1779 >>> zdata = f(thetagrid, phigrid) 

1780 

1781 We next set up the interpolator and use it to evaluate the function 

1782 at points not on the original grid. 

1783 

1784 >>> rsbs = RectSphereBivariateSpline(thetaarr, phiarr, zdata) 

1785 >>> thetainterp = np.linspace(thetaarr[0], thetaarr[-1], 200) 

1786 >>> phiinterp = np.linspace(phiarr[0], phiarr[-1], 200) 

1787 >>> zinterp = rsbs.ev(thetainterp, phiinterp) 

1788 

1789 Finally we plot the original data for a diagonal slice through the 

1790 initial grid, and the spline approximation along the same slice. 

1791 

1792 >>> import matplotlib.pyplot as plt 

1793 >>> fig = plt.figure() 

1794 >>> ax1 = fig.add_subplot(1, 1, 1) 

1795 >>> ax1.plot(np.sin(thetaarr) * np.sin(phiarr), np.diag(zdata), "or") 

1796 >>> ax1.plot(np.sin(thetainterp) * np.sin(phiinterp), zinterp, "-b") 

1797 >>> plt.show() 

1798 """ 

1799 return self.__call__(theta, phi, dtheta=dtheta, dphi=dphi, grid=False) 

1800 

1801 

1802class SmoothSphereBivariateSpline(SphereBivariateSpline): 

1803 """ 

1804 Smooth bivariate spline approximation in spherical coordinates. 

1805 

1806 .. versionadded:: 0.11.0 

1807 

1808 Parameters 

1809 ---------- 

1810 theta, phi, r : array_like 

1811 1-D sequences of data points (order is not important). Coordinates 

1812 must be given in radians. Theta must lie within the interval 

1813 ``[0, pi]``, and phi must lie within the interval ``[0, 2pi]``. 

1814 w : array_like, optional 

1815 Positive 1-D sequence of weights. 

1816 s : float, optional 

1817 Positive smoothing factor defined for estimation condition: 

1818 ``sum((w(i)*(r(i) - s(theta(i), phi(i))))**2, axis=0) <= s`` 

1819 Default ``s=len(w)`` which should be a good value if ``1/w[i]`` is an 

1820 estimate of the standard deviation of ``r[i]``. 

1821 eps : float, optional 

1822 A threshold for determining the effective rank of an over-determined 

1823 linear system of equations. `eps` should have a value within the open 

1824 interval ``(0, 1)``, the default is 1e-16. 

1825 

1826 See Also 

1827 -------- 

1828 BivariateSpline : 

1829 a base class for bivariate splines. 

1830 UnivariateSpline : 

1831 a smooth univariate spline to fit a given set of data points. 

1832 SmoothBivariateSpline : 

1833 a smoothing bivariate spline through the given points 

1834 LSQBivariateSpline : 

1835 a bivariate spline using weighted least-squares fitting 

1836 RectSphereBivariateSpline : 

1837 a bivariate spline over a rectangular mesh on a sphere 

1838 LSQSphereBivariateSpline : 

1839 a bivariate spline in spherical coordinates using weighted 

1840 least-squares fitting 

1841 RectBivariateSpline : 

1842 a bivariate spline over a rectangular mesh. 

1843 bisplrep : 

1844 a function to find a bivariate B-spline representation of a surface 

1845 bisplev : 

1846 a function to evaluate a bivariate B-spline and its derivatives 

1847 

1848 Notes 

1849 ----- 

1850 For more information, see the FITPACK_ site about this function. 

1851 

1852 .. _FITPACK: http://www.netlib.org/dierckx/sphere.f 

1853 

1854 Examples 

1855 -------- 

1856 Suppose we have global data on a coarse grid (the input data does not 

1857 have to be on a grid): 

1858 

1859 >>> import numpy as np 

1860 >>> theta = np.linspace(0., np.pi, 7) 

1861 >>> phi = np.linspace(0., 2*np.pi, 9) 

1862 >>> data = np.empty((theta.shape[0], phi.shape[0])) 

1863 >>> data[:,0], data[0,:], data[-1,:] = 0., 0., 0. 

1864 >>> data[1:-1,1], data[1:-1,-1] = 1., 1. 

1865 >>> data[1,1:-1], data[-2,1:-1] = 1., 1. 

1866 >>> data[2:-2,2], data[2:-2,-2] = 2., 2. 

1867 >>> data[2,2:-2], data[-3,2:-2] = 2., 2. 

1868 >>> data[3,3:-2] = 3. 

1869 >>> data = np.roll(data, 4, 1) 

1870 

1871 We need to set up the interpolator object 

1872 

1873 >>> lats, lons = np.meshgrid(theta, phi) 

1874 >>> from scipy.interpolate import SmoothSphereBivariateSpline 

1875 >>> lut = SmoothSphereBivariateSpline(lats.ravel(), lons.ravel(), 

1876 ... data.T.ravel(), s=3.5) 

1877 

1878 As a first test, we'll see what the algorithm returns when run on the 

1879 input coordinates 

1880 

1881 >>> data_orig = lut(theta, phi) 

1882 

1883 Finally we interpolate the data to a finer grid 

1884 

1885 >>> fine_lats = np.linspace(0., np.pi, 70) 

1886 >>> fine_lons = np.linspace(0., 2 * np.pi, 90) 

1887 

1888 >>> data_smth = lut(fine_lats, fine_lons) 

1889 

1890 >>> import matplotlib.pyplot as plt 

1891 >>> fig = plt.figure() 

1892 >>> ax1 = fig.add_subplot(131) 

1893 >>> ax1.imshow(data, interpolation='nearest') 

1894 >>> ax2 = fig.add_subplot(132) 

1895 >>> ax2.imshow(data_orig, interpolation='nearest') 

1896 >>> ax3 = fig.add_subplot(133) 

1897 >>> ax3.imshow(data_smth, interpolation='nearest') 

1898 >>> plt.show() 

1899 

1900 """ 

1901 

1902 def __init__(self, theta, phi, r, w=None, s=0., eps=1E-16): 

1903 

1904 theta, phi, r = np.asarray(theta), np.asarray(phi), np.asarray(r) 

1905 

1906 # input validation 

1907 if not ((0.0 <= theta).all() and (theta <= np.pi).all()): 

1908 raise ValueError('theta should be between [0, pi]') 

1909 if not ((0.0 <= phi).all() and (phi <= 2.0 * np.pi).all()): 

1910 raise ValueError('phi should be between [0, 2pi]') 

1911 if w is not None: 

1912 w = np.asarray(w) 

1913 if not (w >= 0.0).all(): 

1914 raise ValueError('w should be positive') 

1915 if not s >= 0.0: 

1916 raise ValueError('s should be positive') 

1917 if not 0.0 < eps < 1.0: 

1918 raise ValueError('eps should be between (0, 1)') 

1919 

1920 if np.issubclass_(w, float): 

1921 w = ones(len(theta)) * w 

1922 nt_, tt_, np_, tp_, c, fp, ier = dfitpack.spherfit_smth(theta, phi, 

1923 r, w=w, s=s, 

1924 eps=eps) 

1925 if ier not in [0, -1, -2]: 

1926 message = _spherefit_messages.get(ier, 'ier=%s' % (ier)) 

1927 raise ValueError(message) 

1928 

1929 self.fp = fp 

1930 self.tck = tt_[:nt_], tp_[:np_], c[:(nt_ - 4) * (np_ - 4)] 

1931 self.degrees = (3, 3) 

1932 

1933 def __call__(self, theta, phi, dtheta=0, dphi=0, grid=True): 

1934 

1935 theta = np.asarray(theta) 

1936 phi = np.asarray(phi) 

1937 

1938 if phi.size > 0 and (phi.min() < 0. or phi.max() > 2. * np.pi): 

1939 raise ValueError("requested phi out of bounds.") 

1940 

1941 return SphereBivariateSpline.__call__(self, theta, phi, dtheta=dtheta, 

1942 dphi=dphi, grid=grid) 

1943 

1944 

1945class LSQSphereBivariateSpline(SphereBivariateSpline): 

1946 """ 

1947 Weighted least-squares bivariate spline approximation in spherical 

1948 coordinates. 

1949 

1950 Determines a smoothing bicubic spline according to a given 

1951 set of knots in the `theta` and `phi` directions. 

1952 

1953 .. versionadded:: 0.11.0 

1954 

1955 Parameters 

1956 ---------- 

1957 theta, phi, r : array_like 

1958 1-D sequences of data points (order is not important). Coordinates 

1959 must be given in radians. Theta must lie within the interval 

1960 ``[0, pi]``, and phi must lie within the interval ``[0, 2pi]``. 

1961 tt, tp : array_like 

1962 Strictly ordered 1-D sequences of knots coordinates. 

1963 Coordinates must satisfy ``0 < tt[i] < pi``, ``0 < tp[i] < 2*pi``. 

1964 w : array_like, optional 

1965 Positive 1-D sequence of weights, of the same length as `theta`, `phi` 

1966 and `r`. 

1967 eps : float, optional 

1968 A threshold for determining the effective rank of an over-determined 

1969 linear system of equations. `eps` should have a value within the 

1970 open interval ``(0, 1)``, the default is 1e-16. 

1971 

1972 See Also 

1973 -------- 

1974 BivariateSpline : 

1975 a base class for bivariate splines. 

1976 UnivariateSpline : 

1977 a smooth univariate spline to fit a given set of data points. 

1978 SmoothBivariateSpline : 

1979 a smoothing bivariate spline through the given points 

1980 LSQBivariateSpline : 

1981 a bivariate spline using weighted least-squares fitting 

1982 RectSphereBivariateSpline : 

1983 a bivariate spline over a rectangular mesh on a sphere 

1984 SmoothSphereBivariateSpline : 

1985 a smoothing bivariate spline in spherical coordinates 

1986 RectBivariateSpline : 

1987 a bivariate spline over a rectangular mesh. 

1988 bisplrep : 

1989 a function to find a bivariate B-spline representation of a surface 

1990 bisplev : 

1991 a function to evaluate a bivariate B-spline and its derivatives 

1992 

1993 Notes 

1994 ----- 

1995 For more information, see the FITPACK_ site about this function. 

1996 

1997 .. _FITPACK: http://www.netlib.org/dierckx/sphere.f 

1998 

1999 Examples 

2000 -------- 

2001 Suppose we have global data on a coarse grid (the input data does not 

2002 have to be on a grid): 

2003 

2004 >>> from scipy.interpolate import LSQSphereBivariateSpline 

2005 >>> import numpy as np 

2006 >>> import matplotlib.pyplot as plt 

2007 

2008 >>> theta = np.linspace(0, np.pi, num=7) 

2009 >>> phi = np.linspace(0, 2*np.pi, num=9) 

2010 >>> data = np.empty((theta.shape[0], phi.shape[0])) 

2011 >>> data[:,0], data[0,:], data[-1,:] = 0., 0., 0. 

2012 >>> data[1:-1,1], data[1:-1,-1] = 1., 1. 

2013 >>> data[1,1:-1], data[-2,1:-1] = 1., 1. 

2014 >>> data[2:-2,2], data[2:-2,-2] = 2., 2. 

2015 >>> data[2,2:-2], data[-3,2:-2] = 2., 2. 

2016 >>> data[3,3:-2] = 3. 

2017 >>> data = np.roll(data, 4, 1) 

2018 

2019 We need to set up the interpolator object. Here, we must also specify the 

2020 coordinates of the knots to use. 

2021 

2022 >>> lats, lons = np.meshgrid(theta, phi) 

2023 >>> knotst, knotsp = theta.copy(), phi.copy() 

2024 >>> knotst[0] += .0001 

2025 >>> knotst[-1] -= .0001 

2026 >>> knotsp[0] += .0001 

2027 >>> knotsp[-1] -= .0001 

2028 >>> lut = LSQSphereBivariateSpline(lats.ravel(), lons.ravel(), 

2029 ... data.T.ravel(), knotst, knotsp) 

2030 

2031 As a first test, we'll see what the algorithm returns when run on the 

2032 input coordinates 

2033 

2034 >>> data_orig = lut(theta, phi) 

2035 

2036 Finally we interpolate the data to a finer grid 

2037 

2038 >>> fine_lats = np.linspace(0., np.pi, 70) 

2039 >>> fine_lons = np.linspace(0., 2*np.pi, 90) 

2040 >>> data_lsq = lut(fine_lats, fine_lons) 

2041 

2042 >>> fig = plt.figure() 

2043 >>> ax1 = fig.add_subplot(131) 

2044 >>> ax1.imshow(data, interpolation='nearest') 

2045 >>> ax2 = fig.add_subplot(132) 

2046 >>> ax2.imshow(data_orig, interpolation='nearest') 

2047 >>> ax3 = fig.add_subplot(133) 

2048 >>> ax3.imshow(data_lsq, interpolation='nearest') 

2049 >>> plt.show() 

2050 

2051 """ 

2052 

2053 def __init__(self, theta, phi, r, tt, tp, w=None, eps=1E-16): 

2054 

2055 theta, phi, r = np.asarray(theta), np.asarray(phi), np.asarray(r) 

2056 tt, tp = np.asarray(tt), np.asarray(tp) 

2057 

2058 if not ((0.0 <= theta).all() and (theta <= np.pi).all()): 

2059 raise ValueError('theta should be between [0, pi]') 

2060 if not ((0.0 <= phi).all() and (phi <= 2*np.pi).all()): 

2061 raise ValueError('phi should be between [0, 2pi]') 

2062 if not ((0.0 < tt).all() and (tt < np.pi).all()): 

2063 raise ValueError('tt should be between (0, pi)') 

2064 if not ((0.0 < tp).all() and (tp < 2*np.pi).all()): 

2065 raise ValueError('tp should be between (0, 2pi)') 

2066 if w is not None: 

2067 w = np.asarray(w) 

2068 if not (w >= 0.0).all(): 

2069 raise ValueError('w should be positive') 

2070 if not 0.0 < eps < 1.0: 

2071 raise ValueError('eps should be between (0, 1)') 

2072 

2073 if np.issubclass_(w, float): 

2074 w = ones(len(theta)) * w 

2075 nt_, np_ = 8 + len(tt), 8 + len(tp) 

2076 tt_, tp_ = zeros((nt_,), float), zeros((np_,), float) 

2077 tt_[4:-4], tp_[4:-4] = tt, tp 

2078 tt_[-4:], tp_[-4:] = np.pi, 2. * np.pi 

2079 tt_, tp_, c, fp, ier = dfitpack.spherfit_lsq(theta, phi, r, tt_, tp_, 

2080 w=w, eps=eps) 

2081 if ier > 0: 

2082 message = _spherefit_messages.get(ier, 'ier=%s' % (ier)) 

2083 raise ValueError(message) 

2084 

2085 self.fp = fp 

2086 self.tck = tt_, tp_, c 

2087 self.degrees = (3, 3) 

2088 

2089 def __call__(self, theta, phi, dtheta=0, dphi=0, grid=True): 

2090 

2091 theta = np.asarray(theta) 

2092 phi = np.asarray(phi) 

2093 

2094 if phi.size > 0 and (phi.min() < 0. or phi.max() > 2. * np.pi): 

2095 raise ValueError("requested phi out of bounds.") 

2096 

2097 return SphereBivariateSpline.__call__(self, theta, phi, dtheta=dtheta, 

2098 dphi=dphi, grid=grid) 

2099 

2100 

2101_spfit_messages = _surfit_messages.copy() 

2102_spfit_messages[10] = """ 

2103ERROR: on entry, the input data are controlled on validity 

2104 the following restrictions must be satisfied. 

2105 -1<=iopt(1)<=1, 0<=iopt(2)<=1, 0<=iopt(3)<=1, 

2106 -1<=ider(1)<=1, 0<=ider(2)<=1, ider(2)=0 if iopt(2)=0. 

2107 -1<=ider(3)<=1, 0<=ider(4)<=1, ider(4)=0 if iopt(3)=0. 

2108 mu >= mumin (see above), mv >= 4, nuest >=8, nvest >= 8, 

2109 kwrk>=5+mu+mv+nuest+nvest, 

2110 lwrk >= 12+nuest*(mv+nvest+3)+nvest*24+4*mu+8*mv+max(nuest,mv+nvest) 

2111 0< u(i-1)<u(i)< pi,i=2,..,mu, 

2112 -pi<=v(1)< pi, v(1)<v(i-1)<v(i)<v(1)+2*pi, i=3,...,mv 

2113 if iopt(1)=-1: 8<=nu<=min(nuest,mu+6+iopt(2)+iopt(3)) 

2114 0<tu(5)<tu(6)<...<tu(nu-4)< pi 

2115 8<=nv<=min(nvest,mv+7) 

2116 v(1)<tv(5)<tv(6)<...<tv(nv-4)<v(1)+2*pi 

2117 the schoenberg-whitney conditions, i.e. there must be 

2118 subset of grid co-ordinates uu(p) and vv(q) such that 

2119 tu(p) < uu(p) < tu(p+4) ,p=1,...,nu-4 

2120 (iopt(2)=1 and iopt(3)=1 also count for a uu-value 

2121 tv(q) < vv(q) < tv(q+4) ,q=1,...,nv-4 

2122 (vv(q) is either a value v(j) or v(j)+2*pi) 

2123 if iopt(1)>=0: s>=0 

2124 if s=0: nuest>=mu+6+iopt(2)+iopt(3), nvest>=mv+7 

2125 if one of these conditions is found to be violated,control is 

2126 immediately repassed to the calling program. in that case there is no 

2127 approximation returned.""" 

2128 

2129 

2130class RectSphereBivariateSpline(SphereBivariateSpline): 

2131 """ 

2132 Bivariate spline approximation over a rectangular mesh on a sphere. 

2133 

2134 Can be used for smoothing data. 

2135 

2136 .. versionadded:: 0.11.0 

2137 

2138 Parameters 

2139 ---------- 

2140 u : array_like 

2141 1-D array of colatitude coordinates in strictly ascending order. 

2142 Coordinates must be given in radians and lie within the open interval 

2143 ``(0, pi)``. 

2144 v : array_like 

2145 1-D array of longitude coordinates in strictly ascending order. 

2146 Coordinates must be given in radians. First element (``v[0]``) must lie 

2147 within the interval ``[-pi, pi)``. Last element (``v[-1]``) must satisfy 

2148 ``v[-1] <= v[0] + 2*pi``. 

2149 r : array_like 

2150 2-D array of data with shape ``(u.size, v.size)``. 

2151 s : float, optional 

2152 Positive smoothing factor defined for estimation condition 

2153 (``s=0`` is for interpolation). 

2154 pole_continuity : bool or (bool, bool), optional 

2155 Order of continuity at the poles ``u=0`` (``pole_continuity[0]``) and 

2156 ``u=pi`` (``pole_continuity[1]``). The order of continuity at the pole 

2157 will be 1 or 0 when this is True or False, respectively. 

2158 Defaults to False. 

2159 pole_values : float or (float, float), optional 

2160 Data values at the poles ``u=0`` and ``u=pi``. Either the whole 

2161 parameter or each individual element can be None. Defaults to None. 

2162 pole_exact : bool or (bool, bool), optional 

2163 Data value exactness at the poles ``u=0`` and ``u=pi``. If True, the 

2164 value is considered to be the right function value, and it will be 

2165 fitted exactly. If False, the value will be considered to be a data 

2166 value just like the other data values. Defaults to False. 

2167 pole_flat : bool or (bool, bool), optional 

2168 For the poles at ``u=0`` and ``u=pi``, specify whether or not the 

2169 approximation has vanishing derivatives. Defaults to False. 

2170 

2171 See Also 

2172 -------- 

2173 BivariateSpline : 

2174 a base class for bivariate splines. 

2175 UnivariateSpline : 

2176 a smooth univariate spline to fit a given set of data points. 

2177 SmoothBivariateSpline : 

2178 a smoothing bivariate spline through the given points 

2179 LSQBivariateSpline : 

2180 a bivariate spline using weighted least-squares fitting 

2181 SmoothSphereBivariateSpline : 

2182 a smoothing bivariate spline in spherical coordinates 

2183 LSQSphereBivariateSpline : 

2184 a bivariate spline in spherical coordinates using weighted 

2185 least-squares fitting 

2186 RectBivariateSpline : 

2187 a bivariate spline over a rectangular mesh. 

2188 bisplrep : 

2189 a function to find a bivariate B-spline representation of a surface 

2190 bisplev : 

2191 a function to evaluate a bivariate B-spline and its derivatives 

2192 

2193 Notes 

2194 ----- 

2195 Currently, only the smoothing spline approximation (``iopt[0] = 0`` and 

2196 ``iopt[0] = 1`` in the FITPACK routine) is supported. The exact 

2197 least-squares spline approximation is not implemented yet. 

2198 

2199 When actually performing the interpolation, the requested `v` values must 

2200 lie within the same length 2pi interval that the original `v` values were 

2201 chosen from. 

2202 

2203 For more information, see the FITPACK_ site about this function. 

2204 

2205 .. _FITPACK: http://www.netlib.org/dierckx/spgrid.f 

2206 

2207 Examples 

2208 -------- 

2209 Suppose we have global data on a coarse grid 

2210 

2211 >>> import numpy as np 

2212 >>> lats = np.linspace(10, 170, 9) * np.pi / 180. 

2213 >>> lons = np.linspace(0, 350, 18) * np.pi / 180. 

2214 >>> data = np.dot(np.atleast_2d(90. - np.linspace(-80., 80., 18)).T, 

2215 ... np.atleast_2d(180. - np.abs(np.linspace(0., 350., 9)))).T 

2216 

2217 We want to interpolate it to a global one-degree grid 

2218 

2219 >>> new_lats = np.linspace(1, 180, 180) * np.pi / 180 

2220 >>> new_lons = np.linspace(1, 360, 360) * np.pi / 180 

2221 >>> new_lats, new_lons = np.meshgrid(new_lats, new_lons) 

2222 

2223 We need to set up the interpolator object 

2224 

2225 >>> from scipy.interpolate import RectSphereBivariateSpline 

2226 >>> lut = RectSphereBivariateSpline(lats, lons, data) 

2227 

2228 Finally we interpolate the data. The `RectSphereBivariateSpline` object 

2229 only takes 1-D arrays as input, therefore we need to do some reshaping. 

2230 

2231 >>> data_interp = lut.ev(new_lats.ravel(), 

2232 ... new_lons.ravel()).reshape((360, 180)).T 

2233 

2234 Looking at the original and the interpolated data, one can see that the 

2235 interpolant reproduces the original data very well: 

2236 

2237 >>> import matplotlib.pyplot as plt 

2238 >>> fig = plt.figure() 

2239 >>> ax1 = fig.add_subplot(211) 

2240 >>> ax1.imshow(data, interpolation='nearest') 

2241 >>> ax2 = fig.add_subplot(212) 

2242 >>> ax2.imshow(data_interp, interpolation='nearest') 

2243 >>> plt.show() 

2244 

2245 Choosing the optimal value of ``s`` can be a delicate task. Recommended 

2246 values for ``s`` depend on the accuracy of the data values. If the user 

2247 has an idea of the statistical errors on the data, she can also find a 

2248 proper estimate for ``s``. By assuming that, if she specifies the 

2249 right ``s``, the interpolator will use a spline ``f(u,v)`` which exactly 

2250 reproduces the function underlying the data, she can evaluate 

2251 ``sum((r(i,j)-s(u(i),v(j)))**2)`` to find a good estimate for this ``s``. 

2252 For example, if she knows that the statistical errors on her 

2253 ``r(i,j)``-values are not greater than 0.1, she may expect that a good 

2254 ``s`` should have a value not larger than ``u.size * v.size * (0.1)**2``. 

2255 

2256 If nothing is known about the statistical error in ``r(i,j)``, ``s`` must 

2257 be determined by trial and error. The best is then to start with a very 

2258 large value of ``s`` (to determine the least-squares polynomial and the 

2259 corresponding upper bound ``fp0`` for ``s``) and then to progressively 

2260 decrease the value of ``s`` (say by a factor 10 in the beginning, i.e. 

2261 ``s = fp0 / 10, fp0 / 100, ...`` and more carefully as the approximation 

2262 shows more detail) to obtain closer fits. 

2263 

2264 The interpolation results for different values of ``s`` give some insight 

2265 into this process: 

2266 

2267 >>> fig2 = plt.figure() 

2268 >>> s = [3e9, 2e9, 1e9, 1e8] 

2269 >>> for idx, sval in enumerate(s, 1): 

2270 ... lut = RectSphereBivariateSpline(lats, lons, data, s=sval) 

2271 ... data_interp = lut.ev(new_lats.ravel(), 

2272 ... new_lons.ravel()).reshape((360, 180)).T 

2273 ... ax = fig2.add_subplot(2, 2, idx) 

2274 ... ax.imshow(data_interp, interpolation='nearest') 

2275 ... ax.set_title(f"s = {sval:g}") 

2276 >>> plt.show() 

2277 

2278 """ 

2279 

2280 def __init__(self, u, v, r, s=0., pole_continuity=False, pole_values=None, 

2281 pole_exact=False, pole_flat=False): 

2282 iopt = np.array([0, 0, 0], dtype=dfitpack_int) 

2283 ider = np.array([-1, 0, -1, 0], dtype=dfitpack_int) 

2284 if pole_values is None: 

2285 pole_values = (None, None) 

2286 elif isinstance(pole_values, (float, np.float32, np.float64)): 

2287 pole_values = (pole_values, pole_values) 

2288 if isinstance(pole_continuity, bool): 

2289 pole_continuity = (pole_continuity, pole_continuity) 

2290 if isinstance(pole_exact, bool): 

2291 pole_exact = (pole_exact, pole_exact) 

2292 if isinstance(pole_flat, bool): 

2293 pole_flat = (pole_flat, pole_flat) 

2294 

2295 r0, r1 = pole_values 

2296 iopt[1:] = pole_continuity 

2297 if r0 is None: 

2298 ider[0] = -1 

2299 else: 

2300 ider[0] = pole_exact[0] 

2301 

2302 if r1 is None: 

2303 ider[2] = -1 

2304 else: 

2305 ider[2] = pole_exact[1] 

2306 

2307 ider[1], ider[3] = pole_flat 

2308 

2309 u, v = np.ravel(u), np.ravel(v) 

2310 r = np.asarray(r) 

2311 

2312 if not (0.0 < u[0] and u[-1] < np.pi): 

2313 raise ValueError('u should be between (0, pi)') 

2314 if not -np.pi <= v[0] < np.pi: 

2315 raise ValueError('v[0] should be between [-pi, pi)') 

2316 if not v[-1] <= v[0] + 2*np.pi: 

2317 raise ValueError('v[-1] should be v[0] + 2pi or less ') 

2318 

2319 if not np.all(np.diff(u) > 0.0): 

2320 raise ValueError('u must be strictly increasing') 

2321 if not np.all(np.diff(v) > 0.0): 

2322 raise ValueError('v must be strictly increasing') 

2323 

2324 if not u.size == r.shape[0]: 

2325 raise ValueError('u dimension of r must have same number of ' 

2326 'elements as u') 

2327 if not v.size == r.shape[1]: 

2328 raise ValueError('v dimension of r must have same number of ' 

2329 'elements as v') 

2330 

2331 if pole_continuity[1] is False and pole_flat[1] is True: 

2332 raise ValueError('if pole_continuity is False, so must be ' 

2333 'pole_flat') 

2334 if pole_continuity[0] is False and pole_flat[0] is True: 

2335 raise ValueError('if pole_continuity is False, so must be ' 

2336 'pole_flat') 

2337 

2338 if not s >= 0.0: 

2339 raise ValueError('s should be positive') 

2340 

2341 r = np.ravel(r) 

2342 nu, tu, nv, tv, c, fp, ier = dfitpack.regrid_smth_spher(iopt, ider, 

2343 u.copy(), 

2344 v.copy(), 

2345 r.copy(), 

2346 r0, r1, s) 

2347 

2348 if ier not in [0, -1, -2]: 

2349 msg = _spfit_messages.get(ier, 'ier=%s' % (ier)) 

2350 raise ValueError(msg) 

2351 

2352 self.fp = fp 

2353 self.tck = tu[:nu], tv[:nv], c[:(nu - 4) * (nv-4)] 

2354 self.degrees = (3, 3) 

2355 self.v0 = v[0] 

2356 

2357 def __call__(self, theta, phi, dtheta=0, dphi=0, grid=True): 

2358 

2359 theta = np.asarray(theta) 

2360 phi = np.asarray(phi) 

2361 

2362 return SphereBivariateSpline.__call__(self, theta, phi, dtheta=dtheta, 

2363 dphi=dphi, grid=grid)