Skip to content

Instantly share code, notes, and snippets.

@curran
Last active April 12, 2017 14:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save curran/853fa00b8f0732fb2bee7fccfd7b4523 to your computer and use it in GitHub Desktop.
Save curran/853fa00b8f0732fb2bee7fccfd7b4523 to your computer and use it in GitHub Desktop.
Histogram Smoothing
license: mit
<!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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment