Built with blockbuilder.org
forked from curran's block: Histogram Smoothing
forked from curran's block: Robot Painter
An experiment related to https://github.com/d3/d3-array/issues/56 | |
This shows how repeated iterations of a simple moving average acts as a [Gaussian Filter](https://en.wikipedia.org/wiki/Gaussian_filter). | |
license: mit |
Built with blockbuilder.org
forked from curran's block: Histogram Smoothing
forked from curran's block: Robot Painter
<!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 width = 960; | |
const height = 500; | |
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"); | |
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, (5000 - elapsed)/5000); | |
rainbow.stroke(); | |
} | |
function blur(data){ | |
return data.map((d, i) => { | |
const previous = (i === 0) ? i : i - 1; | |
const sum = data[previous].density + d.density; | |
d.density = sum / 2; | |
return d; | |
}); | |
} | |
d3.timer((elapsed) => { | |
data = blur(data); | |
renderHistogram(elapsed); | |
}); | |
</script> | |
</body> |