
Security News
GitHub Actions Checkout Now Blocks Risky pull_request_target Checkouts
GitHub Actions checkout now blocks risky pull_request_target checkouts by default to help prevent pwn request supply chain attacks.
Interpolation of irregular data in any number of dimensions using inverse distance weighting (IDW). The module offers flexibility through multiple modifiable components.

idw is a JavaScript package for flexible interpolation of any-dimensional data using inverse distance weighting (IDW). It includes functionality for generating tileable noise functions.
This readme contains examples of use, an API reference and an attempt to explain how the package works.
The package is available on npm:
npm install idw
In the one-dimensional case, the positions are specified as an array of numbers:
const { IDW } = require("idw");
const idw = new IDW({
positions: [0, 0.3, 0.6, 0.8, 1],
values: [2, 1.3, -0.3, -0.5, 2]
});
// Interpolate at 100 regularly spaced positions between 0 and 1
const x = Array(100).fill().map((_, i) => i / 99);
const values = x.map(p => idw.evaluate(p, 2));
console.log(values); // Outputs array of 100 values [v₁, v₂,...]
The second parameter in idw.evaluate is the power used when computing the weights.
Here's a comparison using the setup above, with the value of the power above each plot and original data shown as red points:
Now, the positions are represented as an array of arrays:
const data = {
positions: [
[0.1, 0.3],
[0.6, 0.5],
[0.2, 0.8],
[0.9, 0.1]
],
values: [0, 0.33, 0.67, 1]
}
Using the data above, we set up an IDW with tileable edges in the square [0, 1] × [0, 1]. It measures distance using the Manhattan/taxicab distance.
const { IDW } = require("idw");
const options = {
periodicExtent: [[0, 1], [0, 1]]
}
const idw = new IDW(data, options);
idw.useTaxicabDistance();
// Interpolate at 100 random positions
const positions = Array(100).fill().map(() => [Math.random(), Math.random()]);
const values = positions.map(p => idw.evaluate(p, 3));
console.log(values); // Outputs array of values [v1, v2,...]
Here's how the function looks on a 1000 × 1000 grid over [-0.5, 1.5] × [0, 1], with the positions indicated by their index in red:
The black square indiates periodicExtent.
For the three-dimensional example, we'll use the generateNoiseIDW function to generate an IDW object with 20 random positions and values.
The positions are sampled from [-1, 1] × [-1, 1] × [0, 1], and the function is tileable/periodic along the z-dimension.
The RNG is specified using a seed value of 1.
const { generateNoiseIDW } = require("idw");
let idw = generateNoiseIDW({
n: 20,
dimensions: 3,
extent: [[-1, 1], [-1, 1], [0, 1]],
periodic: [false, false, true]
}, 1);
// Interpolate at 100 random positions inside [-1, 1] × [-1, 1] × [0, 1]
const positions = Array(100).fill().map(() => [-1 + 2*Math.random(), -1 + 2*Math.random(), Math.random()]);
const values = positions.map(p => idw.evaluate(p, 5));
console.log(values); // Outputs array of values [v1, v2,...]
The animation below shows the noise function as the z-coordinate increases from 0 to 1. Since the function is periodic along the z-dimension, it leads to a perfect loop!
new IDW(data[, options])
[x₁, x₂,...]). Otherwise, it's an an array of arrays ([[x₁, y₁,...], [x₂, y₂,...], ...]). Required.{ 0: [-1, 1], 1: [0, 1] } for the rectangle [-1, 1] × [0, 1]. Defaults to undefined. (Explanation)w = 1/(distanceᵖ + denominatorOffset)). Defaults to 0.const { IDW } = require("idw");
const idw = new IDW({
positions: [0, 0.25, 0.5, 0.75, 1],
values: [0.1, 0.2, 0.3, 0.4, 0.5]
});
const data = {
positions: [
[0, 0.4],
[0.5, 0.2],
[0.3, 0.9],
],
values: [-0.5, 1.3, 0.4]
}
const options = {
periodicExtent: { 0: [0, 1] }, // Tileable only along x-axis
innerDistFunction: d => Math.exp(d*d) - 1,
outerDistFunction: arr => Math.log(IDW.sum(arr) + 1),
weightFunction: w => (1 + Math.sin(4*Math.PI*w)) / 2
}
const idw = new IDW(data, options);
Computes the interpolated value at a specified position.
position is either a number (1D) or an array of same dimension as the elements of positions in the input data (>=2D).
power is the power parameter.
// 1D: Interpolates value at 0.6
const value = idw.evaluate(0.6);
// 2D: Interpolates value at [0.2, 0.5], using p = 3
const value = idw.evaluate([0.2, 0.5], 3);
Sets the innerDistFunction and outerDistFunction parameters that determine a custom distance function (see explanation).
// Example: Euclidean distance
idw.setDistanceFunctions((d, i) => d*d, arr => Math.sqrt(IDW.sum(arr));
Sets distance functions to compute distance using Euclidean distance. This is the default setup.
idw.useEuclideanDistance();
Sets distance functions to compute distance using taxicab/Manhattan distance.
idw.useTaxicabDistance();
Sets distance functions to compute distance using chessboard/Chebyshev distance.
idw.useChessboardDistance();
Sets distance functions to compute distance using Minkowski distance.
p is the power parameter.
// Equivalent to taxicab distance
idw.useMinkowskiDistance(1);
Sets the weightFunction parameter (see explanation).
idw.setWeightFunction(w => w*w);
Sets the denominatorOffset parameter, a constant that is added to the denominator when computing weights.
idw.setDenominatorOffset(1e-5);
Using a periodic extent can sometimes lead to strange artifacts in the interpolation function, which can be mitigated by smoothing the distance function.
This method sets the amount of smoothing to use.
smoothing must be between 0 and 1, the default value is 0.1.
idw.setPeriodicSmoothing(0.2);
Returns the data (object containing positions and values) that was passed to the constructor.
const { positions, values } = idw.getData();
Generates and returns a noise function by creating an IDW object with randomly generated positions and values.
dimensions = 2)valueFunction is not specified, it will generate the random values as well. Either an RNG function, or an integer seed value. Defaults to Math.random.By default, the random values are guaranteed to have minimum and maximum values equal to minValue and maxValue, respectively.
If valueFunction is specified, the values for minValue and maxValue are ignored.
const { generateNoiseIDW } = require("idw");
const idw = generateNoiseIDW({
n: 10,
dimensions: 2,
minValue: -1,
maxValue: 1,
extent: [[-1, 1], [-2, 2]]
}, 123);
console.log(idw.getData()); // The random positions and values generated for the IDW
console.log(idw.evaluate([0, 0])); // Get interpolated value at [0, 0]
const idw = generateNoiseIDW({
n: 5,
dimensions: 3,
valueFunction: p => p[0] + p[1] + p[2] // Value is determined by sum of coordinates
}, 123);
console.log(idw.evaluate([-0.3, 0.5, 0])); // Get interpolated value at [-0.3, 0.5, 0]
Inverse distance weighting is a method for interpolating data consisting of pairs of positions and values. It interpolates by computing a weighted average of the supplied values, placing a higher amount of weight on those near the position of interest.
Consider, for example, the data consisting of two-dimensional positions p₁ = [0, 0] and p₂ = [1, 1] with corresponding values v₁ = 0 and v₂ = 1, and let p = [0.25, 0.4] be the position that we want to interpolate.
The distances are d₁ = distance(p, p1) = √((0 - 0.25)² + (0 - 0.4)²) = 0.472 and d₂ = distance(p, p2) = 0.960, leading to weights w₁ = 1 / d₁ = 2.112 and w₂ = 1 / d₂ = 1.041.
The interpolated value is then the weighted average v = (w₁*v₁ + w₂*v₂) / (w₁ + w₂) = 0.330.
In practice, the weights are usually computed as w = 1 / dᵖ, where the parameter p is a positive number.
The 1D example compares interpolation with different values for p, and gives some useful intuition.
Using a small value leads to a function that has spikes at the data positions.
As it increases, the function becomes smoother, and eventually flattens out to nearest-neighbor interpolation.
In idw, the parameter p is specified in the evaluate method (see the API description).
The example above measures the distance using the Euclidean distance (i.e. the length of the straight line connecting the positions):
distance([x₁, y₁,...], [x₂, y₂,...]) = √((x₂ - x₁)² + (y₂ - y₁)² + ...)
where ... indicates additional coordinates in three or more dimensions.
In addition to this, idw offers three predefined distance functions:
Taxicab/Manhattan distance (useTaxicabDistance()):
distance([x₁, y₁,...], [x₂, y₂,...]) = |x₂ - x₁| + |y₂ - y₁| + ...
Chebyshev/chessboard distance (useChessboardDistance()):
distance([x₁, y₁,...], [x₂, y₂,...]) = max(|x₂ - x₁|, |y₂ - y₁|,...)
Minkowski distance (useMinkowskiDistance(p)):
distance([x₁, y₁,...], [x₂, y₂,...]) = ((x₂ - x₁)ᵖ + (y₂ - y₁)ᵖ + ...)¹ᐟᵖ
Euclidean distance is the default.
idw also allows the user to define their own distance functions through the innerDistFunction and outerDistFunction parameters.
To understand how this works, first notice that every distance function above can be expressed as
distance([x₁, y₁,...], [x₂, y₂,...]) = outerDistFunction([innerDistFunction(x2 - x1), innerDistFunction(y2 - y1),...]).
Euclidean distance, for example, is
innerDistFunction = d => d*d
outerDistFunction = arr => Math.sqrt(IDW.sum(arr))
where the function IDW.sum takes in an array and computes the sum of its elements.
In addition to the coordinate difference, innerDistFunction is also passed the coordinate index (0 for x, 1 for y and so on).
This makes it possible to create complex distance functions:
innerDistFunction = (d, i) => i === 0 ? d*d : Math.abs(d);
Specifying custom values for innerDistFunction and outerDistFunction can lead to very interesting and unpredictable results.
The optional parameter periodicExtent can be used to create tileable interpolation functions.
The image below demonstrates the situation where periodicExtent = [[0, 2], [0, 1]].
In this case, the rectangle "wraps around", so that the opposite edges are connected, or "glued together".
To better understand how this affects the function, let's compute the distance between the cyan ([0.2, 0.1]) and pink ([1.8, 0.8]) points.
As always, there's the length of the straight line connecting the points, indicated by a solid blue line.
Its length is √((1.8 - 0.2)² + (0.8 - 0.1)²) = 1.75.
However, there's a second straight path connecting the points: moving along the solid brown line, which first crosses the right edge over to the left side, and then from the top to the bottom.
The distance travelled along this path is √((0.2 + 0.2)² + (0.2 + 0.1)²) = 0.5, which is also the distance between the points.
When a function has a periodicExtent specified, it becomes tileable, meaning that it repeats smoothly across the boundaries.
The two-dimensional example demonstrates this.
Note: It's possible to create functions that are tileable along some boundaries, but not others (see the API documentation).
When tileable interpolation functions are evaluated outside periodicExtent, the value at the equivalent position inside periodicExtent is returned.
In the example above, the position [2.1, 1.2] is equivalent to [0.1, 0.2].
The weightFunction parameter gives the user another way to modify the behavior of the interpolation function, by transforming the values of the weights before the weighted average is computed.
With data consisting of position-value pairs (pᵢ, vᵢ), the following steps are performed internally:
wᵢ = 1 / distance(pᵢ, position)ᵖwᵢ = wᵢ / sumwᵢ = weightFunction(wᵢ)(w₁*v₁ + w₂*v₂ + ...) / (w₁ + w₂ + ...)As long as the initial weight values are positive, the inputs to the weight function will always be between 0 and 1.
FAQs
Interpolation of irregular data in any number of dimensions using inverse distance weighting (IDW). The module offers flexibility through multiple modifiable components.
We found that idw demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
GitHub Actions checkout now blocks risky pull_request_target checkouts by default to help prevent pwn request supply chain attacks.

Product
Socket now supports Custom Roles and Repository Access Permissions so organizations can control who can access specific repositories and actions.

Product
Socket MCP now lets AI assistants review org alerts, investigate threats using the Socket threat feed, and inspect package files in addition to dependency scoring.