Choropleth map with D3
A choropleth map is a type of thematic map in which areas are shaded or patterned according to a data variable. The variable is categorized into intervals, with each interval represented by a colour, and the map filled accordingly. Colour progression is used to represent the differences, often blending from dark to light or one colour to another.
More about: Chorepleth map
Chorepleth map
<!DOCTYPE html>
<meta charset="utf-8">
<!-- Include d3 library -->
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-geo@"></script>
<script src="https://cdn.jsdelivr.net/npm/d3-geo-projection@4"></script>
<script src="https://unpkg.com/topojson@3"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.25.6/d3-legend.min.js"></script>
<!-- Create a container to host the chart -->
<div id="viz_container"></div>
//set svg parameters
const width = 450,
height = 350;
const svg = d3.select("#viz_container")
.append("svg")
.attr("width", "100%")
.attr("height", "100%")
.attr("viewBox","0 0 450 350")
.attr("preserveAspectRatio","xMinYMin");
// set map scale, location on screen and its projection
const projection = d3.geoRobinson()
.scale(85)
.center([0, 0])
.translate([width/2.2, height/2]);
// path generator
const path = d3.geoPath()
.projection(projection);
// set color scale
const color = d3.scaleThreshold()
.domain([10000,100000,1000000,1000000])
.range(["#DCE9FF", "#8EBEFF", "#589BE5", "#0072BC"])
.unknown("#E6E6E6");
//declare polygon and polyline
const poly = svg.append("g");
const line = svg.append("g");
// declare URL
const dataURL = "https://raw.githubusercontent.com/GDS-ODSSS/unhcr-dataviz-platform/master/data/geospatial/choropleth_map.csv";
const polygonsURL = "https://raw.githubusercontent.com/GDS-ODSSS/unhcr-dataviz-platform/master/data/geospatial/world_polygons_simplified.json";
const polylinesURL = "https://raw.githubusercontent.com/GDS-ODSSS/unhcr-dataviz-platform/master/data/geospatial/world_lines_simplified.json";
// load data
const promises = [
d3.json(polygonsURL),
d3.csv(dataURL)
];
Promise.all(promises).then(ready)
function ready([topology, population]) {
// prepare pop data to join shapefile
const data = {};
population.forEach(function(d){
data[d.iso3] = +d.refugees
});
// set mouse events
const mouseover = function(d) {
d3.selectAll(".countries")
.transition()
.duration(100)
.style("opacity", .3)
d3.select(this)
.transition()
.duration(100)
.style("opacity", 1)
};
const mouseleave = function(d) {
d3.selectAll(".countries")
.transition()
.duration(100)
.style("opacity", 1)
d3.select(this)
.transition()
.duration(100)
.style("opacity", 1)
};
// load and draw polygons
poly
.selectAll("path")
.data(topojson.feature(topology, topology.objects.world_polygons_simplified).features)
.join("path")
.attr("fill", function(d) { return color(d.refugees = data[d.properties.color_code])})
.attr("d", path)
.attr("class", function(d){ return "countries" })
.on("mouseover", mouseover)
.on("mouseleave", mouseleave)
.append("title")
.text(function(d) { return `${d.properties.gis_name} \nRefugee Population: ${d3.format(",")(d.refugees)}`
}
)};
//load and draw lines
d3.json(polylinesURL).then(function(topology) {
line
.selectAll("path")
.data(topojson.feature(topology, topology.objects.world_lines_simplified).features)
.enter()
.append("path")
.attr("d", path)
.style("fill","none")
.attr("class", function(d) {return d.properties.type;})
});
//zoom function
const zoom = true
if (zoom){
var zoomFunction = d3.zoom()
.scaleExtent([1, 8])
.on('zoom', function(event) {
poly.selectAll('path')
.attr('transform', event.transform);
line.selectAll('path')
.attr('transform', event.transform);
});
svg.call(zoomFunction);
};
// set legend
svg.append("g")
.attr("class", "legendThreshold")
.attr("transform", "translate(5,255)");
const legend = d3.legendColor()
.labelFormat(d3.format(",.0f"))
.labels(d3.legendHelpers.thresholdLabels)
.labelOffset(3)
.shapePadding(0)
.scale(color);
svg.select(".legendThreshold")
.call(legend);
// set note
svg
.append('text')
.attr('class', 'note')
.attr('x', width*0.01)
.attr('y', height*0.96)
.attr('text-anchor', 'start')
.style('font-size', 7)
.text('Source: UNHCR Refugee Data Finder');
svg
.append('text')
.attr('class', 'note')
.attr('x', width*0.01)
.attr('y', height*0.99)
.attr('text-anchor', 'start')
.style('font-size', 7)
.text('The boundaries and names shown and the designations used on this map do not imply official endorsement or acceptance by the United Nations.');