"""Functions for fitting polynomials."""
import numpy as np
[docs]def polyfit2d_index(kx, a, b):
"""Returns index of polynomial from the result of :meth:`polyfit2d` for
:math:`x^{a} y^{b}`.
Parameters
----------
kx : int
X polynomial order computed
a, b : int
x and y polynomial order
"""
return b + ((kx + 1) * a)
[docs]def polyfit2d_eval(x, y, soln, kx, ky):
"""Evaluate polynomial fit from :meth:`polyfit2d`
Parameters
----------
x, y: array-like, 1d
x and y coordinates.
soln: np.ndarray
Array of polynomial coefficients.
kx, ky: int
Polynomial order in x and y, respectively.
"""
return np.polynomial.polynomial.polygrid2d(x, y, soln.reshape((kx + 1, ky + 1)))
[docs]def polyfit2d_indices(kx, ky):
"""Get indicies of polynomials returned by :meth:`polyfit2d`.
Parameters
----------
kx, ky: int
Polynomial order in x and y, respectively.
Returns
-------
indices : array_like
Array of x^a y^b powers
"""
coeffs = np.ones((kx + 1, ky + 1))
return np.array(tuple(np.ndindex(coeffs.shape)), dtype=int)
[docs]def polyfit2d(x, y, z, kx, ky, *, order=None, weights=None):
"""Two dimensional polynomial fitting by least squares.
Fits the functional form f(x,y) = z.
Parameters
----------
x, y: array-like, 1d
x and y coordinates.
z: np.ndarray, 2d
Surface to fit.
kx, ky: int
Polynomial order in x and y, respectively.
order: int or None
If None, all coefficients up to maxiumum kx, ky, ie. up to and including x^kx*y^ky, are considered.
If int, coefficients up to a maximum of kx+ky <= order are considered.
weight: array_like, 2d
Weighting to use for fit. Same dimenstions as z
Returns
-------
Return parameters from np.linalg.lstsq.
soln: np.ndarray
Array of polynomial coefficients.
residuals: np.ndarray
rank: int
s: np.ndarray
Notes
-----
Resultant fit can be evaluated with :meth:`polyfit2d_eval`.
Based on code from:
https://stackoverflow.com/questions/33964913/equivalent-of-polyfit-for-a-2d-polynomial-in-python
"""
# grid coords
x, y = np.meshgrid(x, y)
# coefficient array, up to x^kx, y^ky
coeffs = np.ones((kx + 1, ky + 1))
# solve array
a = np.zeros((coeffs.size, x.size))
b = np.ravel(z)
# for each coefficient produce array x^i, y^j
for index, (j, i) in enumerate(np.ndindex(coeffs.shape)):
# do not include powers greater than order
if order is not None and i + j > order:
arr = np.zeros_like(x)
else:
arr = coeffs[i, j] * x ** i * y ** j
a[index] = arr.ravel()
if weights is not None:
W = np.sqrt(weights).ravel()
a *= W
b *= W
# do leastsq fitting and return leastsq result
return np.linalg.lstsq(a.T, b, rcond=None)