简体   繁体   中英

D3 Javascript Map Scale Scattered Data

I am totally a beginner, and I am building a map with more than 5,000 municipalities. In this case the data is very scattered, for example the population is in a range from 10,000 to 11,500,000. So in a research in the internet I found a walkthrough to build a map in JS D3. And I succeed following the steps. But the scale is my problem.

The scale is defined according the code below that takes the min to max range divided for 15 equal linear limits. The problem is this takes to a first range of 0 to 766,000 what involves more than 95% of the municipalities. So I have a monochromatic map. Due to the scattered data I think that a logarithmic scale would be more appropriate to show a more realistic diffusion of Data. Can someone help me with this?

var quantize = d3.scale.quantize()
  .range(d3.range(15).map(function(i) { return 'q' + i + '-15'; }));
var formatNumber = d3.format(",");
var legendX = d3.scale.linear();

var legendXAxis = d3.svg.axis()
.scale(legendX)
.orient("bottom")
.tickSize(4)
.tickFormat(function(d) {
    return formatNumber(d);
});

var legendSvg = d3.select('#legend').append('svg')
.attr('width', '100%')
.attr('height', '55');

var g = legendSvg.append('g')
    .attr("class", "legend-key YlGnBu")
    .attr("transform", "translate(" + 25 + "," + 25 + ")");

g.selectAll("rect")
    .data(quantize.range().map(function(d) {
      return quantize.invertExtent(d);
    }))
.enter().append("rect");

  var legendWidth = d3.select('#map').node().getBoundingClientRect().width - 50;

  var legendDomain = quantize.range().map(function(d) {
    var r = quantize.invertExtent(d);
    return r[1];
  legendDomain.unshift(quantize.domain()[0]);

By definition, quantize scales are linear:

Quantize scales are a variant of linear scales with a discrete rather than continuous range.

However, we can achieve what you want by mixing some scales: d3.scale.pow() and d3.scale.threshold() .

First, we use a power scale to define a exponential set of limits. Let's say that the minimum is 0 and the maximum is ten millions. So, for 15 colours (what you're using now), you can use this:

 var min = 0, max = 10000000; var logScale = d3.scale.pow() .exponent(2) .domain([0,15]) .range([min,max]); var limits = d3.range(15).map(d=>logScale(d)); console.log(limits); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> 

Now, we use this limits array in a threshold scale:

Threshold scales are similar to quantize scales, except they allow you to map arbitrary subsets of the domain to discrete values in the range. (emphasis mine)

This is the scale:

var myScale = d3.scale.threshold()
    .domain(limits)
    .range(your colors here);

Here is a demo (I'm using letters for the colours):

 var min = 0, max = 10000000; var logScale = d3.scale.pow() .exponent(2) .domain([0,15]) .range([min,max]); var limits = d3.range(15).map(d=>logScale(d)); limits.shift(); var myScale = d3.scale.threshold() .domain(limits) .range("abcdefghijklmno".split("")); console.log(myScale(90)) console.log(myScale(50000)) console.log(myScale(800000)) 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> 

PS : have in mind that you'll have to refactor most of your code, since you're not using quantize anymore in this suggested solution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM