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: card, Wise, and bank transfer.
Related chapters
- Terrain and elevation data, terrain uses bilinear interpolation
- Map clustering algorithms, heat maps are the visual sibling of clustering
