Created
July 28, 2017 23:40
-
-
Save pjsier/299c16ccd8e5c2108e829c6667001fd2 to your computer and use it in GitHub Desktop.
Slopegraph
This file contains 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 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> | |
<html> | |
<head> | |
<title>Slopegraph</title> | |
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" /> | |
<meta charset='utf-8' /> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<script src="//d3js.org/d3-scale-chromatic.v0.3.min.js"></script> | |
<style> | |
div { | |
max-width: 600px; | |
} | |
#chart { | |
display: block; | |
width: 100%; | |
height: 500px; | |
} | |
text { | |
font-family: Verdana, sans-serif; | |
font-size: 11px; | |
} | |
.line { | |
fill: none; | |
stroke-width: 2; | |
stroke-opacity: 0.7; | |
} | |
.overlay { | |
fill: none; | |
pointer-events: all; | |
} | |
.mouse-tooltip { | |
font-weight: bold; | |
text-anchor: middle; | |
} | |
</style> | |
</head> | |
<body> | |
<div> | |
<svg id="chart"></svg> | |
</div> | |
<script src="script.js"></script> | |
</body> | |
</html> |
This file contains 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
// Margin convention from https://bl.ocks.org/mbostock/3019563 | |
var margin = {top: 30, right: 25, bottom: 50, left: 25}; | |
var width = parseInt(d3.select("#chart").style("width")) - margin.left - margin.right; | |
var height = parseInt(d3.select("#chart").style("height")) - margin.top - margin.bottom; | |
var svg = d3.select("#chart") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom) | |
.append("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
var slopeData = [ | |
{demographic: "Black Men 20-29", count250: 33810, count300: 27030, count350: 3983}, | |
{demographic: "Black Women 20-29", count250: 11631, count300: 8730, count350: 490}, | |
{demographic: "Hispanic Men 20-29", count250: 15565, count300: 10940, count350: 792}, | |
{demographic: "Hispanic Women 20-29", count250: 3198, count300: 2269, count350: 72}, | |
{demographic: "White Men 20-29", count250: 5185, count300: 3504, count350: 118}, | |
{demographic: "White Women 20-29", count250: 1777, count300: 1204, count350: 21} | |
]; | |
var padding = 10; | |
var y = d3.scaleLinear() | |
.domain([21, 33810]) | |
.rangeRound([height, 0]); | |
var z = d3.scaleOrdinal(d3.schemePaired); | |
var RACE_SEX_GROUPS = [ | |
"Black Men 20-29", "Black Women 20-29", "Hispanic Men 20-29", | |
"Hispanic Women 20-29", "White Men 20-29", "White Women 20-29" | |
]; | |
z.domain(RACE_SEX_GROUPS); | |
// For handling indices later on | |
var sorted300 = slopeData.sort(function(a, b) { return b.count300 - a.count300 }).map(function(d) { return d.demographic; }); | |
var sorted350 = slopeData.sort(function(a, b) { return b.count350 - a.count350 }).map(function(d) { return d.demographic; }); | |
function resize() { | |
width = parseInt(d3.select("#chart").style("width")) - margin.left - margin.right, | |
height = parseInt(d3.select("#chart").style("height")) - margin.top - margin.bottom; | |
y.rangeRound([height, 0]); | |
svg.selectAll("text.end-vals") | |
.attr("x", width-100); | |
svg.selectAll("line") | |
.attr("x2", width-100-padding); | |
}; | |
(function() { | |
// Create markers to use on lines later | |
var defs = d3.select("#chart").append("defs"); | |
defs.selectAll("marker") | |
.data(RACE_SEX_GROUPS) | |
.enter().append("marker") | |
.attr("id", function(d) { return "marker_" + d.replace(/ /g, "_"); }) | |
.attr("markerWidth", 10) | |
.attr("markerHeight", 10) | |
.attr("refX", 5) | |
.attr("refY", 5) | |
.append("circle") | |
.attr("cx", 5) | |
.attr("cy", 5) | |
.attr("r", 1.5) | |
.attr("fill", function(d) { return z(d); }); | |
var labelVals = svg.append("g") | |
.attr("class", "labels") | |
.selectAll("text") | |
.data(slopeData) | |
.enter(); | |
labelVals.append("text") | |
.attr("class", "start-vals") | |
.attr("text-anchor", "end") | |
.attr("alignment-baseline", "central") | |
.attr("x", 100) | |
.attr("y", function(d) { return y(d.count250);}) | |
.text(function(d) { return d.demographic.substring(0,d.demographic.length-6)+ " " + d3.format(".2s")(d.count250); }); | |
labelVals.append("text") | |
.attr("class", "end-vals") | |
.attr("text-anchor", "start") | |
.attr("alignment-baseline", "central") | |
.attr("x", width-100) | |
.attr("y", function(d) { | |
// For handling collisions in >= 350 | |
if (d.count350 <= 500) { | |
return y(500)+(sorted350.indexOf(d.demographic)*12)-15; | |
} | |
return y(d.count350); | |
}) | |
.text(function(d) { return d.demographic.substring(0,d.demographic.length-6) + " " + d3.format(".2s")(d.count350); }); | |
svg.select("g.labels") | |
.append("text") | |
.attr("class", "start-top") | |
.attr("text-anchor", "end") | |
.attr("x", 100) | |
.attr("y", -15) | |
.attr("font-weight", "bold") | |
.text("# Scores >= 250"); | |
svg.select("g.labels") | |
.append("text") | |
.attr("class", "end-top end-vals") | |
.attr("text-anchor", "start") | |
.attr("x", width-100) | |
.attr("y", -15) | |
.attr("font-weight", "bold") | |
.text("# Scores >= 350"); | |
svg.append("g") | |
.attr("class", "lines") | |
.selectAll("line") | |
.data(slopeData) | |
.enter() | |
.append("line") | |
.attr("x1", 100+padding) | |
.attr("x2", width-100-padding) | |
.attr("y1", function(d) { return y(d.count250); }) | |
.attr("y2", function(d) { return y(d.count350); }) | |
.attr("marker-start", function(d) { return "url(#marker_" + d.demographic.replace(/ /g, "_") + ")"}) | |
.attr("marker-end", function(d) { return "url(#marker_" + d.demographic.replace(/ /g, "_") + ")"}) | |
.style("stroke-width", "2") | |
.style("stroke-linecap", "round") | |
.style("stroke", function(d) { return z(d.demographic); }); | |
d3.select(window).on("resize", resize); | |
resize(); | |
})() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment