Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not too nice ticks for big domains #264

Closed
ZiedHf opened this issue Jul 6, 2022 · 3 comments
Closed

Not too nice ticks for big domains #264

ZiedHf opened this issue Jul 6, 2022 · 3 comments

Comments

@ZiedHf
Copy link

ZiedHf commented Jul 6, 2022

I am not sure if this is what ticks should return for these domains or not. Is there a limit for the max and min ? Or maybe I am missing something to return nicer ticks ? It looks like a floating points problem.

// Good
scaleLinear().domain([0, 1e-21]).ticks(10)
/* [ 0,  1e-22,  2e-22,  3e-22,  4e-22,  5e-22,  6e-22,  7e-22, 8e-22, 9e-22, 1e-21 ] */

// Weird
scaleLinear().domain([0, 1e-22]).ticks(10)
/* [ 0, 1.0000000000000001e-23, 2.0000000000000002e-23, 3e-23, 4.0000000000000004e-23, 5e-23, 6e-23,  7.000000000000001e-23, 8.000000000000001e-23, 9.000000000000001e-23, 1e-22 ] */

// Good
scaleLinear().domain([0, 1e+23]).ticks(10)
/* [ 0, 1e+22, 2e+22, 3e+22, 4e+22, 5e+22, 6e+22, 7e+22, 8e+22, 9e+22, 1e+23 ] */

// Weird
scaleLinear().domain([0, 1e+24]).ticks(10)
/* [ 0, 1e+23, 2e+23, 2.9999999999999997e+23, 4e+23, 5e+23, 5.9999999999999995e+23, 6.999999999999999e+23, 8e+23, 9e+23, 1e+24 ] */
@mbostock
Copy link
Member

mbostock commented Jul 6, 2022

Not sure if we can do anything better here. Feel free to open a pull request if you have a suggestion for a change to the ticks algorithm.

@mbostock mbostock closed this as completed Jul 6, 2022
@ZiedHf
Copy link
Author

ZiedHf commented Jul 6, 2022

Yep, it's floating points issues.

// Problem
r0 + i * step;
0 + 3 * 2e+23; // This returns 5.9999999999999995e+23

It looks like using Big in the ticks method solve the issue. But maybe you don't prefer to use another dependencies to solve it ? I don't know.

Big(2e+23).mul(3).toString(); // 6e+23 Nice result !!

The ticks method

function ticks(start, stop, count) {
  var reverse,
      i = -1,
      n,
      ticks,
      step;

  stop = +stop, start = +start, count = +count;
  if (start === stop && count > 0) return [start];
  if (reverse = stop < start) n = start, start = stop, stop = n;
  if ((step = tickIncrement(start, stop, count)) === 0 || !isFinite(step)) return [];

  if (step > 0) {
    let r0 = Math.round(start / step), r1 = Math.round(stop / step);
    console.log(start, stop, step)
    console.log(r0, r1)
    if (r0 * step < start) ++r0;
    console.log(r0, r1)
    if (r1 * step > stop) --r1;
    console.log(r0, r1)
    ticks = new Array(n = r1 - r0 + 1);
    console.log(ticks, n)
    while (++i < n) ticks[i] = Number(Big(r0).add(i).mul(step).toString());
  } else {
    step = -step;
    let r0 = Math.round(start * step), r1 = Math.round(stop * step);
    if (r0 / step < start) ++r0;
    if (r1 / step > stop) --r1;
    ticks = new Array(n = r1 - r0 + 1);
    while (++i < n) ticks[i] = Number(Big(r0).add(i).div(step).toString());
  }

  if (reverse) ticks.reverse();

  return ticks;
}

@mbostock
Copy link
Member

mbostock commented Jul 6, 2022

JavaScript has native support for big integers now, so we could use that, but I don’t think I’d want to use big integers in the common path (since it’s rare that the domain is so big or so small). And it would need to be a new major version since it would reduce compatibility of d3-array with older JavaScript environments. So I probably don’t think this is worth it unless there is more evidence of demand.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants