diff --git a/src/options.js b/src/options.js
index a655888ed7..5eeb0aefe2 100644
--- a/src/options.js
+++ b/src/options.js
@@ -1,3 +1,4 @@
+import {parse as isoParse} from "isoformat";
import {color, descending} from "d3";
import {symbolAsterisk, symbolDiamond2, symbolPlus, symbolSquare2, symbolTriangle2, symbolX as symbolTimes} from "d3";
import {symbolCircle, symbolCross, symbolDiamond, symbolSquare, symbolStar, symbolTriangle, symbolWye} from "d3";
@@ -210,6 +211,26 @@ export function isTemporal(values) {
}
}
+// Are these strings that might represent dates? This is stricter than ISO 8601
+// because we want to ignore false positives on numbers; for example, the string
+// "1192" is more likely to represent a number than a date even though it is
+// valid ISO 8601 representing 1192-01-01.
+export function isTemporalString(values) {
+ for (const value of values) {
+ if (value == null) continue;
+ return typeof value === "string" && isNaN(value) && isoParse(value);
+ }
+}
+
+// Are these strings that might represent numbers? This is stricter than
+// coercion because we want to ignore false positives on e.g. empty strings.
+export function isNumericString(values) {
+ for (const value of values) {
+ if (value == null || value === "") continue;
+ return typeof value === "string" && !isNaN(value);
+ }
+}
+
export function isNumeric(values) {
for (const value of values) {
if (value == null) continue;
diff --git a/src/plot.js b/src/plot.js
index e1980d8378..5299d73fb2 100644
--- a/src/plot.js
+++ b/src/plot.js
@@ -1,4 +1,4 @@
-import {create, cross, difference, groups, InternMap} from "d3";
+import {create, cross, difference, groups, InternMap, select} from "d3";
import {Axes, autoAxisTicks, autoScaleLabels} from "./axes.js";
import {Channel, channelSort} from "./channel.js";
import {defined} from "./defined.js";
@@ -8,6 +8,7 @@ import {arrayify, isOptions, keyword, range, first, second, where} from "./optio
import {Scales, ScaleFunctions, autoScaleRange, applyScales, exposeScales} from "./scales.js";
import {applyInlineStyles, maybeClassName, maybeClip, styles} from "./style.js";
import {basic} from "./transforms/basic.js";
+import {consumeWarnings} from "./warnings.js";
export function plot(options = {}) {
const {facet, style, caption, ariaLabel, ariaDescription} = options;
@@ -119,6 +120,19 @@ export function plot(options = {}) {
figure.scale = exposeScales(scaleDescriptors);
figure.legend = exposeLegends(scaleDescriptors, options);
+
+ const w = consumeWarnings();
+ if (w > 0) {
+ select(svg).append("text")
+ .attr("x", width)
+ .attr("y", 20)
+ .attr("dy", "-1em")
+ .attr("text-anchor", "end")
+ .text("⚠️")
+ .append("title")
+ .text(`${w.toLocaleString("en-US")} warning${w === 1 ? "" : "s"}. Please check the console.`);
+ }
+
return figure;
}
diff --git a/src/scales.js b/src/scales.js
index 9dffed4168..91bef69edf 100644
--- a/src/scales.js
+++ b/src/scales.js
@@ -1,10 +1,11 @@
import {parse as isoParse} from "isoformat";
-import {isColor, isEvery, isOrdinal, isFirst, isSymbol, isTemporal, maybeSymbol, order} from "./options.js";
+import {isColor, isEvery, isOrdinal, isFirst, isSymbol, isTemporal, maybeSymbol, order, isTemporalString, isNumericString} from "./options.js";
import {registry, color, position, radius, opacity, symbol, length} from "./scales/index.js";
import {ScaleLinear, ScaleSqrt, ScalePow, ScaleLog, ScaleSymlog, ScaleQuantile, ScaleThreshold, ScaleIdentity} from "./scales/quantitative.js";
import {ScaleDiverging, ScaleDivergingSqrt, ScaleDivergingPow, ScaleDivergingLog, ScaleDivergingSymlog} from "./scales/diverging.js";
import {ScaleTime, ScaleUtc} from "./scales/temporal.js";
import {ScaleOrdinal, ScalePoint, ScaleBand, ordinalImplicit} from "./scales/ordinal.js";
+import {warn} from "./warnings.js";
export function Scales(channels, {
inset: globalInset = 0,
@@ -133,6 +134,24 @@ export function normalizeScale(key, scale, hint) {
function Scale(key, channels = [], options = {}) {
const type = inferScaleType(key, channels, options);
+
+ // Warn for common misuses of implicit ordinal scales. We disable this test if
+ // you set the domain or range explicitly, since setting the domain or range
+ // (typically with a cardinality of more than two) is another indication that
+ // you intended for the scale to be ordinal; we also disable it for facet
+ // scales since these are always band scales.
+ if (options.type === undefined
+ && options.domain === undefined
+ && options.range === undefined
+ && key !== "fx"
+ && key !== "fy"
+ && isOrdinalScale({type})) {
+ const values = channels.map(({value}) => value).filter(value => value !== undefined);
+ if (values.some(isTemporal)) warn(`Warning: some data associated with the ${key} scale are dates. Dates are typically associated with a "utc" or "time" scale rather than a "${formatScaleType(type)}" scale. If you are using a bar mark, you probably want a rect mark with the interval option instead; if you are using a group transform, you probably want a bin transform instead. If you want to treat this data as ordinal, you can suppress this warning by setting the type of the ${key} scale to "${formatScaleType(type)}".`);
+ else if (values.some(isTemporalString)) warn(`Warning: some data associated with the ${key} scale are strings that appear to be dates (e.g., YYYY-MM-DD). If these strings represent dates, you should parse them to Date objects. Dates are typically associated with a "utc" or "time" scale rather than a "${formatScaleType(type)}" scale. If you are using a bar mark, you probably want a rect mark with the interval option instead; if you are using a group transform, you probably want a bin transform instead. If you want to treat this data as ordinal, you can suppress this warning by setting the type of the ${key} scale to "${formatScaleType(type)}".`);
+ else if (values.some(isNumericString)) warn(`Warning: some data associated with the ${key} scale are strings that appear to be numbers. If these strings represent numbers, you should parse or coerce them to numbers. Numbers are typically associated with a "linear" scale rather than a "${formatScaleType(type)}" scale. If you want to treat this data as ordinal, you can suppress this warning by setting the type of the ${key} scale to "${formatScaleType(type)}".`);
+ }
+
options.type = type; // Mutates input!
// Once the scale type is known, coerce the associated channel values and any
@@ -190,6 +209,10 @@ function Scale(key, channels = [], options = {}) {
}
}
+function formatScaleType(type) {
+ return typeof type === "symbol" ? type.description : type;
+}
+
function inferScaleType(key, channels, {type, domain, range, scheme}) {
// The facet scales are always band scales; this cannot be changed.
if (key === "fx" || key === "fy") return "band";
@@ -272,7 +295,7 @@ export function isTemporalScale({type}) {
}
export function isOrdinalScale({type}) {
- return type === "ordinal" || type === "point" || type === "band";
+ return type === "ordinal" || type === "point" || type === "band" || type === ordinalImplicit;
}
function isThresholdScale({type}) {
diff --git a/src/transforms/window.js b/src/transforms/window.js
index cb53440f6f..e386dbb91f 100644
--- a/src/transforms/window.js
+++ b/src/transforms/window.js
@@ -1,5 +1,6 @@
import {mapX, mapY} from "./map.js";
import {deviation, max, min, median, mode, variance} from "d3";
+import {warn} from "../warnings.js";
export function windowX(windowOptions = {}, options) {
if (arguments.length === 1) options = windowOptions;
@@ -13,7 +14,11 @@ export function windowY(windowOptions = {}, options) {
export function window(options = {}) {
if (typeof options === "number") options = {k: options};
- let {k, reduce, shift, anchor = maybeShift(shift)} = options;
+ let {k, reduce, shift, anchor} = options;
+ if (anchor === undefined && shift !== undefined) {
+ anchor = maybeShift(shift);
+ warn(`Warning: the shift option is deprecated; please use anchor "${anchor}" instead.`);
+ }
if (!((k = Math.floor(k)) > 0)) throw new Error("invalid k");
return maybeReduce(reduce)(k, maybeAnchor(anchor, k));
}
@@ -28,8 +33,6 @@ function maybeAnchor(anchor = "middle", k) {
}
function maybeShift(shift) {
- if (shift === undefined) return;
- console.warn("shift is deprecated; please use anchor instead");
switch (`${shift}`.toLowerCase()) {
case "centered": return "middle";
case "leading": return "start";
diff --git a/src/warnings.js b/src/warnings.js
new file mode 100644
index 0000000000..6c13e8db1e
--- /dev/null
+++ b/src/warnings.js
@@ -0,0 +1,12 @@
+let warnings = 0;
+
+export function consumeWarnings() {
+ const w = warnings;
+ warnings = 0;
+ return w;
+}
+
+export function warn(message) {
+ console.warn(message);
+ ++warnings;
+}
diff --git a/test/output/crimeanWarOverlapped.svg b/test/output/crimeanWarOverlapped.svg
index e4487a7f97..32b60e552f 100644
--- a/test/output/crimeanWarOverlapped.svg
+++ b/test/output/crimeanWarOverlapped.svg
@@ -57,153 +57,108 @@
2,600
↑ deaths
-
-
+
+
Apr
-
- May
-
-
- Jun
-
-
+
Jul
-
- Aug
-
-
- Sep
-
-
+
Oct
-
- Nov
-
-
- Dec
-
-
+
Jan
-
- Feb
-
-
- Mar
-
-
+
Apr
-
- May
-
-
- Jun
-
-
+
Jul
-
- Aug
-
-
- Sep
-
-
+
Oct
-
- Nov
-
-
- Dec
-
-
+
Jan
-
- Feb
-
-
- Mar
+
+ Apr
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/output/crimeanWarStacked.svg b/test/output/crimeanWarStacked.svg
index a3d1cbc610..f069d566be 100644
--- a/test/output/crimeanWarStacked.svg
+++ b/test/output/crimeanWarStacked.svg
@@ -36,153 +36,108 @@
3,000
↑ deaths
-
-
+
+
Apr
-
- May
-
-
- Jun
-
-
+
Jul
-
- Aug
-
-
- Sep
-
-
+
Oct
-
- Nov
-
-
- Dec
-
-
+
Jan
-
- Feb
-
-
- Mar
-
-
+
Apr
-
- May
-
-
- Jun
-
-
+
Jul
-
- Aug
-
-
- Sep
-
-
+
Oct
-
- Nov
-
-
- Dec
-
-
+
Jan
-
- Feb
-
-
- Mar
+
+ Apr
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/plots/crimean-war-overlapped.js b/test/plots/crimean-war-overlapped.js
index 05b2dec665..071209a38a 100644
--- a/test/plots/crimean-war-overlapped.js
+++ b/test/plots/crimean-war-overlapped.js
@@ -11,7 +11,7 @@ export default async function() {
label: null
},
marks: [
- Plot.barY(data, {x: "date", y2: "deaths", sort: d => -d.deaths, fill: "cause"}),
+ Plot.rectY(data, {x: "date", interval: d3.utcMonth, y2: "deaths", fill: "cause", mixBlendMode: "multiply"}),
Plot.ruleY([0])
]
});
diff --git a/test/plots/crimean-war-stacked.js b/test/plots/crimean-war-stacked.js
index d442a02d17..5387fa8a33 100644
--- a/test/plots/crimean-war-stacked.js
+++ b/test/plots/crimean-war-stacked.js
@@ -11,7 +11,7 @@ export default async function() {
label: null
},
marks: [
- Plot.barY(data, {x: "date", y: "deaths", fill: "cause", reverse: true}),
+ Plot.rectY(data, {x: "date", interval: d3.utcMonth, y: "deaths", fill: "cause", reverse: true}),
Plot.ruleY([0])
]
});
diff --git a/test/plots/fruit-sales-date.js b/test/plots/fruit-sales-date.js
index c5a2de3b64..8116e9b3b2 100644
--- a/test/plots/fruit-sales-date.js
+++ b/test/plots/fruit-sales-date.js
@@ -4,6 +4,9 @@ import * as d3 from "d3";
export default async function() {
const sales = await d3.csv("data/fruit-sales.csv", d3.autoType);
return Plot.plot({
+ x: {
+ type: "band" // treat dates as ordinal, not temporal
+ },
marks: [
Plot.barY(sales, Plot.stackY({x: "date", y: "units", fill: "fruit"})),
Plot.text(sales, Plot.stackY({x: "date", y: "units", text: "fruit" }))
diff --git a/test/plots/software-versions.js b/test/plots/software-versions.js
index b691e7a069..31ef4c0a0e 100644
--- a/test/plots/software-versions.js
+++ b/test/plots/software-versions.js
@@ -30,6 +30,7 @@ export default async function() {
percent: true
},
color: {
+ type: "ordinal",
scheme: "blues"
},
marks: [
diff --git a/test/plots/stargazers-hourly-group.js b/test/plots/stargazers-hourly-group.js
index bea5ff6044..66e3ddbeae 100644
--- a/test/plots/stargazers-hourly-group.js
+++ b/test/plots/stargazers-hourly-group.js
@@ -5,6 +5,7 @@ export default async function() {
const stargazers = await d3.csv("data/stargazers.csv", d3.autoType);
return Plot.plot({
x: {
+ type: "band",
label: "New stargazers per hour →"
},
y: {
diff --git a/test/scales/scales-test.js b/test/scales/scales-test.js
index 6165f4c895..8613e2abc0 100644
--- a/test/scales/scales-test.js
+++ b/test/scales/scales-test.js
@@ -1137,60 +1137,60 @@ it("plot({clamp, …}).scale('x').clamp reflects the given clamp option", () =>
});
it("plot({align, …}).scale('x').align reflects the given align option for point scales", () => {
- assert.strictEqual(Plot.dot(["1", "2", "3"], {x: d => d}).plot({x: {align: 0}}).scale("x").align, 0);
- assert.strictEqual(Plot.dot(["1", "2", "3"], {x: d => d}).plot({x: {align: 0.7}}).scale("x").align, 0.7);
- assert.strictEqual(Plot.dot(["1", "2", "3"], {x: d => d}).plot({x: {align: "0.7"}}).scale("x").align, 0.7);
- assert.strictEqual(Plot.dot(["1", "2", "3"], {x: d => d}).plot({x: {align: 1}}).scale("x").align, 1);
+ assert.strictEqual(Plot.dot("abc", {x: d => d}).plot({x: {align: 0}}).scale("x").align, 0);
+ assert.strictEqual(Plot.dot("abc", {x: d => d}).plot({x: {align: 0.7}}).scale("x").align, 0.7);
+ assert.strictEqual(Plot.dot("abc", {x: d => d}).plot({x: {align: "0.7"}}).scale("x").align, 0.7);
+ assert.strictEqual(Plot.dot("abc", {x: d => d}).plot({x: {align: 1}}).scale("x").align, 1);
});
it("plot({align, …}).scale('x').align reflects the given align option for band scales", () => {
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {align: 0}}).scale("x").align, 0);
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {align: 0.7}}).scale("x").align, 0.7);
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {align: "0.7"}}).scale("x").align, 0.7);
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {align: 1}}).scale("x").align, 1);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {align: 0}}).scale("x").align, 0);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {align: 0.7}}).scale("x").align, 0.7);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {align: "0.7"}}).scale("x").align, 0.7);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {align: 1}}).scale("x").align, 1);
});
it("plot({paddingInner, …}).scale('x').paddingInner reflects the given paddingInner option for band scales", () => {
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {paddingInner: 0}}).scale("x").paddingInner, 0);
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {paddingInner: 0.7}}).scale("x").paddingInner, 0.7);
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {paddingInner: "0.7"}}).scale("x").paddingInner, 0.7);
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {paddingInner: 1}}).scale("x").paddingInner, 1);
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {padding: 0, paddingInner: 0}}).scale("x").paddingInner, 0);
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {padding: 0, paddingInner: 0.7}}).scale("x").paddingInner, 0.7);
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {padding: 0, paddingInner: "0.7"}}).scale("x").paddingInner, 0.7);
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {padding: 0, paddingInner: 1}}).scale("x").paddingInner, 1);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {paddingInner: 0}}).scale("x").paddingInner, 0);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {paddingInner: 0.7}}).scale("x").paddingInner, 0.7);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {paddingInner: "0.7"}}).scale("x").paddingInner, 0.7);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {paddingInner: 1}}).scale("x").paddingInner, 1);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {padding: 0, paddingInner: 0}}).scale("x").paddingInner, 0);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {padding: 0, paddingInner: 0.7}}).scale("x").paddingInner, 0.7);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {padding: 0, paddingInner: "0.7"}}).scale("x").paddingInner, 0.7);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {padding: 0, paddingInner: 1}}).scale("x").paddingInner, 1);
});
it("plot({paddingOuter, …}).scale('x').paddingOuter reflects the given paddingOuter option for band scales", () => {
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {paddingOuter: 0}}).scale("x").paddingOuter, 0);
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {paddingOuter: 0.7}}).scale("x").paddingOuter, 0.7);
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {paddingOuter: "0.7"}}).scale("x").paddingOuter, 0.7);
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {paddingOuter: 1}}).scale("x").paddingOuter, 1);
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {padding: 0, paddingOuter: 0}}).scale("x").paddingOuter, 0);
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {padding: 0, paddingOuter: 0.7}}).scale("x").paddingOuter, 0.7);
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {padding: 0, paddingOuter: "0.7"}}).scale("x").paddingOuter, 0.7);
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {padding: 0, paddingOuter: 1}}).scale("x").paddingOuter, 1);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {paddingOuter: 0}}).scale("x").paddingOuter, 0);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {paddingOuter: 0.7}}).scale("x").paddingOuter, 0.7);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {paddingOuter: "0.7"}}).scale("x").paddingOuter, 0.7);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {paddingOuter: 1}}).scale("x").paddingOuter, 1);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {padding: 0, paddingOuter: 0}}).scale("x").paddingOuter, 0);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {padding: 0, paddingOuter: 0.7}}).scale("x").paddingOuter, 0.7);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {padding: 0, paddingOuter: "0.7"}}).scale("x").paddingOuter, 0.7);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {padding: 0, paddingOuter: 1}}).scale("x").paddingOuter, 1);
});
it("plot({padding, …}).scale('x').paddingInner reflects the given padding option for band scales", () => {
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {padding: 0}}).scale("x").paddingInner, 0);
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {padding: 0.7}}).scale("x").paddingInner, 0.7);
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {padding: "0.7"}}).scale("x").paddingInner, 0.7);
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {padding: 1}}).scale("x").paddingInner, 1);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {padding: 0}}).scale("x").paddingInner, 0);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {padding: 0.7}}).scale("x").paddingInner, 0.7);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {padding: "0.7"}}).scale("x").paddingInner, 0.7);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {padding: 1}}).scale("x").paddingInner, 1);
});
it("plot({padding, …}).scale('x').paddingOuter reflects the given padding option for band scales", () => {
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {padding: 0}}).scale("x").paddingOuter, 0);
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {padding: 0.7}}).scale("x").paddingOuter, 0.7);
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {padding: "0.7"}}).scale("x").paddingOuter, 0.7);
- assert.strictEqual(Plot.cell(["1", "2", "3"], {x: d => d}).plot({x: {padding: 1}}).scale("x").paddingOuter, 1);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {padding: 0}}).scale("x").paddingOuter, 0);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {padding: 0.7}}).scale("x").paddingOuter, 0.7);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {padding: "0.7"}}).scale("x").paddingOuter, 0.7);
+ assert.strictEqual(Plot.cell("abc", {x: d => d}).plot({x: {padding: 1}}).scale("x").paddingOuter, 1);
});
it("plot({padding, …}).scale('x').padding reflects the given padding option for point scales", () => {
- assert.strictEqual(Plot.dot(["1", "2", "3"], {x: d => d}).plot({x: {padding: 0}}).scale("x").padding, 0);
- assert.strictEqual(Plot.dot(["1", "2", "3"], {x: d => d}).plot({x: {padding: 0.7}}).scale("x").padding, 0.7);
- assert.strictEqual(Plot.dot(["1", "2", "3"], {x: d => d}).plot({x: {padding: "0.7"}}).scale("x").padding, 0.7);
- assert.strictEqual(Plot.dot(["1", "2", "3"], {x: d => d}).plot({x: {padding: 1}}).scale("x").padding, 1);
+ assert.strictEqual(Plot.dot("abc", {x: d => d}).plot({x: {padding: 0}}).scale("x").padding, 0);
+ assert.strictEqual(Plot.dot("abc", {x: d => d}).plot({x: {padding: 0.7}}).scale("x").padding, 0.7);
+ assert.strictEqual(Plot.dot("abc", {x: d => d}).plot({x: {padding: "0.7"}}).scale("x").padding, 0.7);
+ assert.strictEqual(Plot.dot("abc", {x: d => d}).plot({x: {padding: 1}}).scale("x").padding, 1);
});
it("plot(…).scale('x').label reflects the default label for named fields, possibly reversed", () => {