Skip to content

Instantly share code, notes, and snippets.

@cgroll
Last active August 29, 2015 14:16
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 cgroll/8312be4e639e2ca64779 to your computer and use it in GitHub Desktop.
Save cgroll/8312be4e639e2ca64779 to your computer and use it in GitHub Desktop.
Absolute GDP values and growth rates

This gist visualizes absolute log GDP values together with growth rates. The data is from The World Bank, and it is stored in a private gist 274e242ead103b56be3e.

// define margins
var margin = {top: 20, right: 80, bottom: 30, left: 150};
// graphics size without axis
var width = 960 - margin.left - margin.right;
var height = 380 - margin.top - margin.bottom;
var svg1 = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var svg2 = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// axes scales
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.log()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5);
var yGrowth = d3.scale.linear()
.range([height, 0]);
var yAxisGrowth = d3.svg.axis()
.scale(yGrowth)
.orient("left")
.ticks(5);
// parse dates and remove missing values
var parseDate = d3.time.format("%Y-%m-%d").parse;
// log scale for y axis
var line = d3.svg.line()
.defined(function(d) { return !isNaN(d.lev); })
// .interpolate("basis")
.x(function(d) { return x(d.idx); })
.y(function(d) { return y(d.lev); });
// linear scale for y axis
var growthLine = d3.svg.line()
.defined(function(d) { return !isNaN(d.diff); })
.x(function(d) { return x(d.idx); })
.y(function(d) { return yGrowth(d.diff); });
// load data
queue()
.defer(d3.csv, "/cgroll/raw/274e242ead103b56be3e/isoCodes.csv")
.defer(d3.csv, "/cgroll/raw/274e242ead103b56be3e/ctryGdp.csv")
.defer(d3.csv, "/cgroll/raw/274e242ead103b56be3e/ctryQuantiles.csv")
.await(makeChart);
function makeChart(error, iso2Codes, ctryGdp, ctryQuantiles, ctryGdpGrowth){
// create associated array for iso code to country name conversion
var ctryLookup = new Array();
for (i = 0; i < iso2Codes.length; i++) {
ctryLookup[iso2Codes[i].iso2c] = iso2Codes[i].name;
}
// get country and quantile names
var countryNames = d3.keys(ctryGdp[0]).filter(function(key) { return key !== "idx"; });
var quantNames = d3.keys(ctryQuantiles[0]).filter(function(key) { return key !== "idx"; });
// parse dates
ctryGdp.forEach(function(d) {
d.idx = parseDate(d.idx);
});
ctryQuantiles.forEach(function(d) {
d.idx = parseDate(d.idx);
});
// get gdp level data as array
var gdpData = countryNames.map(function(name) {
countryData = ctryGdp.map(function(d, i) {
if (!i) {return {idx: d.idx, lev: +d[name], country: name, diff: NaN}}
else {
var diff = Math.log(+d[name]) - Math.log(ctryGdp[(i-1)][name]);
return {idx: d.idx, lev: +d[name], country: name, diff: diff}
};
})
return {country: name,
values: countryData
};
});
// get quantile data as array
var quants = quantNames.map(function(name) {
quants = ctryQuantiles.map(function(d) {
return {idx: d.idx, diff: +d[name]};
})
return {country: name,
values: quants
};
});
// get axis domains
x.domain(d3.extent(ctryGdp, function(d) { return d.idx; }));
y.domain([
d3.min(gdpData, function(c) { return d3.min(c.values, function(v) { return v.lev; }); }),
d3.max(gdpData, function(c) { return d3.max(c.values, function(v) { return v.lev; }); })
]);
// adjust limits to growth rates, not to quantiles
yGrowth.domain([-0.5, 0.5
// d3.min(gdpData, function(c) { return d3.min(c.values, function(v) { return v.diff; }); }),
// d3.max(gdpData, function(c) { return d3.max(c.values, function(v) { return v.diff; }); })
]);
// append axis for gpd level data
svg1.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg1.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("GDP p. cap., in thousand $");
// append axis for gpd growth data
svg2.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg2.append("g")
.attr("class", "y axis")
.call(yAxisGrowth)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("GDP growth");
// draw gdp level data
var gdp = svg1.selectAll(".gdp")
.data(gdpData)
.enter()
.append("g")
.attr("class", "gdp")
.append("path")
.attr("class", "line")
.attr("id", "inactive")
.attr("d", function(d) { d.gdpLine = this; return line(d.values); })
.on("mouseover", onmouseover)
.on("mouseout", onmouseout)
.on("click", clickFunction);
function onmouseover(d, i) {
d3.select(this).attr("class", "line--hover");
d3.select(d.growth).attr("d", function(c) { return growthLine(c.values); });
d3.select(d.growth).attr("class", "line--hover");
// transform iso2c code to name
var ctryName;
ctryName = ctryLookup[this.__data__.country]
d3.selectAll("h2").text(ctryName)
}
function onmouseout(d, i) {
d3.select(this).attr("class", "line");
if (this.id == "active") {d3.select(d.growth).attr("class", "line");}
else {
d3.select(d.growth).attr("d", null);
}
d3.selectAll("h2").text("World")
}
function clickFunction(d, i) {
if (this.id == "inactive") {
d3.select(this).attr("id", "active");
d3.select(d.growth).attr("d", function(c) { return growthLine(c.values); });
d3.select(d.growth).attr("id", "active");
}
else {
d3.select(this).attr("id", "inactive");
d3.select(d.growth).attr("d", null);
};
}
// append empty paths for growth rates
var qs = svg2.selectAll(".growth")
.data(gdpData)
.enter()
.append("g")
.attr("class", "growth")
.append("path")
.attr("class", function(d) { d.growth = this; return "line--hover"; })
// .attr("d", function(d) { d.line = this; return growthLine(d.values); });
// draw quantiles
var qs = svg2.selectAll(".quant")
.data(quants)
.enter()
.append("g")
.attr("class", "quant")
.append("path")
.attr("d", function(d) { d.line = this; return growthLine(d.values); });
};
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 16px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
<!-- display: none; -->
}
.line,
.line#inactive {
fill: none;
stroke: gray;
stroke-width: 1.5px;
stroke-opacity: 0.2;
}
.quant {
fill: none;
stroke: lightblue;
stroke-width: 1.0px;
stroke-opacity: 1;
}
.grid .tick {
stroke: lightgrey;
stroke-opacity: 0.7;
shape-rendering: crispEdges;
}
.grid path {
stroke-width: 0;
}
.line--hover,
.line--hover#active,
.line--hover#inactive {
fill: none;
stroke: darkred;
stroke-width: 3.5px;
stroke-opacity: 1;
}
.line#active {
fill: none;
stroke: black;
stroke-width: 2.5px;
stroke-opacity: 0.7;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="http://d3js.org/queue.v1.min.js"></script>
<h2>World</h2>
<script src="assembly_code.js">
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment