LINEAR_ND_INTERP

Overview

The LINEAR_ND_INTERP function performs piecewise linear interpolation for scattered data in N dimensions (where N > 1). Given a set of known data points with their corresponding values, it estimates values at new, unsampled locations using linear interpolation within a triangulated mesh. This is particularly useful for reconstructing surfaces or multidimensional fields from irregularly spaced measurements.

This implementation uses SciPy’s LinearNDInterpolator class from the scipy.interpolate module. The interpolator constructs a Delaunay triangulation of the input points using Qhull, a computational geometry library. This triangulation partitions the space into simplices (triangles in 2D, tetrahedra in 3D, and higher-dimensional analogues).

For each query point, the algorithm first locates which simplex contains the point. It then computes the interpolated value using barycentric interpolation. Given a point \mathbf{r} inside a simplex with vertices \mathbf{r}_1, \mathbf{r}_2, \ldots, \mathbf{r}_{n+1} and corresponding known values f(\mathbf{r}_1), f(\mathbf{r}_2), \ldots, f(\mathbf{r}_{n+1}), the interpolated value is:

f(\mathbf{r}) \approx \sum_{i=1}^{n+1} \lambda_i \, f(\mathbf{r}_i)

where \lambda_i are the barycentric coordinates of \mathbf{r} with respect to the simplex, satisfying \sum \lambda_i = 1 and 0 \le \lambda_i \le 1 for points inside the simplex.

Points that fall outside the convex hull of the input data cannot be interpolated using this method. The function returns a user-specified fill_value (defaulting to 0) for such points. For alternative approaches that handle extrapolation or use different interpolation schemes, see NearestNDInterpolator for nearest-neighbor interpolation or CloughTocher2DInterpolator for smooth cubic interpolation in 2D.

This example function is provided as-is without any representation of accuracy.

Excel Usage

=LINEAR_ND_INTERP(points, values, xi, fill_value)
  • points (list[list], required): The coordinates of the data points (n_points x n_dims)
  • values (list[list], required): The values at the data points (n_points x 1)
  • xi (list[list], required): The points at which to interpolate (n_new_points x n_dims)
  • fill_value (float, optional, default: 0): Value used for points outside the convex hull

Returns (list[list]): Interpolated values as a 2D list, or error message string.

Example 1: Linear interpolation on 2D unit square

Inputs:

points values xi
0 0 0 0.5 0.5
1 0 1
0 1 1
1 1 2

Excel formula:

=LINEAR_ND_INTERP({0,0;1,0;0,1;1,1}, {0;1;1;2}, {0.5,0.5})

Expected output:

1

Example 2: 2D interpolation with out-of-hull fill value

Inputs:

points values xi fill_value
0 0 1 0.5 0 -999
1 0 2 10 10
0 1 3
1 1 4

Excel formula:

=LINEAR_ND_INTERP({0,0;1,0;0,1;1,1}, {1;2;3;4}, {0.5,0;10,10}, -999)

Expected output:

Result
1.5
-999
Example 3: Linear interpolation in 3D tetrahedron

Inputs:

points values xi
0 0 0 0 0.25 0.25 0.25
1 0 0 1
0 1 0 2
0 0 1 3

Excel formula:

=LINEAR_ND_INTERP({0,0,0;1,0,0;0,1,0;0,0,1}, {0;1;2;3}, {0.25,0.25,0.25})

Expected output:

1.5

Example 4: Multiple query points on 2D square

Inputs:

points values xi fill_value
0 0 0 1 0 0
2 0 4 0 1
0 2 4 1 1
2 2 8

Excel formula:

=LINEAR_ND_INTERP({0,0;2,0;0,2;2,2}, {0;4;4;8}, {1,0;0,1;1,1}, 0)

Expected output:

Result
2
2
4

Python Code

Show Code
import math
import numpy as np
from scipy.interpolate import LinearNDInterpolator as scipy_LinearNDInterpolator

def linear_nd_interp(points, values, xi, fill_value=0):
    """
    Piecewise linear interpolator in N > 1 dimensions.

    See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.LinearNDInterpolator.html

    This example function is provided as-is without any representation of accuracy.

    Args:
        points (list[list]): The coordinates of the data points (n_points x n_dims)
        values (list[list]): The values at the data points (n_points x 1)
        xi (list[list]): The points at which to interpolate (n_new_points x n_dims)
        fill_value (float, optional): Value used for points outside the convex hull Default is 0.

    Returns:
        list[list]: Interpolated values as a 2D list, or error message string.
    """
    try:
        def to2d(x):
            return [[x]] if not isinstance(x, list) else x

        # Normalize inputs to 2D lists
        points = to2d(points)
        values = to2d(values)
        xi = to2d(xi)

        # Validate that inputs are 2D lists
        if not isinstance(points, list) or not all(isinstance(row, list) for row in points):
            return "Error: Invalid input: points must be a 2D list."
        if not isinstance(values, list) or not all(isinstance(row, list) for row in values):
            return "Error: Invalid input: values must be a 2D list."
        if not isinstance(xi, list) or not all(isinstance(row, list) for row in xi):
            return "Error: Invalid input: xi must be a 2D list."

        # Validate fill_value
        if not isinstance(fill_value, (int, float)):
            return "Error: Invalid input: fill_value must be a number."
        fill_value = float(fill_value)

        # Check dimensions
        if len(points) == 0:
            return "Error: Invalid input: points must not be empty."
        if len(values) == 0:
            return "Error: Invalid input: values must not be empty."
        if len(xi) == 0:
            return "Error: Invalid input: xi must not be empty."

        if len(points) != len(values):
            return "Error: Invalid input: points and values must have the same number of rows."

        # Validate that all rows have consistent dimensions
        n_dims = len(points[0])
        if n_dims < 2:
            return "Error: Invalid input: points must have at least 2 dimensions (N > 1)."

        for i, row in enumerate(points):
            if len(row) != n_dims:
                return f"Error: Invalid input: all rows in points must have the same length (row {i} mismatch)."

        for i, row in enumerate(values):
            if len(row) != 1:
                return f"Error: Invalid input: values must be a column vector (row {i} has {len(row)} columns)."

        xi_dims = len(xi[0])
        if xi_dims != n_dims:
            return f"Error: Invalid input: xi must have same dimensions as points ({n_dims})."

        for i, row in enumerate(xi):
            if len(row) != xi_dims:
                return f"Error: Invalid input: all rows in xi must have the same length (row {i} mismatch)."

        # Validate that all values are numeric and finite
        try:
            for i, row in enumerate(points):
                for j, val in enumerate(row):
                    if not isinstance(val, (int, float)):
                        return f"Error: Invalid input: points[{i}][{j}] must be numeric."
                    if math.isinf(val) or math.isnan(val):
                        return f"Error: Invalid input: points[{i}][{j}] must be finite."

            for i, row in enumerate(values):
                val = row[0]
                if not isinstance(val, (int, float)):
                    return f"Error: Invalid input: values[{i}][0] must be numeric."
                if math.isinf(val) or math.isnan(val):
                    return f"Error: Invalid input: values[{i}][0] must be finite."

            for i, row in enumerate(xi):
                for j, val in enumerate(row):
                    if not isinstance(val, (int, float)):
                        return f"Error: Invalid input: xi[{i}][{j}] must be numeric."
                    if math.isinf(val) or math.isnan(val):
                        return f"Error: Invalid input: xi[{i}][{j}] must be finite."
        except Exception as e:
            return f"Error: Invalid input: error validating numeric values: {e}"

        # Convert to numpy arrays
        try:
            points_arr = np.array(points, dtype=float)
            values_arr = np.array(values, dtype=float).flatten()
            xi_arr = np.array(xi, dtype=float)
        except Exception as e:
            return f"Error: Invalid input: error converting to arrays: {e}"

        # Perform interpolation
        try:
            interp = scipy_LinearNDInterpolator(points_arr, values_arr, fill_value=fill_value)
            result = interp(xi_arr)
        except Exception as e:
            return f"Error: scipy.interpolate.LinearNDInterpolator error: {e}"

        # Convert result to 2D list
        try:
            result_2d = [[float(val)] for val in result]
        except Exception as e:
            return f"Error: Error converting result to 2D list: {e}"

        return result_2d
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator

The coordinates of the data points (n_points x n_dims)
The values at the data points (n_points x 1)
The points at which to interpolate (n_new_points x n_dims)
Value used for points outside the convex hull