# math – How to perform bilinear interpolation in Python

## math – How to perform bilinear interpolation in Python

Heres a reusable function you can use. It includes doctests and data validation:

``````def bilinear_interpolation(x, y, points):
Interpolate (x,y) from values associated with four points.

The four points are a list of four triplets:  (x, y, value).
The four points can be in any order.  They should form a rectangle.

>>> bilinear_interpolation(12, 5.5,
...                        [(10, 4, 100),
...                         (20, 4, 200),
...                         (10, 6, 150),
...                         (20, 6, 300)])
165.0

# See formula at:  http://en.wikipedia.org/wiki/Bilinear_interpolation

points = sorted(points)               # order points by x, then by y
(x1, y1, q11), (_x1, y2, q12), (x2, _y1, q21), (_x2, _y2, q22) = points

if x1 != _x1 or x2 != _x2 or y1 != _y1 or y2 != _y2:
raise ValueError(points do not form a rectangle)
if not x1 <= x <= x2 or not y1 <= y <= y2:
raise ValueError((x, y) not within the rectangle)

return (q11 * (x2 - x) * (y2 - y) +
q21 * (x - x1) * (y2 - y) +
q12 * (x2 - x) * (y - y1) +
q22 * (x - x1) * (y - y1)
) / ((x2 - x1) * (y2 - y1) + 0.0)
``````

You can run test code by adding:

``````if __name__ == __main__:
import doctest
doctest.testmod()
``````

Running the interpolation on your dataset produces:

``````>>> n = [(54.5, 17.041667, 31.993),
(54.5, 17.083333, 31.911),
(54.458333, 17.041667, 31.945),
(54.458333, 17.083333, 31.866),
]
>>> bilinear_interpolation(54.4786674627, 17.0470721369, n)
31.95798688313631
``````

Not sure if this helps much, but I get a different value when doing linear interpolation using scipy:

``````>>> import numpy as np
>>> from scipy.interpolate import griddata
>>> n = np.array([(54.5, 17.041667, 31.993),
(54.5, 17.083333, 31.911),
(54.458333, 17.041667, 31.945),
(54.458333, 17.083333, 31.866)])
>>> griddata(n[:,0:2], n[:,2], [(54.4786674627, 17.0470721369)], method=linear)
array([ 31.95817681])
``````

#### math – How to perform bilinear interpolation in Python

Inspired from here, I came up with the following snippet. The API is optimized for reusing a lot of times the same table:

``````from bisect import bisect_left

class BilinearInterpolation(object):
Bilinear interpolation.
def __init__(self, x_index, y_index, values):
self.x_index = x_index
self.y_index = y_index
self.values = values

def __call__(self, x, y):
# local lookups
x_index, y_index, values = self.x_index, self.y_index, self.values

i = bisect_left(x_index, x) - 1
j = bisect_left(y_index, y) - 1

x1, x2 = x_index[i:i + 2]
y1, y2 = y_index[j:j + 2]
z11, z12 = values[j][i:i + 2]
z21, z22 = values[j + 1][i:i + 2]

return (z11 * (x2 - x) * (y2 - y) +
z21 * (x - x1) * (y2 - y) +
z12 * (x2 - x) * (y - y1) +
z22 * (x - x1) * (y - y1)) / ((x2 - x1) * (y2 - y1))
``````

You can use it like this:

``````table = BilinearInterpolation(
x_index=(54.458333, 54.5),
y_index=(17.041667, 17.083333),
values=((31.945, 31.866), (31.993, 31.911))
)

print(table(54.4786674627, 17.0470721369))
# 31.957986883136307
``````

This version has no error checking and you will run into trouble if you try to use it at the boundaries of the indexes (or beyond). For the full version of the code, including error checking and optional extrapolation, look here.
{"found_math": false, "script_math_tex": 0, "script_math_asciimath": 0, "math_annotations": 0, "math_alttext": 0, "mathml": 0, "mathjax_tag": 0, "mathjax_inline_tex": 0, "mathjax_display_tex": 0, "mathjax_asciimath": 0, "img_math": 0, "codecogs_latex": 0, "wp_latex": 0, "mimetex.cgi": 0, "/images/math/codecogs": 0, "mathtex.cgi": 0, "katex": 0, "math-container": 0, "wp-katex-eq": 0, "align": 0, "equation": 0, "x-ck12": 0, "texerror": 0, "url": "https://winmundo.com/math-how-to-perform-bilinear-interpolation-in-python/", "fetch_time": 1685613841000000000, "content_mime_type": "text/html", "warc_filename": "crawl-data/CC-MAIN-2023-23/segments/1685224647639.37/warc/CC-MAIN-20230601074606-20230601104606-00706.warc.gz", "warc_record_offset": 679812099, "warc_record_length": 16293, "token_count": 1163, "char_count": 3334, "score": 3.703125, "int_score": 4, "crawl": "CC-MAIN-2023-23", "snapshot_type": "latest", "language": "en", "language_score": 0.6376580595970154, "file_path": "/sailhome/yjruan/project/latent-lm/data/processed/finemath-4plus/finemath-4plus/train-00025-of-00064.parquet"}