Skip to content

Commit

Permalink
Fix #97 - add scale.unknown.
Browse files Browse the repository at this point in the history
  • Loading branch information
mbostock committed Jan 26, 2019
1 parent 19a03ec commit 4d89464
Show file tree
Hide file tree
Showing 10 changed files with 103 additions and 19 deletions.
10 changes: 8 additions & 2 deletions src/continuous.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ export function copy(source, target) {
.domain(source.domain())
.range(source.range())
.interpolate(source.interpolate())
.clamp(source.clamp());
.clamp(source.clamp())
.unknown(source.unknown());
}

export function transformer() {
Expand All @@ -68,6 +69,7 @@ export function transformer() {
interpolate = interpolateValue,
transform,
untransform,
unknown,
clamp = identity,
piecewise,
output,
Expand All @@ -80,7 +82,7 @@ export function transformer() {
}

function scale(x) {
return (output || (output = piecewise(domain.map(transform), range, interpolate)))(transform(clamp(x)));
return isNaN(x = +x) ? unknown : (output || (output = piecewise(domain.map(transform), range, interpolate)))(transform(clamp(x)));
}

scale.invert = function(y) {
Expand All @@ -107,6 +109,10 @@ export function transformer() {
return arguments.length ? (interpolate = _, rescale()) : interpolate;
};

scale.unknown = function(_) {
return arguments.length ? (unknown = _, scale) : unknown;
};

return function(t, u) {
transform = t, untransform = u;
return rescale();
Expand Down
10 changes: 7 additions & 3 deletions src/diverging.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ function transformer() {
k21,
interpolator = identity,
transform,
clamp = false;
clamp = false,
unknown;

function scale(x) {
var t = 0.5 + ((x = +transform(x)) - t1) * (x < t1 ? k10 : k21);
return interpolator(clamp ? Math.max(0, Math.min(1, t)) : t);
return isNaN(x = +x) ? unknown : (x = 0.5 + ((x = +transform(x)) - t1) * (x < t1 ? k10 : k21), interpolator(clamp ? Math.max(0, Math.min(1, x)) : x));
}

scale.domain = function(_) {
Expand All @@ -36,6 +36,10 @@ function transformer() {
return arguments.length ? (interpolator = _, scale) : interpolator;
};

scale.unknown = function(_) {
return arguments.length ? (unknown = _, scale) : unknown;
};

return function(t) {
transform = t, t0 = t(x0), t1 = t(x1), t2 = t(x2), k10 = t0 === t1 ? 0 : 0.5 / (t1 - t0), k21 = t1 === t2 ? 0 : 0.5 / (t2 - t1);
return scale;
Expand Down
9 changes: 7 additions & 2 deletions src/identity.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import {linearish} from "./linear";
import number from "./number";

export default function identity(domain) {
var unknown;

function scale(x) {
return +x;
return isNaN(x = +x) ? unknown : x;
}

scale.invert = scale;
Expand All @@ -14,8 +15,12 @@ export default function identity(domain) {
return arguments.length ? (domain = map.call(_, number), scale) : domain.slice();
};

scale.unknown = function(_) {
return arguments.length ? (unknown = _, scale) : unknown;
};

scale.copy = function() {
return identity(domain);
return identity(domain).unknown(unknown);
};

domain = arguments.length ? map.call(domain, number) : [0, 1];
Expand Down
12 changes: 9 additions & 3 deletions src/quantile.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import {initRange} from "./init";
export default function quantile() {
var domain = [],
range = [],
thresholds = [];
thresholds = [],
unknown;

function rescale() {
var i = 0, n = Math.max(1, range.length);
Expand All @@ -15,7 +16,7 @@ export default function quantile() {
}

function scale(x) {
if (!isNaN(x = +x)) return range[bisect(thresholds, x)];
return isNaN(x = +x) ? unknown : range[bisect(thresholds, x)];
}

scale.invertExtent = function(y) {
Expand All @@ -38,14 +39,19 @@ export default function quantile() {
return arguments.length ? (range = slice.call(_), rescale()) : range.slice();
};

scale.unknown = function(_) {
return arguments.length ? (unknown = _, scale) : unknown;
};

scale.quantiles = function() {
return thresholds.slice();
};

scale.copy = function() {
return quantile()
.domain(domain)
.range(range);
.range(range)
.unknown(unknown);
};

return initRange.apply(scale, arguments);
Expand Down
12 changes: 9 additions & 3 deletions src/quantize.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ export default function quantize() {
x1 = 1,
n = 1,
domain = [0.5],
range = [0, 1];
range = [0, 1],
unknown;

function scale(x) {
if (x <= x) return range[bisect(domain, x, 0, n)];
return x <= x ? range[bisect(domain, x, 0, n)] : unknown;
}

function rescale() {
Expand All @@ -37,10 +38,15 @@ export default function quantize() {
: [domain[i - 1], domain[i]];
};

scale.unknown = function(_) {
return arguments.length ? (unknown = _, scale) : scale;
};

scale.copy = function() {
return quantize()
.domain([x0, x1])
.range(range);
.range(range)
.unknown(unknown);
};

return initRange.apply(linearish(scale), arguments);
Expand Down
13 changes: 9 additions & 4 deletions src/sequential.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ function transformer() {
k10,
transform,
interpolator = identity,
clamp = false;
clamp = false,
unknown;

function scale(x) {
var t = (transform(x) - t0) * k10;
return interpolator(clamp ? Math.max(0, Math.min(1, t)) : t);
return isNaN(x = +x) ? unknown : (x = (transform(x) - t0) * k10, interpolator(clamp ? Math.max(0, Math.min(1, x)) : x));
}

scale.domain = function(_) {
Expand All @@ -32,6 +32,10 @@ function transformer() {
return arguments.length ? (interpolator = _, scale) : interpolator;
};

scale.unknown = function(_) {
return arguments.length ? (unknown = _, scale) : unknown;
};

return function(t) {
transform = t, t0 = t(x0), t1 = t(x1), k10 = t0 === t1 ? 0 : 1 / (t1 - t0);
return scale;
Expand All @@ -42,7 +46,8 @@ export function copy(source, target) {
return target
.domain(source.domain())
.interpolator(source.interpolator())
.clamp(source.clamp());
.clamp(source.clamp())
.unknown(source.unknown());
}

export default function sequential() {
Expand Down
10 changes: 8 additions & 2 deletions src/threshold.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import {initRange} from "./init";
export default function threshold() {
var domain = [0.5],
range = [0, 1],
unknown,
n = 1;

function scale(x) {
if (x <= x) return range[bisect(domain, x, 0, n)];
return x <= x ? range[bisect(domain, x, 0, n)] : unknown;
}

scale.domain = function(_) {
Expand All @@ -24,10 +25,15 @@ export default function threshold() {
return [domain[i - 1], domain[i]];
};

scale.unknown = function(_) {
return arguments.length ? (unknown = _, scale) : unknown;
};

scale.copy = function() {
return threshold()
.domain(domain)
.range(range);
.range(range)
.unknown(unknown);
};

return initRange.apply(scale, arguments);
Expand Down
23 changes: 23 additions & 0 deletions test/linear-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ tape("scaleLinear() has the expected defaults", function(test) {
test.deepEqual(s.domain(), [0, 1]);
test.deepEqual(s.range(), [0, 1]);
test.equal(s.clamp(), false);
test.equal(s.unknown(), undefined);
test.deepEqual(s.interpolate()({array: ["red"]}, {array: ["blue"]})(0.5), {array: ["rgb(128, 0, 128)"]});
test.end();
});
Expand Down Expand Up @@ -184,6 +185,15 @@ tape("linear.rangeRound(range) is an alias for linear.range(range).interpolate(i
test.end();
});

tape("linear.unknown(value) sets the return value for undefined and NaN input", function(test) {
var s = scale.scaleLinear().unknown(-1);
test.equal(s(undefined), -1);
test.equal(s(NaN), -1);
test.equal(s("N/A"), -1);
test.equal(s(0.4), 0.4);
test.end();
});

tape("linear.clamp() is false by default", function(test) {
test.equal(scale.scaleLinear().clamp(), false);
test.equal(scale.scaleLinear().range([10, 20])(2), 30);
Expand Down Expand Up @@ -471,3 +481,16 @@ tape("linear.copy() returns a copy with changes to clamping are isolated", funct
test.equal(x.clamp(), false);
test.end();
});

tape("linear.copy() returns a copy with changes to the unknown value are isolated", function(test) {
var x = scale.scaleLinear(), y = x.copy();
x.unknown(2);
test.equal(x(NaN), 2);
test.equal(isNaN(y(NaN)), true);
test.equal(y.unknown(), undefined);
y.unknown(3);
test.equal(x(NaN), 2);
test.equal(y(NaN), 3);
test.equal(x.unknown(), 2);
test.end();
});
12 changes: 12 additions & 0 deletions test/quantile-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ tape("scaleQuantile() has the expected default", function(test) {
var s = scale.scaleQuantile();
test.deepEqual(s.domain(), []);
test.deepEqual(s.range(), []);
test.equal(s.unknown(), undefined);
test.end();
});

Expand Down Expand Up @@ -115,3 +116,14 @@ tape("quantile.invertExtent() returns the first match if duplicate values exist
test.deepEqual(s.invertExtent(2), [9, 14.5]);
test.end();
});

tape("quantile.unknown(value) sets the return value for undefined and NaN input", function(test) {
var s = scale.scaleQuantile().domain([3, 6, 7, 8, 8, 10, 13, 15, 16, 20]).range([0, 1, 2, 3]).unknown(-1);
test.equal(s(undefined), -1);
test.equal(s(NaN), -1);
test.equal(s("N/A"), -1);
test.equal(s(2), 0);
test.equal(s(3), 0);
test.equal(s(21), 3);
test.end();
});
11 changes: 11 additions & 0 deletions test/sequential-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ tape("scaleSequential() has the expected defaults", function(test) {
test.deepEqual(s.domain(), [0, 1]);
test.equal(s.interpolator()(0.42), 0.42);
test.equal(s.clamp(), false);
test.equal(s.unknown(), undefined);
test.equal(s(-0.5), -0.5);
test.equal(s( 0.0), 0.0);
test.equal(s( 0.5), 0.5);
Expand All @@ -25,6 +26,16 @@ tape("sequential.clamp(true) enables clamping", function(test) {
test.end();
});

tape("sequential.unknown(value) sets the return value for undefined and NaN input", function(test) {
var s = scale.scaleSequential().unknown(-1);
test.equal(s.unknown(), -1);
test.equal(s(undefined), -1);
test.equal(s(NaN), -1);
test.equal(s("N/A"), -1);
test.equal(s(0.4), 0.4);
test.end();
});

tape("sequential.domain() coerces domain values to numbers", function(test) {
var s = scale.scaleSequential().domain(["-1.20", "2.40"]);
test.deepEqual(s.domain(), [-1.2, 2.4]);
Expand Down

0 comments on commit 4d89464

Please sign in to comment.