D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
jthomassie
Full window
Github gist
Histogram: grouped, stacked, normalized
<!DOCTYPE html> <meta charset="utf-8"> <style> body { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 13px; margin: auto; position: relative; width: 960px; color: #333; } text { font: 10px sans-serif; fill: #666; } .axis path, .axis line { fill: none; stroke: #666; shape-rendering: crispEdges; } .form { position: relative; float: right; right: 10px; top: 10px; margin: 40px 40px 0 0; } label{ margin: 6px; } </style> <div class="form"> <label><input type="radio" name="mode" value="grouped" checked> Grouped</label> <label><input type="radio" name="mode" value="stacked"> Stacked</label> <label><input type="radio" name="mode" value="normalized"> Normalized</label> </div> <div id="chart"></div> <script src="https://d3js.org/d3.v3.min.js"></script> <script> var n = 5, // number of layers m = 65; // number of samples per layer var transitionDuration = 250; // transition duration var stack = d3.layout.stack(), layers = stack(d3.range(n).map(function() { return bumpLayer(m, 0.6); })), yGroupMax = d3.max(layers, function(layer) { return d3.max(layer, function(d) { return d.y; }); }), yStackMax = d3.max(layers, function(layer) { return d3.max(layer, function(d) { return d.y0 + d.y; }); }); console.log(layers); var margin = {top: 40, right: 10, bottom: 20, left: 30}, width = 960 - margin.left - margin.right, height = 350 - margin.top - margin.bottom; var color = d3.scale.linear() .domain([0, n - 1]) .range(["#ffc014", "#990000"]); var x = d3.scale.ordinal() .domain(d3.range(m)) .rangeRoundBands([0, width], 0.1); var y = d3.scale.linear() .domain([0, yGroupMax]) .range([height, 0]); var xAxis = d3.svg.axis() .scale(x) .tickSize(0) .tickPadding(6) .orient("bottom"); var yAxis = d3.svg.axis() .scale(y) .tickSize(0) .tickPadding(6) .orient("left"); var svg = d3.select("#chart").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); var layer = svg.selectAll(".layer") .data(layers) .enter().append("g") .attr("class", "layer") .style("fill", function(d, i) { return color(i); }); var rect = layer.selectAll("rect") .data(function(d) { return d; }) .enter().append("rect") .attr("x", function(d, i, j) { return x(d.x) + x.rangeBand() / n * j; }) .attr("y", height) .attr("width", x.rangeBand() / n) .attr("height", 0); rect.transition() .duration(transitionDuration) .attr("y", function(d) { return y(d.y); }) .attr("height", function(d) { return height - y(d.y); }); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); svg.append("g") .attr("class", "y axis") .call(yAxis); d3.selectAll("input").on("change", change); function change() { if (this.value === "grouped") { transitionGrouped(); } if (this.value === "stacked") { transitionStacked(); } if (this.value === "normalized") { transitionNormalized(); } } function transitionGrouped() { y.domain([0, yGroupMax]).nice(); rect.transition() .duration(transitionDuration) .attr("x", function(d, i, j) { return x(d.x) + x.rangeBand() / n * j; }) .attr("width", x.rangeBand() / n) .transition() .attr("y", function(d) { return y(d.y); }) .attr("height", function(d) { return height - y(d.y); }); // update the y-axis svg.select('g.y.axis') .transition() .duration(transitionDuration) .call(yAxis); } function transitionStacked() { y.domain([0, yStackMax]).nice(); rect.transition() .duration(transitionDuration) .attr("y", function(d) { return y(d.y0 + d.y); }) .attr("height", function(d) { return y(d.y0) - y(d.y0 + d.y); }) .transition() .attr("x", function(d) { return x(d.x); }) .attr("width", x.rangeBand()); // update the y-axis svg.select('g.y.axis') .transition() .duration(transitionDuration) .call(yAxis); } function transitionNormalized() { function total(i) { var t = 0; for (var j = 0; j < n; j++) { t = t + layers[j][i].y; } return t; } y.domain([0, 100]); rect.transition() .duration(transitionDuration) .attr("y", function(d,i,j) { var t = total(i); var yy = y((d.y0 + d.y)/t*100); return yy; }) .attr("height", function(d,i) { var t = total(i); var hh = y(d.y0/t*100) - y((d.y0 + d.y)/t*100); return hh; }) .transition() .attr("x", function(d) { return x(d.x); }) .transition() .attr("x", function(d) { return x(d.x); }) .attr("width", x.rangeBand()); // update the y-axis svg.select('g.y.axis') .transition() .duration(transitionDuration) .call(yAxis); } // random data generator - inspired by Lee Byron's test data generator function bumpLayer(n, o) { function bump(a) { var x = 1 / ( 0.1 + Math.random() ), y = 2 * Math.random() - 0.5, z = 10 / ( 0.1 + Math.random() ); for ( var i = 0; i < n; i++ ) { var w = ( i / n - y ) * z; a[i] += x * Math.exp(-w * w); } } var a = [], i; for (i = 0; i < n; ++i) { a[i] = o + o * Math.random(); } for (i = 0; i < 5; ++i) { bump(a); } return a.map(function(d, i) { return {x: i, y: Math.max(0, d)}; }); } </script>
Modified
http://d3js.org/d3.v3.min.js
to a secure url
https://d3js.org/d3.v3.min.js