block by kcsluis 875d1b1a48b737567388

Jobs Growth Under Obama

Full Screen

index.html

<!DOCTYPE html>
<meta charset="utf-8">

<style type="text/css">
	/*svg {*/
	/*	border: 1px solid #f0f;*/
	/*}*/
	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>

	// additional data sourced from
	// //data.bls.gov/timeseries/CES0000000001?output_view=net_1mth

	// okay to keep these global
	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 is an object, but now we need arrays
		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) );

		});

		// use map to strip out jobs_change
		var jobs = data.map( function (d) { return d.jobs_change; });
		var months = data.map( function (d) { return d.month_year; });
		// reduce, anyone?
		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; });
		
		// console.log(data);
		// console.log(jobs);
		// console.log(months);

		var jobsMin = d3.min(jobs);
		var jobsMax = d3.max(jobs);

		// console.log(jobsMin, jobsMax);

		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");

    	// could use some pointers about abstracting out this function / variable access
    	// kFormat = function (number) {
    	// 	return (number > 0) ? "+" + d + "k" : d + "k";
    	// };
    	// var changeLabel;
    	// function kFormat(number) {
    	// 	return (number > 0) ? "+" + d + "k" : d + "k";
    	// };

    	// adding yAxis up so it draws below bars
    	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";
			});
			// .text( function	(d) { 
			// 	console.log(d);
			// 	var changeLabel = d;
			// 	return kFormat(changeLabel);
			// });

		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())
			// this returns the higher of either d.jobs_change (so, positive numbers) or 0
			.attr('y', function(d) { return yScale(Math.max(d.jobs_change, 0)); })
			// this returns height as absolute value of change minus scaled value of 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")
			// yadda yadda yadda, use if then to add custom classes
			.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,")
		};

		// labels
 		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");

 		// streak label
 		// draw a line from october 2010 to last positive month
 		// then below and centered
 		// add a label that counts number of positive months

 		var mnth, stopStreakMonth;
 		var startStreakMonth = 21;
 		// there's probably a more elegant way to do this
		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>

jobs.tsv

month_year	jobs_change	private_job_change	unemployment_rate
2009-01	-818	-839	7.8
2009-02	-724	-725	8.3
2009-03	-799	-787	8.7
2009-04	-692	-802	8.9
2009-05	-361	-312	9.4
2009-06	-482	-426	9.5
2009-07	-339	-296	9.5
2009-08	-231	-219	9.6
2009-09	-199	-184	9.8
2009-10	-202	-232	10
2009-11	-42	-42	9.9
2009-12	-171	-120	9.9
2010-01	-40	-40	9.7
2010-02	-35	-27	9.8
2010-03	189	141	9.8
2010-04	239	193	9.9
2010-05	516	84	9.6
2010-06	-167	92	9.4
2010-07	-58	92	9.5
2010-08	-51	128	9.6
2010-09	-27	115	9.5
2010-10	220	196	9.5
2010-11	121	134	9.8
2010-12	120	140	9.4
2011-01	110	119	9.1
2011-02	220	257	9
2011-03	246	261	8.9
2011-04	251	264	9
2011-05	54	108	9
2011-06	84	102	9.1
2011-07	96	175	9.1
2011-08	85	52	9.1
2011-09	202	216	9
2011-10	112	139	8.9
2011-11	157	178	8.7
2011-12	223	234	8.5
2012-01	275	277	8.3
2012-02	259	254	8.3
2012-03	143	147	8.2
2012-04	68	85	8.1
2012-05	87	116	8.2
2012-06	45	63	8.2
2012-07	181	163	8.3
2012-08	142	97	8.1
2012-09	114	104	7.8
2012-10	213	0	0
2012-11	164	0	0
2012-12	293	0	0
2013-01	205	0	0
2013-02	314	0	0
2013-03	115	0	0
2013-04	187	0	0
2013-05	219	0	0
2013-06	127	0	0
2013-07	164	0	0
2013-08	256	0	0
2013-09	150	0	0
2013-10	225	0	0
2013-11	317	0	0
2013-12	109	0	0
2014-01	166	0	0
2014-02	188	0	0
2014-03	225	0	0
2014-04	330	0	0
2014-05	236	0	0
2014-06	286	0	0
2014-07	249	0	0
2014-08	213	0	0
2014-09	250	0	0
2014-10	221	0	0
2014-11	423	0	0
2014-12	329	0	0
2015-01	201	0	0
2015-02	266	0	0
2015-03	119	0	0
2015-04	187	0	0
2015-05	254	0	0
2015-06	223	0	0