block by nsonnad 4544985

Area + donut: History of energy use in the US

Full Screen

index.html

<!DOCTYPE html>
<html>
  <head>
    <title>US Historical Energy Consumption</title>
    <script type="text/javascript" src="//d3js.org/d3.v3.min.js"></script>
    <script type="text/javascript" src="//code.jquery.com/jquery-1.8.3.min.js"></script>
  <!--<script src="//code.jquery.com/jquery-1.8.3.min.js" type="text/javascript" charset="utf-8"></script>
	<script src="jquery.tipsy.js" type="text/javascript" charset="utf-8"></script>
	<link rel="stylesheet" href="//onehackoranother.com/projects/jquery/tipsy/stylesheets/tipsy.css" type="text/css" title="no title" charset="utf-8"/> -->
<style type="text/css">
body { font-size: 11px; font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; }

.axis path, line { stroke: #000; fill:none; shape-rendering: crispEdges;}

line.tick { stroke: #cccccc; opacity:.4; }

.arc path {
  stroke: #fff;
}

div#stack { width: 550px; float:left; }
div#pie { width: 350px; float:left; }
.yLabels { stroke: none; font-size: 1em; fill:#191919; }
.donutLabels { font-size:12px; font-weight: bold; stroke: none; fill:white; }
.underlay { visibility: hidden; pointer-events:all; }
.underlay rect { fill:gray; opacity:.3; }
.tooltip { position:absoulte; }
</style>
</head>
<body>
<div id="stack">
</div>
<div id="pie">
</div>

<script type="text/javascript">
// global variables
var margin = {t:20, r:20, b:20, l:30 },
		w1 = 550 - margin.l - margin.r,
		w2 = 300 - margin.r,
		h = 350 - margin.t - margin.b,
		x = d3.time.scale().range([0, w1]).clamp(true),
		y = d3.scale.linear().range([h, 0]).domain([0, 110]),
		color = d3.scale.ordinal().range(["#37A36A", "#3A5A64", "#DABD49", "#C78739", "#8AB8D9", "#A81F5E"]),
		formatTime = d3.time.format("%Y").parse;

var	dataChange,
		latest,
		data;

// settings for stacked area chart
var stacked = d3.select("#stack").append("svg")
		.attr("width", w1 + margin.l + margin.r)
		.attr("height", h + margin.t + margin.b)
  .append("g")
    .attr("class", "stackWrapper")
		.attr("transform", "translate(" + margin.l + "," + margin.t + ")");

var xAxis = d3.svg.axis()
		.scale(x)
		.tickSubdivide(true)
		.orient("bottom");
	stacked.append("g")
	.attr("class", "x axis")
	.attr("transform", "translate(0," + h + ")")

var yAxis = d3.svg.axis()
		.scale(y)
		.tickSubdivide(true)
		.tickSize(-w1, 0, 0)
		.orient("left");

var stack = d3.layout.stack()
		.values(function(d) { return d.values; });

var area = d3.svg.area().interpolate("cardinal")
		.x(function(d) { return x(d.year); })
		.y0(function(d) { return y(d.y0); })
		.y1(function(d) { return y(d.y + d.y0); })

stacked.append("g")
		.attr("class", "y axis")
		.call(yAxis);

// settings for donut chart		
var radius = Math.min((w2), h) / 2,
		labelRadius = radius - 20;

var krispy = d3.select("#pie").append("svg")
		.attr("width", w2 + margin.r + margin.l)
		.attr("height", h + margin.t + margin.b)
  .append("g")
		.attr("transform", "translate(150," + (h/2 + margin.t) + ")");

var arc = d3.svg.arc()
		.outerRadius(radius - 15)
		.innerRadius(radius - 55);

var pie = d3.layout.pie()
		.sort(null)
		.value(function(d) { return d.values; });

// bring in the data
d3.csv("us-historical-energy.csv", function(csv) {	
	// data variable that will be used throughout
	data = csv;

	// format dates
	data.forEach(function(d) { 
		d.Year = formatTime(d.Year);
	});

	// function for adding data points one at a time
	var latest = 1;

	function update() {
		// create array that will update with each new data point
		dataChange = data.slice(0, latest)
		latest++;
		if (latest < csv.length) {
		// redraw function draws the meat of the charts
		redraw();			
		};
	};
	// update data every 500ms
	var interval = setInterval(update, 500);

	// create list energy sources to be used as keys
	color.domain(d3.keys(data[0]).filter(function(key) { return key !== "Year" && key !== "sourcesPie"; }))

	// create legend
	var legend = stacked.append("g")
				.attr("class", "legendBox")

	var legends = legend.selectAll(".legend")
			.data(color.domain())
		.enter().append("g")
			.attr("class", "legend")
			.attr("transform", function(d, i) { return "translate(10," + (5 + (i * 20)) + ")"; });

		legends.append("rect")
			.attr("width", 15)
			.attr("height", 15)
			.style("fill", color)

		legends.append("text")
			.attr("x", 20)
			.attr("y", 8)
			.attr("dy", ".35em")
			.text(function(d) { return d; });

// draw the charts			
function redraw() {

// map vales to d3.layout.stack() for the area chart
var sourcesStack = stack(color.domain().map(function(name) {
  return {
	name: name,
	values: data.map(function(d) { 
	  return { year: d.Year, y: +d[name] };
	  })
  };
}));

// set x domain to extend to the most recently added data point
x.domain([d3.min(dataChange, function(d) { 
		return d.Year; }),
	d3.max(dataChange, function(d) { 
		return d.Year; })]);

// set data for energy sources stacked areas
var stacks = stacked.selectAll(".sources")
	.data(sourcesStack);


// call enter() for stacked areas
var stacksEnter = stacks.enter().append("g")
    .attr("class", "sources");

// draw paths and areas
stacksEnter.append("path")
	.attr("class", "area")
	.attr("d", function(d) { return area(d.values); })
	.style("fill", function(d) { return color(d.name); });

// update and transition area values
var stacksUpdate = d3.transition(stacks)

stacksUpdate.transition().select("path").duration(500)
	.attr("d", function(d) { return area(d.values); });

// update x axis
d3.selectAll(".x.axis").transition(stacked).duration(500).call(xAxis)

// create rect underlays that will be used for mouseovers
var underlay = stacks.selectAll(".underlay").data(data),
		underlayWidth = w1/dataChange.length;

// enter() underlay g and append rects
var underlayEnter = underlay.enter().append("g")
	.attr("class", "underlay");

underlayEnter.append("rect")
	.attr("x", function(d, i) { return x(d.Year); })
	.attr("width", underlayWidth)
	.attr("y", 0)
	.attr("height", h);

// update and move underlays; reduce width to svgwidth/data.length
var underlayUpdate = d3.transition(underlay);

underlayUpdate.transition().selectAll("rect").duration(500)
	.attr("x", function(d, i) { return x(d.Year); })
	.attr("width", underlayWidth);

// what to do when we mouse on or off a rect
underlay.on("mouseover", rectOn)
underlay.on("mouseout", rectOff)

// now for the donut
// map values to color.domain key
data.forEach(function(d) {
  d.sourcesPie = color.domain().map(function(name) {
    return {name: name, values: +d[name]};
  });
});

// set data for the donut
var donut = krispy.selectAll(".arc")
	.data(pie(dataChange[dataChange.length - 1].sourcesPie))

// enter() the donut "g"
var donutEnter = donut.enter().append("g")
	.attr("class", "arc")

// things we will use to compute percentages
var total = d3.sum(dataChange[dataChange.length - 1].sourcesPie, function(d) { return d.values; })
var formatPercent = d3.format("%")

// draw donut arcs
donutEnter.append("path")
	.attr("class", "donutPath")
	.attr("d", arc)
	.each(function(d) { this._current = d; })
	.style("fill", function(d) { return color(d.data.name); })

// draw percentage labels inside arcs	
donutEnter.append("text")
	.attr("class", "donutLabels")
	.attr("transform", function(d) {
		return "translate(" + arc.centroid(d) + ")rotate(" + angle(d) + ")"; })
	.attr("dy", ".35em")
	.attr("text-anchor", "middle")
	.style("fill-opacity", function(d) {return d.value==0 ? 1e-6 : 1;})
	.text(function(d) { 
		return formatPercent(d.data.values/total) });

// angle function used for rotating labels		
function angle(d) {
  var a = (d.startAngle + d.endAngle) * 90 / Math.PI - 90;
  return a > 90 ? a - 180 : a;
  }

// update and transition arcs and labels	
var donutUpdate = d3.transition(donut);

donutUpdate.transition().select("text").duration(500)
	.attr("transform", function(d) {
    return "translate(" + arc.centroid(d) + ")rotate(" + angle(d) + ")"; }) 
	.style("fill-opacity", function(d) {return d.value==0 ? 1e-6 : 1;})
	.text(function(d) {
		return formatPercent(d.data.values/total) });

donutUpdate.transition().select("path").duration(500)
	.attrTween("d", arcTween)

function arcTween(a) {
  var i = d3.interpolate(this._current, a);
  this._current = i(0);
		return function(t) {
		return arc(i(t));
		 };
	}
};

// helper functions

// what happens when we go on or off of a rect
var rectOn = function() {
	var hoverRect = d3.select(this)
	hoverRect.style("visibility", "visible")
	}

var rectOff = function() {
	var hoverRect = d3.select(this)
	hoverRect.style("visibility", "hidden")
	}

// stop animation when we roll over stacked area, restart when leaving
$('#stack').hover(function() {
		clearInterval(interval);
		},
		function() {
		 interval = setInterval(update, 500);
		});

	});

</script>
</body>
</html>

us-historical-energy.csv

Year,Biomass,Coal,Petroleum,Natural Gas,Captured Energy,Nuclear
1775,0.249,0,0,0,0,0
1785,0.31,0,0,0,0,0
1795,0.402,0,0,0,0,0
1805,0.537,0,0,0,0,0
1815,0.714,0,0,0,0,0
1825,0.96,0,0,0,0,0
1835,1.305,0,0,0,0,0
1845,1.757,0,0,0,0,0
1850,2.138,0.219,0,0,0,0
1855,2.389,0.421,0,0,0,0
1860,2.641,0.518,0.003,0,0,0
1865,2.767,0.632,0.01,0,0,0
1870,2.893,1.048,0.011,0,0,0
1875,2.872,1.44,0.011,0,0,0
1880,2.851,2.054,0.096,0,0,0
1885,2.683,2.84,0.04,0.082,0,0
1890,2.515,4.062,0.156,0.257,0.022,0
1895,2.306,4.95,0.168,0.147,0.09,0
1900,2.015,6.841,0.229,0.252,0.25,0
1905,1.843,10.001,0.61,0.372,0.386,0
1910,1.765,12.714,1.007,0.54,0.539,0
1915,1.688,13.294,1.418,0.673,0.659,0
1920,1.61,15.504,2.676,0.813,0.738,0
1925,1.533,14.706,4.28,1.191,0.668,0
1930,1.455,13.639,5.897,1.932,0.752,0
1935,1.397,10.634,5.675,1.919,0.806,0
1940,1.358,12.535,7.76,2.665,0.88,0
1945,1.261,15.972,10.11,3.871,1.442,0
1949,1.549262,11.980905,11.882722,5.145142,1.424722,0
1950,1.562307,12.347109,13.315484,5.968371,1.415411,0
1951,1.534669,12.552996,14.428043,7.048518,1.423795,0
1952,1.474369,11.306479,14.955682,7.549621,1.465812,0
1953,1.418601,11.372684,15.555829,7.906645,1.412859,0
1954,1.394327,9.714667,15.839176,8.330202,1.359772,0
1955,1.424143,11.167259,17.254955,8.997935,1.359844,0
1956,1.415871,11.349723,17.937473,9.613975,1.434711,0
1957,1.333581,10.820631,17.931667,10.190753,1.515613,0.000112
1958,1.323123,9.533287,18.526937,10.663199,1.591967,0.001915
1959,1.352874,9.518353,19.32265,11.717422,1.548465,0.002187
1960,1.31987,9.837785,19.91923,12.385366,1.608334,0.006026
1961,1.294762,9.623351,20.216387,12.926392,1.657464,0.019678
1962,1.300242,9.906454,21.048981,13.730841,1.817202,0.026394
1963,1.323316,10.412538,21.700828,14.403306,1.773115,0.038147
1964,1.336802,10.964385,22.301257,15.28785,1.888446,0.039819
1965,1.334761,11.580608,23.24568,15.768667,2.061055,0.043164
1966,1.368985,12.14308,24.400523,16.995332,2.063477,0.064158
1967,1.340249,11.91375,25.283661,17.944788,2.349964,0.088456
1968,1.419495,12.330677,26.979447,19.209656,2.353161,0.141534
1969,1.440487,12.38154,28.338336,20.677984,2.654405,0.153722
1970,1.430962,12.264528,29.520695,21.794707,2.639059,0.239347
1971,1.432323,11.598411,30.56129,22.469052,2.82989,0.412939
1972,1.503065,12.076917,32.946738,22.69819,2.878944,0.583752
1973,1.529068,12.97149,34.837435,22.512399,2.88187,0.910177
1974,1.539657,12.662878,33.45366,21.732488,3.20219,1.272083
1975,1.498734,12.662786,32.732323,19.947883,3.188386,1.899798
1976,1.713373,13.584067,35.177782,20.345426,3.013778,2.111121
1977,1.838332,13.922103,37.12398,19.930513,2.370634,2.701762
1978,2.037605,13.765575,37.962821,20.0004,2.967834,3.024126
1979,2.151906,15.039586,37.122274,20.665817,2.970948,2.775827
1980,2.4755,15.422809,34.20452,20.235459,2.952843,2.739169
1981,2.596283,15.907526,31.932206,19.747309,2.817406,3.007589
1982,2.663452,15.321581,30.232226,18.356222,3.316185,3.131148
1983,2.904414,15.894442,30.052216,17.220836,3.591198,3.202549
1984,2.971119,17.070622,31.053237,18.393613,3.466744,3.552531
1985,3.016233,17.478428,30.924732,17.703482,3.067784,4.075563
1986,2.932094,17.260405,32.19826,16.591364,3.179046,4.380109
1987,2.874884,18.008451,32.863733,17.639801,2.746923,4.753933
1988,3.016049,18.846312,34.222795,18.448393,2.440706,5.586968
1989,3.159358,19.069762,34.209296,19.601689,3.075876,5.602161
1990,2.73511,19.172635,33.551623,19.603168,3.305565,6.10435
1991,2.781798,18.99167,32.846032,20.032957,3.286719,6.422132
1992,2.931678,19.122471,33.524957,20.713632,2.889674,6.479206
1993,2.908172,19.835148,33.744546,21.228902,3.174333,6.410499
1994,3.027535,19.909463,34.560541,21.728065,2.960583,6.693877
1995,3.101142,20.088727,34.43837,22.671138,3.459341,7.075436
1996,3.156806,21.001914,35.67535,23.084647,3.856872,7.086674
1997,3.10522,21.445411,36.158897,23.222717,3.910322,6.596992
1998,2.927489,21.655744,36.815915,22.830226,3.565409,7.067809
1999,2.963291,21.622544,37.837705,22.909227,3.552327,7.610256
2000,3.008228,22.579528,38.261705,23.823978,3.098124,7.862349
2001,2.622347,21.914268,38.18551,22.772558,2.540203,8.028853
2002,2.700598,21.903989,38.224147,23.510081,3.028521,8.145429
2003,2.807132,22.320928,38.811443,22.830642,3.176232,7.958858
2004,3.009666,22.466195,40.29178,22.923061,3.072751,8.221985
2005,3.116765,22.796543,40.388116,22.565364,3.125178,8.16081
2006,3.266757,22.44716,39.955351,22.238738,3.382414,8.215414
2007,3.474262,22.749466,39.773964,23.662759,3.048323,8.455364
2008,3.848548,22.385196,37.279917,23.842954,3.337857,8.427297
2009,3.9117,19.692203,35.403266,23.41594,3.687903,8.356019
2010,4.294066,20.84952,36.009541,24.256183,3.795848,8.434433
2011,4.411164,19.643039,35.282604,24.842548,4.724236,8.259432