Why is my choropleth coming out all the same colour?

222 Views Asked by At

This is my first question on here so please bear with.

I'm trying to make a choropleth (a map where different sections are coloured in based on some value assigned to them) using d3.js. I'm using the example given at https://www.d3-graph-gallery.com/graph/choropleth_basic.html, but changing the map to one of Scotland and changing the values to population density.

When I run it, I get a map but it's all coloured in the same shade of blue. I've tried changing the domain of colorScale but to no avail.

This is what I've got at the minute:

// The svg
var svg = d3.select("svg"),
  width = +svg.attr("width"),
  height = +svg.attr("height");

// Map and projection
var path = d3.geoPath();
var projection = d3.geoNaturalEarth()
  .scale(20 * width / Math.PI)
  .translate([width / 2 + 150, height / 2 + 2500]);


// Data and color scale
var data = d3.map();
var colorScale = d3.scaleThreshold()
  .domain([0, 600])
  .range(d3.schemeBlues[7]);

// Load external data and boot
d3.queue()
  .defer(d3.json, "https://raw.githubusercontent.com/squirrel-star/scotland/main/geojsonscotlandladjson.geojson")
  .defer(d3.csv, "https://raw.githubusercontent.com/squirrel-star/scotland/main/scotlanddensitywithid.csv", function(d) {
    data.set(d.code, +d.density);
  })
  .await(ready);

function ready(error, topo) {

  console.log(data);

  // Draw the map
  svg.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(d.id) || 0;
      return colorScale(d.total);
    });
}
<script src="https://d3js.org/d3.v4.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<script src="https://d3js.org/d3-geo-projection.v2.min.js"></script>
<svg id="my_dataviz" width="400" height="400"></svg>

Any suggestions for fixing it would be greatly appreciated. Thank you!

1

There are 1 best solutions below

0
On BEST ANSWER

I think you may have misread the documentation for d3.scaleThreshold, because it says you need to have N values in your domain if you have N + 1 values in your range. In your case, that makes N = 6.

Also, d.id didn't exist. I used d.properties.LAD13NM instead, because that field contained the name of the relevant county.

Finally, there was no need to use a map, since you were only using it as an object of some sorts, so I just replaced it with a regular object.

// The svg
var svg = d3.select("svg"),
  width = +svg.attr("width"),
  height = +svg.attr("height");

// Map and projection
var path = d3.geoPath();
var projection = d3.geoNaturalEarth()
  .scale(20 * width / Math.PI)
  .translate([width / 2 + 150, height / 2 + 2500]);


// Data and color scale
var data = {};
var colorScale = d3.scaleThreshold()
  .domain([100, 200, 300, 400, 500, 600])
  .range(d3.schemeBlues[7]);

// Load external data and boot
d3.queue()
  .defer(d3.json, "https://raw.githubusercontent.com/squirrel-star/scotland/main/geojsonscotlandladjson.geojson")
  .defer(d3.csv, "https://raw.githubusercontent.com/squirrel-star/scotland/main/scotlanddensitywithid.csv", function(d) {
    data[d.code] = +d.density;
  })
  .await(ready);

function ready(error, topo) {
  // Draw the map
  svg.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[d.properties.LAD13NM] || 0;
      return colorScale(d.total);
    });
}
<script src="https://d3js.org/d3.v4.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<script src="https://d3js.org/d3-geo-projection.v2.min.js"></script>
<svg id="my_dataviz" width="400" height="400"></svg>