Search code examples
javascriptd3.jsmathlogarithm

Logarithmic scale returns NaN


I have issues creating a logarithmic scale in d3. The scale works fine if it is set to linear.

This works:

var myLinScale = d3.scale.linear()
      .domain([0, 100])
      .range([50, 1150]);

console.log(myLinScale(71)); //output = 831

However, this doesn't work:

var myLogScale = d3.scale.log()
      .domain([0, 100])
      .range([50, 1150]);

console.log(myLogScale(71)); //output = NaN

What is wrong with the logarithmic scale?


Solution

  • New solution (using D3 v5.8)

    After more than 2 years this question finally has a D3-based answer that doesn't suggest removing 0 from the domain, as I did in my original answer (see below).

    This is possible due to the new Symlog scale in D3 v5.8, based on a by-symmetric log transformation, which allows 0 in the domain.

    So, using your domain and range without any modification:

    var myLogScale = d3.scaleSymlog()
      .domain([0, 100])
      .range([50, 1150]);
    
    console.log(myLogScale(71));
    <script src="https://d3js.org/d3.v5.min.js"></script>

    Or even shorter, with the new scale constructors in D3 v5.8:

    var myLogScale = d3.scaleSymlog([0, 100], [50, 1150]);
    
    console.log(myLogScale(71));
    <script src="https://d3js.org/d3.v5.min.js"></script>


    Original answer (for D3 v3)

    Change your domain so it doesn't include or cross zero:

    var myLogScale = d3.scale.log()
          .domain([1e-6, 100])//domain doesn't include zero now
          .range([50, 1150]);
    
    console.log(myLogScale(71));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

    In the above demo I'm using 1e-6, which is 0.000001.

    Explanation:

    The logarithm of zero is undefined (or not defined). In base 10, for instance, log(0) is a number x so that 10 raised to the power of x is zero... that number, of course, doesn't exist. The limit, however, when we approach zero from the positive side is minus infinity.

    In pure JavaScript:

    console.log("Log of 0 is: " + Math.log(0))

    Thus, in JavaScript, log(0) is negative infinity, or minus infinity.

    That being said, according to the API:

    a log scale must have either an exclusively-positive or exclusively-negative domain; the domain must not include or cross zero. (emphasis mine)