index.html
<!DOCTYPE html>
<meta charset="utf-8">
<style type="text/css">
body {
font-family: 'arial', sans-serif;
font-size: 9px;
}
h1 {
font-size: 36px;
}
.barPositive {
fill: #069;
}
.barNegative {
fill: lightGray;
}
.axis path {
display: none;
}
.axis line {
stroke-width: 1px;
stroke: #ccc;
stroke-dasharray: 2px 2px;
}
.xAxis {
font-weight: bold;
}
.label {
fill: #AAA;
}
.streakLine {
stroke: #069;
stroke-width: 3px;
}
.streakLabel {
text-anchor: middle;
fill: #069;
font-weight: bold;
font-size: 15px;
}
</style>
<body>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js" charset="utf-8"></script>
<script>
var marginCore = 20;
var margin = {top: 60, right: marginCore, bottom: 20, left: marginCore};
var width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.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 + ")");
d3.tsv("jobs.tsv", function(error, data) {
if (error) throw error;
data.forEach( function (d) {
d.jobs_change = +d.jobs_change;
d.private_job_change = +d.private_job_change;
d.private_job_change = +d.private_job_change;
var s = d.month_year.split("-");
d.date = new Date(s[0], (+s[1]-1) );
});
var jobs = data.map( function (d) { return d.jobs_change; });
var months = data.map( function (d) { return d.month_year; });
var totalJobsChange = jobs.reduce( function (a, b) {
return a+b;
});
var totalJobsIncrease = jobs.reduce ( function (a, b) {
return (b > 0) ? a+b : a;
});
data.sort( function (a,b) { return a.date - b.date; });
var jobsMin = d3.min(jobs);
var jobsMax = d3.max(jobs);
var xScale = d3.scale.ordinal()
.rangeRoundBands([0, width], 0.333)
.domain(months);
var yScale = d3.scale.linear()
.range([height, 0])
.domain([jobsMin, jobsMax]);
var yAxis = d3.svg.axis()
.scale(yScale)
.tickSize(-width+35)
.tickPadding(6)
.orient("left");
svg.append("g")
.attr("class", "axis")
.call(yAxis)
.attr("transform", "translate(18,0)")
.selectAll("text")
.text( function (d) {
var changeLabel = d;
return d = (changeLabel > 0) ? "+" + d + "k" : d + "k";
});
var xAxis = d3.svg.axis()
.scale(xScale)
.tickSize(0)
.tickPadding(6)
.orient("bottom");
var bars = svg.selectAll("bars")
.data(data)
.enter()
.append("rect")
.attr('class', function (d) {
if (d.jobs_change > 0) { return 'bar barPositive'}
else { return 'bar barNegative'};
})
.attr('x', function(d) { return xScale(d.month_year); })
.attr("width", xScale.rangeBand())
.attr('y', function(d) { return yScale(Math.max(d.jobs_change, 0)); })
.attr("height", function(d) { return Math.abs(yScale(d.jobs_change) - yScale(0)); });
svg.append("line")
.attr('x1', 17)
.attr("x2", width-17)
.attr("y1", yScale(0))
.attr("y2", yScale(0))
.style("stroke", "#333")
.style("stroke-width", 1);
svg.append("g")
.attr("class", "xAxis")
.call(xAxis)
.attr("transform", "translate(0," + yScale(0) + ")")
.selectAll("g")
.attr("class", function (d) { return d })
.selectAll("text")
.text(function (d) {
var dateSplit = d.split("-");
if ( dateSplit[1] === "01" ) {
return dateSplit[0];
};
});
function formatNumber (num) {
return num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,")
};
svg.append("text")
.attr("class", "label")
.attr("transform", "translate(-10,-25)")
.style("font-size", "13px")
.text(function() {
var tJS = "+" + formatNumber(totalJobsChange) + "k";
var tJI = "+" + formatNumber(totalJobsIncrease) + "k";
return "Overall Increase in Jobs: " + tJS + " | Total Jobs Added: " + tJI;
});
svg.append("text")
.attr("class", "label")
.attr("transform", "translate(-10,-40)")
.text("Monthly Change in U.S. Nonfarm Jobs for Extent of Obama Administration");
var mnth, stopStreakMonth;
var startStreakMonth = 21;
for (mnth = startStreakMonth; mnth < data.length; mnth++) {
if (data[mnth].jobs_change < 0) {
stopStreakMonth = mnth;
mnth = data.length;
} else {
stopStreakMonth = data.length-1;
};
};
var firstStreakMonth = xScale(months[startStreakMonth]);
var lastStreakMonth = xScale(months[stopStreakMonth]);
var lengthOfStreak = stopStreakMonth - startStreakMonth;
var labelBelowZero = yScale(0)+25;
svg.append("g")
.attr("class", "streakLabel")
.attr("transform", "translate(" + xScale.rangeBand()/2 + ",0)")
.append("line")
.attr("class", "streakLine")
.attr('x1', firstStreakMonth)
.attr("x2", lastStreakMonth)
.attr("y1", labelBelowZero)
.attr("y2", labelBelowZero);
svg.select(".streakLabel")
.append("text")
.attr("x", (lastStreakMonth - firstStreakMonth)/2 + firstStreakMonth)
.attr("y", labelBelowZero+20)
.text(lengthOfStreak + " Months of Continued Jobs Growth");
});
</script>