D3
OG
Old school D3 from simpler times
All examples
By author
By category
About
tlfrd
Full window
Github gist
Heat Map
Visualising the results of Imperial's 2017 NSS as a Heat Map.
<!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; } .score rect { fill: none; } text { opacity: 0.7; font-family: 'Open Sans', sans-serif; } .legend-labels { font-size: 16px; } .score-labels { font-size: 15px; } .x-label { font-weight: 600; } .uni-labels { font-size: 14px; } .annotation { font-size: 12px; } </style> </head> <body> <script> var margin = {top: 100, right: 100, bottom: 125, left: 250}; 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 + ")"); var negativeScale = d3.scaleLinear().range(["red", "white"]); var positiveScale = d3.scaleLinear().range(["white", "green"]); var config = {}; function getValues(d) { for (var i = 1; i <= 27; i++) { d[i] = +d[i]; } return d; } 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; d.engAvgDiffSum = d3.sum(d.englandAvgDiff); d.impAvgDiffSum = d3.sum(d.imperialAvgDiff); }); results.sort(function(a, b) { if (a.engAvgDiffSum < b.engAvgDiffSum) return 1; if (a.engAvgDiffSum > b.engAvgDiffSum) return -1; return 0; }) var rectWidth = width / results[0].englandAvgDiff.length, rectHeight = height / results.length; var grid = svg.append("g") .attr("class", "grid"); var max = d3.max(results, function(d) { return d3.max(d.englandAvgDiff, function(x) { return +x; }) }); var min = d3.min(results, function(d) { return d3.min(d.englandAvgDiff, function(x) { return +x; }) }); var maxAbs = Math.max(Math.abs(max), Math.abs(min)); negativeScale.domain([-maxAbs, 0]); positiveScale.domain([0, maxAbs]); var xLabel = svg.append("g") .attr("transform", "translate(" + [width / 2, -margin.top / 2] + ")") .append("text") .attr("class", "x-label") .attr("text-anchor", "middle") .text("How each Department Scores per NSS Question"); var annotation = svg.append("g") .attr("transform", "translate(" + [width / 2, height + margin.bottom / 3] + ")"); annotation.append("text") .attr("class", "annotation") .text("*Molecular Biology, Biophysics, and Biochemisty") var universities = grid.selectAll("g") .data(results) .enter().append("g") .attr("class", "university") .attr("transform", (d, i) => "translate(" + [0, i * rectHeight] + ")"); var universityLabels = universities.append("text") .attr("class", "uni-labels") .attr("text-anchor", "end") .attr("x", -10) .attr("y", rectHeight) .attr("dy", -3) .text(d => d.department); var scoreLabels = grid.append("g") .attr("class", "score-labels") .selectAll("text") .data(d3.range(results[0].englandAvgDiff.length)) .enter().append("text") .attr("x", d => (rectWidth * d) + rectWidth / 2) .attr("dy", -10) .attr("text-anchor", "middle") .text(d => d + 1); var scores = universities.selectAll("g") .data(d => d.englandAvgDiff) .enter().append("g") .attr("class", "score") .attr("transform", (d, i) => "translate(" + [i * rectWidth, 0] + ")"); var scoreRect = scores.append("rect") .attr("width", rectWidth + 1) .attr("height", rectHeight + 2) .style("fill", function(d) { if (d < 0) { return negativeScale(d); } else if (d > 0) { return positiveScale(d); } else { return "#fff"; } }); var legend = svg.append("g") .attr("class", "legend") .attr("transform", "translate(" + [0, height + 50] + ")"); var colours = legend.selectAll("rect") .data(d3.range(-maxAbs, maxAbs + maxAbs/3, maxAbs/3)) .enter().append("rect") .attr("x", (d, i) => i * rectWidth) .attr("width", rectWidth + 1) .attr("height", rectHeight) .style("fill", function(d) { if (d < 0) { return negativeScale(d); } else if (d > 0) { return positiveScale(d); } else { return "#fff"; } }); var legendOffsets = 30; var legendLabels = legend.append("g") .attr("class", "legend-labels") .attr("transform", "translate(" + [-legendOffsets, -10] + ")") legendLabels.append("text") .attr("text-anchor", "start") .text("← Below Avg") legendLabels.append("text") .attr("x", rectWidth * 7 + legendOffsets * 2) .attr("text-anchor", "end") .text("Above Avg →") }); </script> </body>
https://d3js.org/d3.v4.min.js