CHAPTER 23
Interpolation and heat maps
Turning sparse sample points into continuous surfaces — IDW, kernel density, Kriging, and rendering techniques.
You have 50 air quality sensors across a city. How do you draw a continuous pollution map? You have 1,000 crime incidents. How do you show hotspots? Interpolation and kernel density estimation answer these questions.
IDW interpolation · click to add samples
Inverse Distance Weighting (IDW)
The simplest interpolation method: the estimated value at a point is a weighted average of all samples, where weight = 1/distance^p.
function idw(queryLat, queryLon, samples, power = 2) {
let weightedSum = 0, totalWeight = 0;
for (const { lat, lon, value } of samples) {
const d = haversine(queryLat, queryLon, lat, lon);
if (d < 1) return value; // query is on a sample point
const w = 1 / Math.pow(d, power);
weightedSum += w * value;
totalWeight += w;
}
return weightedSum / totalWeight;
}
The power parameter controls smoothness:
- : linear falloff, smooth but influences far points
- : common default, balanced
- : very local, sharp transitions
Kernel Density Estimation (KDE)
KDE and IDW solve different problems. IDW answers "what is the value here, given measured values nearby?" — useful for temperature, elevation, pollution levels. KDE answers "how concentrated are events here?" — useful for crime, accidents, shop locations. The input to KDE is just a set of points with no values; the output is a density surface.
KDE doesn't interpolate values — it estimates the density of point events. Each point spreads a smooth "bump" (the kernel) over the surrounding area.
The Gaussian kernel is most common:
function gaussianKDE(queryLat, queryLon, points, bandwidth) {
let sum = 0;
for (const [lat, lon] of points) {
const d = haversine(queryLat, queryLon, lat, lon);
const u = d / bandwidth;
sum += Math.exp(-0.5 * u * u);
}
return sum / (points.length * bandwidth * Math.sqrt(2 * Math.PI));
}
The bandwidth (analogous to search radius) controls smoothness — too small and you see individual points; too large and everything blurs into one blob.
Rendering strategies
Canvas-based (CPU): Rasterise the interpolation grid into a canvas, apply a colour scale.
function renderHeatmap(canvas, samples, colorScale) {
const ctx = canvas.getContext("2d");
const imageData = ctx.createImageData(canvas.width, canvas.height);
for (let px = 0; px < canvas.width; px++) {
for (let py = 0; py < canvas.height; py++) {
const [lat, lon] = pixelToLatLon(px, py);
const value = idw(lat, lon, samples);
const [r, g, b] = colorScale(value);
const idx = (py * canvas.width + px) * 4;
imageData.data.set([r, g, b, 200], idx);
}
}
ctx.putImageData(imageData, 0, 0);
}
Continue reading "Interpolation and heat maps"
You've reached the end of the free preview. Unlock all 22 paid chapters, including distance math, bearings, polygons, spatial indexing, and 3D map rendering — plus a downloadable PDF and the companion code repo.
- All 22 paid chapters with worked examples
- Downloadable PDF for offline reading
- Companion GitHub repo (JavaScript + Python)
- Free updates for life
Multiple payment options including Wise, PayPal, and bank transfer.
Related chapters
- Terrain and elevation data — terrain uses bilinear interpolation
- Map clustering algorithms — heat maps are the visual sibling of clustering