|
1 | 1 | import {parse as isoParse} from "isoformat";
|
2 |
| -import {isColor, isEvery, isOrdinal, isFirst, isSymbol, isTemporal, maybeSymbol, order} from "./options.js"; |
| 2 | +import {isColor, isEvery, isOrdinal, isFirst, isSymbol, isTemporal, maybeSymbol, order, isTemporalString} from "./options.js"; |
3 | 3 | import {registry, color, position, radius, opacity, symbol, length} from "./scales/index.js";
|
4 | 4 | import {ScaleLinear, ScaleSqrt, ScalePow, ScaleLog, ScaleSymlog, ScaleQuantile, ScaleThreshold, ScaleIdentity} from "./scales/quantitative.js";
|
5 | 5 | import {ScaleDiverging, ScaleDivergingSqrt, ScaleDivergingPow, ScaleDivergingLog, ScaleDivergingSymlog} from "./scales/diverging.js";
|
6 | 6 | import {ScaleTime, ScaleUtc} from "./scales/temporal.js";
|
7 | 7 | import {ScaleOrdinal, ScalePoint, ScaleBand, ordinalImplicit} from "./scales/ordinal.js";
|
| 8 | +import {warn} from "./warnings.js"; |
8 | 9 |
|
9 | 10 | export function Scales(channels, {
|
10 | 11 | inset: globalInset = 0,
|
@@ -133,6 +134,14 @@ export function normalizeScale(key, scale, hint) {
|
133 | 134 |
|
134 | 135 | function Scale(key, channels = [], options = {}) {
|
135 | 136 | const type = inferScaleType(key, channels, options);
|
| 137 | + |
| 138 | + // Warn for common misuse of implicit band scales. |
| 139 | + if (options.type === undefined && type === "band") { |
| 140 | + const values = channels.map(({value}) => value).filter(value => value !== undefined); |
| 141 | + 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 "band" scale. If you are using a bar mark, you probably want to switch to a rect mark with the interval option; if you are using a group transform, you probably want to switch to a bin transform. If you intend to treat this data as ordinal, you can suppress this warning by setting the type of the ${key} scale to "band".`); |
| 142 | + 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 and convert them to Date objects. Dates are typically associated with a "utc" or "time" scale rather than a "band" scale. If you are using a bar mark, you probably want to switch to a rect mark with the interval option; if you are using a group transform, you probably want to switch to a bin transform. If you intend to treat this data as ordinal, you can suppress this warning by setting the type of the ${key} scale to "${typeof type === "symbol" ? type.description : type}".`); |
| 143 | + } |
| 144 | + |
136 | 145 | options.type = type; // Mutates input!
|
137 | 146 |
|
138 | 147 | // Once the scale type is known, coerce the associated channel values and any
|
@@ -246,7 +255,11 @@ function inferScaleType(key, channels, {type, domain, range, scheme}) {
|
246 | 255 |
|
247 | 256 | // If any channel is ordinal or temporal, it takes priority.
|
248 | 257 | const values = channels.map(({value}) => value).filter(value => value !== undefined);
|
249 |
| - if (values.some(isOrdinal)) return asOrdinalType(kind); |
| 258 | + if (values.some(isOrdinal)) { |
| 259 | + const type = asOrdinalType(kind); |
| 260 | + 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 and convert them to Date objects. If you intend to treat this data as ordinal, you can suppress this warning by setting the type of the ${key} scale to "${typeof type === "symbol" ? type.description : type}".`); |
| 261 | + return type; |
| 262 | + } |
250 | 263 | if (values.some(isTemporal)) return "utc";
|
251 | 264 | return "linear";
|
252 | 265 | }
|
|
0 commit comments