Skip to content

Instantly share code, notes, and snippets.

@brazilnut2000
Created May 8, 2018 03:40
Show Gist options
  • Save brazilnut2000/fc0a57518132ac9200f9094b5ef9f18b to your computer and use it in GitHub Desktop.
Save brazilnut2000/fc0a57518132ac9200f9094b5ef9f18b 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.

forked from tlfrd's block: Stacked Bar Chart

<!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