Published
Edited
Feb 28, 2021
Fork of d3.line
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
numeric = require('https://bundle.run/numericjs@1.2.6')
Insert cell
function distanceThinPlate(r) {
if(r === 0) return 0;
return Math.pow(r, 2) * Math.log(r);
}
Insert cell
function norm(pa, pb) {
return numeric.norm2(numeric.sub(pb, pa));
}
Insert cell
function RBF(points, values, distanceFunction, epsilon) {

var distance = distanceThinPlate;

// `identity` here serves as a shorthand to allocate
// the matrix nested array.
var M = numeric.identity(points.length);

// First compute the point to point distance matrix
// to allow computing epsilon if it's not provided
for(var j=0; j<points.length; j++) {
for(var i=0; i<points.length; i++) {
M[j][i] = norm(points[i], points[j]);
}
}

// if needed, compute espilon as the average distance between points
if(epsilon === undefined) {
epsilon = numeric.sum(M) / (Math.pow(points.length, 2) - points.length);
}

// update the matrix to reflect the requested distance function
for(var j=0; j<points.length; j++) {
for(var i=0; i<points.length; i++) {
M[j][i] = distance(M[j][i], epsilon);
}
}

// determine dimensionality of target values
var sample = values[0];
var D = typeof sample === 'number'
? 1
: sample.length;

// generalize to vector values
if(D === 1) {
values = values.map(function(value) {
return [value];
});
}

// reshape values by component
var tmp = new Array(D);
for(var i=0; i<D; i++) {
tmp[i] = values.map(function(value) {
return value[i];
});
}
values = tmp;

// Compute basis functions weights by solving
// the linear system of equations for each target component
var w = new Array(D);
var LU = numeric.LU(M);
for(var i=0; i<D; i++) {
w[i] = numeric.LUsolve(LU, values[i]);
}

// The returned interpolant will compute the value at any point
// by summing the weighted contributions of the input points
function interpolant(p) {

var distances = new Array(points.length);
for(var i=0; i<points.length; i++) {
distances[i] = distance(norm(p, points[i]), epsilon);
}

var sums = new Array(D);
for(var i=0; i<D; i++) {
sums[i] = numeric.sum(numeric.mul(distances, w[i]));
}

return sums;
}

return interpolant;
}
Insert cell
points = [0,1,2,3,4,5,7];
Insert cell
values = [0.1,0.4,1.2,0.3,2.0,1.2,0.5]
Insert cell
interpolant = RBF(points, values)
Insert cell
output = new Array(100);
Insert cell
{for(var i=0; i<100; i++) {
output[i] = [i*2,20*interpolant(i/20.0)];
}
}
Insert cell
countrydata = FileAttachment("nations.json").json()
Insert cell
usa_lifeExpectancy = countrydata[102]["lifeExpectancy"]
Insert cell
usa_points = new Array(usa_lifeExpectancy.length)
Insert cell
usa_values = new Array(usa_lifeExpectancy.length)
Insert cell
{
for(var i=0;i<usa_lifeExpectancy.length;i++) {
usa_points[i] = usa_lifeExpectancy[i][0]
usa_values[i] = usa_lifeExpectancy[i][1]
}
}
Insert cell
usa_interpolant = RBF(usa_points, usa_values)
Insert cell
usa_interpolant(1800)
Insert cell
usa_output = new Array(209);
Insert cell
{for(var i=0; i<209; i++) {
usa_output[i] = [i,usa_interpolant(i+1800)[0]];
}
}
Insert cell
usa_output
Insert cell
q = d3.line()(usa_output)
Insert cell
d3 = require("d3@5")
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more