An example of a divering bar chart. Visualising the population growth rate of European countries (2016). Uses d3-scale-chromatic for bar colours.
This is part of a series of visualisations called My Visual Vocabulary which aims to recreate every visualisation in the FT’s Visual Vocabulary from scratch using D3.
forked from tlfrd‘s block: Diverging bar chart
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<style>
body { margin:0; position:fixed; top:0; right:0; bottom:0; left:0; }
body {
font-family: monospace;
}
.y-axis line{
stroke: black;
}
.annual-growth {
fill: black;
}
.bar-label, .x-axis {
font-size: 8px;
}
.domain, .tick line {
opacity: 0.5;
}
</style>
</head>
<body>
<script>
var margin = {top: 40, right: 50, bottom: 60, left: 50};
var width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var svg = 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 + ")");
// Config
var cfg = {
labelMargin: 5,
xAxisMargin: 10,
legendRightMargin: 0
}
var x = d3.scaleLinear()
.range([0, width]);
var colour = d3.scaleSequential(d3.interpolatePRGn);
var y = d3.scaleBand()
.range([height, 0])
.padding(0.1);
function parse(d) {
d.rank = +d.rank;
d.annual_growth = +d.annual_growth;
return d;
}
var legend = svg.append("g")
.attr("class", "legend");
legend.append("text")
.attr("x", width - cfg.legendRightMargin)
.attr("text-anchor", "end")
.text("European Countries by");
legend.append("text")
.attr("x", width - cfg.legendRightMargin)
.attr("y", 20)
.attr("text-anchor", "end")
.style("opacity", 0.5)
.text("2016 Population Growth Rate (%)");
d3.csv("popgrowth.csv", parse, function(error, data) {
if (error) throw error;
y.domain(data.map(function(d) { return d.country; }));
x.domain(d3.extent(data, function(d) { return d.annual_growth; }));
var max = d3.max(data, function(d) { return d.annual_growth; });
colour.domain([-max, max]);
var yAxis = svg.append("g")
.attr("class", "y-axis")
.attr("transform", "translate(" + x(0) + ",0)")
.append("line")
.attr("y1", 0)
.attr("y2", height);
var xAxis = svg.append("g")
.attr("class", "x-axis")
.attr("transform", "translate(0," + (height + cfg.xAxisMargin) + ")")
.call(d3.axisBottom(x).tickSizeOuter(0));
var bars = svg.append("g")
.attr("class", "bars")
bars.selectAll("rect")
.data(data)
.enter().append("rect")
.attr("class", "annual-growth")
.attr("x", function(d) {
return x(Math.min(0, d.annual_growth));
})
.attr("y", function(d) { return y(d.country); })
.attr("height", y.bandwidth())
.attr("width", function(d) {
return Math.abs(x(d.annual_growth) - x(0))
})
.style("fill", function(d) {
return colour(d.annual_growth)
});
var labels = svg.append("g")
.attr("class", "labels");
labels.selectAll("text")
.data(data)
.enter().append("text")
.attr("class", "bar-label")
.attr("x", x(0))
.attr("y", function(d) { return y(d.country )})
.attr("dx", function(d) {
return d.annual_growth < 0 ? cfg.labelMargin : -cfg.labelMargin;
})
.attr("dy", y.bandwidth())
.attr("text-anchor", function(d) {
return d.annual_growth < 0 ? "start" : "end";
})
.text(function(d) { return d.country })
.style("fill", function(d) {
if (d.country == "European Union") {
return "blue";
}
});
});
</script>
</body>
rank,country,annual_growth
1,Luxembourg,2.05
2,Cyprus,1.38
3,Ireland,1.20
4,Iceland,1.17
5,Kazakhstan,1.09
6,Norway,1.07
7,Azerbaijan,0.92
8,Turkey,0.90
9,Spain,0.84
10,Liechtenstein,0.82
11,Sweden,0.81
12,Belgium,0.73
13,Switzerland,0.70
14,United Kingdom,0.53
15,Austria,0.51
16,France,0.41
17,Netherlands,0.40
18,Finland,0.38
19,Albania,0.31
20,Malta,0.29
-,European Union,0.25
21,Italy,0.23
22,Denmark,0.22
23,Macedonia,0.18
23,Monaco,0.18
25,Czech Republic,0.14
26,Andorra,0.07
26,Portugal,0.07
28,Slovakia,0.01
29,Greece,-0.03
30,Georgia,-0.05
31,Russia,-0.06
32,Poland,-0.11
33,Bosnia and Herzegovina,-0.14
34,Germany,-0.16
35,Armenia,-0.18
36,Belarus,-0.21
37,Hungary,-0.24
38,Slovenia,-0.29
39,Romania,-0.32
40,Montenegro,-0.35
41,Ukraine,-0.39
42,Serbia,-0.46
43,Croatia,-0.50
44,Estonia,-0.54
45,Bulgaria,-0.60
46,Moldova,-1.04
47,Lithuania,-1.06
48,Latvia,-1.07