Skip to content

Instantly share code, notes, and snippets.

@yudataguy
Last active June 27, 2018 03:37
Show Gist options
  • Save yudataguy/51ac2a1afc66a759201808cb9fb668b5 to your computer and use it in GitHub Desktop.
Save yudataguy/51ac2a1afc66a759201808cb9fb668b5 to your computer and use it in GitHub Desktop.
Udaicty D3 Project

#Graph: World Oil Consumption by major nations

##(OECD and nonOECD), between 1990 and 2016

Unit: Mt

##Summary

Oil consumption is one of the essential indicator of a country's strength in modern time. Machine, automobile, and airplane, almost every parts of our society runs on oil. Therefore, oil consumption can be a good measurement of countries' strength and development pace.

###Trend 1:

The nonOECD nations total consumption is growing in recent years. While OECD nations total consumption is declining, maybe attributes to the push of renewable energy in OECD nations.

###Trend 2:

Among nonOECD nations, country such as China and India has significant growth in recent years. Even though it may not look significant in combined chart, but individual country graph shows significant growth year over year.

##Design

The initial design was centered around region and individual nations, such as Asia, Africa and so on. After initial graph, the graph was a total mess due to the lack of available color options for each nations. It makes more sence to compare OECD and nonOECD nations. Additionally, the earlier graph suggested data with different grouping maybe able to show a better trend in the overall period. With nonOECD nations' fast development in recent years, their oil consumption has been growing tremendously, but the growth is still small in absolute term when compare with OECD nations. Therefore a separate individual nation graph is a better representation of the specific country. Other graph type bar chart was explored in design process, but deemed difficult to interpret due to the large number of nations.

Also, Scaling Y-axis was introduced due to the large difference between different nations. Since a small oil consumption nation data would be hard to view on the same scale, therefore scaling Y-axis was added. Initially, Y-axis was placed on left side like most graphs. But visually, it presented a problem, since readers had problem understand the scale of the present(2016) data. Therefore, Y-axis was moved to the right for better reading. On color, there was not enough different colors to represent all the nations at first. Therefore, the overall was changed to reflect this, and use spread to better show the color difference between nations.

##Feedback

  • Initial color was too dis-organized, difficult to distinguish each countries.
  • Hoover country name display was difficult to grasp at fist
  • Initial trend was different to spot, due to region grouping sometimes lack of difference in data
  • Need grid line to better understand the oil consumption number in a given year

##Resource

d3.js Official Tutorials

Stackoverflow communities for helping on solving errors;

Book "Interactive Data Visualization for the Web" by Scott Murray; Note: My graph can not be made without the help of this book. The tutorial guided me while making this graph, especially the part of re-drawing graph.

Book "Learning d3.js Data Visualization - Second Edition" by Ændrew Rininsland, Swizec Teller; Note: Another invaluable resource for guiding me through d3 visualization process.

Raw oil consumption data from Enerdata

###Additional comment from original data

Consumption (or domestic supply) is the balance of production, external trade and stock changes. Marine bunkers are excluded for countries. They are included at the world level. Consumption is mainly divided between power plants, industry, transport and the residential and tertiary sectors, one part is used or lost in the energy transformation.

Petroleum products are all liquid hydrocarbons, obtained by the refining of crude oil and NGL and by treatment of natural gas ; in particular, LPG production (Liquid Petroleum Gas) includes LPG from natural gas separation plants. The alcohol used as motor fuel in Brazil as well as fuels derived from coal in South Africa are not included in oil products.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3: World Oil Consumption by Major Nations</title>
<script type="text/javascript" src="d3.min.js"></script>
<style type="text/css">
h1 {
font-family: Helvetica, sans-serif;
font-size: 14px;
font-weight: bold;
}
.area {
stroke: none;
}
.area:hover {
fill: yellow;
}
.grid line {
stroke: lightgrey;
stroke-opacity: 0.7;
shape-rendering: crispEdges;
}
.grid path {
stroke-width: 0;
}
</style>
</head>
<body>
<h1>World Oil Consumption by major nations(OECD and Non OECD), between 1990 and 2016</h1>
<script type="text/javascript">
//Width and height
var w = 800;
var h = 500;
var padding = 20;
var dataset, xScale, yScale, xAxis, yAxis, area; //Empty, for now
//For converting strings to Dates
var parseTime = d3.timeParse("%Y");
//For converting Dates to strings
var formatTime = d3.timeFormat("%Y");
//Set up stack method
var stack = d3.stack()
.order(d3.stackOrderDescending); // <-- Flipped stacking order
//Load in data
d3.request("world_oil.csv")
.mimeType("text/csv")
.get(function(response) {
//Parse each row of the CSV into an array
var rows = d3.csvParseRows(response.responseText);
dataset = [];
//Loop from row 3
for (var i = 3; i < rows.length; i++) {
dataset[i - 3] = {
date: parseTime(rows[i][0])
};
for (var j = 1; j < rows[i].length; j++) {
var region = rows[0][j];
var nation = rows[1][j];
var regionNation = rows[0][j] + " " + rows[1][j];
var type = rows[2][j];
var consumption = rows[i][j];
//If consumption value exists
if (consumption) {
consumption = parseInt(consumption);
} else {
consumption = 0;
}
//Append a new object with type, nation, and consumption
dataset[i - 3][regionNation] = {
"region": region,
"nation": nation,
"type": type,
"consumption": consumption
};
}
}
var keys = Object.keys(dataset[0]).slice(1);
//Tell stack function where to find the keys
stack.keys(keys)
.value(function value(d, key) {
return d[key].consumption;
});
//Stack the data
var series = stack(dataset);
//Create scale functions
xScale = d3.scaleTime()
.domain([
d3.min(dataset, function(d) { return d.date; }),
d3.max(dataset, function(d) { return d.date; })
])
.range([padding, w - padding * 2]);
yScale = d3.scaleLinear()
.domain([
0,
d3.max(dataset, function(d) {
var sum = 0;
//Loops once for each row, to calculate total
for (var i = 0; i < keys.length; i++) {
sum += d[keys[i]].consumption;
};
return sum;
})
])
.range([h - padding, padding / 2])
.nice();
//Define X axis
xAxis = d3.axisBottom()
.scale(xScale)
.ticks(10)
.tickFormat(formatTime);
//Define Y axis
yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(5);
//Define area
area = d3.area()
.x(function(d) { return xScale(d.data.date); })
.y0(function(d) { return yScale(d[0]); })
.y1(function(d) { return yScale(d[1]); });
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Create areas
svg.selectAll("path")
.data(series)
.enter()
.append("path")
.attr("class", "area")
.attr("d", area)
.attr("fill", function(d, i) {
return d3.schemeCategory20[i];
})
.append("title") //Make tooltip
.text(function(d) {
return d.key;
});
//Create axes
svg.append("g")
.attr("class", "axis x")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
svg.append("g")
.attr("class", "axis y")
//.attr("transform", "translate(" + (w - padding * 2) + ",0)")
.call(yAxis);
});
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3: World Oil Consumption by Major Nations</title>
<script type="text/javascript" src="../d3.js"></script>
<style type="text/css">
/* CSS elements for the graph */
h1 {
font-family: Helvetica, sans-serif;
font-size: 18px;
font-weight: bold;
}
h3 {
font-family: Helvetica, sans-serif;
font-size: 12px;
}
.area {
stroke: none;
cursor: pointer;
}
.area:hover {
fill: rgb(175, 240, 91);
}
#backButton {
cursor: pointer;
}
#backButton rect {
fill: #3E50B4;
}
#backButton text {
font-family: Helvetica, sans-serif;
font-weight: bold;
font-size: 14px;
fill: white;
}
#backButton:hover rect {
fill: rgb(26, 199, 194);
}
#backButton:hover text {
fill: white;
}
.unclickable {
pointer-events: none;
}
</style>
</head>
<body>
<h1>World Oil Consumption by major nations(OECD and Non OECD), between 1990 and 2016</h1>
<h3>Unit: Mt</h3>
<script type="text/javascript">
//Width and height
var w = 1400;
var h = 450;
var padding = 20;
//Tracks view state.
var viewState = 0;
//Tracks most recently viewed/clicked 'type'. Possible values:
//"OECD" or "nonOECD"
var viewType;
var dataset, thisTypeDataset, xScale, yScale, xAxis, yAxis, area;
//For converting strings to Dates
var parseTime = d3.timeParse("%Y");
//For converting Dates to strings
var formatTime = d3.timeFormat("%Y");
//Define key function, to be used when binding data
var key = function(d) {
return d.key;
};
//Set up stack methods
var nationStack = d3.stack();
var typeStack = d3.stack();
//Load in data
d3.request("world_oil.csv")
.mimeType("text/csv")
.get(function(response) {
//Parse each row of the CSV into an array of string values
var rows = d3.csvParseRows(response.responseText);
//Make dataset an empty array
dataset = [];
for (var i = 3; i < rows.length; i++) {
dataset[i - 3] = {
date: parseTime(rows[i][0]) //Make a new Date object for each year
};
//Loop once for each nation in this row
for (var j = 1; j < rows[i].length; j++) {
var region = rows[0][j];
var nation = rows[1][j];
var regionNation = rows[0][j] + " " + rows[1][j];
var type = rows[2][j];
var consumption = rows[i][j];
//If consumption value exists
if (consumption) {
consumption = parseInt(consumption);
} else {
consumption = 0;
}
//Append a new object with type, nation, and consumption
dataset[i - 3][regionNation] = {
"region": region,
"nation": nation,
"type": type,
"consumption": consumption
};
}
}
//Make typeDataset an empty array for separate type of nations for annual total
typeDataset = [];
for (var i = 3; i < rows.length; i++) {
//Create a new object
typeDataset[i - 3] = {
date: parseTime(rows[i][0]), //Make a new Date object for each year
"OECD": 0,
"nonOECD": 0,
};
//Loop once for each nation in this row
for (var j = 1; j < rows[i].length; j++) {
var type = rows[2][j];
var consumption = rows[i][j];
//If consumption value exists
if (consumption) {
consumption = parseInt(consumption); //Convert from string to int
} else {
consumption = 0;
}
//Add consumption value to existing sum
typeDataset[i - 3][type] += consumption;
}
}
//Tell stack function where to find the keys
var types = [ "OECD", "nonOECD" ];
typeStack.keys(types);
//Stack the data and log it out
var typeSeries = typeStack(typeDataset);
//D3 CHART
//Create scale functions
xScale = d3.scaleTime()
.domain([
d3.min(dataset, function(d) { return d.date; }),
d3.max(dataset, function(d) { return d.date; })
])
.range([padding, w - padding * 2]);
yScale = d3.scaleLinear()
.domain([
0,
d3.max(typeDataset, function(d) {
var sum = 0;
//Loops once for each row, to calculate the total (sum) of consumption of all nations
for (var i = 0; i < types.length; i++) {
sum += d[types[i]];
};
return sum;
})
])
.range([h - padding, padding / 2])
.nice();
//Define X axis
xAxis = d3.axisBottom()
.scale(xScale)
.ticks(10)
.tickFormat(formatTime);
//Define Y axis
yAxis = d3.axisRight()
.scale(yScale)
.ticks(5);
//Define area
area = d3.area()
.x(function(d) { return xScale(d.data.date); })
.y0(function(d) { return yScale(d[0]); })
.y1(function(d) { return yScale(d[1]); });
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
//Create areas for each nation
svg.append("g")
.attr("id", "nations");
//Create areas for TYPES
svg.append("g")
.attr("id", "types")
.selectAll("path")
.data(typeSeries, key)
.enter()
.append("path")
.attr("class", "area")
.attr("opacity", 1)
.attr("d", area)
.attr("fill", function(d) {
//Which type
var thisType = d.key;
//New color var
var color;
switch (thisType) {
case "OECD":
color = "rgb(110, 64, 170)";
break;
case "nonOECD":
color = "rgb(76, 110, 219)";
break;
}
return color;
})
.on("click", function(d) {
//Update view state
viewState++;
//TYPES
//Which type was clicked?
var thisType = d.key;
viewType = thisType;
//Generate a new data set with all-zero values, except the type data
thisTypeDataset = [];
for (var i = 0; i < typeDataset.length; i++) {
thisTypeDataset[i] = {
date: typeDataset[i].date,
OECD: 0,
nonOECD: 0,
[thisType]: typeDataset[i][thisType]
}
}
var thisTypeSeries = typeStack(thisTypeDataset);
//Bind the new data set to paths, overwriting old bound data.
var paths = d3.selectAll("#types path")
.data(thisTypeSeries, key)
.classed("unclickable", true);
//Transition areas into new positions
var areaTransitions = paths.transition()
.duration(1000)
.attr("d", area);
//Update scale
yScale.domain([
0,
d3.max(thisTypeDataset, function(d) {
var sum = 0;
sum += d[thisType];
return sum;
})
]);
//Append this transition
areaTransitions.transition()
.delay(200)
.on("start", function() {
//Transition axis to new scale concurrently
d3.select("g.axis.y")
.transition()
.duration(1000)
.call(yAxis);
})
.duration(1000)
.attr("d", area)
.transition()
.on("start", function() {
//Make nations visible
d3.selectAll("g#nations path")
.attr("opacity", 1);
})
.duration(1000)
.attr("opacity", 0)
.on("end", function(d, i) {
//Reveal back button
if (i == 0) {
toggleBackButton();
}
});
// Nations
//Get all possible keys (region + nation)
var keysAll = Object.keys(dataset[0]).slice(1);
//Loop once for each key
var keysOfThisType = [];
for (var i = 0; i < keysAll.length; i++) {
if (dataset[0][keysAll[i]].type == thisType) {
keysOfThisType.push(keysAll[i]);
}
}
//Give the new keys to the stack function
nationStack.keys(keysOfThisType)
.value(function value(d, key) {
return d[key].consumption;
});
//Stack the data
var nationSeries = nationStack(dataset);
//Create areas for each nation
svg.select("g#nations")
.selectAll("path")
.data(nationSeries, key)
.enter()
.append("path")
.attr("class", "area")
.attr("opacity", 0)
.attr("d", area)
.attr("fill", function(d, i) {
//Pick the nation
var thisKey = d.key;
var thisType = d[0].data[thisKey].type;
//Find a cool color
var spread = 0.4;
var startingPoint;
//Choose the color spectrum
switch (thisType) {
case "OECD":
startingPoint = 0;
break;
case "nonOECD":
startingPoint = 0.4;
break;
}
//How many cars?
var numNations = keysOfThisType.length;
//Get a value between 0.0 and 1.0
var normalized = startingPoint + ((i / numNations) * spread);
//Get that color on the spectrum
return d3.interpolateCool(normalized);
})
.on("click", function(d) {
//Update view state
viewState++;
//Hide the back button during this view transition
toggleBackButton();
var thisType = d.key;
//Fade out all other nation
d3.selectAll("g#nations path")
.classed("unclickable", true)
.filter(function(d) {
if (d.key !== thisType) {
return true;
}
})
.transition()
.duration(1000)
.attr("opacity", 0);
//Define area for single nation
var singleNationArea = d3.area()
.x(function(d) { return xScale(d.data.date); })
.y0(function(d) { return yScale(0); })
.y1(function(d) { return yScale(d.data[thisType].consumption); });
//Use this new area generator to transition the area downward
var thisAreaTransition = d3.select(this)
.transition()
.delay(1000)
.duration(1500)
.attr("d", singleNationArea);
//Update y scale domain
yScale.domain([
0,
d3.max(dataset, function(d) {
return d[thisType].consumption;
})
]);
//Transitions the clicked area and y axis into place, to fit the new domain
thisAreaTransition
.transition()
.duration(1500)
.attr("d", singleNationArea)
.on("start", function() {
//Transition axis to new scale
d3.select("g.axis.y")
.transition()
.duration(1500)
.call(yAxis);
})
.on("end", function() {
//Restore clickability
d3.select(this).classed("unclickable", "false");
//Reveal back button
toggleBackButton();
});
})
.append("title") //Make tooltip
.text(function(d) {
return d.key;
});
})
.append("title") //Make tooltip
.text(function(d) {
return d.key;
});
//Create axes
svg.append("g")
.attr("class", "axis x")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
svg.append("g")
.attr("class", "axis y")
.attr("transform", "translate(" + (w - padding * 2) + ",0)")
.call(yAxis);
//Create back button
var backButton = svg.append("g")
.attr("id", "backButton")
.attr("opacity", 0)
.classed("unclickable", true)
.attr("transform", "translate(" + xScale.range()[0] + "," + yScale.range()[1] + ")");
backButton.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("rx", 5)
.attr("rx", 5)
.attr("width", 70)
.attr("height", 30);
backButton.append("text")
.attr("x", 7)
.attr("y", 20)
.html("&larr; Back");
//Define click behavior
backButton.on("click", function() {
//Hide the back button, as it was just clicked
toggleBackButton();
if (viewState == 1) {
//Go back to default view
//Update view state
viewState--;
//Re-bind type data and fade in types
var typeAreaTransitions = d3.selectAll("g#types path")
.data(typeSeries, key)
.transition()
.duration(250)
.attr("opacity", 1)
.on("end", function() {
d3.selectAll("g#nations path").remove();
});
//Set y scale back to original domain
yScale.domain([
0,
d3.max(typeDataset, function(d) {
var sum = 0;
//Loops once for each row, to calculate total consumption
for (var i = 0; i < types.length; i++) {
sum += d[types[i]];
};
return sum;
})
]);
//Transition type areas and y scale back into place
typeAreaTransitions.transition()
.duration(1000)
.on("start", function() {
//Transition axis to new scale concurrently
d3.select("g.axis.y")
.transition()
.duration(1000)
.call(yAxis);
})
.attr("d", area)
.on("end", function() {
d3.select(this).classed("unclickable", false);
});
} else if (viewState == 2) {
//Update view state
viewState--;
//Restore the old y scale
yScale.domain([
0,
d3.max(thisTypeDataset, function(d) {
var sum = 0;
//Calculate the total (sum) of consumption of this type
sum += d[viewType];
return sum;
})
]);
//Transition the y axis and visible area back into place
d3.selectAll("g#nations path")
.transition()
.on("start", function() {
//Transition y axis to new scale concurrently
d3.select("g.axis.y")
.transition()
.duration(1000)
.call(yAxis);
})
.duration(1000)
.attr("d", area)
.transition()
.duration(1000)
.attr("opacity", 1)
.on("end", function(d, i) {
//Restore clickability
d3.select(this).classed("unclickable", false);
//Reveal back button
if (i == 0) {
toggleBackButton();
}
});
}
});
});
var toggleBackButton = function() {
//Select the button
var backButton = d3.select("#backButton");
//Is the button hidden right now?
var hidden = backButton.classed("unclickable");
//Decide whether to reveal or hide it
if (hidden) {
//Reveal it
//Set up dynamic button text
var buttonText = "&larr; Back to ";
//Text varies by mode and type
if (viewState == 1) {
buttonText += "home";
} else if (viewState == 2) {
buttonText += "all " + viewType + " nations";
}
//Set text
backButton.select("text").html(buttonText);
//Resize button depending on text width
var rectWidth = Math.round(backButton.select("text").node().getBBox().width + 16);
backButton.select("rect").attr("width", rectWidth);
//Fade button in
backButton.classed("unclickable", false)
.transition()
.duration(500)
.attr("opacity", 1);
} else {
//Hide it
backButton.classed("unclickable", true)
.transition()
.duration(200)
.attr("opacity", 0);
}
};
</script>
</body>
</html>
Region Europe Europe Europe Europe Europe Europe Europe Europe Europe Europe Europe Europe Europe Europe CIS CIS CIS CIS North-America North-America Latin-America Latin-America Latin-America Latin-America Latin-America Latin-America Asia Asia Asia Asia Asia Asia Asia Asia Pacific Pacific Africa Africa Africa Africa Middle-East Middle-East Middle-East Middle-East
Country Belgium Czech Rep. France Germany Italy Netherlands Poland Portugal Romania Spain Sweden United Kingdom Norway Turkey Kazakhstan Russia Ukraine Uzbekistan Canada United States Argentina Brazil Chile Colombia Mexico Venezuela China India Indonesia Japan Malaysia South Korea Taiwan Thailand Australia New Zealand Algeria Egypt Nigeria South Africa Iran Kuwait Saudi Arabia United Arab Emirates
OECD OECD OECD OECD OECD OECD OECD OECD OECD nonOECD OECD OECD OECD OECD OECD nonOECD nonOECD nonOECD nonOECD OECD OECD nonOECD nonOECD OECD nonOECD nonOECD nonOECD nonOECD nonOECD nonOECD OECD nonOECD OECD nonOECD nonOECD OECD OECD nonOECD nonOECD nonOECD nonOECD nonOECD nonOECD nonOECD nonOECD
1990 18 9 80 119 88 22 13 11 17 44 15 73 8 22 19 214 67 10 77 732 19 57 6 8 69 18 144 56 30 217 12 48 25 17 31 4 8 21 7 15 46 4 34 6
1991 19 7 86 127 87 23 13 11 14 46 15 74 8 22 22 221 64 10 73 716 20 58 7 9 74 17 153 58 32 218 13 58 26 18 31 4 8 20 9 15 48 2 36 7
1992 20 8 85 128 89 23 13 12 12 48 16 74 8 23 21 196 39 8 75 729 21 60 7 9 74 19 162 61 33 223 14 69 26 20 30 4 8 20 10 15 53 5 39 7
1993 19 8 83 130 88 22 14 12 11 45 16 74 8 26 17 174 28 8 76 738 21 62 8 10 77 19 177 63 37 221 15 76 28 23 31 4 8 20 9 14 53 4 41 7
1994 22 8 82 128 87 23 14 12 11 49 17 73 8 25 12 135 25 7 77 759 23 66 8 11 84 19 177 68 37 228 15 81 29 27 32 5 8 18 7 15 57 5 42 7
1995 21 8 84 128 91 23 14 13 11 52 16 72 8 28 11 133 25 7 79 753 23 70 9 11 77 20 191 76 43 233 18 88 32 30 33 5 7 19 8 16 56 6 41 7
1996 23 8 85 130 90 24 16 12 13 51 18 74 9 30 9 125 16 6 81 779 23 75 10 12 78 20 197 81 45 233 19 91 32 34 34 5 7 20 9 16 59 6 45 7
1997 23 8 85 129 90 24 18 13 13 53 16 72 9 29 8 120 18 7 84 793 25 81 10 12 81 22 214 85 48 232 20 97 32 33 34 5 7 22 10 17 60 6 45 7
1998 23 8 89 129 90 24 18 15 11 57 17 70 9 29 9 117 17 7 85 810 27 85 11 12 85 22 218 89 47 226 18 79 33 30 35 5 7 24 9 17 59 7 48 7
1999 23 8 88 124 88 24 19 15 10 59 16 70 9 28 7 121 12 7 87 829 26 87 11 11 84 20 229 97 51 232 19 87 35 31 35 5 8 24 9 17 63 9 50 7
2000 22 8 86 121 86 24 19 15 10 61 15 68 8 30 8 119 12 6 87 837 25 88 10 11 88 22 242 108 51 227 19 90 36 31 36 5 8 23 10 16 65 8 52 7
2001 23 8 89 123 85 24 18 15 11 63 15 67 9 28 7 120 13 6 89 847 23 88 9 11 87 25 247 106 53 222 20 89 38 30 36 5 8 22 12 17 68 9 55 8
2002 22 8 86 118 87 24 18 16 11 64 15 67 9 29 8 117 13 6 89 841 21 85 10 11 83 25 259 110 53 226 21 90 38 34 36 6 9 23 12 17 67 10 60 8
2003 23 8 86 116 86 27 19 14 10 65 15 68 9 29 8 118 13 6 96 859 22 82 10 10 83 23 282 114 54 223 20 90 39 37 38 6 10 22 12 18 67 12 63 9
2004 23 9 86 114 84 27 20 14 10 67 14 69 9 29 8 117 13 6 99 888 25 85 11 11 86 25 331 117 60 220 21 88 41 41 39 6 10 27 12 19 70 12 68 9
2005 23 10 85 112 81 27 21 15 10 68 14 69 9 28 9 117 14 5 101 887 25 87 11 11 88 28 335 119 60 216 21 88 40 41 39 6 10 27 12 20 75 13 70 10
2006 22 10 85 112 81 26 22 13 10 66 13 68 9 30 10 121 14 5 101 871 28 88 11 11 88 27 355 129 57 207 22 87 41 40 40 6 11 28 10 20 84 14 75 10
2007 21 10 83 99 78 27 23 13 10 67 13 66 9 30 10 123 14 4 104 860 28 92 15 11 91 28 368 139 58 205 25 89 43 40 40 6 12 29 9 23 86 13 78 11
2008 23 10 81 105 74 26 23 13 10 63 12 64 9 30 11 127 14 4 103 804 30 95 15 11 90 31 376 142 60 188 24 84 40 38 41 6 13 31 11 24 86 16 84 11
2009 21 9 77 100 68 25 23 12 9 59 11 60 9 31 9 121 14 4 100 755 29 94 14 10 87 32 383 144 61 183 26 87 40 40 41 6 14 33 9 23 87 17 81 12
2010 22 9 75 101 67 26 25 11 8 57 12 60 9 29 9 127 13 4 103 775 30 104 14 10 88 35 401 147 65 183 24 89 42 42 42 6 14 34 12 23 76 16 84 12
2011 21 8 73 98 64 25 24 10 8 54 11 57 9 29 10 139 13 3 104 761 31 109 14 12 90 32 419 154 69 185 27 89 38 44 44 6 15 34 11 25 76 16 89 12
2012 20 8 71 98 59 25 23 9 9 49 11 57 9 31 10 140 13 3 108 740 32 116 14 12 89 37 438 164 69 188 25 92 38 46 45 6 16 36 12 25 80 18 96 13
2013 21 8 70 100 53 25 21 9 8 47 10 56 9 33 11 140 12 3 106 739 31 120 15 12 88 34 461 166 70 186 28 92 39 50 47 6 17 31 11 26 86 17 99 14
2014 21 9 68 97 54 24 21 9 8 45 10 56 8 32 11 153 11 3 104 750 33 124 14 13 85 34 476 172 71 175 29 93 39 50 47 6 18 29 10 25 84 17 107 15
2015 22 8 69 96 54 24 23 9 9 47 10 59 9 37 10 145 10 3 101 767 34 115 15 12 84 30 502 192 67 170 30 97 39 52 47 6 19 30 10 27 82 18 114 17
2016 22 8 69 98 54 24 25 9 9 48 11 60 9 40 10 149 11 2 102 771 34 110 15 12 81 29 520 203 68 167 32 104 40 53 46 7 19 31 11 26 80 17 112 18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment