Skip to content

Instantly share code, notes, and snippets.

@nsonnad
Created January 16, 2013 05:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nsonnad/4544985 to your computer and use it in GitHub Desktop.
Save nsonnad/4544985 to your computer and use it in GitHub Desktop.
Area + donut: History of energy use in the US
<!DOCTYPE html>
<html>
<head>
<title>US Historical Energy Consumption</title>
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
<!--<script src="http://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="http://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>
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment