Interpolation, smoothing and integration

Fit a smooth curve through noisy samples, interpolate scattered data in many dimensions, and integrate functions you cannot solve analytically.

Interpolation

import numpy as np
from scipy import interpolate

x = np.linspace(0, 2 * np.pi, 20)
y = np.sin(x) + np.random.default_rng(0).normal(0, 0.05, x.size)

cs = interpolate.CubicSpline(x, y, bc_type="natural")
xs = np.linspace(x[0], x[-1], 400)
print(cs(xs).shape, float(cs.derivative()(np.pi)))

# smoothing instead of passing through every noisy point
spl = interpolate.UnivariateSpline(x, y, s=len(x) * 0.05)

# scattered data in 2D
pts = np.random.default_rng(1).random((200, 2))
vals = np.sin(pts[:, 0]) * np.cos(pts[:, 1])
rbf = interpolate.RBFInterpolator(pts, vals, kernel="thin_plate_spline", smoothing=1e-6)
print(rbf(np.array([[0.5, 0.5], [0.2, 0.8]])).shape)

# scattered samples onto a regular grid
gx, gy = np.meshgrid(np.linspace(0, 1, 50), np.linspace(0, 1, 50))
grid = interpolate.griddata(pts, vals, (gx, gy), method="cubic")
MethodPasses through dataUse when
interp1d(kind="linear")YesFast, monotone-safe, no smoothness needed
CubicSplineYesSmooth curves, derivatives available
UnivariateSpline with sNoData is noisy and you want a trend
PchipInterpolatorYesSmooth but must not overshoot between points
RBFInterpolatorDepends on smoothingScattered points in 2D or more
griddataYesScattered points evaluated on a regular grid

Integration

from scipy import integrate

area, err = integrate.quad(lambda t: np.exp(-t ** 2), 0, np.inf)
print(area, err)                          # sqrt(pi)/2 = 0.8862...

val, _ = integrate.quad(lambda t: np.log(t) / (1 + t ** 2), 0, 1, weight="alg", wvar=-0.5)

volume, _ = integrate.dblquad(lambda y, x: x * y, 0, 1, 0, lambda x: 1 - x)

# integrate sampled data rather than a function
t = np.linspace(0, 10, 500)
v = np.sin(t) + 0.3 * t
cum = integrate.cumulative_trapezoid(v, t, initial=0.0)
print(cum[-1] - cum[0])
  • quad returns the estimate and an absolute error estimate; ignore the second value at your peril.
  • For sampled data use trapezoid or simpson; for a callable use quad. They are not interchangeable.
  • Infinite bounds are allowed and handled by a transformation, so quad(f, 0, np.inf) is legitimate.
  • cumulative_trapezoid with initial=0 returns an array the same length as the input, which is what plotting usually wants.

Choosing between methods

Interpolation choices trade smoothness against overshoot. A cubic spline is smooth but can swing past your data points; a PCHIP interpolant is monotone and will not overshoot, which matters when the interpolated values are physical quantities such as concentrations.

⚠️
Extrapolation is the classic trap. interp1d and CubicSpline happily evaluate outside the fitted range, returning confident nonsense. Pass extrapolate=False to get NaN instead of a plausible wrong answer, or bound your evaluation to the ends of the data.

FAQ

My interpolated curve oscillates wildly between points. Why?
You are interpolating too high a degree through noisy or unevenly spaced data. Use PCHIP, reduce to a smoothing spline, or fit a model rather than interpolating. Runge-type oscillation is a property of the data and the method, not a bug.
How accurate is quad by default?
It adaptively refines until the estimated absolute error is below epsabs (about 1.5e-8) or the relative error is below epsrel. Tighten both for sensitive work, and always check the returned error against the magnitude of the answer.

Optimisation and curve fitting Root finding and special functions

Last refreshed 2026-09-18.