D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
LGBY4
Full window
Github gist
TEST
Built with
blockbuilder.org
<!DOCTYPE html> <meta charset="utf-8"> <style> body { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; margin: auto; position: relative; width: 960px; } text { font: 10px sans-serif; } .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispEdges; } form { position: absolute; right: 10px; top: 10px; } </style> <form> <label><input type="radio" name="mode" value="grouped"> Grouped</label> <label><input type="radio" name="mode" value="stacked" checked> Stacked</label> </form> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> <script> d3.csv("police_killings.csv", function(err, data) { var allRaces = ["Black","Hispanic/Latino", "White", "Unknown", "Asian/Pacific Islander", "Native American"]; var months = ["January", "February", "March", "April", "May", "June"] console.log("original data", data) // we want to "pivot" our data into deaths by month by race // this is a rather ugly way to do it in javascript. would probably be easier // to group the data in another tool (excel, google sheets, etc) and load that var groups = {} var races = {}; var gkey = "raceethnicity" // what we group by var xkey = "month" // the x axis // first we group all the events by race data.forEach(function(d) { if(!groups[d[gkey]]) { groups[d[gkey]] = [d]; } else { groups[d[gkey]].push(d) } }) var processed = []; // we are making a "layer" for each race allRaces.forEach(function(race,i) { var xdata = {}; groups[race].forEach(function(event) { if(!xdata[event[xkey]]) { xdata[event[xkey]] = 1 } else { xdata[event[xkey]]++; } }) // our "result" is an orered array with a count for each month // (for the race we are currently working on) var result = []; months.forEach(function(g, j) { result.push({ x: g, y: xdata[g] || 0 }) }) processed.push(result) }) console.log("layer data", processed) var n = allRaces.length, // number of layers m = processed.length, // number of samples per layer stack = d3.layout.stack(); var layers = stack(processed); // calculate the stack layout var yGroupMax = d3.max(layers, function(layer) { return d3.max(layer, function(d) { return d.y; }); }) var yStackMax = d3.max(layers, function(layer) { return d3.max(layer, function(d) { return d.y0 + d.y; }); }); var margin = {top: 40, right: 10, bottom: 20, left: 10}, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; var x = d3.scale.ordinal() .domain(months) .rangeRoundBands([0, width], .08); var y = d3.scale.linear() .domain([0, yStackMax]) .range([height, 0]); var color = d3.scale.category20c() .domain([0, n-1]) var xAxis = d3.svg.axis() .scale(x) .tickSize(0) .tickPadding(6) .orient("bottom"); 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 + ")"); 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) { return x(d.x); }) .attr("y", height) .attr("width", x.rangeBand()) .attr("height", 0); rect.transition() .delay(function(d, i) { return i * 10; }) .attr("y", function(d) { return y(d.y0 + d.y); }) .attr("height", function(d) { return y(d.y0) - y(d.y0 + d.y); }); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); var legend = svg.selectAll(".legend") .data(allRaces) .enter().append("g") .attr("class", "legend") .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; }); legend.append("rect") .attr("x", width - 18) .attr("width", 18) .attr("height", 18) .style("fill", function(d,i) { return color(i) }); legend.append("text") .attr("x", width - 24) .attr("y", 9) .attr("dy", ".35em") .style("text-anchor", "end") .text(function(d) { return d; }); d3.selectAll("input").on("change", change); var timeout = setTimeout(function() { d3.select("input[value=\"grouped\"]").property("checked", true).each(change); }, 2000); function change() { clearTimeout(timeout); if (this.value === "grouped") transitionGrouped(); else transitionStacked(); } function transitionGrouped() { y.domain([0, yGroupMax]); rect.transition() .duration(500) .delay(function(d, i) { return i * 10; }) .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); }); } function transitionStacked() { y.domain([0, yStackMax]); rect.transition() .duration(500) .delay(function(d, i) { return i * 10; }) .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()); } }); </script>
https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js