D3: Mappa coropletica - Sagome dei Paesi
<style>
.country:hover {
stroke: #b64;
stroke-width: 1px;
}
</style>
<script>
let svg = d3.select("body").append("svg")
.attr("width",670).attr("height",350)
let margin = { top: 0, right: 0, bottom: 0, left: 40 }
let graphWidth = 670 - margin.left - margin.right
let graphHeight = 350 - margin.top - margin.bottom
let graph = svg.append("g")
.attr("transform", "translate("+margin.left+","+margin.top+")")
let projection = d3.geoNaturalEarth1()
projection.translate([graphWidth/2, graphHeight/2])
.scale(projection.scale() * (graphHeight/500))
let pathGenerator = d3.geoPath().projection(projection)
Promise.all([
d3.json("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson"),
d3.tsv("https://unpkg.com/world-atlas@1.1.4/world/50m.tsv")
]).then(function([geoData, tsvData]) {
let countryIncomes = {}
tsvData.forEach(d => {
countryIncomes[d.iso_a3] = d.income_grp
})
let incomeGroups = []
tsvData.forEach(d => {
if (!incomeGroups.includes(d.income_grp)) {
incomeGroups.push(d.income_grp)
}
})
let colorScale = d3.scaleOrdinal()
.domain(incomeGroups.sort())
.range(d3.schemeBlues[incomeGroups.length+1].slice().reverse())
graph.selectAll(".country")
.data(geoData.features)
.join("path")
.attr("class", "country")
.attr("d", pathGenerator)
.attr("fill", d => {
let incomeGroup = countryIncomes[d.id]
return incomeGroup ? colorScale(incomeGroup) : "#bbb"
})
.append("title")
.text(d => {
let countryName = d.properties.name
let incomeGroup = countryIncomes[d.id] || "Unclassified"
return countryName + ":\n" + incomeGroup
})
let legendY = svg.attr("height") - incomeGroups.length*18 - 20
let legend = svg.append("g")
.attr("class", "legend")
.attr("transform", "translate(10, " + legendY + ")")
incomeGroups.forEach((group, i) => {
let legendRow = legend.append("g")
.attr("transform", "translate(0, " + (i*18) + ")")
legendRow.append("rect")
.attr("width", 15)
.attr("height", 15)
.attr("fill", colorScale(group))
legendRow.append("text")
.attr("x", 22)
.attr("y", 12)
.style("font-family", "sans-serif")
.style("font-size", "12px")
.text(group)
})
})
</script>
Per semplificare e accelerare le operazioni successive, vengono ricavati alcuni dati dal file TSV.
L’oggetto countryIncomes conterrà un numero di proprietà pari alle righe del file TSV usando come chiavi i codici dei Paesi (d.iso_a3 ) e come valori i relativi gruppi di reddito (d.income_grp ). In questo modo il gruppo di reddito di un Paese si potrà ottenere semplicemente con: countryIncomes[ codicePaese ]
L’array incomGroups conterrà l’elenco dei possibili gruppi di reddito letti dalla colonna income_grp evitando di memorizzare più volte lo stesso valore.