An example of a column chart visualising NSS scores per question 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.
license: mit |
An example of a column chart visualising NSS scores per question 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> | |
<style> | |
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } | |
text { | |
font-family: monospace; | |
} | |
.outline { | |
fill: none; | |
} | |
.below-bar { | |
fill: #d7191c; | |
} | |
.eq-bar { | |
fill: #c9c9c9; | |
} | |
.above-bar { | |
fill: #2c7bb6; | |
} | |
.legend-label { | |
font-size: 11px; | |
} | |
</style> | |
</head> | |
<body> | |
<script> | |
var margin = {top: 100, right: 200, bottom: 100, left: 100}; | |
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 + ")"); | |
function getValues(d) { | |
for (var i = 1; i <= 27; i++) { | |
d[i] = +d[i]; | |
} | |
return d; | |
} | |
var englandMode = true; | |
var x = d3.scaleBand() | |
.range([0, width]) | |
.padding(0.2); | |
var y = d3.scaleLinear() | |
.range([height, 0]); | |
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(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; | |
}); | |
var resultsByQuestion = d3.range(27); | |
resultsByQuestion = resultsByQuestion.map(d => c = { | |
belowEng: 0, | |
equalEng: 0, | |
aboveEng: 0, | |
belowImp: 0, | |
equalImp: 0, | |
aboveImp: 0 | |
}); | |
results.forEach(d => { | |
d.englandAvgDiff.forEach((x, i) => { | |
if (x > 0) resultsByQuestion[i].aboveEng++; | |
if (x < 0) resultsByQuestion[i].belowEng++; | |
if (x == 0) resultsByQuestion[i].equalEng++; | |
}) | |
d.imperialAvgDiff.forEach((x, i) => { | |
if (x > 0) resultsByQuestion[i].aboveImp++; | |
if (x < 0) resultsByQuestion[i].belowImp++; | |
if (x == 0) resultsByQuestion[i].equalImp++; | |
}) | |
}); | |
x.domain(d3.range(27)); | |
y.domain([0, results.length]); | |
var title = svg.append("g") | |
.attr("transform", "translate(" + [width / 2, -30] + ")"); | |
title.append("text") | |
.attr("text-anchor", "middle") | |
.text("No. of Departments w/ Scores Above or Below England Avg Per Question"); | |
var legend = svg.append("g") | |
.attr("transform", "translate(" + [width + margin.right / 5, 0] + ")"); | |
legend.selectAll("rect") | |
.data(["above-bar", "eq-bar", "below-bar"]) | |
.enter().append("rect") | |
.attr("class", d => d) | |
.attr("y", (d, i) => (height / 3) * i) | |
.attr("height", d => height / 3) | |
.attr("width", x.bandwidth()); | |
legend.append("rect") | |
.attr("class", "outline") | |
.attr("height", height) | |
.attr("width", x.bandwidth()); | |
legend.selectAll("text") | |
.data(["Above", "Equal", "Below"]) | |
.enter().append("text") | |
.attr("class", "legend-label") | |
.attr("y", (d, i) => (height / 3) * i) | |
.attr("x", x.bandwidth()) | |
.attr("dx", 10) | |
.attr("dy", height / 6) | |
.text(d => d) | |
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(" + [-5, 0] + ")"); | |
yAxis.select(".domain").style("opacity", 0); | |
var xAxisGroup = svg.append("g") | |
.attr("class", "x-axis-group") | |
.attr("transform", "translate(" + [0, height] + ")") | |
var xAxis = xAxisGroup.append("g") | |
.attr("class", "x-axis") | |
.call(d3.axisBottom(x).tickSize(0).tickFormat(d => d + 1)); | |
xAxis.attr("transform", "translate(" + [0, 5] + ")") | |
xAxis.select(".domain").style("opacity", 0); | |
var xLabel = xAxisGroup.append("text") | |
.attr("transform", "translate(" + [width / 2, margin.bottom / 2] + ")") | |
.attr("text-anchor", "middle") | |
.text("Question Number") | |
var barGroups = svg.append("g") | |
.attr("class", "bar-groups") | |
.selectAll("g") | |
.data(resultsByQuestion) | |
.enter().append("g") | |
.attr("class", "bar-group") | |
.attr("transform", (d, i) => "translate(" + [x(i), 0] + ")") | |
var aboveBars = barGroups.append("rect") | |
.attr("class", "above-bar") | |
.attr("y", d => y(d.belowEng + d.equalEng + d.aboveEng)) | |
.attr("height", d => height - y(d.belowEng + d.equalEng + d.aboveEng)) | |
.attr("width", x.bandwidth()); | |
var eqBars = barGroups.append("rect") | |
.attr("class", "eq-bar") | |
.attr("y", d => y(d.equalEng + d.belowEng)) | |
.attr("height", d => height - y(d.equalEng + d.belowEng)) | |
.attr("width", x.bandwidth()); | |
var belowBars = barGroups.append("rect") | |
.attr("class", "below-bar") | |
.attr("y", d => y(d.belowEng)) | |
.attr("height", d => height - y(d.belowEng)) | |
.attr("width", x.bandwidth()); | |
var outlines = barGroups.append("rect") | |
.attr("class", "outline") | |
.attr("height", d => y(0)) | |
.attr("width", x.bandwidth()); | |
d3.select("svg").on("click", switchBetween); | |
function switchBetween() { | |
function newY(d) { | |
var aY, eY, bY; | |
if (englandMode) { | |
aY = y(d.belowImp + d.equalImp + d.aboveImp), | |
eY = y(d.equalImp + d.belowImp), | |
bY = y(d.belowImp); | |
} else { | |
aY = y(d.belowEng + d.equalEng + d.aboveEng), | |
eY = y(d.equalEng + d.belowEng), | |
bY = y(d.belowEng); | |
} | |
return [aY, eY, bY]; | |
} | |
aboveBars | |
.transition() | |
.attr("y", d => newY(d)[0]) | |
.attr("height", d => height - newY(d)[0]); | |
eqBars | |
.transition() | |
.attr("y", d => newY(d)[1]) | |
.attr("height", d => height - newY(d)[1]); | |
belowBars | |
.transition() | |
.attr("y", d => newY(d)[2]) | |
.attr("height", d => height - newY(d)[2]); | |
if (englandMode) { | |
title.select("text") | |
.text("No. of Departments w/ Scores Above or Below Imperial Avg Per Question"); | |
} else { | |
title.select("text") | |
.text("No. of Departments w/ Scores Above or Below England Avg Per Question"); | |
} | |
englandMode = !englandMode; | |
} | |
}); | |
</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 | |
Other Med | 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 | |
Other Bio | 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 | |
Phys & Astro | 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 | |
Maths & Stats | 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 | |
Computing | 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 | |
Gen Eng | 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 | |
Mech Eng | 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 | |
Aero Eng | 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 | |
E&E Eng | 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 | |
Civ Eng | 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 | |
Chem Eng | 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 | |
Business | 0.79 | 0.64 | 0.71 | 0.67 | 0.69 | 0.76 | 0.76 | 0.57 | 0.67 | 0.50 | 0.55 | 0.79 | 0.57 | 0.59 | 0.62 | 0.69 | 0.79 | 0.81 | 0.83 | 0.88 | 0.56 | 0.88 | 0.80 | 0.69 | 0.66 | 0.59 | 0.66 | |
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 |