Example of sequencing through temporal data using D3.js. Script binds CSV data to geometries at runtime.
Updated from Yet another animated choropleth map ...
Example of sequencing through temporal data using D3.js. Script binds CSV data to geometries at runtime.
Updated from Yet another animated choropleth map ...
id | 2010 | 2011 | 2012 | 2013 | 2014 | 2015 | 2016 | |
---|---|---|---|---|---|---|---|---|
1 | 5.0989242 | 5.1071601 | 5.1251884 | 5.1423388 | 5.1451654 | 5.146771 | 5.1470571 | |
2 | 4.9367247 | 4.9445963 | 4.9618983 | 4.978291 | 4.9809551 | 4.9825864 | 4.9827614 | |
3 | 5.0192266 | 5.0273027 | 5.0450058 | 5.0618234 | 5.0645833 | 5.0661912 | 5.0664377 | |
4 | 5.4870582 | 5.4958878 | 5.5151806 | 5.5335665 | 5.5366168 | 5.53829 | 5.5386457 | |
5 | 4.7672024 | 4.7748523 | 4.791666 | 4.8075972 | 4.8101869 | 4.8117704 | 4.8119426 | |
6 | 4.8474455 | 4.8552446 | 4.8723626 | 4.8886042 | 4.8912573 | 4.8928399 | 4.8930478 | |
7 | 4.856298 | 4.86413 | 4.8813052 | 4.897615 | 4.9002881 | 4.9018579 | 4.9020863 | |
8 | 5.1594591 | 5.1678715 | 5.186233 | 5.2037487 | 5.206665 | 5.2082362 | 5.2085986 | |
9 | 5.0730085 | 5.0812154 | 5.0991807 | 5.1162705 | 5.1190867 | 5.120688 | 5.1209717 | |
10 | 4.9116721 | 4.9195366 | 4.9368153 | 4.9531932 | 4.9558587 | 4.9574776 | 4.9576635 | |
11 | 5.0580745 | 5.0663204 | 5.0843325 | 5.1015019 | 5.1043539 | 5.1059117 | 5.1062493 | |
12 | 4.8068585 | 4.8144374 | 4.831162 | 4.8469458 | 4.8494754 | 4.8511348 | 4.851213 | |
13 | 4.9077721 | 4.9156227 | 4.9328814 | 4.9492307 | 4.9518857 | 4.9535146 | 4.9536872 | |
14 | 4.921865 | 4.9298401 | 4.9473066 | 4.9639139 | 4.9666467 | 4.968214 | 4.9684782 | |
15 | 5.0372849 | 5.045403 | 5.0631924 | 5.0800977 | 5.0828743 | 5.0844827 | 5.0847387 | |
16 | 5.1141939 | 5.122551 | 5.1407981 | 5.1581998 | 5.1610932 | 5.1626606 | 5.1630139 | |
17 | 4.2812109 | 4.2879834 | 4.3029666 | 4.3170729 | 4.3193126 | 4.3208456 | 4.3208642 | |
18 | 4.2709394 | 4.2777634 | 4.292841 | 4.307055 | 4.3093233 | 4.310842 | 4.3108873 | |
19 | 5.1829953 | 5.1915421 | 5.2101483 | 5.2279429 | 5.2309327 | 5.2324619 | 5.2328987 |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<title>Sequenced choropleth map</title> | |
<style> | |
#map { | |
width: 960px; | |
height: 480px; | |
margin: 18px auto 0; | |
background: whitesmoke; | |
position: relative; | |
} | |
#ui { | |
position: absolute; | |
left: 8px; | |
bottom: 8px; | |
} | |
#ui output { | |
padding: 3px 6px; | |
margin: 0 0 8px 0; | |
width: 40px; | |
border: 1px solid gray; | |
display: block; | |
text-align: center; | |
} | |
#ui input { | |
width: 280px; | |
} | |
.region { | |
stroke: #fff; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="map"> | |
<div id="ui"> | |
<output id="output">2010</output> | |
<input id="sequence" type='range' min="2010", max="2016", value="2010", step="1" > | |
</div> | |
</div> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<script src="https://unpkg.com/simple-statistics@4.1.0/dist/simple-statistics.min.js"></script> | |
<script> | |
(function(){ | |
var width = 960, | |
height = 480; | |
var svg = d3.select("#map") | |
.append("svg") | |
.attr("width", width) | |
.attr("height", height); | |
var projection = d3.geoConicEqualArea() | |
.center([0, -29]) | |
.rotate([-24,0]) | |
.scale(2000) | |
.translate([width / 2, height / 2]); | |
var path = d3.geoPath() | |
.projection(projection); | |
// colors from https://github.com/CartoDB/CartoColor/blob/master/cartocolor.js | |
var colors = ["#f9ddda", "#eda8bd", "#ce78b3", "#9955a8", "#573b88"]; | |
// function to take a number and output a color | |
var colorize = d3.scaleThreshold() | |
.range(colors); | |
d3.queue() | |
.defer(d3.json, 'sa.json') | |
.defer(d3.csv, 'data.csv') | |
.await(processData); | |
function processData(err, geoms, dataSet){ | |
// empty array for holding all values for later | |
// classifying data | |
var dataValues = []; | |
// loop through your geometry features | |
geoms.features.forEach(function(geom){ | |
// loop through CSV data | |
dataSet.forEach(function(data){ | |
// if they match | |
if(geom.properties.WMA_DWAF_I === +data.id){ | |
// loop through all years | |
for(var datum in data){ | |
// if isn't id code | |
if (datum != "id") { | |
// add CSV data to geom properties | |
geom.properties[datum] = +data[datum]; // convert from string to number | |
// push value to our array | |
dataValues.push(+data[datum]); | |
} | |
} | |
} | |
}) | |
}); | |
// determine cluster arrays from data values | |
var clusters = ss.ckmeans(dataValues, 5); | |
var breaks = clusters.map(function(cluster){ | |
// return the last element of the cluster array | |
return cluster.pop(); | |
}); | |
// remove last array item for colorize domain | |
breaks.splice(-1,1); | |
// update colorize function with domain values | |
colorize.domain(breaks); | |
// send updated geoms to be drawn | |
drawMap(geoms); | |
} | |
function drawMap(geoms) { | |
// append a g to the svg, use data from geoms | |
// and path generator to draw map | |
svg.append("g") | |
.selectAll("path") | |
.data(geoms.features) | |
.enter() | |
.append("path") | |
.attr("d", path) | |
.attr("class", "region"); | |
// call to color map with initial/min value | |
updateMap(d3.select("#sequence").attr("min")); | |
} | |
function updateMap(year) { | |
// select all the regions | |
d3.selectAll('.region') | |
.attr("fill", function(d){ | |
if(d.properties[year] != undefined) { | |
return colorize(d.properties[year]); | |
} else { | |
// something wrong with data | |
return 'lightgray' | |
} | |
}); | |
} | |
// IIFE to attach listeners to range UI | |
(function() { | |
// select the output | |
var output = d3.select("#output"); | |
// select range | |
d3.select('#sequence') | |
.on('input', function(d) { // when it changes | |
updateMap(+this.value); // update the map | |
output.html(+this.value) // update the output | |
}); | |
})(); | |
})(); | |
</script> | |
</body> | |
</html> |