From a8ac7f958c04ed95778dfed9690063ecee4b12ef Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Tue, 21 Sep 2021 12:15:09 -0500 Subject: [PATCH 1/8] feat: add optional base to ticks functions --- src/ticks.js | 18 +++++------ test/tickIncrement-test.js | 33 +++++++++++++++++++ test/tickStep-test.js | 66 ++++++++++++++++++++++++++++++++++++++ test/ticks-test.js | 7 ++++ 4 files changed, 115 insertions(+), 9 deletions(-) diff --git a/src/ticks.js b/src/ticks.js index 6ce69777..c5949002 100644 --- a/src/ticks.js +++ b/src/ticks.js @@ -2,7 +2,7 @@ var e10 = Math.sqrt(50), e5 = Math.sqrt(10), e2 = Math.sqrt(2); -export default function ticks(start, stop, count) { +export default function ticks(start, stop, count, base = 10) { var reverse, i = -1, n, @@ -12,7 +12,7 @@ export default function ticks(start, stop, count) { 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 = tickIncrement(start, stop, count, base)) === 0 || !isFinite(step)) return []; if (step > 0) { let r0 = Math.round(start / step), r1 = Math.round(stop / step); @@ -34,18 +34,18 @@ export default function ticks(start, stop, count) { return ticks; } -export function tickIncrement(start, stop, count) { +export function tickIncrement(start, stop, count, base = 10) { var step = (stop - start) / Math.max(0, count), - power = Math.floor(Math.log(step) / Math.LN10), - error = step / Math.pow(10, power); + power = Math.floor(Math.log(step) / Math.log(base) + Number.EPSILON), + error = step / Math.pow(base, power); return power >= 0 - ? (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1) * Math.pow(10, power) - : -Math.pow(10, -power) / (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1); + ? (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1) * Math.pow(base, power) + : -Math.pow(base, -power) / (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1); } -export function tickStep(start, stop, count) { +export function tickStep(start, stop, count, base = 10) { var step0 = Math.abs(stop - start) / Math.max(0, count), - step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)), + step1 = Math.pow(base, Math.floor(Math.log(step0) / Math.log(base) + Number.EPSILON)), error = step0 / step1; if (error >= e10) step1 *= 10; else if (error >= e5) step1 *= 5; diff --git a/test/tickIncrement-test.js b/test/tickIncrement-test.js index 68c64ded..5b2bb331 100644 --- a/test/tickIncrement-test.js +++ b/test/tickIncrement-test.js @@ -60,3 +60,36 @@ it("tickIncrement(start, stop, count) returns approximately count + 1 tickIncrem assert.strictEqual(tickIncrement(-10, 10, 2), 10); assert.strictEqual(tickIncrement(-10, 10, 1), 20); }); + +it("tickIncrement(start, stop, count, base) returns approximately count + 1 tickIncrement when start < stop", () => { + 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); +}); diff --git a/test/tickStep-test.js b/test/tickStep-test.js index 79b7ca72..fe90ba72 100644 --- a/test/tickStep-test.js +++ b/test/tickStep-test.js @@ -93,3 +93,69 @@ it("tickStep(start, stop, count) returns -tickStep(stop, start, count)", () => { assert.strictEqual(tickStep(-10, 10, 2), -tickStep(10, -10, 2)); assert.strictEqual(tickStep(-10, 10, 1), -tickStep(10, -10, 1)); }); + +it("tickStep(start, stop, count) with base 2 returns approximately count + 1 tickStep when start < stop", () => { + assert.strictEqual(tickStep( 0, 1, 10, 2), 0.125); + assert.strictEqual(tickStep( 0, 1, 9, 2), 0.125); + assert.strictEqual(tickStep( 0, 1, 8, 2), 0.125); + assert.strictEqual(tickStep( 0, 1, 7, 2), 0.125); + assert.strictEqual(tickStep( 0, 1, 6, 2), 0.125); + assert.strictEqual(tickStep( 0, 1, 5, 2), 0.25); + assert.strictEqual(tickStep( 0, 1, 4, 2), 0.25); + assert.strictEqual(tickStep( 0, 1, 3, 2), 0.25); + assert.strictEqual(tickStep( 0, 1, 2, 2), 0.5); + assert.strictEqual(tickStep( 0, 1, 1, 2), 1); + assert.strictEqual(tickStep( 0, 10, 10, 2), 1); + assert.strictEqual(tickStep( 0, 10, 9, 2), 1); + assert.strictEqual(tickStep( 0, 10, 8, 2), 1); + assert.strictEqual(tickStep( 0, 10, 7, 2), 2); + assert.strictEqual(tickStep( 0, 10, 6, 2), 2); + assert.strictEqual(tickStep( 0, 10, 5, 2), 2); + assert.strictEqual(tickStep( 0, 10, 4, 2), 2); + assert.strictEqual(tickStep( 0, 10, 3, 2), 4); + assert.strictEqual(tickStep( 0, 10, 2, 2), 4); + assert.strictEqual(tickStep( 0, 10, 1, 2), 8); + assert.strictEqual(tickStep(-10, 10, 10, 2), 2); + assert.strictEqual(tickStep(-10, 10, 9, 2), 2); + assert.strictEqual(tickStep(-10, 10, 8, 2), 2); + assert.strictEqual(tickStep(-10, 10, 7, 2), 4); + assert.strictEqual(tickStep(-10, 10, 6, 2), 4); + assert.strictEqual(tickStep(-10, 10, 5, 2), 4); + assert.strictEqual(tickStep(-10, 10, 4, 2), 4); + assert.strictEqual(tickStep(-10, 10, 3, 2), 8); + assert.strictEqual(tickStep(-10, 10, 2, 2), 8); + assert.strictEqual(tickStep(-10, 10, 1, 2), 16); +}); + +it("tickStep(start, stop, count, base) with base 2 returns -tickStep(stop, start, count)", () => { + assert.strictEqual(tickStep( 0, 1, 10, 2), -tickStep( 1, 0, 10, 2)); + assert.strictEqual(tickStep( 0, 1, 9, 2), -tickStep( 1, 0, 9, 2)); + assert.strictEqual(tickStep( 0, 1, 8, 2), -tickStep( 1, 0, 8, 2)); + assert.strictEqual(tickStep( 0, 1, 7, 2), -tickStep( 1, 0, 7, 2)); + assert.strictEqual(tickStep( 0, 1, 6, 2), -tickStep( 1, 0, 6, 2)); + assert.strictEqual(tickStep( 0, 1, 5, 2), -tickStep( 1, 0, 5, 2)); + assert.strictEqual(tickStep( 0, 1, 4, 2), -tickStep( 1, 0, 4, 2)); + assert.strictEqual(tickStep( 0, 1, 3, 2), -tickStep( 1, 0, 3, 2)); + assert.strictEqual(tickStep( 0, 1, 2, 2), -tickStep( 1, 0, 2, 2)); + assert.strictEqual(tickStep( 0, 1, 1, 2), -tickStep( 1, 0, 1, 2)); + assert.strictEqual(tickStep( 0, 10, 10, 2), -tickStep(10, 0, 10, 2)); + assert.strictEqual(tickStep( 0, 10, 9, 2), -tickStep(10, 0, 9, 2)); + assert.strictEqual(tickStep( 0, 10, 8, 2), -tickStep(10, 0, 8, 2)); + assert.strictEqual(tickStep( 0, 10, 7, 2), -tickStep(10, 0, 7, 2)); + assert.strictEqual(tickStep( 0, 10, 6, 2), -tickStep(10, 0, 6, 2)); + assert.strictEqual(tickStep( 0, 10, 5, 2), -tickStep(10, 0, 5, 2)); + assert.strictEqual(tickStep( 0, 10, 4, 2), -tickStep(10, 0, 4, 2)); + assert.strictEqual(tickStep( 0, 10, 3, 2), -tickStep(10, 0, 3, 2)); + assert.strictEqual(tickStep( 0, 10, 2, 2), -tickStep(10, 0, 2, 2)); + assert.strictEqual(tickStep( 0, 10, 1, 2), -tickStep(10, 0, 1, 2)); + assert.strictEqual(tickStep(-10, 10, 10, 2), -tickStep(10, -10, 10, 2)); + assert.strictEqual(tickStep(-10, 10, 9, 2), -tickStep(10, -10, 9, 2)); + assert.strictEqual(tickStep(-10, 10, 8, 2), -tickStep(10, -10, 8, 2)); + assert.strictEqual(tickStep(-10, 10, 7, 2), -tickStep(10, -10, 7, 2)); + assert.strictEqual(tickStep(-10, 10, 6, 2), -tickStep(10, -10, 6, 2)); + assert.strictEqual(tickStep(-10, 10, 5, 2), -tickStep(10, -10, 5, 2)); + assert.strictEqual(tickStep(-10, 10, 4, 2), -tickStep(10, -10, 4, 2)); + assert.strictEqual(tickStep(-10, 10, 3, 2), -tickStep(10, -10, 3, 2)); + assert.strictEqual(tickStep(-10, 10, 2, 2), -tickStep(10, -10, 2, 2)); + assert.strictEqual(tickStep(-10, 10, 1, 2), -tickStep(10, -10, 1, 2)); +}); diff --git a/test/ticks-test.js b/test/ticks-test.js index 3b4fd985..bbad7aec 100644 --- a/test/ticks-test.js +++ b/test/ticks-test.js @@ -109,3 +109,10 @@ it("ticks(start, stop, count) returns the reverse of ticks(stop, start, count)", it("ticks(start, stop, count) handles precision problems", () => { assert.deepStrictEqual(ticks(0.98, 1.14, 10), [0.98, 1, 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14]); }); + +it("ticks(start, stop, count, base) returns ticks in base 2", () => { + assert.deepStrictEqual(ticks(0, 10, 5, 2), [0, 2, 4, 6, 8, 10]); + assert.deepStrictEqual(ticks(0, 1024, 10, 2), [0, 128, 256, 384, 512, 640, 768, 896, 1024]); + assert.deepStrictEqual(ticks(-1024, 1024, 20, 2), [-1024, -896, -768, -640, -512, -384, -256, -128, 0, 128, 256, 384, 512, 640, 768, 896, 1024]); + assert.deepStrictEqual(ticks(0, 2000, 5, 2), [0, 512, 1024, 1536]); +}); From 73a4b62f59b7a40efb16b13d6bf64dfacc6813ab Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Thu, 28 Oct 2021 12:34:27 -0500 Subject: [PATCH 2/8] add better tests around base e and 2 --- test/tickIncrement-test.js | 159 +++++++++++++++++++++++++++++-------- test/tickStep-test.js | 52 +++++++++++- 2 files changed, 178 insertions(+), 33 deletions(-) diff --git a/test/tickIncrement-test.js b/test/tickIncrement-test.js index 5b2bb331..b36c6527 100644 --- a/test/tickIncrement-test.js +++ b/test/tickIncrement-test.js @@ -61,35 +61,130 @@ it("tickIncrement(start, stop, count) returns approximately count + 1 tickIncrem assert.strictEqual(tickIncrement(-10, 10, 1), 20); }); -it("tickIncrement(start, stop, count, base) returns approximately count + 1 tickIncrement when start < stop", () => { - 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); -}); + +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("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("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); + }); +}) + +export function normalizeLn(value) { + let tries = 0, normValue = value; + while (tries++ < 10 && normValue % 0.5 !== 0) normValue *= Math.E; + if (tries > 10) { + tries = 0, normValue = value + while (tries++ < 10 && normValue % 0.5 !== 0) normValue /= Math.E; + } + return tries > 10 ? NaN : normValue; +} diff --git a/test/tickStep-test.js b/test/tickStep-test.js index fe90ba72..bcae7178 100644 --- a/test/tickStep-test.js +++ b/test/tickStep-test.js @@ -1,4 +1,5 @@ import assert from "assert"; +import {normalizeLn} from "./tickIncrement-test.js"; import {tickStep} from "../src/index.js"; it("tickStep(start, stop, count) returns NaN if any argument is NaN", () => { @@ -94,7 +95,7 @@ it("tickStep(start, stop, count) returns -tickStep(stop, start, count)", () => { assert.strictEqual(tickStep(-10, 10, 1), -tickStep(10, -10, 1)); }); -it("tickStep(start, stop, count) with base 2 returns approximately count + 1 tickStep when start < stop", () => { +it("tickStep(start, stop, count, base) with base 2 returns approximately count + 1 tickStep when start < stop", () => { assert.strictEqual(tickStep( 0, 1, 10, 2), 0.125); assert.strictEqual(tickStep( 0, 1, 9, 2), 0.125); assert.strictEqual(tickStep( 0, 1, 8, 2), 0.125); @@ -127,6 +128,22 @@ it("tickStep(start, stop, count) with base 2 returns approximately count + 1 tic assert.strictEqual(tickStep(-10, 10, 1, 2), 16); }); +it("tickStep(start, stop, count, base) with base e returns approximately count + 1 tickStep when start < stop", () => { + assert.strictEqual(normalizeLn(tickStep( 0, Math.E / 100, 10, Math.E)), 1); + assert.strictEqual(normalizeLn(tickStep( 0, Math.E / 10, 10, Math.E)), 2); + assert.strictEqual(normalizeLn(tickStep( 0, Math.E / 10, 1, Math.E)), 2); + assert.strictEqual(normalizeLn(tickStep( 0, Math.E, 3, Math.E)), 2); + assert.strictEqual(normalizeLn(tickStep( -Math.E, Math.E, 2, Math.E)), 1); + assert.strictEqual(normalizeLn(tickStep( 0, Math.E * 10, 10, Math.E)), 1); + assert.strictEqual(normalizeLn(tickStep( 1, Math.E * 10, 10, Math.E)), 2); + assert.strictEqual(normalizeLn(tickStep( -Math.E * 10, Math.E * 10, 10, Math.E)), 2); + assert.strictEqual(normalizeLn(tickStep( Math.E, Math.E * 100, 10, Math.E)), 1); + assert.strictEqual(normalizeLn(tickStep( -Math.E * 100, Math.E * 100, 10, Math.E)), 2); + assert.strictEqual(normalizeLn(tickStep( 0, Math.E * 100, 10, Math.E)), 1); + assert.strictEqual(tickStep( 0, 10, 10, Math.E), 1); + assert.strictEqual(tickStep( -10, 10, 10, Math.E), 2); +}); + it("tickStep(start, stop, count, base) with base 2 returns -tickStep(stop, start, count)", () => { assert.strictEqual(tickStep( 0, 1, 10, 2), -tickStep( 1, 0, 10, 2)); assert.strictEqual(tickStep( 0, 1, 9, 2), -tickStep( 1, 0, 9, 2)); @@ -159,3 +176,36 @@ it("tickStep(start, stop, count, base) with base 2 returns -tickStep(stop, start assert.strictEqual(tickStep(-10, 10, 2, 2), -tickStep(10, -10, 2, 2)); assert.strictEqual(tickStep(-10, 10, 1, 2), -tickStep(10, -10, 1, 2)); }); + +it("tickStep(start, stop, count, base) with base e returns -tickStep(stop, start, count)", () => { + assert.strictEqual(tickStep( 0, 1, 10, Math.E), -tickStep( 1, 0, 10, Math.E)); + assert.strictEqual(tickStep( 0, 1, 9, Math.E), -tickStep( 1, 0, 9, Math.E)); + assert.strictEqual(tickStep( 0, 1, 8, Math.E), -tickStep( 1, 0, 8, Math.E)); + assert.strictEqual(tickStep( 0, 1, 7, Math.E), -tickStep( 1, 0, 7, Math.E)); + assert.strictEqual(tickStep( 0, 1, 6, Math.E), -tickStep( 1, 0, 6, Math.E)); + assert.strictEqual(tickStep( 0, 1, 5, Math.E), -tickStep( 1, 0, 5, Math.E)); + assert.strictEqual(tickStep( 0, 1, 4, Math.E), -tickStep( 1, 0, 4, Math.E)); + assert.strictEqual(tickStep( 0, 1, 3, Math.E), -tickStep( 1, 0, 3, Math.E)); + assert.strictEqual(tickStep( 0, 1, 2, Math.E), -tickStep( 1, 0, 2, Math.E)); + assert.strictEqual(tickStep( 0, 1, 1, Math.E), -tickStep( 1, 0, 1, Math.E)); + assert.strictEqual(tickStep( 0, 10, 10, Math.E), -tickStep(10, 0, 10, Math.E)); + assert.strictEqual(tickStep( 0, 10, 9, Math.E), -tickStep(10, 0, 9, Math.E)); + assert.strictEqual(tickStep( 0, 10, 8, Math.E), -tickStep(10, 0, 8, Math.E)); + assert.strictEqual(tickStep( 0, 10, 7, Math.E), -tickStep(10, 0, 7, Math.E)); + assert.strictEqual(tickStep( 0, 10, 6, Math.E), -tickStep(10, 0, 6, Math.E)); + assert.strictEqual(tickStep( 0, 10, 5, Math.E), -tickStep(10, 0, 5, Math.E)); + assert.strictEqual(tickStep( 0, 10, 4, Math.E), -tickStep(10, 0, 4, Math.E)); + assert.strictEqual(tickStep( 0, 10, 3, Math.E), -tickStep(10, 0, 3, Math.E)); + assert.strictEqual(tickStep( 0, 10, 2, Math.E), -tickStep(10, 0, 2, Math.E)); + assert.strictEqual(tickStep( 0, 10, 1, Math.E), -tickStep(10, 0, 1, Math.E)); + assert.strictEqual(tickStep(-10, 10, 10, Math.E), -tickStep(10, -10, 10, Math.E)); + assert.strictEqual(tickStep(-10, 10, 9, Math.E), -tickStep(10, -10, 9, Math.E)); + assert.strictEqual(tickStep(-10, 10, 8, Math.E), -tickStep(10, -10, 8, Math.E)); + assert.strictEqual(tickStep(-10, 10, 7, Math.E), -tickStep(10, -10, 7, Math.E)); + assert.strictEqual(tickStep(-10, 10, 6, Math.E), -tickStep(10, -10, 6, Math.E)); + assert.strictEqual(tickStep(-10, 10, 5, Math.E), -tickStep(10, -10, 5, Math.E)); + assert.strictEqual(tickStep(-10, 10, 4, Math.E), -tickStep(10, -10, 4, Math.E)); + assert.strictEqual(tickStep(-10, 10, 3, Math.E), -tickStep(10, -10, 3, Math.E)); + assert.strictEqual(tickStep(-10, 10, 2, Math.E), -tickStep(10, -10, 2, Math.E)); + assert.strictEqual(tickStep(-10, 10, 1, Math.E), -tickStep(10, -10, 1, Math.E)); +}); From e983ad4047944c1a8e5f4facb213d016769beee5 Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Thu, 28 Oct 2021 12:58:33 -0500 Subject: [PATCH 3/8] add base to nice function --- src/nice.js | 4 ++-- test/nice-test.js | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/nice.js b/src/nice.js index 579b418c..bedff3f1 100644 --- a/src/nice.js +++ b/src/nice.js @@ -1,9 +1,9 @@ import {tickIncrement} from "./ticks.js"; -export default function nice(start, stop, count) { +export default function nice(start, stop, count, base) { let prestep; while (true) { - const step = tickIncrement(start, stop, count); + const step = tickIncrement(start, stop, count, base); if (step === prestep || step === 0 || !isFinite(step)) { return [start, stop]; } else if (step > 0) { diff --git a/test/nice-test.js b/test/nice-test.js index bbc4f708..d9c31be8 100644 --- a/test/nice-test.js +++ b/test/nice-test.js @@ -44,3 +44,24 @@ it("nice(start, stop, count) returns the expected values", () => { assert.deepStrictEqual(nice(132, 876, 5), [0, 1000]); 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 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]); +}); From 4ecda5fdd568313f4bdb63207e6cdbc80347444c Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Thu, 28 Oct 2021 12:58:59 -0500 Subject: [PATCH 4/8] update docs to reflect addition of new base argument --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d51686a9..f5a33849 100644 --- a/README.md +++ b/README.md @@ -621,23 +621,23 @@ const shuffle = d3.shuffler(random); shuffle([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); // returns [7, 4, 5, 3, 9, 0, 6, 1, 2, 8] ``` -# d3.ticks(start, stop, count) · [Source](https://github.com/d3/d3-array/blob/master/src/ticks.js), [Examples](https://observablehq.com/@d3/d3-ticks) +# d3.ticks(start, stop, count, base) · [Source](https://github.com/d3/d3-array/blob/master/src/ticks.js), [Examples](https://observablehq.com/@d3/d3-ticks) -Returns an array of approximately *count* + 1 uniformly-spaced, nicely-rounded values between *start* and *stop* (inclusive). Each value is a power of ten multiplied by 1, 2 or 5. See also [d3.tickIncrement](#tickIncrement), [d3.tickStep](#tickStep) and [*linear*.ticks](https://github.com/d3/d3-scale/blob/master/README.md#linear_ticks). +Returns an array of approximately *count* + 1 uniformly-spaced, nicely-rounded values between *start* and *stop* (inclusive). Each value is a power of the *base* (default is `10`) multiplied by 1, 2 or 5. See also [d3.tickIncrement](#tickIncrement), [d3.tickStep](#tickStep) and [*linear*.ticks](https://github.com/d3/d3-scale/blob/master/README.md#linear_ticks). Ticks are inclusive in the sense that they may include the specified *start* and *stop* values if (and only if) they are exact, nicely-rounded values consistent with the inferred [step](#tickStep). More formally, each returned tick *t* satisfies *start* ≤ *t* and *t* ≤ *stop*. -# d3.tickIncrement(start, stop, count) · [Source](https://github.com/d3/d3-array/blob/master/src/ticks.js), [Examples](https://observablehq.com/@d3/d3-ticks) +# d3.tickIncrement(start, stop, count, base) · [Source](https://github.com/d3/d3-array/blob/master/src/ticks.js), [Examples](https://observablehq.com/@d3/d3-ticks) Like [d3.tickStep](#tickStep), except requires that *start* is always less than or equal to *stop*, and if the tick step for the given *start*, *stop* and *count* would be less than one, returns the negative inverse tick step instead. This method is always guaranteed to return an integer, and is used by [d3.ticks](#ticks) to guarantee that the returned tick values are represented as precisely as possible in IEEE 754 floating point. -# d3.tickStep(start, stop, count) · [Source](https://github.com/d3/d3-array/blob/master/src/ticks.js), [Examples](https://observablehq.com/@d3/d3-ticks) +# d3.tickStep(start, stop, count, base) · [Source](https://github.com/d3/d3-array/blob/master/src/ticks.js), [Examples](https://observablehq.com/@d3/d3-ticks) -Returns the difference between adjacent tick values if the same arguments were passed to [d3.ticks](#ticks): a nicely-rounded value that is a power of ten multiplied by 1, 2 or 5. Note that due to the limited precision of IEEE 754 floating point, the returned value may not be exact decimals; use [d3-format](https://github.com/d3/d3-format) to format numbers for human consumption. +Returns the difference between adjacent tick values if the same arguments were passed to [d3.ticks](#ticks): a nicely-rounded value that is a power of the *base* (default is `10`) multiplied by 1, 2 or 5. Note that due to the limited precision of IEEE 754 floating point, the returned value may not be exact decimals; use [d3-format](https://github.com/d3/d3-format) to format numbers for human consumption. -# d3.nice(start, stop, count) · [Source](https://github.com/d3/d3-array/blob/master/src/nice.js) +# d3.nice(start, stop, count, base) · [Source](https://github.com/d3/d3-array/blob/master/src/nice.js) -Returns a new interval [*niceStart*, *niceStop*] covering the given interval [*start*, *stop*] and where *niceStart* and *niceStop* are guaranteed to align with the corresponding [tick step](#tickStep). Like [d3.tickIncrement](#tickIncrement), this requires that *start* is less than or equal to *stop*. +Returns a new interval [*niceStart*, *niceStop*] covering the given interval [*start*, *stop*] and where *niceStart* and *niceStop* are guaranteed to align with the corresponding [tick step](#tickStep) given the provided *base* (default is `10`). Like [d3.tickIncrement](#tickIncrement), this requires that *start* is less than or equal to *stop*. # d3.range([start, ]stop[, step]) · [Source](https://github.com/d3/d3-array/blob/master/src/range.js), [Examples](https://observablehq.com/@d3/d3-range) From 13793c9f56682e60253136299a0498bec9760cb5 Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Thu, 28 Oct 2021 13:14:50 -0500 Subject: [PATCH 5/8] add more tests for tick with different bases --- test/ticks-test.js | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/test/ticks-test.js b/test/ticks-test.js index bbad7aec..43c8a2df 100644 --- a/test/ticks-test.js +++ b/test/ticks-test.js @@ -111,8 +111,25 @@ it("ticks(start, stop, count) handles precision problems", () => { }); it("ticks(start, stop, count, base) returns ticks in base 2", () => { - assert.deepStrictEqual(ticks(0, 10, 5, 2), [0, 2, 4, 6, 8, 10]); - assert.deepStrictEqual(ticks(0, 1024, 10, 2), [0, 128, 256, 384, 512, 640, 768, 896, 1024]); + assert.deepStrictEqual(ticks( 0, 10, 5, 2), [0, 2, 4, 6, 8, 10]); + assert.deepStrictEqual(ticks( 0, 1024, 10, 2), [0, 128, 256, 384, 512, 640, 768, 896, 1024]); assert.deepStrictEqual(ticks(-1024, 1024, 20, 2), [-1024, -896, -768, -640, -512, -384, -256, -128, 0, 128, 256, 384, 512, 640, 768, 896, 1024]); - assert.deepStrictEqual(ticks(0, 2000, 5, 2), [0, 512, 1024, 1536]); + assert.deepStrictEqual(ticks( 0, 2000, 5, 2), [0, 512, 1024, 1536]); +}); + +it.only("ticks(start, stop, count, base) returns ticks in base e", () => { + assert.deepStrictEqual(ticks( 0, 10, 5, Math.E), [0, 2, 4, 6, 8, 10]); + assert.deepStrictEqual(ticks( 0, 10, 10, Math.E), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + assert.deepStrictEqual(ticks( 0, Math.E * 10, 10, Math.E), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((v) => v *= Math.E)); + assert.deepStrictEqual(ticks(-Math.E * 10, Math.E * 10, 10, Math.E), [-10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10].map((v) => v *= Math.E)); + assert.deepStrictEqual(ticks(-Math.E * 10, 0, 10, Math.E), [-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0].map((v) => v *= Math.E)); +}); + +it("ticks(start, stop, count, base) returns ticks in base 60", () => { + assert.deepStrictEqual(ticks( 0, 10, 10, 60), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); + assert.deepStrictEqual(ticks( 0, 120, 10, 60), [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120]); + assert.deepStrictEqual(ticks( 0, 60 * 10, 10, 60), [0, 60, 120, 180, 240, 300, 360, 420, 480, 540, 600]); + assert.deepStrictEqual(ticks(-60 * 10, 0, 10, 60), [-600, -540, -480, -420, -360, -300, -240, -180, -120, -60, 0]); + assert.deepStrictEqual(ticks(-60 * 10, 60 * 10, 20, 60), [-600, -540, -480, -420, -360, -300, -240, -180, -120, -60, 0, 60, 120, 180, 240, 300, 360, 420, 480, 540, 600]); + assert.deepStrictEqual(ticks( 0, 2000, 5, 60), [0, 300, 600, 900, 1200, 1500, 1800]); }); From a7642583a9b8d601ae78be762159f20e2a50e4b1 Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Thu, 28 Oct 2021 13:15:28 -0500 Subject: [PATCH 6/8] remove it.only in tests --- test/ticks-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ticks-test.js b/test/ticks-test.js index 43c8a2df..13b73983 100644 --- a/test/ticks-test.js +++ b/test/ticks-test.js @@ -117,7 +117,7 @@ it("ticks(start, stop, count, base) returns ticks in base 2", () => { assert.deepStrictEqual(ticks( 0, 2000, 5, 2), [0, 512, 1024, 1536]); }); -it.only("ticks(start, stop, count, base) returns ticks in base e", () => { +it("ticks(start, stop, count, base) returns ticks in base e", () => { assert.deepStrictEqual(ticks( 0, 10, 5, Math.E), [0, 2, 4, 6, 8, 10]); assert.deepStrictEqual(ticks( 0, 10, 10, Math.E), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); assert.deepStrictEqual(ticks( 0, Math.E * 10, 10, Math.E), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((v) => v *= Math.E)); From 79c5d110bc6f9b2f92881da53fef9b8eeb4ffd22 Mon Sep 17 00:00:00 2001 From: Nick Partridge Date: Tue, 23 Nov 2021 08:10:25 -0600 Subject: [PATCH 7/8] Cleanup markdown styles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Philippe Rivière --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ba6a46d0..f3bac356 100644 --- a/README.md +++ b/README.md @@ -634,7 +634,7 @@ shuffle([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); // returns [7, 4, 5, 3, 9, 0, 6, 1, 2, # d3.ticks(start, stop, count, base) · [Source](https://github.com/d3/d3-array/blob/main/src/ticks.js), [Examples](https://observablehq.com/@d3/d3-ticks) -Returns an array of approximately *count* + 1 uniformly-spaced, nicely-rounded values between *start* and *stop* (inclusive). Each value is a power of the *base* (default is `10`) multiplied by 1, 2 or 5. See also [d3.tickIncrement](#tickIncrement), [d3.tickStep](#tickStep) and [*linear*.ticks](https://github.com/d3/d3-scale/blob/main/README.md#linear_ticks). +Returns an array of approximately *count* + 1 uniformly-spaced, nicely-rounded values between *start* and *stop* (inclusive). Each value is a power of the *base* (default is 10) multiplied by 1, 2 or 5. See also [d3.tickIncrement](#tickIncrement), [d3.tickStep](#tickStep) and [*linear*.ticks](https://github.com/d3/d3-scale/blob/main/README.md#linear_ticks). Ticks are inclusive in the sense that they may include the specified *start* and *stop* values if (and only if) they are exact, nicely-rounded values consistent with the inferred [step](#tickStep). More formally, each returned tick *t* satisfies *start* ≤ *t* and *t* ≤ *stop*. @@ -644,11 +644,11 @@ Like [d3.tickStep](#tickStep), except requires that *start* is always less than # d3.tickStep(start, stop, count, base) · [Source](https://github.com/d3/d3-array/blob/main/src/ticks.js), [Examples](https://observablehq.com/@d3/d3-ticks) -Returns the difference between adjacent tick values if the same arguments were passed to [d3.ticks](#ticks): a nicely-rounded value that is a power of the *base* (default is `10`) multiplied by 1, 2 or 5. Note that due to the limited precision of IEEE 754 floating point, the returned value may not be exact decimals; use [d3-format](https://github.com/d3/d3-format) to format numbers for human consumption. +Returns the difference between adjacent tick values if the same arguments were passed to [d3.ticks](#ticks): a nicely-rounded value that is a power of the *base* (default is 10) multiplied by 1, 2 or 5. Note that due to the limited precision of IEEE 754 floating point, the returned value may not be exact decimals; use [d3-format](https://github.com/d3/d3-format) to format numbers for human consumption. # d3.nice(start, stop, count, base) · [Source](https://github.com/d3/d3-array/blob/main/src/nice.js) -Returns a new interval [*niceStart*, *niceStop*] covering the given interval [*start*, *stop*] and where *niceStart* and *niceStop* are guaranteed to align with the corresponding [tick step](#tickStep) given the provided *base* (default is `10`). Like [d3.tickIncrement](#tickIncrement), this requires that *start* is less than or equal to *stop*. +Returns a new interval [*niceStart*, *niceStop*] covering the given interval [*start*, *stop*] and where *niceStart* and *niceStop* are guaranteed to align with the corresponding [tick step](#tickStep) given the provided *base* (default is 10). Like [d3.tickIncrement](#tickIncrement), this requires that *start* is less than or equal to *stop*. # d3.range([start, ]stop[, step]) · [Source](https://github.com/d3/d3-array/blob/main/src/range.js), [Examples](https://observablehq.com/@d3/d3-range) From c6ae4250b3b645a8d80dc80209e661fabbbbd13b Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Fri, 8 Dec 2023 10:13:41 -0700 Subject: [PATCH 8/8] merge with changes to main and use high precision Math methods --- src/nice.js | 4 +- src/ticks.js | 38 ++++--- test/nice-test.js | 34 +++--- test/tickIncrement-test.js | 185 +++++++++++++------------------- test/tickStep-test.js | 214 ++++++++++++++++++------------------- test/ticks-test.js | 50 ++------- 6 files changed, 236 insertions(+), 289 deletions(-) diff --git a/src/nice.js b/src/nice.js index bedff3f1..ba31011b 100644 --- a/src/nice.js +++ b/src/nice.js @@ -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) { diff --git a/src/ticks.js b/src/ticks.js index 5868d8d2..d4ad08bf 100644 --- a/src/ticks.js +++ b/src/ticks.js @@ -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) { @@ -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); } diff --git a/test/nice-test.js b/test/nice-test.js index d9c31be8..400f92ac 100644 --- a/test/nice-test.js +++ b/test/nice-test.js @@ -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]); }); diff --git a/test/tickIncrement-test.js b/test/tickIncrement-test.js index b36c6527..3e36b18b 100644 --- a/test/tickIncrement-test.js +++ b/test/tickIncrement-test.js @@ -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); }); }) diff --git a/test/tickStep-test.js b/test/tickStep-test.js index bcae7178..9561d240 100644 --- a/test/tickStep-test.js +++ b/test/tickStep-test.js @@ -95,117 +95,117 @@ it("tickStep(start, stop, count) returns -tickStep(stop, start, count)", () => { assert.strictEqual(tickStep(-10, 10, 1), -tickStep(10, -10, 1)); }); -it("tickStep(start, stop, count, base) with base 2 returns approximately count + 1 tickStep when start < stop", () => { - assert.strictEqual(tickStep( 0, 1, 10, 2), 0.125); - assert.strictEqual(tickStep( 0, 1, 9, 2), 0.125); - assert.strictEqual(tickStep( 0, 1, 8, 2), 0.125); - assert.strictEqual(tickStep( 0, 1, 7, 2), 0.125); - assert.strictEqual(tickStep( 0, 1, 6, 2), 0.125); - assert.strictEqual(tickStep( 0, 1, 5, 2), 0.25); - assert.strictEqual(tickStep( 0, 1, 4, 2), 0.25); - assert.strictEqual(tickStep( 0, 1, 3, 2), 0.25); - assert.strictEqual(tickStep( 0, 1, 2, 2), 0.5); - assert.strictEqual(tickStep( 0, 1, 1, 2), 1); - assert.strictEqual(tickStep( 0, 10, 10, 2), 1); - assert.strictEqual(tickStep( 0, 10, 9, 2), 1); - assert.strictEqual(tickStep( 0, 10, 8, 2), 1); - assert.strictEqual(tickStep( 0, 10, 7, 2), 2); - assert.strictEqual(tickStep( 0, 10, 6, 2), 2); - assert.strictEqual(tickStep( 0, 10, 5, 2), 2); - assert.strictEqual(tickStep( 0, 10, 4, 2), 2); - assert.strictEqual(tickStep( 0, 10, 3, 2), 4); - assert.strictEqual(tickStep( 0, 10, 2, 2), 4); - assert.strictEqual(tickStep( 0, 10, 1, 2), 8); - assert.strictEqual(tickStep(-10, 10, 10, 2), 2); - assert.strictEqual(tickStep(-10, 10, 9, 2), 2); - assert.strictEqual(tickStep(-10, 10, 8, 2), 2); - assert.strictEqual(tickStep(-10, 10, 7, 2), 4); - assert.strictEqual(tickStep(-10, 10, 6, 2), 4); - assert.strictEqual(tickStep(-10, 10, 5, 2), 4); - assert.strictEqual(tickStep(-10, 10, 4, 2), 4); - assert.strictEqual(tickStep(-10, 10, 3, 2), 8); - assert.strictEqual(tickStep(-10, 10, 2, 2), 8); - assert.strictEqual(tickStep(-10, 10, 1, 2), 16); +it("tickStep(start, stop, count, base) with binary log returns approximately count + 1 tickStep when start < stop", () => { + assert.strictEqual(tickStep( 0, 1, 10, 'binary'), 0.125); + assert.strictEqual(tickStep( 0, 1, 9, 'binary'), 0.125); + assert.strictEqual(tickStep( 0, 1, 8, 'binary'), 0.125); + assert.strictEqual(tickStep( 0, 1, 7, 'binary'), 0.125); + assert.strictEqual(tickStep( 0, 1, 6, 'binary'), 0.125); + assert.strictEqual(tickStep( 0, 1, 5, 'binary'), 0.25); + assert.strictEqual(tickStep( 0, 1, 4, 'binary'), 0.25); + assert.strictEqual(tickStep( 0, 1, 3, 'binary'), 0.25); + assert.strictEqual(tickStep( 0, 1, 2, 'binary'), 0.5); + assert.strictEqual(tickStep( 0, 1, 1, 'binary'), 1); + assert.strictEqual(tickStep( 0, 10, 10, 'binary'), 1); + assert.strictEqual(tickStep( 0, 10, 9, 'binary'), 1); + assert.strictEqual(tickStep( 0, 10, 8, 'binary'), 1); + assert.strictEqual(tickStep( 0, 10, 7, 'binary'), 2); + assert.strictEqual(tickStep( 0, 10, 6, 'binary'), 2); + assert.strictEqual(tickStep( 0, 10, 5, 'binary'), 2); + assert.strictEqual(tickStep( 0, 10, 4, 'binary'), 2); + assert.strictEqual(tickStep( 0, 10, 3, 'binary'), 4); + assert.strictEqual(tickStep( 0, 10, 2, 'binary'), 4); + assert.strictEqual(tickStep( 0, 10, 1, 'binary'), 8); + assert.strictEqual(tickStep(-10, 10, 10, 'binary'), 2); + assert.strictEqual(tickStep(-10, 10, 9, 'binary'), 2); + assert.strictEqual(tickStep(-10, 10, 8, 'binary'), 2); + assert.strictEqual(tickStep(-10, 10, 7, 'binary'), 4); + assert.strictEqual(tickStep(-10, 10, 6, 'binary'), 4); + assert.strictEqual(tickStep(-10, 10, 5, 'binary'), 4); + assert.strictEqual(tickStep(-10, 10, 4, 'binary'), 4); + assert.strictEqual(tickStep(-10, 10, 3, 'binary'), 8); + assert.strictEqual(tickStep(-10, 10, 2, 'binary'), 8); + assert.strictEqual(tickStep(-10, 10, 1, 'binary'), 16); }); -it("tickStep(start, stop, count, base) with base e returns approximately count + 1 tickStep when start < stop", () => { - assert.strictEqual(normalizeLn(tickStep( 0, Math.E / 100, 10, Math.E)), 1); - assert.strictEqual(normalizeLn(tickStep( 0, Math.E / 10, 10, Math.E)), 2); - assert.strictEqual(normalizeLn(tickStep( 0, Math.E / 10, 1, Math.E)), 2); - assert.strictEqual(normalizeLn(tickStep( 0, Math.E, 3, Math.E)), 2); - assert.strictEqual(normalizeLn(tickStep( -Math.E, Math.E, 2, Math.E)), 1); - assert.strictEqual(normalizeLn(tickStep( 0, Math.E * 10, 10, Math.E)), 1); - assert.strictEqual(normalizeLn(tickStep( 1, Math.E * 10, 10, Math.E)), 2); - assert.strictEqual(normalizeLn(tickStep( -Math.E * 10, Math.E * 10, 10, Math.E)), 2); - assert.strictEqual(normalizeLn(tickStep( Math.E, Math.E * 100, 10, Math.E)), 1); - assert.strictEqual(normalizeLn(tickStep( -Math.E * 100, Math.E * 100, 10, Math.E)), 2); - assert.strictEqual(normalizeLn(tickStep( 0, Math.E * 100, 10, Math.E)), 1); - assert.strictEqual(tickStep( 0, 10, 10, Math.E), 1); - assert.strictEqual(tickStep( -10, 10, 10, Math.E), 2); +it("tickStep(start, stop, count, base) with natural log returns approximately count + 1 tickStep when start < stop", () => { + assert.strictEqual(normalizeLn(tickStep( 0, Math.E / 100, 10, 'natural')), 1); + assert.strictEqual(normalizeLn(tickStep( 0, Math.E / 10, 10, 'natural')), 2); + assert.strictEqual(normalizeLn(tickStep( 0, Math.E / 10, 1, 'natural')), 2); + assert.strictEqual(normalizeLn(tickStep( 0, Math.E, 3, 'natural')), 2); + assert.strictEqual(normalizeLn(tickStep( -Math.E, Math.E, 2, 'natural')), 1); + assert.strictEqual(normalizeLn(tickStep( 0, Math.E * 10, 10, 'natural')), 1); + assert.strictEqual(normalizeLn(tickStep( 1, Math.E * 10, 10, 'natural')), 2); + assert.strictEqual(normalizeLn(tickStep( -Math.E * 10, Math.E * 10, 10, 'natural')), 2); + assert.strictEqual(normalizeLn(tickStep( Math.E, Math.E * 100, 10, 'natural')), 1); + assert.strictEqual(normalizeLn(tickStep( -Math.E * 100, Math.E * 100, 10, 'natural')), 2); + assert.strictEqual(normalizeLn(tickStep( 0, Math.E * 100, 10, 'natural')), 1); + assert.strictEqual(tickStep( 0, 10, 10, 'natural'), 1); + assert.strictEqual(tickStep( -10, 10, 10, 'natural'), 2); }); -it("tickStep(start, stop, count, base) with base 2 returns -tickStep(stop, start, count)", () => { - assert.strictEqual(tickStep( 0, 1, 10, 2), -tickStep( 1, 0, 10, 2)); - assert.strictEqual(tickStep( 0, 1, 9, 2), -tickStep( 1, 0, 9, 2)); - assert.strictEqual(tickStep( 0, 1, 8, 2), -tickStep( 1, 0, 8, 2)); - assert.strictEqual(tickStep( 0, 1, 7, 2), -tickStep( 1, 0, 7, 2)); - assert.strictEqual(tickStep( 0, 1, 6, 2), -tickStep( 1, 0, 6, 2)); - assert.strictEqual(tickStep( 0, 1, 5, 2), -tickStep( 1, 0, 5, 2)); - assert.strictEqual(tickStep( 0, 1, 4, 2), -tickStep( 1, 0, 4, 2)); - assert.strictEqual(tickStep( 0, 1, 3, 2), -tickStep( 1, 0, 3, 2)); - assert.strictEqual(tickStep( 0, 1, 2, 2), -tickStep( 1, 0, 2, 2)); - assert.strictEqual(tickStep( 0, 1, 1, 2), -tickStep( 1, 0, 1, 2)); - assert.strictEqual(tickStep( 0, 10, 10, 2), -tickStep(10, 0, 10, 2)); - assert.strictEqual(tickStep( 0, 10, 9, 2), -tickStep(10, 0, 9, 2)); - assert.strictEqual(tickStep( 0, 10, 8, 2), -tickStep(10, 0, 8, 2)); - assert.strictEqual(tickStep( 0, 10, 7, 2), -tickStep(10, 0, 7, 2)); - assert.strictEqual(tickStep( 0, 10, 6, 2), -tickStep(10, 0, 6, 2)); - assert.strictEqual(tickStep( 0, 10, 5, 2), -tickStep(10, 0, 5, 2)); - assert.strictEqual(tickStep( 0, 10, 4, 2), -tickStep(10, 0, 4, 2)); - assert.strictEqual(tickStep( 0, 10, 3, 2), -tickStep(10, 0, 3, 2)); - assert.strictEqual(tickStep( 0, 10, 2, 2), -tickStep(10, 0, 2, 2)); - assert.strictEqual(tickStep( 0, 10, 1, 2), -tickStep(10, 0, 1, 2)); - assert.strictEqual(tickStep(-10, 10, 10, 2), -tickStep(10, -10, 10, 2)); - assert.strictEqual(tickStep(-10, 10, 9, 2), -tickStep(10, -10, 9, 2)); - assert.strictEqual(tickStep(-10, 10, 8, 2), -tickStep(10, -10, 8, 2)); - assert.strictEqual(tickStep(-10, 10, 7, 2), -tickStep(10, -10, 7, 2)); - assert.strictEqual(tickStep(-10, 10, 6, 2), -tickStep(10, -10, 6, 2)); - assert.strictEqual(tickStep(-10, 10, 5, 2), -tickStep(10, -10, 5, 2)); - assert.strictEqual(tickStep(-10, 10, 4, 2), -tickStep(10, -10, 4, 2)); - assert.strictEqual(tickStep(-10, 10, 3, 2), -tickStep(10, -10, 3, 2)); - assert.strictEqual(tickStep(-10, 10, 2, 2), -tickStep(10, -10, 2, 2)); - assert.strictEqual(tickStep(-10, 10, 1, 2), -tickStep(10, -10, 1, 2)); +it("tickStep(start, stop, count, base) with binary log returns -tickStep(stop, start, count)", () => { + assert.strictEqual(tickStep( 0, 1, 10, 'binary'), -tickStep( 1, 0, 10, 'binary')); + assert.strictEqual(tickStep( 0, 1, 9, 'binary'), -tickStep( 1, 0, 9, 'binary')); + assert.strictEqual(tickStep( 0, 1, 8, 'binary'), -tickStep( 1, 0, 8, 'binary')); + assert.strictEqual(tickStep( 0, 1, 7, 'binary'), -tickStep( 1, 0, 7, 'binary')); + assert.strictEqual(tickStep( 0, 1, 6, 'binary'), -tickStep( 1, 0, 6, 'binary')); + assert.strictEqual(tickStep( 0, 1, 5, 'binary'), -tickStep( 1, 0, 5, 'binary')); + assert.strictEqual(tickStep( 0, 1, 4, 'binary'), -tickStep( 1, 0, 4, 'binary')); + assert.strictEqual(tickStep( 0, 1, 3, 'binary'), -tickStep( 1, 0, 3, 'binary')); + assert.strictEqual(tickStep( 0, 1, 2, 'binary'), -tickStep( 1, 0, 2, 'binary')); + assert.strictEqual(tickStep( 0, 1, 1, 'binary'), -tickStep( 1, 0, 1, 'binary')); + assert.strictEqual(tickStep( 0, 10, 10, 'binary'), -tickStep(10, 0, 10, 'binary')); + assert.strictEqual(tickStep( 0, 10, 9, 'binary'), -tickStep(10, 0, 9, 'binary')); + assert.strictEqual(tickStep( 0, 10, 8, 'binary'), -tickStep(10, 0, 8, 'binary')); + assert.strictEqual(tickStep( 0, 10, 7, 'binary'), -tickStep(10, 0, 7, 'binary')); + assert.strictEqual(tickStep( 0, 10, 6, 'binary'), -tickStep(10, 0, 6, 'binary')); + assert.strictEqual(tickStep( 0, 10, 5, 'binary'), -tickStep(10, 0, 5, 'binary')); + assert.strictEqual(tickStep( 0, 10, 4, 'binary'), -tickStep(10, 0, 4, 'binary')); + assert.strictEqual(tickStep( 0, 10, 3, 'binary'), -tickStep(10, 0, 3, 'binary')); + assert.strictEqual(tickStep( 0, 10, 2, 'binary'), -tickStep(10, 0, 2, 'binary')); + assert.strictEqual(tickStep( 0, 10, 1, 'binary'), -tickStep(10, 0, 1, 'binary')); + assert.strictEqual(tickStep(-10, 10, 10, 'binary'), -tickStep(10, -10, 10, 'binary')); + assert.strictEqual(tickStep(-10, 10, 9, 'binary'), -tickStep(10, -10, 9, 'binary')); + assert.strictEqual(tickStep(-10, 10, 8, 'binary'), -tickStep(10, -10, 8, 'binary')); + assert.strictEqual(tickStep(-10, 10, 7, 'binary'), -tickStep(10, -10, 7, 'binary')); + assert.strictEqual(tickStep(-10, 10, 6, 'binary'), -tickStep(10, -10, 6, 'binary')); + assert.strictEqual(tickStep(-10, 10, 5, 'binary'), -tickStep(10, -10, 5, 'binary')); + assert.strictEqual(tickStep(-10, 10, 4, 'binary'), -tickStep(10, -10, 4, 'binary')); + assert.strictEqual(tickStep(-10, 10, 3, 'binary'), -tickStep(10, -10, 3, 'binary')); + assert.strictEqual(tickStep(-10, 10, 2, 'binary'), -tickStep(10, -10, 2, 'binary')); + assert.strictEqual(tickStep(-10, 10, 1, 'binary'), -tickStep(10, -10, 1, 'binary')); }); -it("tickStep(start, stop, count, base) with base e returns -tickStep(stop, start, count)", () => { - assert.strictEqual(tickStep( 0, 1, 10, Math.E), -tickStep( 1, 0, 10, Math.E)); - assert.strictEqual(tickStep( 0, 1, 9, Math.E), -tickStep( 1, 0, 9, Math.E)); - assert.strictEqual(tickStep( 0, 1, 8, Math.E), -tickStep( 1, 0, 8, Math.E)); - assert.strictEqual(tickStep( 0, 1, 7, Math.E), -tickStep( 1, 0, 7, Math.E)); - assert.strictEqual(tickStep( 0, 1, 6, Math.E), -tickStep( 1, 0, 6, Math.E)); - assert.strictEqual(tickStep( 0, 1, 5, Math.E), -tickStep( 1, 0, 5, Math.E)); - assert.strictEqual(tickStep( 0, 1, 4, Math.E), -tickStep( 1, 0, 4, Math.E)); - assert.strictEqual(tickStep( 0, 1, 3, Math.E), -tickStep( 1, 0, 3, Math.E)); - assert.strictEqual(tickStep( 0, 1, 2, Math.E), -tickStep( 1, 0, 2, Math.E)); - assert.strictEqual(tickStep( 0, 1, 1, Math.E), -tickStep( 1, 0, 1, Math.E)); - assert.strictEqual(tickStep( 0, 10, 10, Math.E), -tickStep(10, 0, 10, Math.E)); - assert.strictEqual(tickStep( 0, 10, 9, Math.E), -tickStep(10, 0, 9, Math.E)); - assert.strictEqual(tickStep( 0, 10, 8, Math.E), -tickStep(10, 0, 8, Math.E)); - assert.strictEqual(tickStep( 0, 10, 7, Math.E), -tickStep(10, 0, 7, Math.E)); - assert.strictEqual(tickStep( 0, 10, 6, Math.E), -tickStep(10, 0, 6, Math.E)); - assert.strictEqual(tickStep( 0, 10, 5, Math.E), -tickStep(10, 0, 5, Math.E)); - assert.strictEqual(tickStep( 0, 10, 4, Math.E), -tickStep(10, 0, 4, Math.E)); - assert.strictEqual(tickStep( 0, 10, 3, Math.E), -tickStep(10, 0, 3, Math.E)); - assert.strictEqual(tickStep( 0, 10, 2, Math.E), -tickStep(10, 0, 2, Math.E)); - assert.strictEqual(tickStep( 0, 10, 1, Math.E), -tickStep(10, 0, 1, Math.E)); - assert.strictEqual(tickStep(-10, 10, 10, Math.E), -tickStep(10, -10, 10, Math.E)); - assert.strictEqual(tickStep(-10, 10, 9, Math.E), -tickStep(10, -10, 9, Math.E)); - assert.strictEqual(tickStep(-10, 10, 8, Math.E), -tickStep(10, -10, 8, Math.E)); - assert.strictEqual(tickStep(-10, 10, 7, Math.E), -tickStep(10, -10, 7, Math.E)); - assert.strictEqual(tickStep(-10, 10, 6, Math.E), -tickStep(10, -10, 6, Math.E)); - assert.strictEqual(tickStep(-10, 10, 5, Math.E), -tickStep(10, -10, 5, Math.E)); - assert.strictEqual(tickStep(-10, 10, 4, Math.E), -tickStep(10, -10, 4, Math.E)); - assert.strictEqual(tickStep(-10, 10, 3, Math.E), -tickStep(10, -10, 3, Math.E)); - assert.strictEqual(tickStep(-10, 10, 2, Math.E), -tickStep(10, -10, 2, Math.E)); - assert.strictEqual(tickStep(-10, 10, 1, Math.E), -tickStep(10, -10, 1, Math.E)); +it("tickStep(start, stop, count, base) with natural log returns -tickStep(stop, start, count)", () => { + assert.strictEqual(tickStep( 0, 1, 10, 'natural'), -tickStep( 1, 0, 10, 'natural')); + assert.strictEqual(tickStep( 0, 1, 9, 'natural'), -tickStep( 1, 0, 9, 'natural')); + assert.strictEqual(tickStep( 0, 1, 8, 'natural'), -tickStep( 1, 0, 8, 'natural')); + assert.strictEqual(tickStep( 0, 1, 7, 'natural'), -tickStep( 1, 0, 7, 'natural')); + assert.strictEqual(tickStep( 0, 1, 6, 'natural'), -tickStep( 1, 0, 6, 'natural')); + assert.strictEqual(tickStep( 0, 1, 5, 'natural'), -tickStep( 1, 0, 5, 'natural')); + assert.strictEqual(tickStep( 0, 1, 4, 'natural'), -tickStep( 1, 0, 4, 'natural')); + assert.strictEqual(tickStep( 0, 1, 3, 'natural'), -tickStep( 1, 0, 3, 'natural')); + assert.strictEqual(tickStep( 0, 1, 2, 'natural'), -tickStep( 1, 0, 2, 'natural')); + assert.strictEqual(tickStep( 0, 1, 1, 'natural'), -tickStep( 1, 0, 1, 'natural')); + assert.strictEqual(tickStep( 0, 10, 10, 'natural'), -tickStep(10, 0, 10, 'natural')); + assert.strictEqual(tickStep( 0, 10, 9, 'natural'), -tickStep(10, 0, 9, 'natural')); + assert.strictEqual(tickStep( 0, 10, 8, 'natural'), -tickStep(10, 0, 8, 'natural')); + assert.strictEqual(tickStep( 0, 10, 7, 'natural'), -tickStep(10, 0, 7, 'natural')); + assert.strictEqual(tickStep( 0, 10, 6, 'natural'), -tickStep(10, 0, 6, 'natural')); + assert.strictEqual(tickStep( 0, 10, 5, 'natural'), -tickStep(10, 0, 5, 'natural')); + assert.strictEqual(tickStep( 0, 10, 4, 'natural'), -tickStep(10, 0, 4, 'natural')); + assert.strictEqual(tickStep( 0, 10, 3, 'natural'), -tickStep(10, 0, 3, 'natural')); + assert.strictEqual(tickStep( 0, 10, 2, 'natural'), -tickStep(10, 0, 2, 'natural')); + assert.strictEqual(tickStep( 0, 10, 1, 'natural'), -tickStep(10, 0, 1, 'natural')); + assert.strictEqual(tickStep(-10, 10, 10, 'natural'), -tickStep(10, -10, 10, 'natural')); + assert.strictEqual(tickStep(-10, 10, 9, 'natural'), -tickStep(10, -10, 9, 'natural')); + assert.strictEqual(tickStep(-10, 10, 8, 'natural'), -tickStep(10, -10, 8, 'natural')); + assert.strictEqual(tickStep(-10, 10, 7, 'natural'), -tickStep(10, -10, 7, 'natural')); + assert.strictEqual(tickStep(-10, 10, 6, 'natural'), -tickStep(10, -10, 6, 'natural')); + assert.strictEqual(tickStep(-10, 10, 5, 'natural'), -tickStep(10, -10, 5, 'natural')); + assert.strictEqual(tickStep(-10, 10, 4, 'natural'), -tickStep(10, -10, 4, 'natural')); + assert.strictEqual(tickStep(-10, 10, 3, 'natural'), -tickStep(10, -10, 3, 'natural')); + assert.strictEqual(tickStep(-10, 10, 2, 'natural'), -tickStep(10, -10, 2, 'natural')); + assert.strictEqual(tickStep(-10, 10, 1, 'natural'), -tickStep(10, -10, 1, 'natural')); }); diff --git a/test/ticks-test.js b/test/ticks-test.js index afaa543f..05db95ea 100644 --- a/test/ticks-test.js +++ b/test/ticks-test.js @@ -126,68 +126,38 @@ it("ticks(start, stop, count) tries to return at least one tick if count >= 0.5" assert.deepStrictEqual(ticks(-0.364, -0.001, 0.5), [-0.2]); }); -it("ticks(start, stop, count, base) returns ticks in base 2", () => { - assert.deepStrictEqual(ticks(0, 10, 5, 2), [0, 2, 4, 6, 8, 10]); +it("ticks(start, stop, count, base) returns ticks for binary log", () => { + assert.deepStrictEqual(ticks(0, 10, 5, 'binary'), [0, 2, 4, 6, 8, 10]); assert.deepStrictEqual( - ticks(0, 1024, 10, 2), + ticks(0, 1024, 10, 'binary'), [0, 128, 256, 384, 512, 640, 768, 896, 1024] ); assert.deepStrictEqual( - ticks(-1024, 1024, 20, 2), + ticks(-1024, 1024, 20, 'binary'), [ -1024, -896, -768, -640, -512, -384, -256, -128, 0, 128, 256, 384, 512, 640, 768, 896, 1024, ] ); - assert.deepStrictEqual(ticks(0, 2000, 5, 2), [0, 512, 1024, 1536]); + assert.deepStrictEqual(ticks(0, 2000, 5, 'binary'), [0, 512, 1024, 1536]); }); -it("ticks(start, stop, count, base) returns ticks in base e", () => { +it("ticks(start, stop, count, base) returns ticks for natural log", () => { assert.deepStrictEqual(ticks(0, 10, 5, Math.E), [0, 2, 4, 6, 8, 10]); assert.deepStrictEqual( - ticks(0, 10, 10, Math.E), + ticks(0, 10, 10, 'natural'), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ); assert.deepStrictEqual( - ticks(0, Math.E * 10, 10, Math.E), + ticks(0, Math.E * 10, 10, 'natural'), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((v) => (v *= Math.E)) ); assert.deepStrictEqual( - ticks(-Math.E * 10, Math.E * 10, 10, Math.E), + ticks(-Math.E * 10, Math.E * 10, 10, 'natural'), [-10, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10].map((v) => (v *= Math.E)) ); assert.deepStrictEqual( - ticks(-Math.E * 10, 0, 10, Math.E), + ticks(-Math.E * 10, 0, 10, 'natural'), [-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0].map((v) => (v *= Math.E)) ); }); - -it("ticks(start, stop, count, base) returns ticks in base 60", () => { - assert.deepStrictEqual( - ticks(0, 10, 10, 60), - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - ); - assert.deepStrictEqual( - ticks(0, 120, 10, 60), - [0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120] - ); - assert.deepStrictEqual( - ticks(0, 60 * 10, 10, 60), - [0, 60, 120, 180, 240, 300, 360, 420, 480, 540, 600] - ); - assert.deepStrictEqual( - ticks(-60 * 10, 0, 10, 60), - [-600, -540, -480, -420, -360, -300, -240, -180, -120, -60, 0] - ); - assert.deepStrictEqual( - ticks(-60 * 10, 60 * 10, 20, 60), - [ - -600, -540, -480, -420, -360, -300, -240, -180, -120, -60, 0, 60, 120, - 180, 240, 300, 360, 420, 480, 540, 600, - ] - ); - assert.deepStrictEqual( - ticks(0, 2000, 5, 60), - [0, 300, 600, 900, 1200, 1500, 1800] - ); -});