|
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, isNumericString} 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,24 @@ 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 misuses of implicit ordinal scales. We disable this test if |
| 139 | + // you set the domain or range explicitly, since setting the domain or range |
| 140 | + // (typically with a cardinality of more than two) is another indication that |
| 141 | + // you intended for the scale to be ordinal; we also disable it for facet |
| 142 | + // scales since these are always band scales. |
| 143 | + if (options.type === undefined |
| 144 | + && options.domain === undefined |
| 145 | + && options.range === undefined |
| 146 | + && key !== "fx" |
| 147 | + && key !== "fy" |
| 148 | + && isOrdinalScale({type})) { |
| 149 | + const values = channels.map(({value}) => value).filter(value => value !== undefined); |
| 150 | + 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)}".`); |
| 151 | + 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)}".`); |
| 152 | + 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)}".`); |
| 153 | + } |
| 154 | + |
136 | 155 | options.type = type; // Mutates input!
|
137 | 156 |
|
138 | 157 | // Once the scale type is known, coerce the associated channel values and any
|
@@ -190,6 +209,10 @@ function Scale(key, channels = [], options = {}) {
|
190 | 209 | }
|
191 | 210 | }
|
192 | 211 |
|
| 212 | +function formatScaleType(type) { |
| 213 | + return typeof type === "symbol" ? type.description : type; |
| 214 | +} |
| 215 | + |
193 | 216 | function inferScaleType(key, channels, {type, domain, range, scheme}) {
|
194 | 217 | // The facet scales are always band scales; this cannot be changed.
|
195 | 218 | if (key === "fx" || key === "fy") return "band";
|
@@ -272,7 +295,7 @@ export function isTemporalScale({type}) {
|
272 | 295 | }
|
273 | 296 |
|
274 | 297 | export function isOrdinalScale({type}) {
|
275 |
| - return type === "ordinal" || type === "point" || type === "band"; |
| 298 | + return type === "ordinal" || type === "point" || type === "band" || type === ordinalImplicit; |
276 | 299 | }
|
277 | 300 |
|
278 | 301 | function isThresholdScale({type}) {
|
|
0 commit comments