Skip to content

Commit 9f9dd9c

Browse files
authored
boolean greys (#694)
1 parent 99e89f6 commit 9f9dd9c

File tree

4 files changed

+72
-47
lines changed

4 files changed

+72
-47
lines changed

src/scales/ordinal.js

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {ascendingDefined} from "../defined.js";
44
import {maybeSymbol} from "../options.js";
55
import {none} from "../style.js";
66
import {registry, color, symbol} from "./index.js";
7-
import {ordinalScheme, quantitativeScheme} from "./schemes.js";
7+
import {maybeBooleanRange, ordinalScheme, quantitativeScheme} from "./schemes.js";
88

99
export function ScaleO(scale, channels, {
1010
type,
@@ -26,26 +26,34 @@ export function ScaleO(scale, channels, {
2626

2727
export function ScaleOrdinal(key, channels, {
2828
type,
29+
domain = inferDomain(channels),
2930
range,
30-
scheme = range === undefined ? type === "ordinal" ? "turbo" : "tableau10" : undefined,
31+
scheme,
3132
unknown,
3233
...options
3334
}) {
3435
let hint;
3536
if (registry.get(key) === symbol) {
3637
hint = inferSymbolHint(channels);
3738
range = range === undefined ? inferSymbolRange(hint) : Array.from(range, maybeSymbol);
38-
} else if (registry.get(key) === color && scheme !== undefined) {
39-
if (range !== undefined) {
40-
const interpolate = quantitativeScheme(scheme);
41-
const t0 = range[0], d = range[1] - range[0];
42-
range = ({length: n}) => quantize(t => interpolate(t0 + d * t), n);
43-
} else {
44-
range = ordinalScheme(scheme);
39+
} else if (registry.get(key) === color) {
40+
if (scheme === undefined
41+
&& range === undefined
42+
&& (range = maybeBooleanRange(domain, "greys")) === undefined) {
43+
scheme = type === "ordinal" ? "turbo" : "tableau10";
44+
}
45+
if (scheme !== undefined) {
46+
if (range !== undefined) {
47+
const interpolate = quantitativeScheme(scheme);
48+
const t0 = range[0], d = range[1] - range[0];
49+
range = ({length: n}) => quantize(t => interpolate(t0 + d * t), n);
50+
} else {
51+
range = ordinalScheme(scheme);
52+
}
4553
}
4654
}
4755
if (unknown === scaleImplicit) throw new Error("implicit unknown is not supported");
48-
return ScaleO(scaleOrdinal().unknown(unknown), channels, {...options, type, range, hint});
56+
return ScaleO(scaleOrdinal().unknown(unknown), channels, {...options, type, domain, range, hint});
4957
}
5058

5159
export function ScalePoint(key, channels, {

src/scales/schemes.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ const ordinalSchemes = new Map([
143143

144144
function scheme9(scheme, interpolate) {
145145
return ({length: n}) => {
146+
if (n === 1) return [scheme[3][1]]; // favor midpoint
147+
if (n === 2) return [scheme[3][0], scheme[3][2]]; // favor extrema
146148
n = Math.max(3, Math.floor(n));
147149
return n > 9 ? quantize(interpolate, n) : scheme[n];
148150
};
@@ -184,6 +186,21 @@ export function ordinalRange(scheme, length) {
184186
return r.length !== length ? r.slice(0, length) : r;
185187
}
186188

189+
// If the specified domain contains only booleans (ignoring null and undefined),
190+
// returns a corresponding range where false is mapped to the low color and true
191+
// is mapped to the high color of the specified scheme.
192+
export function maybeBooleanRange(domain, scheme) {
193+
const range = new Set();
194+
const [f, t] = ordinalScheme(scheme)({length: 2});
195+
for (const value of domain) {
196+
if (value == null) continue;
197+
if (value === true) range.add(t);
198+
else if (value === false) range.add(f);
199+
else return;
200+
}
201+
return [...range];
202+
}
203+
187204
const quantitativeSchemes = new Map([
188205
// diverging
189206
["brbg", interpolateBrBG],

0 commit comments

Comments
 (0)