Skip to content

Instantly share code, notes, and snippets.

@tlfrd
Last active September 13, 2019 10:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save tlfrd/356896b8570ba156c4e6e9db71cc7ebb to your computer and use it in GitHub Desktop.
Save tlfrd/356896b8570ba156c4e6e9db71cc7ebb to your computer and use it in GitHub Desktop.
Stacked Bar Chart
license: mit
height: 700

An example of a stacked bar chart visualising NSS scores per department at Imperial.

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.

<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400, 600" rel="stylesheet">
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
text {
font-family: 'Open Sans', sans-serif;
}
.title {
font-size: 17px;
opacity: 0.7;
font-weight: 600;
}
.outline {
fill: none;
}
.below-bar {
fill: #a0448c;
}
.eq-bar {
fill: #b5b6b9;
}
.above-bar {
fill: #adce49;
}
.legend-label {
font-size: 14px;
opacity: 0.7;
}
.y-axis text {
font-size: 12px;
opacity: 0.7;
}
.bar-groups text {
fill: white;
font-weight: 600;
}
.annotation {
font-size: 12px;
opacity: 0.7;
}
</style>
</head>
<body>
<script>
var margin = {top: 150, right: 100, bottom: 125, left: 200};
var width = 960 - margin.left - margin.right,
height = 700 - 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 + ")");
function getValues(d) {
for (var i = 1; i <= 27; i++) {
d[i] = +d[i];
}
return d;
}
var x = d3.scaleLinear()
.range([0, width]);
var y = d3.scaleBand()
.range([0, height])
.padding(0.2);
d3.csv("nss-results.csv", getValues, function(error, results) {
if (error) throw error;
var englandAverage = results[results.length - 2],
imperialAverage = results[results.length - 1];
results = results.slice(0, -2);
results.forEach(function(d) {
var eng = [],
imp = [];
for (var i = 1; i <= 27; i++) {
eng[i - 1] = (d[i] - englandAverage[i]).toPrecision(2);
imp[i - 1] = (d[i] - imperialAverage[i]).toPrecision(2);
}
d.englandAvgDiff = eng;
d.imperialAvgDiff = imp;
});
results.forEach(function(d) {
var above = 0,
equal = 0,
below = 0;
for (var x in d.englandAvgDiff) {
if (+d.englandAvgDiff[x] < 0) {
below++;
} else if (+d.englandAvgDiff[x] > 0) {
above++;
} else {
equal++;
}
}
d.above = above;
d.equal = equal;
d.below = below;
});
results.sort(function(a, b) {
if (a.below < b.below) return 1;
if (a.below > b.below) return -1;
return 0;
})
x.domain([0, results[0].englandAvgDiff.length]);
y.domain(results.map(d => d.department));
var title = svg.append("g")
.attr("class", "title")
.attr("transform", "translate(" + [0, -margin.top / 2] + ")");
title.append("text")
.attr("text-anchor", "stat")
.text("No. of NSS Questions with Scores Above or Below the England Average");
var legend = svg.append("g")
.attr("transform", "translate(" + [0, -margin.top / 4] + ")");
legend.selectAll("rect")
.data(["below-bar", "eq-bar", "above-bar"])
.enter().append("rect")
.attr("class", d => d)
.attr("x", (d, i) => (width / 4) * i)
.attr("width", d => 20)
.attr("height", y.bandwidth());
legend.append("rect")
.attr("class", "outline")
.attr("width", width)
.attr("height", y.bandwidth());
legend.selectAll("text")
.data(["Below Average", "Equal To Average", "Above Average"])
.enter().append("text")
.attr("class", "legend-label")
.attr("x", (d, i) => (width / 4) * i + 30)
.attr("y", y.bandwidth() / 2)
.attr("dy", 5)
.text(d => d);
var annotation = svg.append("g")
.attr("transform", "translate(" + [0, height + margin.bottom / 3] + ")");
annotation.append("text")
.attr("class", "annotation")
.text("*Molecular Biology, Biophysics, and Biochemisty")
var yAxisGroup = svg.append("g")
.attr("class", "y-axis-group");
var yAxis = yAxisGroup.append("g")
.attr("class", "y-axis")
.call(d3.axisLeft(y).tickSize(0));
yAxis.attr("transform", "translate(" + [-10, -1] + ")")
yAxis.select(".domain").style("opacity", 0);
var xAxisGroup = svg.append("g")
.attr("class", "x-axis-group")
.attr("transform", "translate(" + [0, height] + ")")
var barGroups = svg.append("g")
.attr("class", "bar-groups")
.selectAll("g")
.data(results)
.enter().append("g")
.attr("class", "bar-group")
.attr("transform", d => "translate(" + [0, y(d.department)] + ")")
var lowerBars = barGroups.append("rect")
.attr("class", "below-bar")
.attr("x", 0)
.attr("width", d => x(d.below))
.attr("height", y.bandwidth());
var lowerLabels = barGroups.append("text")
.attr("x", d => x(d.below) / 2)
.attr("y", y.bandwidth())
.attr("text-anchor", "middle")
.text(d => d.below > 0 ? d.below : "");
var eqBars = barGroups.append("rect")
.attr("class", "eq-bar")
.attr("x", d => x(d.below))
.attr("width", d => x(d.equal))
.attr("height", y.bandwidth());
var eqLabels = barGroups.append("text")
.attr("x", d => x(d.below) + x(d.equal) / 2)
.attr("y", y.bandwidth())
.attr("text-anchor", "middle")
.text(d => d.equal > 0 ? d.equal : "");
var aboveBars = barGroups.append("rect")
.attr("class", "above-bar")
.attr("x", d => x(d.below + d.equal))
.attr("width", d => x(d.above))
.attr("height", y.bandwidth());
var aboveLabels = barGroups.append("text")
.attr("x", d => x(d.below) + x(d.equal) + x(d.above) / 2)
.attr("y", y.bandwidth())
.attr("text-anchor", "middle")
.text(d => d.above > 0 ? d.above : "");
barGroups.selectAll("text")
.attr("dy", -y.bandwidth() * 0.225)
.style("font-size", y.bandwidth() * 0.7)
var outlines = barGroups.append("rect")
.attr("class", "outline")
.attr("width", width + 1)
.attr("height", y.bandwidth());
});
</script>
</body>
department 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
Medicine 0.88 0.82 0.91 0.80 0.75 0.82 0.93 0.73 0.76 0.56 0.55 0.85 0.74 0.72 0.76 0.77 0.75 0.88 0.93 0.91 0.78 0.91 0.93 0.80 0.72 0.75 0.90
Biomedical Sciences 0.88 0.74 0.89 0.86 0.80 0.77 0.70 0.50 0.68 0.35 0.59 0.73 0.68 0.59 0.35 0.53 0.59 0.71 0.84 0.85 0.64 0.88 0.92 0.83 0.64 0.56 0.70
Biology 0.87 0.84 0.89 0.82 0.83 0.81 0.71 0.75 0.62 0.71 0.48 0.85 0.66 0.67 0.72 0.86 0.75 0.88 0.82 0.86 0.52 0.89 0.87 0.69 0.62 0.47 0.81
MBBPBC* 0.90 0.78 0.83 0.82 0.83 0.86 0.80 0.66 0.64 0.70 0.52 0.82 0.58 0.62 0.67 0.86 0.86 0.78 0.85 0.86 0.51 0.89 0.88 0.74 0.74 0.51 0.83
Chemistry 0.84 0.75 0.89 0.75 0.80 0.74 0.82 0.51 0.56 0.59 0.53 0.75 0.60 0.52 0.52 0.74 0.67 0.85 0.84 0.89 0.57 0.78 0.79 0.63 0.48 0.53 0.73
Physics 0.82 0.73 0.86 0.71 0.71 0.68 0.60 0.47 0.43 0.46 0.56 0.82 0.56 0.62 0.57 0.70 0.70 0.78 0.81 0.87 0.45 0.76 0.82 0.54 0.50 0.40 0.67
Geology 0.99 0.97 0.96 0.93 0.93 0.94 0.97 0.93 0.87 0.97 0.94 0.97 0.97 0.99 0.99 0.91 0.99 1.00 0.96 1.00 0.89 0.94 0.99 0.99 0.97 0.86 0.97
Mathematics 0.87 0.76 0.83 0.79 0.85 0.70 0.62 0.57 0.69 0.53 0.55 0.87 0.68 0.68 0.76 0.73 0.81 0.91 0.82 0.91 0.59 0.70 0.88 0.78 0.67 0.52 0.78
Computer Science 0.82 0.79 0.94 0.82 0.85 0.87 0.91 0.54 0.79 0.54 0.63 0.90 0.78 0.64 0.74 0.74 0.87 0.92 0.89 0.93 0.71 0.98 0.95 0.85 0.80 0.66 0.86
Bioengineering 0.92 0.91 0.97 0.86 0.91 0.97 0.85 0.57 0.74 0.77 0.66 0.91 0.80 0.69 0.86 0.82 0.85 0.80 0.81 0.91 0.85 0.94 0.92 0.94 0.83 0.57 0.97
Mechanical Engineering 0.91 0.83 0.93 0.87 0.91 0.90 0.88 0.77 0.81 0.78 0.83 0.90 0.87 0.88 0.85 0.83 0.92 0.85 0.88 0.89 0.74 0.99 0.99 0.84 0.89 0.57 0.86
Aerospace Engineering 0.71 0.67 0.81 0.75 0.72 0.77 0.74 0.65 0.67 0.43 0.57 0.86 0.73 0.59 0.70 0.70 0.75 0.90 0.87 0.87 0.57 0.96 0.86 0.61 0.57 0.53 0.78
EEE 0.88 0.81 0.92 0.85 0.88 0.89 0.86 0.75 0.71 0.60 0.65 0.86 0.69 0.68 0.80 0.79 0.88 0.89 0.88 0.97 0.72 0.96 0.92 0.80 0.85 0.66 0.86
Civil Engineering 0.93 0.81 0.94 0.88 0.86 0.89 0.93 0.69 0.75 0.87 0.69 0.96 0.90 0.82 0.90 0.90 0.90 0.96 0.96 0.94 0.85 0.97 0.94 0.92 0.79 0.77 0.94
Chemical Engineering 0.86 0.79 0.88 0.94 0.88 0.87 0.86 0.75 0.70 0.61 0.68 0.95 0.74 0.74 0.84 0.82 0.95 0.80 0.84 0.86 0.70 0.96 0.94 0.85 0.92 0.58 0.84
Materials 0.85 0.78 0.85 0.73 0.91 0.90 0.73 0.54 0.69 0.65 0.69 0.79 0.71 0.73 0.66 0.82 0.77 0.94 0.89 0.98 0.72 0.91 0.85 0.80 0.65 0.71 0.87
England Average 0.89 0.83 0.85 0.82 0.84 0.85 0.82 0.72 0.73 0.73 0.74 0.86 0.79 0.75 0.71 0.79 0.77 0.83 0.87 0.86 0.72 0.86 0.84 0.76 0.62 0.58 0.84
Imperial Average 0.87 0.80 0.89 0.82 0.83 0.83 0.82 0.66 0.69 0.62 0.62 0.87 0.73 0.70 0.74 0.78 0.81 0.87 0.87 0.91 0.68 0.90 0.90 0.78 0.73 0.61 0.84
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment