Skip to content

Instantly share code, notes, and snippets.

@whitews
Last active December 16, 2015 07:09
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 whitews/5396879 to your computer and use it in GitHub Desktop.
Save whitews/5396879 to your computer and use it in GitHub Desktop.
US Government Spending

A plot of US government spending over time with an animate pie chart showing the annual percentage breakdown by spending category.

Year NationalDefense EduTrainEmploySocial Health Medicare IncomeSecurity SocialSecurity Veterans Interest Other
1940 1660 1972 55 0 1514 28 570 899 2770
1941 6435 1592 60 0 1855 91 560 943 2117
1942 25658 1062 71 0 1828 137 501 1052 4828
1943 66699 375 92 0 1739 177 276 1529 7668
1944 79143 160 174 0 1503 217 -126 2219 8014
1945 82965 134 211 0 1137 267 110 3112 4776
1946 42681 85 201 0 2384 358 2465 4111 2947
1947 12808 102 177 0 2820 466 6344 4204 7575
1948 9105 191 162 0 2499 558 6457 4341 6451
1949 13150 178 197 0 3174 657 6599 4523 10357
1950 13724 241 268 0 4097 781 8834 4812 9805
1951 23566 235 323 0 3352 1565 5526 4665 6282
1952 46089 339 347 0 3655 2063 5341 4701 5151
1953 52802 441 336 0 3823 2717 4519 5156 6307
1954 49266 370 307 0 4434 3352 4613 4811 3702
1955 42729 445 291 0 5071 4427 4675 4850 5956
1956 42523 591 359 0 4734 5478 4891 5079 6985
1957 45430 590 479 0 5427 6661 5005 5354 7632
1958 46815 643 541 0 7535 8219 5350 5604 7698
1959 49015 789 685 0 8239 9737 5443 5762 12428
1960 48130 968 795 0 7378 11602 5441 6947 10930
1961 49601 1063 913 0 9683 12474 5705 6716 11568
1962 52345 1241 1198 0 9207 14365 5619 6889 15957
1963 53400 1458 1451 0 9311 15788 5514 7740 16654
1964 54757 1555 1788 0 9657 16620 5675 8199 20277
1965 50620 2140 1791 0 9469 17460 5716 8591 22441
1966 58111 4363 2543 64 9678 20694 5916 9386 23777
1967 71417 6453 3351 2748 10261 21725 6735 10268 24506
1968 81926 7634 4390 4649 11816 23854 7032 11090 25743
1969 82497 7548 5162 5695 13076 27298 7631 12699 22034
1970 81692 8634 5907 6213 15655 30270 8669 14380 24229
1971 78872 9849 6843 6622 22946 35872 9768 14841 24559
1972 79174 12529 8674 7479 27650 40157 10720 15478 28820
1973 76681 12745 9356 8052 28276 49090 12003 17349 32155
1974 79347 12457 10733 9639 33713 55867 13374 21449 32780
1975 86509 16022 12930 12875 50176 64658 16584 23244 49334
1976 89619 18910 15734 15834 60799 73899 18419 26727 51851
1977 97241 21104 17302 19345 61060 85061 18022 29901 60182
1978 104495 26710 18524 22768 61505 93861 18961 35458 76464
1979 116342 30223 20494 26495 66376 104073 19914 42633 77478
1980 133995 31843 23169 32090 86557 118547 21169 52533 91038
1981 157513 33152 26866 39149 100299 139584 22973 68766 89939
1982 185309 26612 27445 46567 108155 155964 23938 85032 86721
1983 209903 26197 28641 52588 123031 170724 24824 89808 82648
1984 227411 26920 30417 57540 113352 178223 25575 111102 81265
1985 252743 28592 33541 65822 128979 188623 26251 129478 92315
1986 273373 29776 35933 70164 120633 198757 26314 136017 99415
1987 281996 28921 39964 75120 124088 207352 26729 138611 81236
1988 290360 30931 44483 78878 130377 219341 29367 151803 88876
1989 303555 35328 48380 84964 137426 232542 30003 168981 102565
1990 299321 37171 57699 98102 148668 248623 29034 184347 150028
1991 273285 41235 71168 104489 172462 269015 31275 194448 166849
1992 298346 42741 89486 119024 199562 287584 34037 199344 111405
1993 291084 47380 99401 130552 209969 304585 35642 198713 92060
1994 281640 43286 107107 144747 217166 319565 37559 202932 107751
1995 272063 51027 115399 159855 223799 335846 37862 232134 87757
1996 265748 48321 119365 174225 229736 349671 36956 241053 95409
1997 270502 48975 123832 190016 235032 365251 39283 243984 84241
1998 268194 50512 131425 192822 237750 379215 41741 241118 109681
1999 274769 50605 141048 190447 242478 390037 43155 229755 139548
2000 294363 53764 154504 197113 253724 409423 46989 222949 156121
2001 304732 57094 172233 217384 269774 432958 44974 206167 157530
2002 348456 70566 196497 230855 312720 455980 50929 170949 173942
2003 404744 82587 219541 249433 334632 474680 56984 153073 184225
2004 455833 87974 240122 269360 333059 495548 59746 160245 190954
2005 495308 97555 250548 298638 345847 523305 70120 183986 206650
2006 521827 118482 252739 329868 352477 548549 69811 226603 234694
2007 551271 91656 266382 375407 365975 586153 72818 237109 181915
2008 616073 91287 280599 390758 431313 617027 84653 252757 218077
2009 661049 79749 334335 430093 533224 682963 95429 186902 513933
2010 693586 127710 369054 451636 622210 706737 108384 196194 180702
2011 705625 101233 372500 485653 597352 730811 127189 229968 252730
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>US Government Spending</title>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript">
window.onload = function() {
var width = 960;
var height = 500;
var marginHorz = 75;
var marginVert = 25;
var opacity = 1.0;
var radius = 4.5;
var stroke = 1.0;
var strokeColor = "#333";
var outerRadius = 140;
var innerRadius = 60;
var textOffset = 14;
var tweenDuration = 1000;
var dataDuration = 1500;
var updateInterval = window.setInterval(update, dataDuration);
var startYear = 1940;
var endYear = 2011;
var currentYear = startYear;
var startAmount = 0;
var endAmount = 750000;
// Stuff to be populated later
var paths;
var lines;
var valueLabels;
var pieChart = [];
var oldData = []; // for saving the previous angles for tweening
var spendingData;
var category = [];
var categoryLabels;
var categoryColor = [];
var yearData;
var yearTotalAmount;
/////////////////////
// PLACEMENT STUFF //
/////////////////////
var svg = d3.select("#graph").append("svg:svg")
.attr("width", width)
.attr("height", height);
// Pie Chart
var pie = svg.append("svg:g")
.attr("class", "pie")
.attr("transform", "translate(320, 240)");
// Group together all the pie chart arcs & paths
var arc_group = pie.append("svg:g")
.attr("class", "arc");
// Group our pie chart labels
var label_group = pie.append("svg:g")
.attr("class", "label_group");
// Group our pie chart center label stuff
var center_group = pie.append("svg:g")
.attr("class", "center_group");
var totalLabel = center_group.append("svg:text")
.attr("class", "label")
.attr("dy", -21)
.attr("text-anchor", "middle") // text-align: right
.text("TOTAL");
var totalAmountLabel = center_group.append("svg:text")
.attr("class", "total")
.attr("dy", 12)
.attr("text-anchor", "middle") // text-align: right
.text("Loading...");
var totalUnits = center_group.append("svg:text")
.attr("class", "units")
.attr("dy", 32)
.attr("text-anchor", "middle") // text-align: right
.text("billion");
// Current Year Label
var currentYearLabel = center_group.append("svg:text")
.attr("class", "year")
.attr("dx", 300)
.attr("dy", -100)
.attr("text-anchor", "right") // text-align: right
// Plot axes
var x = d3.scale.linear()
.domain([startYear, endYear])
.range([marginHorz, width-marginVert]);
var y = d3.scale.linear()
.domain([startAmount, endAmount])
.range([height-marginVert, marginVert]);
// X-axis
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (height - marginVert) + ")")
.call(xAxis);
// Y-axis
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + marginHorz + ",0)")
.call(yAxis);
///////////////
// LOAD DATA //
///////////////
d3.csv("govt_spending.csv", function(csv) {
spendingData = csv;
for (var key in spendingData[0]) {
if (spendingData[0].hasOwnProperty(key)) {
category.push(key);
}
}
categoryColor = d3.scale.category10().domain(category);
for (var cat in category) {
if (category[cat] == "Year" || category[cat] === undefined) {
continue;
}
// Plot the data on the graph
svg.selectAll(category[cat]).data(spendingData).enter()
.append("circle")
.attr("cx", function(d) { return x(+d.Year); })
.attr("cy", function(d) { return y(+d[category[cat]]); })
.attr("r", radius)
.style("fill", categoryColor(category[cat]))
.style("opacity", opacity)
.style("stroke", strokeColor)
.style("stroke-width", stroke)
.append("title")
.text(function(d) { return category[cat] + ": " + d[category[cat]] });
}
});
///////////////
// FUNCTIONS //
///////////////
// D3 helper function to draw arcs, populates parameter "d" in path object
var arc = d3.svg.arc()
.startAngle(function(d){ return d.startAngle; })
.endAngle(function(d){ return d.endAngle; })
.innerRadius(innerRadius)
.outerRadius(outerRadius);
// Pull out data for one year as an array...spendingData is an array of objects
function getDataForYear(year) {
var yearData = [];
var object;
for (var i = 0; i < spendingData.length; i++) {
if (spendingData[i].Year === year.toString()) {
for (var c in category.sort()) {
if (spendingData[i].hasOwnProperty(category[c]) && category[c] !== "Year") {
object = new Object();
object.category = category[c];
object.amount = spendingData[i][category[c]];
yearData.push(object);
}
}
}
}
return yearData;
}
// Update the pie chart
function update() {
if (currentYear > endYear) {
currentYear = startYear;
}
yearData = getDataForYear(currentYear);
yearTotalAmount = 0;
// Save the old paths so we can get the old angles for the tween animations
if (paths !== undefined) {
oldData = paths.data();
}
// Associate our data with the arc and label groups
arc_group.data([yearData]);
label_group.data([yearData]);
// Create pie skeleton, must provide function for getting values
pieChart = d3.layout.pie()
.value(function(d) { return d.amount })
.sort(null);
// Tally up the total amount & show it
yearData.forEach(function (y) {
yearTotalAmount += parseInt(y.amount, 10);
});
totalAmountLabel.text(function() {
var billions = yearTotalAmount/1000;
return "$" + billions.toFixed(1);
});
// Show the current year used for the pie graph
currentYearLabel.text(currentYear);
// Draw arc paths
paths = arc_group.selectAll("path").data(pieChart); // introduce our pie to the data
paths.enter().append("svg:path")
.attr("stroke", "white")
.attr("stroke-width", 0.5)
.attr("fill", function(d, i) {
return categoryColor(category[i]);
})
.transition()
.duration(tweenDuration)
.attrTween("d", pieTween);
paths.transition()
.duration(tweenDuration)
.attrTween("d", pieTween);
paths.exit()
.transition()
.duration(tweenDuration)
.attrTween("d", removePieTween)
.remove();
// Draw tick marks for the pie graph labels
lines = label_group.selectAll("line").data(pieChart); // introduce our pie to the data
lines.enter().append("svg:line")
.attr("x1", 0)
.attr("x2", 0)
.attr("y1", -outerRadius-1)
.attr("y2", -outerRadius-8)
.attr("stroke", "gray")
.attr("transform", function(d) {
return "rotate(" + (d.startAngle+d.endAngle)/2 * (180/Math.PI) + ")";
});
lines.transition()
.duration(tweenDuration)
.attr("transform", function(d) {
return "rotate(" + (d.startAngle+d.endAngle)/2 * (180/Math.PI) + ")";
});
lines.exit().remove();
// Draw labels for percentage values
valueLabels = label_group.selectAll("text.value").data(pieChart) // introduce our pie to the data
.attr("dy", function(d) {
if ((d.startAngle+d.endAngle)/2 > Math.PI/2 && (d.startAngle+d.endAngle)/2 < Math.PI*1.5 ) {
return 5;
}
else {
return -7;
}
})
.attr("text-anchor", function(d) {
if ( (d.startAngle+d.endAngle)/2 < Math.PI ) {
return "beginning";
} else {
return "end";
}
})
.text(function(d) {
var percentage = (d.value/yearTotalAmount)*100;
return percentage.toFixed(1) + "%";
});
valueLabels.enter().append("svg:text")
.attr("class", "value")
.attr("transform", function(d) {
return "translate(" + Math.cos(((d.startAngle+d.endAngle - Math.PI)/2)) * (outerRadius+textOffset) + "," + Math.sin((d.startAngle+d.endAngle - Math.PI)/2) * (outerRadius+textOffset) + ")";
})
.attr("dy", function(d) {
if ((d.startAngle+d.endAngle)/2 > Math.PI/2 && (d.startAngle+d.endAngle)/2 < Math.PI*1.5 ) {
return 5;
}
else {
return -7;
}
})
.attr("text-anchor", function(d) {
if ( (d.startAngle+d.endAngle)/2 < Math.PI ) {
return "beginning";
} else {
return "end";
}
}).text(function(d) {
var percentage = (d.value/yearTotalAmount)*100;
return percentage.toFixed(1) + "%";
});
valueLabels.transition().duration(tweenDuration).attrTween("transform", textTween);
valueLabels.exit().remove();
// Draw category labels
categoryLabels = label_group.selectAll("text.units").data(pieChart)
.attr("dy", function(d) {
if ((d.startAngle+d.endAngle)/2 > Math.PI/2 && (d.startAngle+d.endAngle)/2 < Math.PI*1.5 ) {
return 21;
} else {
return 9;
}
})
.attr("text-anchor", function(d) {
if ((d.startAngle+d.endAngle)/2 < Math.PI ) {
return "beginning";
} else {
return "end";
}
}).text(function(d) {
return d.data.category;
});
categoryLabels.enter().append("svg:text")
.attr("class", "units")
.attr("transform", function(d) {
return "translate(" + Math.cos(((d.startAngle+d.endAngle - Math.PI)/2)) * (outerRadius+textOffset) + "," + Math.sin((d.startAngle+d.endAngle - Math.PI)/2) * (outerRadius+textOffset) + ")";
})
.attr("dy", function(d){
if ((d.startAngle+d.endAngle)/2 > Math.PI/2 && (d.startAngle+d.endAngle)/2 < Math.PI*1.5 ) {
return 21;
} else {
return 9;
}
})
.attr("text-anchor", function(d) {
if ((d.startAngle+d.endAngle)/2 < Math.PI ) {
return "beginning";
} else {
return "end";
}
}).text(function(d) {
return d.data.category;
});
categoryLabels.transition().duration(tweenDuration).attrTween("transform", textTween);
categoryLabels.exit().remove();
currentYear++;
}
// Animation for the pie arcs
function pieTween(d, i) {
var s0;
var e0;
if (oldData[i]) {
s0 = oldData[i].startAngle;
e0 = oldData[i].endAngle;
} else if (!(oldData[i]) && oldData[i-1]) {
s0 = oldData[i-1].endAngle;
e0 = oldData[i-1].endAngle;
} else if(!(oldData[i-1]) && oldData.length > 0) {
s0 = oldData[oldData.length-1].endAngle;
e0 = oldData[oldData.length-1].endAngle;
} else {
s0 = 0;
e0 = 0;
}
var i = d3.interpolate({startAngle: s0, endAngle: e0}, {startAngle: d.startAngle, endAngle: d.endAngle});
return function(t) {
var b = i(t);
return arc(b);
};
}
function removePieTween(d, i) {
s0 = 2 * Math.PI;
e0 = 2 * Math.PI;
var i = d3.interpolate({startAngle: d.startAngle, endAngle: d.endAngle}, {startAngle: s0, endAngle: e0});
return function(t) {
var b = i(t);
return arc(b);
};
}
// Animation for text
function textTween(d, i) {
var a;
if (oldData[i]) {
a = (oldData[i].startAngle + oldData[i].endAngle - Math.PI)/2;
}
else if (!(oldData[i]) && oldData[i-1]) {
a = (oldData[i-1].startAngle + oldData[i-1].endAngle - Math.PI)/2;
}
else if (!(oldData[i-1]) && oldData.length > 0) {
a = (oldData[oldData.length-1].startAngle + oldData[oldData.length-1].endAngle - Math.PI)/2;
}
else {
a = 0;
}
var b = (d.startAngle + d.endAngle - Math.PI)/2;
var fn = d3.interpolateNumber(a, b);
return function(t) {
var val = fn(t);
return "translate(" + Math.cos(val) * (outerRadius+textOffset) + "," + Math.sin(val) * (outerRadius+textOffset) + ")";
};
}
}
</script>
<style type='text/css'>
body {
margin: 0px;
}
.h,.v {
stroke:black;
stroke-dasharray: 4 4;
stroke-width: 1;
stroke-opacity: 0.5;
}
.axis path,
.axis line
{
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
#graph {
background-color: #ffffff;
font: 10px sans-serif;
text-shadow: none;
}
#graph .total{
font-size: 32px;
font-weight: bold;
}
#graph .units{
fill: gray;
font-size: 14px;
}
#graph .label{
fill: #CCC;
font-size: 14px;
font-weight: bold;
}
#graph .year{
fill: #777;
font-size: 64px;
font-weight: bold;
}
#graph .value{
font-size: 14px;
font-weight: bold;
}
</style>
</head>
<body>
<div id="graph"></div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment