Built with blockbuilder.org
Created
February 15, 2020 23:08
-
-
Save yi-ye-zhi-qiu/961758fbbc3b9b696f6c8714650d19cb to your computer and use it in GitHub Desktop.
fresh block
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
license: mit |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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://d3js.org/d3.v4.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"] | |
// 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 xkey = "raceethnicity" // the x axis | |
var gkey = "month" // what we group by | |
// 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 = []; | |
//Next we count how many incidents happended for each month | |
months.forEach(function(month,i) { | |
var xdata = {}; | |
groups[month].forEach(function(event) { | |
if(!xdata[event[xkey]]) { | |
xdata[event[xkey]] = 1 | |
} else { | |
xdata[event[xkey]]++; | |
} | |
}) | |
// our "result" is an ordered array with a count for each month | |
// (for the race we are currently working on) | |
var result = {}; | |
allRaces.forEach(function(g) { | |
result[g]= xdata[g]||0; | |
}) | |
processed.push(result) | |
}) | |
var n = allRaces.length, // number of layers | |
m = processed.length, // number of samples per layer | |
stack = d3.stack().keys(allRaces); | |
var layers = stack(processed); // calculate the stack layout | |
layers.forEach(function(d,i) { //adding keys to every datapoint | |
d.forEach(function(dd,j){ | |
dd.month = months[j]; | |
dd.race = allRaces[i]; | |
}) | |
}); | |
var yGroupMax = d3.max(layers, function(layer) { | |
return d3.max(layer, function(d) { | |
return d[1] - d[0]; | |
}); | |
}), | |
yStackMax = d3.max(layers, function(layer) { | |
return d3.max(layer, function(d) { | |
return d[1]; | |
}); | |
}); | |
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.scaleBand() | |
.domain(months) | |
.rangeRound([0, width]) | |
.padding(0.08); | |
var y = d3.scaleLinear() | |
.domain([0, yStackMax]) | |
.range([height, 0]); | |
var z = d3.scaleBand().domain(allRaces).rangeRound([0, x.bandwidth()]); | |
var color = d3.scaleOrdinal(d3.schemeCategory20c) | |
.domain([0, n-1]) | |
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.month); }) | |
.attr("y", height) | |
.attr("width", x.bandwidth()) | |
.attr("height", 0); | |
rect.transition() | |
.delay(function(d, i) { return i * 10; }) | |
.attr("y", function(d) { | |
return y(d[1]); | |
}) | |
.attr("height", function(d) { | |
return y(d[0]) - y(d[1]); | |
}); | |
svg.append("g") | |
.attr("class", "x axis") | |
.attr("transform", "translate(0," + height + ")") | |
.call(d3.axisBottom(x).tickSizeOuter(0)); | |
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) { | |
return x(d.month)+ z(d.race); | |
}) | |
.attr("width", x.bandwidth() / m) | |
.transition() | |
.attr("y", function(d) { | |
return y(d.data[d.race]); | |
}) | |
.attr("height", function(d) { | |
return height - y(d.data[d.race]); | |
}); | |
} | |
function transitionStacked() { | |
y.domain([0, yStackMax]); | |
rect.transition() | |
.duration(500) | |
.delay(function(d, i) { return i * 10; }) | |
.attr("y", function(d) { | |
return y(d[1]); | |
}) | |
.attr("height", function(d) { | |
return y(d[0]) - y(d[1]); | |
}) | |
.transition() | |
.attr("x", function(d) { return x(d.month); }) | |
.attr("width", x.bandwidth()); | |
} | |
}); | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment