Skip to content

Commit

Permalink
merge with changes to main and use high precision Math methods
Browse files Browse the repository at this point in the history
  • Loading branch information
nickofthyme committed Dec 8, 2023
1 parent 28d1a03 commit c6ae425
Show file tree
Hide file tree
Showing 6 changed files with 236 additions and 289 deletions.
4 changes: 2 additions & 2 deletions src/nice.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {tickIncrement} from "./ticks.js";

export default function nice(start, stop, count, base) {
export default function nice(start, stop, count, log) {
let prestep;
while (true) {
const step = tickIncrement(start, stop, count, base);
const step = tickIncrement(start, stop, count, log);
if (step === prestep || step === 0 || !isFinite(step)) {
return [start, stop];
} else if (step > 0) {
Expand Down
38 changes: 24 additions & 14 deletions src/ticks.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,42 @@ const e10 = Math.sqrt(50),
e5 = Math.sqrt(10),
e2 = Math.sqrt(2);

function tickSpec(start, stop, count) {
const logParams = {
binary: [Math.log2, 2],
natural: [(n) => Math.log1p(n - 1), Math.E],
common: [Math.log10, 10],
}

function tickSpec(start, stop, count, log = 'common') {
const [logFn, base] = logParams[log] || logParams.common;
const step = (stop - start) / Math.max(0, count),
power = Math.floor(Math.log10(step)),
error = step / Math.pow(10, power),
factor = error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1;
power = Math.floor(logFn(step)),
error = step / Math.pow(base, power),
factor = error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1;
let i1, i2, inc;
if (power < 0) {
inc = Math.pow(10, -power) / factor;
inc = Math.pow(base, -power) / factor;
i1 = Math.round(start * inc);
i2 = Math.round(stop * inc);
if (i1 / inc < start) ++i1;
if (i2 / inc > stop) --i2;
inc = -inc;
} else {
inc = Math.pow(10, power) * factor;
inc = Math.pow(base, power) * factor;
i1 = Math.round(start / inc);
i2 = Math.round(stop / inc);
if (i1 * inc < start) ++i1;
if (i2 * inc > stop) --i2;
}
if (i2 < i1 && 0.5 <= count && count < 2) return tickSpec(start, stop, count * 2);
if (i2 < i1 && 0.5 <= count && count < 2) return tickSpec(start, stop, count * 2, log);
return [i1, i2, inc];
}

export default function ticks(start, stop, count) {
export default function ticks(start, stop, count, log) {
stop = +stop, start = +start, count = +count;
if (!(count > 0)) return [];
if (start === stop) return [start];
const reverse = stop < start, [i1, i2, inc] = reverse ? tickSpec(stop, start, count) : tickSpec(start, stop, count);
const reverse = stop < start, [i1, i2, inc] = reverse ? tickSpec(stop, start, count, log) : tickSpec(start, stop, count, log);
if (!(i2 >= i1)) return [];
const n = i2 - i1 + 1, ticks = new Array(n);
if (reverse) {
Expand All @@ -43,13 +50,16 @@ export default function ticks(start, stop, count) {
return ticks;
}

export function tickIncrement(start, stop, count) {
stop = +stop, start = +start, count = +count;
return tickSpec(start, stop, count)[2];
export function tickIncrement(start, stop, count, log) {
(stop = +stop), (start = +start), (count = +count);
return tickSpec(start, stop, count, log)[2];
}

export function tickStep(start, stop, count) {
export function tickStep(start, stop, count, log) {
stop = +stop, start = +start, count = +count;
const reverse = stop < start, inc = reverse ? tickIncrement(stop, start, count) : tickIncrement(start, stop, count);
const reverse = stop < start,
inc = reverse
? tickIncrement(stop, start, count, log)
: tickIncrement(start, stop, count, log);
return (reverse ? -1 : 1) * (inc < 0 ? 1 / -inc : inc);
}
34 changes: 17 additions & 17 deletions test/nice-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,23 +45,23 @@ it("nice(start, stop, count) returns the expected values", () => {
assert.deepStrictEqual(nice(132, 876, 1), [0, 1000]);
});

it("nice(start, stop, count, base) returns the expected values with base 2", () => {
assert.deepStrictEqual(nice(0.126, 0.51, 32, 2), [0.125, 0.515625]);
assert.deepStrictEqual(nice(0.126, 0.48, 10, 2), [0.125, 0.5]);
assert.deepStrictEqual(nice(0.126, 0.48, 6, 2), [0.125, 0.5]);
assert.deepStrictEqual(nice(0.126, 0.48, 5, 2), [0.125, 0.5]);
assert.deepStrictEqual(nice(0.126, 0.48, 1, 2), [0, 0.5]);
assert.deepStrictEqual(nice(129, 876, 1000, 2), [129, 876]);
assert.deepStrictEqual(nice(129, 876, 100, 2), [128, 880]);
assert.deepStrictEqual(nice(129, 876, 30, 2), [128, 896]);
assert.deepStrictEqual(nice(129, 876, 10, 2), [128, 896]);
assert.deepStrictEqual(nice(129, 876, 6, 2), [128, 896]);
assert.deepStrictEqual(nice(129, 876, 5, 2), [128, 896]);
assert.deepStrictEqual(nice(129, 876, 1, 2), [0, 1024]);
it("nice(start, stop, count, base) returns the expected values for binary log", () => {
assert.deepStrictEqual(nice(0.126, 0.51, 32, 'binary'), [0.125, 0.515625]);
assert.deepStrictEqual(nice(0.126, 0.48, 10, 'binary'), [0.125, 0.5]);
assert.deepStrictEqual(nice(0.126, 0.48, 6, 'binary'), [0.125, 0.5]);
assert.deepStrictEqual(nice(0.126, 0.48, 5, 'binary'), [0.125, 0.5]);
assert.deepStrictEqual(nice(0.126, 0.48, 1, 'binary'), [0, 0.5]);
assert.deepStrictEqual(nice(129, 876, 1000, 'binary'), [129, 876]);
assert.deepStrictEqual(nice(129, 876, 100, 'binary'), [128, 880]);
assert.deepStrictEqual(nice(129, 876, 30, 'binary'), [128, 896]);
assert.deepStrictEqual(nice(129, 876, 10, 'binary'), [128, 896]);
assert.deepStrictEqual(nice(129, 876, 6, 'binary'), [128, 896]);
assert.deepStrictEqual(nice(129, 876, 5, 'binary'), [128, 896]);
assert.deepStrictEqual(nice(129, 876, 1, 'binary'), [0, 1024]);
});

it("nice(start, stop, count, base) returns the expected values with base e", () => {
assert.deepStrictEqual(nice(Math.E + 0.1, Math.E * 3 + 0.1, 2, Math.E), [0, Math.E * 4]);
assert.deepStrictEqual(nice(-Math.E - 0.1, Math.E + 0.1, 2, Math.E), [-Math.E * 2, Math.E * 2]);
assert.deepStrictEqual(nice(-Math.E * 10 - 0.5, Math.E * 20 - 0.5, 30, Math.E), [-Math.E * 11, Math.E * 20]);
it("nice(start, stop, count, base) returns the expected values for natural log", () => {
assert.deepStrictEqual(nice(Math.E + 0.1, Math.E * 3 + 0.1, 2, 'natural'), [0, Math.E * 4]);
assert.deepStrictEqual(nice(-Math.E - 0.1, Math.E + 0.1, 2, 'natural'), [-Math.E * 2, Math.E * 2]);
assert.deepStrictEqual(nice(-Math.E * 10 - 0.5, Math.E * 20 - 0.5, 30, 'natural'), [-Math.E * 11, Math.E * 20]);
});
185 changes: 76 additions & 109 deletions test/tickIncrement-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,119 +63,86 @@ it("tickIncrement(start, stop, count) returns approximately count + 1 tickIncrem


describe("tickIncrement(start, stop, count, base) returns approximately count + 1 tickIncrement when start < stop", () => {
it("base 2", () => {
assert.strictEqual(tickIncrement( 0, 1, 10, 2), -8);
assert.strictEqual(tickIncrement( 0, 1, 9, 2), -8);
assert.strictEqual(tickIncrement( 0, 1, 8, 2), -8);
assert.strictEqual(tickIncrement( 0, 1, 7, 2), -8);
assert.strictEqual(tickIncrement( 0, 1, 6, 2), -8);
assert.strictEqual(tickIncrement( 0, 1, 5, 2), -4);
assert.strictEqual(tickIncrement( 0, 1, 4, 2), -4);
assert.strictEqual(tickIncrement( 0, 1, 3, 2), -4);
assert.strictEqual(tickIncrement( 0, 1, 2, 2), -2);
assert.strictEqual(tickIncrement( 0, 1, 1, 2), 1);
assert.strictEqual(tickIncrement( 0, 10, 10, 2), 1);
assert.strictEqual(tickIncrement( 0, 10, 9, 2), 1);
assert.strictEqual(tickIncrement( 0, 10, 8, 2), 1);
assert.strictEqual(tickIncrement( 0, 10, 7, 2), 2);
assert.strictEqual(tickIncrement( 0, 10, 6, 2), 2);
assert.strictEqual(tickIncrement( 0, 10, 5, 2), 2);
assert.strictEqual(tickIncrement( 0, 10, 4, 2), 2);
assert.strictEqual(tickIncrement( 0, 10, 3, 2), 4);
assert.strictEqual(tickIncrement( 0, 10, 2, 2), 4);
assert.strictEqual(tickIncrement( 0, 10, 1, 2), 8);
assert.strictEqual(tickIncrement(-10, 10, 10, 2), 2);
assert.strictEqual(tickIncrement(-10, 10, 9, 2), 2);
assert.strictEqual(tickIncrement(-10, 10, 8, 2), 2);
assert.strictEqual(tickIncrement(-10, 10, 7, 2), 4);
assert.strictEqual(tickIncrement(-10, 10, 6, 2), 4);
assert.strictEqual(tickIncrement(-10, 10, 5, 2), 4);
assert.strictEqual(tickIncrement(-10, 10, 4, 2), 4);
assert.strictEqual(tickIncrement(-10, 10, 3, 2), 8);
assert.strictEqual(tickIncrement(-10, 10, 2, 2), 8);
assert.strictEqual(tickIncrement(-10, 10, 1, 2), 16);
it("common", () => {
assert.strictEqual(tickIncrement( 0, 1, 10), -10);
assert.strictEqual(tickIncrement( 0, 1, 9), -10);
assert.strictEqual(tickIncrement( 0, 1, 8), -10);
assert.strictEqual(tickIncrement( 0, 1, 7), -5);
assert.strictEqual(tickIncrement( 0, 1, 6), -5);
assert.strictEqual(tickIncrement( 0, 1, 5), -5);
assert.strictEqual(tickIncrement( 0, 1, 4), -5);
assert.strictEqual(tickIncrement( 0, 1, 3), -2);
assert.strictEqual(tickIncrement( 0, 1, 2), -2);
assert.strictEqual(tickIncrement( 0, 1, 1), 1);
assert.strictEqual(tickIncrement( 0, 10, 10), 1);
assert.strictEqual(tickIncrement( 0, 10, 9), 1);
assert.strictEqual(tickIncrement( 0, 10, 8), 1);
assert.strictEqual(tickIncrement( 0, 10, 7), 2);
assert.strictEqual(tickIncrement( 0, 10, 6), 2);
assert.strictEqual(tickIncrement( 0, 10, 5), 2);
assert.strictEqual(tickIncrement( 0, 10, 4), 2);
assert.strictEqual(tickIncrement( 0, 10, 3), 5);
assert.strictEqual(tickIncrement( 0, 10, 2), 5);
assert.strictEqual(tickIncrement( 0, 10, 1), 10);
assert.strictEqual(tickIncrement(-10, 10, 10), 2);
assert.strictEqual(tickIncrement(-10, 10, 9), 2);
assert.strictEqual(tickIncrement(-10, 10, 8), 2);
assert.strictEqual(tickIncrement(-10, 10, 7), 2);
assert.strictEqual(tickIncrement(-10, 10, 6), 5);
assert.strictEqual(tickIncrement(-10, 10, 5), 5);
assert.strictEqual(tickIncrement(-10, 10, 4), 5);
assert.strictEqual(tickIncrement(-10, 10, 3), 5);
assert.strictEqual(tickIncrement(-10, 10, 2), 10);
assert.strictEqual(tickIncrement(-10, 10, 1), 20);
});

it("base 5", () => {
assert.strictEqual(tickIncrement( 0, 1, 10, 5), -12.5);
assert.strictEqual(tickIncrement( 0, 1, 9, 5), -12.5);
assert.strictEqual(tickIncrement( 0, 1, 8, 5), -12.5);
assert.strictEqual(tickIncrement( 0, 1, 7, 5), -5);
assert.strictEqual(tickIncrement( 0, 1, 6, 5), -5);
assert.strictEqual(tickIncrement( 0, 1, 5, 5), -5);
assert.strictEqual(tickIncrement( 0, 1, 4, 5), -5);
assert.strictEqual(tickIncrement( 0, 1, 3, 5), -2.5);
assert.strictEqual(tickIncrement( 0, 1, 2, 5), -2.5);
assert.strictEqual(tickIncrement( 0, 1, 1, 5), 1);
assert.strictEqual(tickIncrement( 0, 10, 10, 5), 1);
assert.strictEqual(tickIncrement( 0, 10, 9, 5), 1);
assert.strictEqual(tickIncrement( 0, 10, 8, 5), 1);
assert.strictEqual(tickIncrement( 0, 10, 7, 5), 2);
assert.strictEqual(tickIncrement( 0, 10, 6, 5), 2);
assert.strictEqual(tickIncrement( 0, 10, 5, 5), 2);
assert.strictEqual(tickIncrement( 0, 10, 4, 5), 2);
assert.strictEqual(tickIncrement( 0, 10, 3, 5), 5);
assert.strictEqual(tickIncrement( 0, 10, 2, 5), 5);
assert.strictEqual(tickIncrement( 0, 10, 1, 5), 10);
assert.strictEqual(tickIncrement(-10, 10, 10, 5), 2);
assert.strictEqual(tickIncrement(-10, 10, 9, 5), 2);
assert.strictEqual(tickIncrement(-10, 10, 8, 5), 2);
assert.strictEqual(tickIncrement(-10, 10, 7, 5), 2);
assert.strictEqual(tickIncrement(-10, 10, 6, 5), 5);
assert.strictEqual(tickIncrement(-10, 10, 5, 5), 5);
assert.strictEqual(tickIncrement(-10, 10, 4, 5), 5);
assert.strictEqual(tickIncrement(-10, 10, 3, 5), 5);
assert.strictEqual(tickIncrement(-10, 10, 2, 5), 10);
assert.strictEqual(tickIncrement(-10, 10, 1, 5), 25);
it("binary", () => {
assert.strictEqual(tickIncrement(0, 1, 10, "binary"), -8);
assert.strictEqual(tickIncrement(0, 1, 9, "binary"), -8);
assert.strictEqual(tickIncrement(0, 1, 8, "binary"), -8);
assert.strictEqual(tickIncrement(0, 1, 7, "binary"), -8);
assert.strictEqual(tickIncrement(0, 1, 6, "binary"), -8);
assert.strictEqual(tickIncrement(0, 1, 5, "binary"), -4);
assert.strictEqual(tickIncrement(0, 1, 4, "binary"), -4);
assert.strictEqual(tickIncrement(0, 1, 3, "binary"), -4);
assert.strictEqual(tickIncrement(0, 1, 2, "binary"), -2);
assert.strictEqual(tickIncrement(0, 1, 1, "binary"), 1);
assert.strictEqual(tickIncrement(0, 10, 10, "binary"), 1);
assert.strictEqual(tickIncrement(0, 10, 9, "binary"), 1);
assert.strictEqual(tickIncrement(0, 10, 8, "binary"), 1);
assert.strictEqual(tickIncrement(0, 10, 7, "binary"), 2);
assert.strictEqual(tickIncrement(0, 10, 6, "binary"), 2);
assert.strictEqual(tickIncrement(0, 10, 5, "binary"), 2);
assert.strictEqual(tickIncrement(0, 10, 4, "binary"), 2);
assert.strictEqual(tickIncrement(0, 10, 3, "binary"), 4);
assert.strictEqual(tickIncrement(0, 10, 2, "binary"), 4);
assert.strictEqual(tickIncrement(0, 10, 1, "binary"), 8);
assert.strictEqual(tickIncrement(-10, 10, 10, "binary"), 2);
assert.strictEqual(tickIncrement(-10, 10, 9, "binary"), 2);
assert.strictEqual(tickIncrement(-10, 10, 8, "binary"), 2);
assert.strictEqual(tickIncrement(-10, 10, 7, "binary"), 4);
assert.strictEqual(tickIncrement(-10, 10, 6, "binary"), 4);
assert.strictEqual(tickIncrement(-10, 10, 5, "binary"), 4);
assert.strictEqual(tickIncrement(-10, 10, 4, "binary"), 4);
assert.strictEqual(tickIncrement(-10, 10, 3, "binary"), 8);
assert.strictEqual(tickIncrement(-10, 10, 2, "binary"), 8);
assert.strictEqual(tickIncrement(-10, 10, 1, "binary"), 16);
});

it("base 10", () => {
assert.strictEqual(tickIncrement( 0, 1, 10, 10), -10);
assert.strictEqual(tickIncrement( 0, 1, 9, 10), -10);
assert.strictEqual(tickIncrement( 0, 1, 8, 10), -10);
assert.strictEqual(tickIncrement( 0, 1, 7, 10), -5);
assert.strictEqual(tickIncrement( 0, 1, 6, 10), -5);
assert.strictEqual(tickIncrement( 0, 1, 5, 10), -5);
assert.strictEqual(tickIncrement( 0, 1, 4, 10), -5);
assert.strictEqual(tickIncrement( 0, 1, 3, 10), -2);
assert.strictEqual(tickIncrement( 0, 1, 2, 10), -2);
assert.strictEqual(tickIncrement( 0, 1, 1, 10), 1);
assert.strictEqual(tickIncrement( 0, 10, 10, 10), 1);
assert.strictEqual(tickIncrement( 0, 10, 9, 10), 1);
assert.strictEqual(tickIncrement( 0, 10, 8, 10), 1);
assert.strictEqual(tickIncrement( 0, 10, 7, 10), 2);
assert.strictEqual(tickIncrement( 0, 10, 6, 10), 2);
assert.strictEqual(tickIncrement( 0, 10, 5, 10), 2);
assert.strictEqual(tickIncrement( 0, 10, 4, 10), 2);
assert.strictEqual(tickIncrement( 0, 10, 3, 10), 5);
assert.strictEqual(tickIncrement( 0, 10, 2, 10), 5);
assert.strictEqual(tickIncrement( 0, 10, 1, 10), 10);
assert.strictEqual(tickIncrement(-10, 10, 10, 10), 2);
assert.strictEqual(tickIncrement(-10, 10, 9, 10), 2);
assert.strictEqual(tickIncrement(-10, 10, 8, 10), 2);
assert.strictEqual(tickIncrement(-10, 10, 7, 10), 2);
assert.strictEqual(tickIncrement(-10, 10, 6, 10), 5);
assert.strictEqual(tickIncrement(-10, 10, 5, 10), 5);
assert.strictEqual(tickIncrement(-10, 10, 4, 10), 5);
assert.strictEqual(tickIncrement(-10, 10, 3, 10), 5);
assert.strictEqual(tickIncrement(-10, 10, 2, 10), 10);
assert.strictEqual(tickIncrement(-10, 10, 1, 10), 20);
});

it("base e", () => {
assert.strictEqual(normalizeLn(tickIncrement( 0, Math.E / 100, 10, Math.E)), -1);
assert.strictEqual(normalizeLn(tickIncrement( 0, Math.E / 10, 10, Math.E)), -0.5);
assert.strictEqual(normalizeLn(tickIncrement( 0, Math.E / 10, 1, Math.E)), -0.5);
assert.strictEqual(normalizeLn(tickIncrement( 0, Math.E, 3, Math.E)), -0.5);
assert.strictEqual(normalizeLn(tickIncrement( -Math.E, Math.E, 2, Math.E)), 1);
assert.strictEqual(normalizeLn(tickIncrement( 0, Math.E * 10, 10, Math.E)), 1);
assert.strictEqual(normalizeLn(tickIncrement( 1, Math.E * 10, 10, Math.E)), 2);
assert.strictEqual(normalizeLn(tickIncrement( -Math.E * 10, Math.E * 10, 10, Math.E)), 2);
assert.strictEqual(normalizeLn(tickIncrement( Math.E, Math.E * 100, 10, Math.E)), 1);
assert.strictEqual(normalizeLn(tickIncrement( -Math.E * 100, Math.E * 100, 10, Math.E)), 2);
assert.strictEqual(normalizeLn(tickIncrement( 0, Math.E * 100, 10, Math.E)), 1);
assert.strictEqual(tickIncrement( 0, 10, 10, Math.E), 1);
assert.strictEqual(tickIncrement( -10, 10, 10, Math.E), 2);
it("natural", () => {
assert.strictEqual(normalizeLn(tickIncrement( 0, Math.E / 100, 10, 'natural')), -1);
assert.strictEqual(normalizeLn(tickIncrement( 0, Math.E / 10, 10, 'natural')), -0.5);
assert.strictEqual(normalizeLn(tickIncrement( 0, Math.E / 10, 1, 'natural')), -0.5);
assert.strictEqual(normalizeLn(tickIncrement( 0, Math.E, 3, 'natural')), -0.5);
assert.strictEqual(normalizeLn(tickIncrement( -Math.E, Math.E, 2, 'natural')), 1);
assert.strictEqual(normalizeLn(tickIncrement( 0, Math.E * 10, 10, 'natural')), 1);
assert.strictEqual(normalizeLn(tickIncrement( 1, Math.E * 10, 10, 'natural')), 2);
assert.strictEqual(normalizeLn(tickIncrement( -Math.E * 10, Math.E * 10, 10, 'natural')), 2);
assert.strictEqual(normalizeLn(tickIncrement( Math.E, Math.E * 100, 10, 'natural')), 1);
assert.strictEqual(normalizeLn(tickIncrement( -Math.E * 100, Math.E * 100, 10, 'natural')), 2);
assert.strictEqual(normalizeLn(tickIncrement( 0, Math.E * 100, 10, 'natural')), 1);
assert.strictEqual(tickIncrement( 0, 10, 10, 'natural'), 1);
assert.strictEqual(tickIncrement( -10, 10, 10, 'natural'), 2);
});
})

Expand Down
Loading

0 comments on commit c6ae425

Please sign in to comment.