Home > Software engineering >  Choropleth map coloring
Choropleth map coloring

Time:01-16

I am creating a choropleth map in d3 v6, but the map is showing only one color. I want the map to be covered based on total_cases. This is the code I am using:

// The svg
const margin ={ top: 500, bottom: 500, left: 100, right: 0},
width = 600,
height = 500;

//Choropleth Map
const svg1 = d3.select('body')
  .append('svg')
    .attr('width', width   margin.left   margin.right)
    .attr('height', height   margin.top   margin.bottom)

// Map and projection
const path = d3.geoPath();
const projection = d3.geoMercator()
  .scale(70)
  .center([0,20])
  .translate([width / 2, height / 2]);

// Data and color scale
const data = new Map();
const colorScale = d3.scaleThreshold()
  .domain([0, 300000000])
  .range(d3.schemeBlues[9]);

// Load external data and boot
Promise.all([
d3.json("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson"),
d3.csv("mapdata.csv", function(d) {
    data.set(d.country,  d.total_cases_per_million);
})
]).then(function(loadData){
    let topo = loadData[0]
    console.log(data);

    let mouseOver = function(d) {
    d3.selectAll(".Country")
      .transition()
      .duration(200)
      .style("opacity", .5)
    d3.select(this)
      .transition()
      .duration(200)
      .style("opacity", 1)
      .style("stroke", "black")
  }

  let mouseLeave = function(d) {
    d3.selectAll(".Country")
      .transition()
      .duration(200)
      .style("opacity", .8)
    d3.select(this)
      .transition()
      .duration(200)
      .style("stroke", "transparent")
  }

  // Draw the map
  svg1.append("g")
    .selectAll("path")
    .data(topo.features)
    .enter()
    .append("path")
      // draw each country
      .attr("d", d3.geoPath()
        .projection(projection)
      )
      // set the color of each country
      .attr("fill", function (d) { 
        d.total = data.get(data.total_cases_per_million) || 0;
        return colorScale(d.total);
      })
      .style("stroke", "transparent")
      .attr("class", function(d){ return "Country" } )
      .style("opacity", .8)
      .on("mouseover", mouseOver )
      .on("mouseleave", mouseLeave )
})

This is how the map looks and I don't get any error message on the console. Would really appreciate it if someone could help me out!

enter image description hereThis is how the map looks and I don't get any error message on the console. Would really appreciate it if someone could help me out!

EDIT: The csv file looks like this

iso_code,country,total_cases_per_million 
AFG,Afghanistan,2917418.02 
ALB,Albania,58135447.4 
DZA,Algeria,3715179.438 
AND,Andorra,270897098

CodePudding user response:

In the Map object, you set the country name as the key:

data.set(d.country,  d.total_cases_per_million);

Also, in the GeoJSON, the country name is found under properties.name for each feature.

Therefore, this is how you should fill the paths:

.attr("fill", function (d) { 
    d.total = data.get(d.properties.name) || 0;
    return colorScale(d.total);
})

The CSV you pasted is incorrect, it has spaces after the numbers, check that.

Finally, the threshold scale is not the adequate choice, even more given that you have only two values in the domain. You can use a linear scale, or, most commonly used in choropleths, a quantile or a quantize scale. You can still use a threshold scale, but set the thresholds adequately.

  • Related