D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
romsson
Full window
Github gist
Grouped to stacked
Built with
blockbuilder.org
<!DOCTYPE html> <head> <meta charset="utf-8"> <script src="https://d3js.org/d3.v4.min.js"></script> </head> <body> <div> <label><input type="radio" name="mode" value="grouped" checked>Grouped</label> <label><input type="radio" name="mode" value="stacked">Stacked</label> </div> <script> var margin = {top: 20, right: 20, bottom: 20, left: 20}, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; var n = 10, m = 5; var duration = 500; // Random data // (10) [Array(5), Array(5), Array(5), Array(5), Array(5), Array(5), Array(5), Array(5), Array(5), Array(5)] // 0: (5) [0.8976472929321404, 0.16527384338607165, 0.5102470192425659, 0.9127164580119789, 0.12280753488611529] // 1: (5) [0.36324654194776396, 0.7564192480661098, 0.5087518603046575, 0.1921867799203365, 0.8480531388829291] // ... var data = d3.range(n).map(function() { return d3.range(m).map(Math.random); }); // Create the vertical layout layer used for the stacked // (5) [Array(10), Array(10), Array(10), Array(10), Array(10)] // 0: (10) [Array(2), Array(2), Array(2), Array(2), Array(2), ... // 1: (10) [Array(2), Array(2), Array(2), Array(2), Array(2), ... // ... var layers = d3.stack().keys(d3.range(m))(data); // IMPORTANT // Max stack seeks for max absolute height var max_stack = d3.max(layers, function(e) { return d3.max(e, function(d) { return d[1] - 0; }); }); // Max group seeks for max relative height var max_group = d3.max(layers, function(e) { return d3.max(e, function(d) { return d[1] - d[0]; }); }); var x = d3.scaleBand() .rangeRound([0, width]) .paddingInner(0.1) .domain(d3.range(n)); var y = d3.scaleLinear() .domain([0, max_group]) .rangeRound([height, 0]); var color = d3.scaleOrdinal(d3.schemeCategory10); var svg = d3.select("body").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 +")"); // ADD groups (will not change) var layer = svg.selectAll(".layer") .data(layers) .enter() .append("g") .attr("class", "layer") // IMPORTANT: memorize the nested group (useful for children) .attr("id", function(d, i) { return d.key; }) .style("fill", function(d, i) { return color(i); }); // ADD rects (will change!) var rect = layer.selectAll("rect") .data(function(d) { return d; }) .enter() .append("rect") .attr("x", function(d, i) { return x(i); }) .attr("y", height) .attr("width", x.bandwidth()) .attr("height", 0); function swap() { this.value == "grouped" ? grouped(): stacked(); } d3.selectAll("input").on("change", swap); function grouped() { // Adjust the Y-scale height y.domain([0, max_group]); rect // 1st transition .transition() .duration(duration) .delay(function(d, i) { return i * duration / n; }) .attr("x", function(d, i) { // OPTION 1: use the parent's ID to retrieve the nested group var gid = layers.indexOf(this.parentNode.__data__); // OPTION 2: browse the original dataset gid = this.parentNode.id; return x(i) + gid * (x.bandwidth() / m); }) .attr("width", x.bandwidth() / m) // 2nd transition .transition() .attr("y", function(d) { return height - (y(d[0]) - y(d[1])); }) .attr("height", function(d) { return y(d[0]) - y(d[1]); }); } function stacked() { // Adjust the Y-scale height y.domain([0, max_stack]); rect // 1st transition .transition() .duration(duration) .delay(function(d, i) { return i * duration / n; }) .attr("y", function(d) { return y(d[1]); }) .attr("height", function(d) { return y(d[0]) - y(d[1]); }) // 2nd transition .transition() .attr("x", function(d, i) { return x(i); }) .attr("width", x.bandwidth()); } // INIT with grouped mode grouped(); </script> </body>
https://d3js.org/d3.v4.min.js