Skip to content

Instantly share code, notes, and snippets.

@arisatha
Created December 2, 2015 03:36
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 arisatha/01d71ff8eec1fa07f392 to your computer and use it in GitHub Desktop.
Save arisatha/01d71ff8eec1fa07f392 to your computer and use it in GitHub Desktop.
Household Budget Survey of Brussels 1978-2010
Expenditure 1979 1988 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010
Food and Beverages 2660 3134 3913 3822 3832 3960 3959 4205 4383 4557 4212 4401 4407 4563 4649 4754 4859
Clothing 851 1074 1160 1227 1100 1135 1324 1228 1165 1269 1183 1214 1239 1364 1183 1495 1326
Primary and Secondary Housing 3119 5151 6786 7349 7271 7737 8124 8055 8311 8629 8412 7764 8065 8434 8476 9263 9003
Furniture and appliances 873 1134 1305 1371 1481 1356 1525 1454 1332 1683 1319 1501 1899 1435 2148 1641 1720
Health 411 746 1177 1181 1158 1458 1239 1615 1523 1320 1255 1493 1368 1368 1673 1570 1628
Transportation and Communication 1440 1730 2549 2409 3229 3106 4487 3488 4294 4302 4049 4099 4204 4039 4291 4366 4595
Culture; Recreation and Education 818 1393 2031 2259 2193 2482 2448 2202 2404 2581 2505 2618 2510 2575 2294 2708 2603
Other goods and services 2320 3694 4579 4146 4730 4667 4810 4867 4759 4804 4985 5042 5734 5411 5981 6023 6018
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Stacked area chart</title>
<script type="text/javascript" src="http://d3js.org/d3.v3.js"></script>
<style type="text/css">
body {
margin: 0;
background-color: lightGray;
font-family: Helvetica, Arial, sans-serif;
}
#container {
width: 900px;
margin-left: auto;
margin-right: auto;
margin-top: 50px;
padding: 50px;
background-color: white;
box-shadow: 3px 3px 5px 6px #ccc;
}
h1 {
font-size: 24px;
margin: 0;
}
p {
font-size: 14px;
margin: 10px 0 0 0;
}
svg {
background-color: white;
}
g.bar text {
font-size: 14px;
font-weight: bold;
text-anchor: end;
opacity: 0;
fill: white;
}
g.bar:hover text {
opacity: 1;
}
path:hover {
fill: yellow;
opacity: 0.5;
}
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
</style>
</head>
<body>
<div id="container">
<h1>Evolution of Brussels' Household Expenditure</h1>
<p>Household expenditure by type of goods and services (in euros), 1979-2010. Source: <a href="http://statbel.fgov.be/fr/statistiques/chiffres/travailvie/budget/historique/composition/">DGSIE</a>, 2015</p>
<script type="text/javascript">
//Set up stack method
var stack = d3.layout.stack()
.values(function(d) {
return d.expenditure;
})
.order("reverse");
//Width, height, padding
var w = 900;
var h = 600;
var padding = [ 20, 10, 50, 100 ]; //Top, right, bottom, left
//Set up date format function (years)
var dateFormat = d3.time.format("%Y");
//Set up scales
var xScale = d3.time.scale()
.range([ padding[3], w - padding[1] - padding[3] ]);
var yScale = d3.scale.linear()
.range([ padding[0], h - padding[2] ]);
//Configure axis generators
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(15)
.tickFormat(function(d) {
return dateFormat(d);
});
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(5);
//Configure area generator
var area = d3.svg.area()
.x(function(d) {
return xScale(dateFormat.parse(d.x));
})
.y0(function(d) {
return yScale(d.y0); //Updated
})
.y1(function(d) {
return yScale(d.y0 + d.y); //Updated
});
//Easy colors accessible via a 10-step ordinal scale
var color = d3.scale.category20c();
//Create the empty SVG image
var svg = d3.select("#container")
.append("svg")
.attr("width", w)
.attr("height", h);
//Load data
d3.csv("HouseholdBudgetSurvey.csv", function(data) {
//Uncomment to log the newly loaded data to the console
//console.log(data);
//Data is loaded in, but we need to restructure it.
//Remember, each line requires an array of x/y pairs;
//that is, an array of arrays, like so:
//
// [ [x: 1, y: 1], [x: 2, y: 2], [x: 3, y: 3] ]
//
//Our x value will be the year, and y will be the amount
//of CO2. We also need to know which expenditure_type belongs to
//each line, so we will build an array of objects that is
//structured like this:
//
/*
[
{
expenditure_type: "Australia",
expenditure: [
{ x: "1961", y: 90589.568 },
{ x: "1962", y: 94912.961 },
{ x: "1963", y: 101029.517 },
]
},
{
expenditure_type: "Bermuda",
expenditure: [
{ x: "1961", y: 176.016 },
{ x: "1962", y: 157.681 },
{ x: "1963", y: 150.347 },
]
},
]
*/
//
//Note that this is an array of objects. Each object
//contains two values, 'expenditure_type' and 'expenditure'.
//The 'expenditure' value is itself an array, containing
//more objects, each one holding x and y values.
//
//The x (year) values have to be strings in this case,
//because the date format function expects a string
//to parse into a Date object.
//New array with all the years, for referencing later
var years = ["1979", "1988", "1996", "1997", "1998", "1999", "2000", "2001", "2002", "2003", "2004", "2005", "2006", "2007", "2008", "2009", "2010"];
//Create a new, empty array to hold our restructured dataset
var dataset = [];
//Loop once for each row in data
for (var i = 0; i < data.length; i++) {
//Create new object with this expenditure_type's name and empty array
dataset[i] = {
expenditure_type: data[i].Expenditure,
expenditure: []
};
//Loop through all the years
for (var j = 0; j < years.length; j++) {
//Default value, used in case no value is present
var amount = null;
// If value is not empty
if (data[i][years[j]]) {
amount = +data[i][years[j]];
}
//Add a new object to the expenditure data array
//for this expenditure_type
dataset[i].expenditure.push({
x: years[j],
y: amount
});
}
}
//Stack the data!
stack(dataset);
//Uncomment to log the original data to the console
//console.log(data);
//Uncomment to log the newly restructured dataset to the console
//console.log(dataset);
//Now that the data is ready, we can check its
//min and max values to set our scales' domains!
xScale.domain([
d3.min(years, function(d) {
return dateFormat.parse(d);
}),
d3.max(years, function(d) {
return dateFormat.parse(d);
})
]);
//Need to recalcluate the max value for yScale
//differently, now that everything is stacked.
//Loop once for each year, and get the total value
//of CO2 for that year.
var totals = [];
for (i = 0; i < years.length; i++) {
totals[i] = 0;
for (j = 0; j < dataset.length; j++) {
totals[i] += dataset[j].expenditure[i].y;
}
}
yScale.domain([ d3.max(totals), 0 ]);
//Areas
//
//Now that we are creating multiple paths, we can use the
//selectAll/data/enter/append pattern to generate as many
//as needed.
//Make a path for each expenditure_type
var paths = svg.selectAll("path")
.data(dataset)
.enter()
.append("path")
.attr("class", "area")
.attr("d", function(d) {
//Calculate path based on only d.expenditure array,
//not all of d (which would include the expenditure_type name)
return area(d.expenditure);
})
.attr("stroke", "none")
.attr("fill", function(d, i) {
return color(i);
})
.attr("area", 0);
//Append a title with the expenditure_type name (so we get easy tooltips)
paths.append("title")
.text(function(d) {
return d.expenditure_type;
});
paths.transition()
.delay(function(d, i) {
return i * 50;
})
.duration(1000)
.attr("width", function(d) {
return yScale(d.expenditure_type);
});
//Create axes
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (h - padding[2]) + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + padding[3] + ",0)")
.call(yAxis);
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment