An experiment related to d3/d3-array#56.
This shows how repeated iterations of a simple moving average acts as a Gaussian Filter.
Built with blockbuilder.org
license: mit |
An experiment related to d3/d3-array#56.
This shows how repeated iterations of a simple moving average acts as a Gaussian Filter.
Built with blockbuilder.org
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<style> | |
* { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } | |
</style> | |
</head> | |
<body> | |
<canvas id="rainbow" width="960" height="500"></canvas> | |
<canvas id="foreground" width="960" height="500"></canvas> | |
<script> | |
const numRandomPoints = 300; | |
const numHistogramBins = 500; | |
const canvas = d3.select("canvas"); | |
const width = canvas.attr("width"); | |
const height = canvas.attr("height"); | |
const randomPoints = d3.range(numRandomPoints).map(d3.randomNormal()); | |
const histogram = d3.histogram() | |
.domain([-3, 3]) | |
.thresholds(numHistogramBins); | |
let data = histogram(randomPoints) | |
.map(d => Object.assign({}, d, { density: d.length})); | |
const yValue = d => d.density; | |
const xValue = d => (d.x0 + d.x1) / 2; | |
const xScale = d3.scaleLinear() | |
.domain(d3.extent(data, xValue)) | |
.range([0, width]); | |
const yScale = d3.scaleLinear() | |
.domain([0, 2]) | |
.range([height, 0]); | |
const rainbow = d3.select("#rainbow").node().getContext("2d"); | |
const foreground = d3.select("#foreground").node().getContext("2d"); | |
// .attr("fill-opacity", .3) | |
// .attr("stroke", "black") | |
const area = d3.area() | |
.x(d => xScale(xValue(d))) | |
.y0(yScale(0)) | |
.y1(d => yScale(yValue(d))); | |
function renderHistogram(elapsed){ | |
const t = elapsed / 2 + 175; // Start at blue | |
rainbow.beginPath(); | |
area.context(rainbow)(data); | |
rainbow.strokeStyle = d3.hsl(t, 1, 0.5); | |
rainbow.stroke(); | |
foreground.beginPath(); | |
area.context(foreground)(data); | |
foreground.fillStyle = d3.hsl(t, 1, 0.5, 0.2); | |
foreground.clearRect(0, 0, width, height); | |
foreground.fill(); | |
} | |
function blur(data){ | |
return data.map((d, i) => { | |
const previous = (i === 0) ? i : i - 1; | |
const next = (i === data.length - 1) ? i : i + 1; | |
const sum = data[previous].density + d.density + data[next].density; | |
d.density = sum / 3; | |
return d; | |
}); | |
} | |
d3.timer((elapsed) => { | |
data = blur(data); | |
renderHistogram(elapsed); | |
}); | |
</script> | |
</body> |