Question

I have a very sparse dataset and I want to plot it in a histogram with a logarithmic scale. I would like the X axis to look something similar to:

[1, 10, 100, 1000, 10000]

Meaning that the first bin would include the observations with a cost of 1-10, the second 11-10 and so on, and the last would be +10.000.

function (pow, min, max) {
    var range = [];         
    for (i = min; i < max; i++) {
        range.push(Math.pow(pow, i));
    }
    return range;
}

I am able to generate the given array of powers of 10. Now, what I would like is to map a set of continuous values to that array, meaning that:

[1, 23, 2, 105, 2000, 30000]

would be output as:

[1, 10, 1, 100, 1000, 10000]

I have tried using d3.scale.threshold, but it does not seem to be working as expecting.

Was it helpful?

Solution 2

A d3 Threshold Scale splits a quantitive dataset into discrete categories based on threshold points that you choose.

Unlike simple linear scales, the domain of the the threshold scale is not the min and max values. Instead, the threshold scale's domain is the list of threshold values at which you want to split your data.

As with all d3 scales, the range is the desired output values. For a threshold scale, however, the number of output values in the range has to be equal to the number of threshold (domain) values plus one. The first value in the range is assigned to values that are less than the first threshold, the second value in the range is assigned to values that are equal to or greater than the first threshold but less than the second, and so on, until the last value in the range is assigned to values that are equal to or greater than the last value in the domain.

So to split an array of positive integers into categories based on powers of 10, you could use the powers of 10 as your domain, and a set of strings describing the categories as your range:

scale = d3.scale.threshold()
          .domain([1, 11, 101, 1001, 10001])
          .range(["<1", "1-10", "11-100", "101-1000", "1001-10,000", ">10,001"]);

Of course, depending on what you are using the scale for, a custom function like @Daniele Torino suggested may be more versatile, since it doesn't require you to specify max and min threshold above/below which everything gets bunched in the same category. But if that is what you want, the threshold scale above should do it.

OTHER TIPS

If you are just looking for a function that maps your values, all you need is some simple math:

function f(x) {
  return Math.pow(10, Math.floor(Math.log(x) / Math.log(10)));
}

alert( f(1) );
alert( f(23) );
alert( f(2) );
alert( f(105) );
alert( f(2000) );
alert( f(30000) );

I have no experience with d3 so I cannot help you there.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top