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

linear.nice should use d3.tickIncrement for precise rounding. #81

Closed
pavlin99th opened this issue Oct 18, 2016 · 3 comments
Closed

linear.nice should use d3.tickIncrement for precise rounding. #81

pavlin99th opened this issue Oct 18, 2016 · 3 comments
Assignees

Comments

@pavlin99th
Copy link

Say you want a nice linear scale and ticks for your [5.83, 6.2] domain.
Due to float calculations .nice() sets the domain to:

d3.scaleLinear().domain([5.83, 6.2]).nice().domain()
[5.800000000000001, 6.2]

and .ticks() returns:

d3.scaleLinear().domain([5.83, 6.2]).nice().ticks()
[5.8500000000000005, 5.9, 5.95, 6.000000000000001, 6.050000000000001, 6.1000000000000005, 6.15, 6.2]

Now you are missing the first 5.8 tick.

I know this happens because of float calculations (0.05 * 116), what is the best way to deal with the situation? Should it be solved by d3 or by a user?

I ended up with rounding and resetting the domain with the help of d3.format, but looking for a more general solution.

@mbostock
Copy link
Member

Thanks for the report. I think we can fix this without too much trouble. This will affect both d3-array and d3-scale, since the core tick methods are in d3-array, but the implementation of linear.nice will be affected. Rather than tracking this in both places, let’s just use d3/d3-array#45.

@pmalouin
Copy link

Just a heads up that I can still reproduce this issue with the latest version of d3-array (1.2.0). I expected d3/d3-array@04cf783 would solve the problem.

Here are my dependencies:

└─┬ d3-scale@1.0.5
  ├── d3-array@1.2.0
  ├── d3-collection@1.0.3
  ├── d3-color@1.0.3
  ├── d3-format@1.2.0
  ├── d3-interpolate@1.1.4
  ├── d3-time@1.0.6
  └── d3-time-format@2.0.5
> var d3Scale = require('d3-scale');
undefined
> d3Scale.scaleLinear().domain([5.83, 6.2]).nice().domain()
[ 5.800000000000001, 6.2 ]
> d3Scale.scaleLinear().domain([5.83, 6.2]).nice().ticks()
[ 5.85, 5.9, 5.95, 6, 6.05, 6.1, 6.15, 6.2 ]

@mbostock
Copy link
Member

No; linear scales still use d3.tickStep, not the new d3.tickIncrement, and so there’s no protection against rounding errors. See linear.js.

However, I don’t see any reason why we couldn’t update linear.nice to use d3.tickIncrement and thus guarantee exact behavior (within the limits of IEEE 754). So I’ll reopen and retitle this issue accordingly.

@mbostock mbostock reopened this Apr 18, 2017
@mbostock mbostock changed the title scale.nice float rounding issue linear.nice should use d3.tickIncrement for precise rounding. Apr 18, 2017
@mbostock mbostock self-assigned this Apr 18, 2017
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

3 participants