ggaction 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +55 -2
- package/README.md +95 -72
- package/package.json +15 -5
- package/src/actions/boxPlots/components.js +3 -3
- package/src/actions/boxPlots/edit.js +277 -0
- package/src/actions/boxPlots/index.js +2 -0
- package/src/actions/boxPlots/materialize.js +12 -1
- package/src/actions/boxPlots/options.js +25 -14
- package/src/actions/canvas/actions.js +21 -17
- package/src/actions/composition/actions.js +247 -0
- package/src/actions/composition/index.js +1 -0
- package/src/actions/coordinates/actions.js +2 -5
- package/src/actions/data/density.js +7 -1
- package/src/actions/data/filter.js +3 -1
- package/src/actions/data/regression.js +1 -1
- package/src/actions/encodings/appearance.js +12 -1
- package/src/actions/encodings/barWidth.js +5 -3
- package/src/actions/encodings/color/continuous.js +137 -0
- package/src/actions/encodings/color/index.js +151 -0
- package/src/actions/encodings/color/layout.js +91 -0
- package/src/actions/encodings/color/policy.js +88 -0
- package/src/actions/encodings/index.js +4 -2
- package/src/actions/encodings/offset.js +91 -73
- package/src/actions/encodings/position/apply.js +66 -0
- package/src/actions/encodings/position/index.js +130 -0
- package/src/actions/encodings/position/policies/arc.js +26 -0
- package/src/actions/encodings/position/policies/bar.js +9 -5
- package/src/actions/encodings/position/policies/index.js +5 -1
- package/src/actions/encodings/position/policies/line.js +20 -3
- package/src/actions/encodings/position/resolve.js +58 -9
- package/src/actions/encodings/ranged.js +30 -8
- package/src/actions/encodings/shared.js +17 -21
- package/src/actions/encodings/strokeDash.js +1 -1
- package/src/actions/encodings/text.js +73 -0
- package/src/actions/errorBands/create.js +37 -29
- package/src/actions/errorBands/edit.js +206 -0
- package/src/actions/errorBands/index.js +9 -0
- package/src/actions/errorBands/options.js +39 -0
- package/src/actions/errorBars/create.js +50 -43
- package/src/actions/errorBars/edit.js +130 -0
- package/src/actions/errorBars/index.js +3 -0
- package/src/actions/errorBars/options.js +52 -0
- package/src/actions/facets/actions.js +162 -0
- package/src/actions/facets/derive.js +200 -0
- package/src/actions/facets/guides.js +16 -0
- package/src/actions/facets/index.js +1 -0
- package/src/actions/facets/replay.js +69 -0
- package/src/actions/guides/applicability.js +113 -0
- package/src/actions/guides/axes/axes.js +70 -16
- package/src/actions/guides/axes/edit.js +126 -0
- package/src/actions/guides/axes/index.js +12 -0
- package/src/actions/guides/axes/labels.js +22 -19
- package/src/actions/guides/axes/remove.js +60 -0
- package/src/actions/guides/axes/tickGroups.js +7 -5
- package/src/actions/guides/axes/ticks.js +10 -5
- package/src/actions/guides/axes/titles.js +8 -6
- package/src/actions/guides/grids/grid.js +144 -15
- package/src/actions/guides/grids/resolve.js +6 -14
- package/src/actions/guides/guides.js +17 -75
- package/src/actions/guides/index.js +6 -0
- package/src/actions/guides/legends/categorical/actions.js +48 -9
- package/src/actions/guides/legends/categorical/components.js +16 -16
- package/src/actions/guides/legends/categorical/index.js +14 -14
- package/src/actions/guides/legends/categorical/layout.js +7 -3
- package/src/actions/guides/legends/categorical/options.js +2 -5
- package/src/actions/guides/legends/categorical/resolve.js +2 -2
- package/src/actions/guides/legends/categorical/symbols.js +14 -14
- package/src/actions/guides/legends/continuous/common.js +7 -7
- package/src/actions/guides/legends/continuous/interval.js +6 -6
- package/src/actions/guides/legends/continuous/opacity.js +1 -1
- package/src/actions/guides/legends/edit.js +4 -26
- package/src/actions/guides/legends/focused.js +63 -0
- package/src/actions/guides/legends/index.js +4 -0
- package/src/actions/guides/legends/remove.js +46 -0
- package/src/actions/guides/legends/size.js +13 -15
- package/src/actions/guides/legends/target.js +25 -0
- package/src/actions/guides/polar/axes/facade.js +219 -0
- package/src/actions/guides/polar/axes/index.js +55 -0
- package/src/actions/guides/polar/axes/labels.js +188 -0
- package/src/actions/guides/polar/axes/lines.js +113 -0
- package/src/actions/guides/polar/axes/shared.js +112 -0
- package/src/actions/guides/polar/axes/ticks.js +164 -0
- package/src/actions/guides/polar/axes/titles.js +165 -0
- package/src/actions/guides/polar/grids.js +252 -0
- package/src/actions/guides/polar/index.js +2 -0
- package/src/actions/guides/polar/resolve.js +269 -0
- package/src/actions/guides/tickValues.js +1 -1
- package/src/actions/index.js +4 -0
- package/src/actions/intervals/resolve.js +1 -1
- package/src/actions/marks/arc/actions.js +239 -0
- package/src/actions/marks/arc/index.js +1 -0
- package/src/actions/marks/{area.js → area/actions.js} +51 -38
- package/src/actions/marks/area/index.js +4 -0
- package/src/actions/marks/bar/create.js +26 -5
- package/src/actions/marks/bar/edit.js +1 -1
- package/src/actions/marks/bar/materialize.js +25 -31
- package/src/actions/marks/index.js +12 -4
- package/src/actions/marks/lifecycle.js +27 -0
- package/src/actions/marks/line/actions.js +373 -0
- package/src/actions/marks/line/index.js +1 -0
- package/src/actions/marks/{point.js → point/actions.js} +67 -108
- package/src/actions/marks/point/index.js +1 -0
- package/src/actions/marks/rect/actions.js +165 -0
- package/src/actions/marks/rect/index.js +1 -0
- package/src/actions/marks/remove.js +214 -0
- package/src/actions/marks/{rule.js → rule/actions.js} +34 -28
- package/src/actions/marks/rule/index.js +1 -0
- package/src/actions/marks/shared.js +156 -25
- package/src/actions/marks/text/actions.js +192 -0
- package/src/actions/marks/text/index.js +1 -0
- package/src/actions/primitives/createGraphics.js +13 -6
- package/src/actions/primitives/editGraphics.js +10 -3
- package/src/actions/primitives/semantic.js +26 -3
- package/src/actions/primitives/semanticValue.js +26 -4
- package/src/actions/regression/components.js +2 -2
- package/src/actions/regression/create.js +19 -2
- package/src/actions/regression/edit.js +247 -0
- package/src/actions/regression/index.js +3 -0
- package/src/actions/regression/resolve.js +3 -1
- package/src/actions/scales/consumers/common.js +91 -0
- package/src/actions/scales/consumers/families.js +47 -0
- package/src/actions/scales/consumers/index.js +41 -0
- package/src/actions/scales/{consumers.js → consumers/seriesLayout.js} +14 -127
- package/src/actions/scales/create.js +1 -1
- package/src/actions/scales/definitions.js +15 -6
- package/src/actions/scales/edit.js +45 -22
- package/src/actions/scales/materialize.js +58 -409
- package/src/actions/selection/actions.js +38 -24
- package/src/actions/selection/index.js +2 -0
- package/src/actions/titles/actions.js +63 -2
- package/src/actions/titles/index.js +2 -0
- package/src/actions/titles/resolve.js +12 -17
- package/src/composition.js +10 -0
- package/src/core/ChartProgram.js +49 -65
- package/src/core/action.js +10 -0
- package/src/core/compositionState.js +169 -0
- package/src/core/materializationState.js +65 -0
- package/src/core/programState.js +28 -0
- package/src/core/validation.js +16 -0
- package/src/core/vocabulary.js +154 -4
- package/src/grammar/arcs.js +154 -0
- package/src/grammar/areaSeries.js +1 -1
- package/src/grammar/bars/aggregate.js +3 -3
- package/src/grammar/bars/geometry.js +3 -3
- package/src/grammar/bars/policy.js +7 -1
- package/src/grammar/coordinates.js +3 -7
- package/src/grammar/density.js +21 -2
- package/src/grammar/facets/dependencies.js +185 -0
- package/src/grammar/facets/guides.js +257 -0
- package/src/grammar/facets/index.js +122 -0
- package/src/grammar/facets/scales.js +254 -0
- package/src/grammar/interval.js +2 -96
- package/src/grammar/lineSeries.js +112 -4
- package/src/grammar/palettes.js +5 -7
- package/src/grammar/polar.js +102 -0
- package/src/grammar/polarGuides.js +243 -0
- package/src/grammar/polarLineCommands.js +43 -0
- package/src/grammar/polarPaths.js +161 -0
- package/src/grammar/positionCompatibility.js +18 -2
- package/src/grammar/rects.js +26 -0
- package/src/grammar/regression/derive.js +97 -0
- package/src/grammar/regression/index.js +22 -0
- package/src/grammar/regression/models.js +282 -0
- package/src/grammar/regression/parameters.js +106 -0
- package/src/grammar/rules.js +1 -1
- package/src/grammar/scales/color.js +4 -2
- package/src/grammar/scales/continuous.js +6 -1
- package/src/grammar/scales/fields.js +7 -0
- package/src/grammar/scales/ordinal.js +5 -2
- package/src/grammar/scales/policies.js +1 -1
- package/src/grammar/schemas/graphic.js +1 -1
- package/src/grammar/schemas/graphicBounds.js +64 -9
- package/src/grammar/schemas/graphicTree.js +44 -10
- package/src/grammar/schemas/semanticPath.js +31 -9
- package/src/grammar/seriesLayout.js +13 -2
- package/src/grammar/statistics/studentT.js +98 -0
- package/src/grammar/text.js +71 -0
- package/src/grammar/ticks.js +50 -13
- package/src/grammar/transforms.js +1 -1
- package/src/index.js +1 -0
- package/src/layout/composition.js +310 -0
- package/src/layout/facets.js +131 -0
- package/src/layout/title.js +6 -0
- package/src/materialization/bars/aggregate.js +6 -3
- package/src/materialization/bars/grouped.js +75 -37
- package/src/materialization/bars/histogram.js +1 -1
- package/src/materialization/bars/ranged.js +1 -1
- package/src/materialization/composition.js +152 -0
- package/src/materialization/compositionSnapshot.js +114 -0
- package/src/materialization/density.js +1 -1
- package/src/materialization/dependencies.js +47 -73
- package/src/materialization/encodings.js +14 -28
- package/src/materialization/facetGuides/index.js +2 -0
- package/src/materialization/facetGuides/legacyCategorical.js +125 -0
- package/src/materialization/facetGuides/placement.js +126 -0
- package/src/materialization/facetGuides/preparation.js +188 -0
- package/src/materialization/facets.js +214 -0
- package/src/materialization/graphicHierarchy.js +15 -5
- package/src/materialization/guides/resources.js +46 -0
- package/src/materialization/marks/capabilities.js +141 -0
- package/src/materialization/marks/index.js +105 -0
- package/src/materialization/marks/policies.js +87 -0
- package/src/materialization/planner.js +105 -12
- package/src/materialization/rect.js +138 -0
- package/src/materialization/rectConfig.js +38 -0
- package/src/materialization/rowEncoding.js +33 -0
- package/src/materialization/scaleGuideDependencies.js +94 -0
- package/src/materialization/scales/map.js +40 -0
- package/src/materialization/scales/policies/arc.js +37 -0
- package/src/materialization/scales/policies/bar.js +132 -0
- package/src/materialization/scales/policies/series.js +76 -0
- package/src/materialization/scales/resolve.js +326 -0
- package/src/materialization/selection/items/arc.js +29 -0
- package/src/materialization/selection/items/bar.js +255 -0
- package/src/materialization/selection/items/common.js +131 -0
- package/src/materialization/selection/items/index.js +6 -0
- package/src/materialization/selection/items/path.js +59 -0
- package/src/materialization/selection/items/point.js +55 -0
- package/src/materialization/selection/items/rect.js +23 -0
- package/src/materialization/selection/items/rule.js +25 -0
- package/src/materialization/selection/policies/arc.js +10 -0
- package/src/materialization/selection/policies/area.js +1 -1
- package/src/materialization/selection/policies/bar.js +1 -1
- package/src/materialization/selection/policies/index.js +5 -1
- package/src/materialization/selection/policies/line.js +1 -1
- package/src/materialization/selection/policies/point.js +1 -1
- package/src/materialization/selection/policies/rect.js +10 -0
- package/src/materialization/selection/policies/rule.js +1 -1
- package/src/materialization/selection/styles.js +25 -17
- package/src/materialization/text.js +156 -0
- package/src/renderers/canvas/index.js +68 -22
- package/src/renderers/canvas/text.js +14 -1
- package/types/extension.d.ts +5 -1
- package/types/index.d.ts +56 -1
- package/types/program.d.ts +664 -27
- package/src/actions/encodings/color.js +0 -329
- package/src/actions/encodings/position.js +0 -176
- package/src/actions/marks/line.js +0 -248
- package/src/grammar/regression.js +0 -578
- package/src/grammar/scales.js +0 -1
- package/src/materialization/marks.js +0 -110
- package/src/materialization/selection/items.js +0 -503
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { action } from "../../core/action.js";
|
|
2
|
+
import { isPlainObject } from "../../core/immutable.js";
|
|
3
|
+
import { validateUserId } from "../../core/identifiers.js";
|
|
4
|
+
import {
|
|
5
|
+
validateKeys,
|
|
6
|
+
validateNonEmptyString,
|
|
7
|
+
validateNonNegativeFinite,
|
|
8
|
+
validateUnitInterval
|
|
9
|
+
} from "../../core/validation.js";
|
|
10
|
+
import { normalizeRegressionParameters } from "../../grammar/regression/index.js";
|
|
11
|
+
import { validateCurveInterpolation } from "../../grammar/curveCommands.js";
|
|
12
|
+
import { hasDataset } from "../../selectors/index.js";
|
|
13
|
+
import { findLayer } from "../../selectors/layers.js";
|
|
14
|
+
|
|
15
|
+
const OPTIONS = Object.freeze([
|
|
16
|
+
"target", "method", "degree", "span", "confidence", "interval", "band", "line"
|
|
17
|
+
]);
|
|
18
|
+
const STATISTICAL_OPTIONS = Object.freeze([
|
|
19
|
+
"method", "degree", "span", "confidence", "interval"
|
|
20
|
+
]);
|
|
21
|
+
const BAND_OPTIONS = Object.freeze([
|
|
22
|
+
"color", "opacity", "stroke", "strokeWidth", "curve"
|
|
23
|
+
]);
|
|
24
|
+
const LINE_OPTIONS = Object.freeze(["strokeWidth", "curve"]);
|
|
25
|
+
|
|
26
|
+
function resolveRegressionOwner(program, requested) {
|
|
27
|
+
const eligible = program.semanticSpec.layers.filter(
|
|
28
|
+
layer => program.markConfigs[layer.id]?.regression !== undefined
|
|
29
|
+
);
|
|
30
|
+
if (requested !== undefined) {
|
|
31
|
+
const id = validateUserId(requested, "Regression owner id");
|
|
32
|
+
const layer = findLayer(program, id);
|
|
33
|
+
if (layer === undefined || !eligible.includes(layer)) {
|
|
34
|
+
throw new Error(`Unknown regression owner "${id}".`);
|
|
35
|
+
}
|
|
36
|
+
return layer;
|
|
37
|
+
}
|
|
38
|
+
const current = findLayer(program, program.context.currentMark);
|
|
39
|
+
if (current !== undefined && eligible.includes(current)) return current;
|
|
40
|
+
if (eligible.length === 1) return eligible[0];
|
|
41
|
+
if (eligible.length === 0) throw new Error("No regression owner is available.");
|
|
42
|
+
throw new Error("Regression owner is ambiguous; provide target.");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function requirePatch(value, keys, label) {
|
|
46
|
+
if (!isPlainObject(value)) {
|
|
47
|
+
throw new TypeError(`${label} must be a plain object.`);
|
|
48
|
+
}
|
|
49
|
+
validateKeys(value, keys, label);
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function validateBandPatch(value) {
|
|
54
|
+
if (value === false) return false;
|
|
55
|
+
const patch = requirePatch(value, BAND_OPTIONS, "editRegression band");
|
|
56
|
+
if (Object.hasOwn(patch, "color")) {
|
|
57
|
+
validateNonEmptyString(patch.color, "Regression band color");
|
|
58
|
+
}
|
|
59
|
+
if (Object.hasOwn(patch, "opacity")) {
|
|
60
|
+
validateUnitInterval(patch.opacity, "Regression band opacity");
|
|
61
|
+
}
|
|
62
|
+
if (Object.hasOwn(patch, "stroke")) {
|
|
63
|
+
if (patch.stroke !== false) {
|
|
64
|
+
validateNonEmptyString(patch.stroke, "Regression band stroke");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (Object.hasOwn(patch, "strokeWidth")) {
|
|
68
|
+
validateNonNegativeFinite(
|
|
69
|
+
patch.strokeWidth,
|
|
70
|
+
"Regression band strokeWidth"
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
if (patch.stroke === false && Object.hasOwn(patch, "strokeWidth")) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
"editRegression band cannot set strokeWidth while removing stroke."
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
if (Object.hasOwn(patch, "curve")) {
|
|
79
|
+
validateCurveInterpolation(patch.curve);
|
|
80
|
+
}
|
|
81
|
+
return patch;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function validateLinePatch(value) {
|
|
85
|
+
const patch = requirePatch(value, LINE_OPTIONS, "editRegression line");
|
|
86
|
+
if (Object.hasOwn(patch, "strokeWidth")) {
|
|
87
|
+
validateNonNegativeFinite(
|
|
88
|
+
patch.strokeWidth,
|
|
89
|
+
"Regression line strokeWidth"
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
if (Object.hasOwn(patch, "curve")) {
|
|
93
|
+
validateCurveInterpolation(patch.curve);
|
|
94
|
+
}
|
|
95
|
+
return patch;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function resolveParameters(previous, args) {
|
|
99
|
+
const method = args.method ?? previous.method;
|
|
100
|
+
const raw = { method };
|
|
101
|
+
for (const key of ["degree", "span", "confidence", "interval"]) {
|
|
102
|
+
if (Object.hasOwn(args, key)) raw[key] = args[key];
|
|
103
|
+
}
|
|
104
|
+
if (method === previous.method) {
|
|
105
|
+
for (const key of ["degree", "span", "confidence", "interval"]) {
|
|
106
|
+
if (!Object.hasOwn(raw, key) && Object.hasOwn(previous, key)) {
|
|
107
|
+
raw[key] = previous[key];
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
} else if (method !== "loess" && previous.method !== "loess") {
|
|
111
|
+
for (const key of ["confidence", "interval"]) {
|
|
112
|
+
if (!Object.hasOwn(raw, key) && Object.hasOwn(previous, key)) {
|
|
113
|
+
raw[key] = previous[key];
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return normalizeRegressionParameters(raw);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function nextRevisionId(program, ownerId) {
|
|
121
|
+
let revision = 1;
|
|
122
|
+
while (hasDataset(program, `${ownerId}RegressionDataRevision${revision}`)) {
|
|
123
|
+
revision += 1;
|
|
124
|
+
}
|
|
125
|
+
return `${ownerId}RegressionDataRevision${revision}`;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function removeBand(program, id) {
|
|
129
|
+
return program
|
|
130
|
+
.editSemantic({ property: `layer[${id}]`, remove: true })
|
|
131
|
+
.editGraphics({ target: id, remove: true })
|
|
132
|
+
._withoutMaterializationConfig(["marks", id]);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export const editRegression = action(
|
|
136
|
+
{
|
|
137
|
+
op: "editRegression",
|
|
138
|
+
description: "Revise a regression model and its owned visible components."
|
|
139
|
+
},
|
|
140
|
+
function (args = {}) {
|
|
141
|
+
validateKeys(args, OPTIONS, "editRegression");
|
|
142
|
+
if (!OPTIONS.slice(1).some(key => Object.hasOwn(args, key))) {
|
|
143
|
+
throw new Error("editRegression requires a statistical or component option.");
|
|
144
|
+
}
|
|
145
|
+
const owner = resolveRegressionOwner(this, args.target);
|
|
146
|
+
const current = this.markConfigs[owner.id].regression;
|
|
147
|
+
const parameters = resolveParameters(current.parameters, args);
|
|
148
|
+
const changesStatistics = STATISTICAL_OPTIONS.some(
|
|
149
|
+
key => Object.hasOwn(args, key)
|
|
150
|
+
) && JSON.stringify(parameters) !== JSON.stringify(current.parameters);
|
|
151
|
+
const bandPatch = Object.hasOwn(args, "band")
|
|
152
|
+
? validateBandPatch(args.band)
|
|
153
|
+
: undefined;
|
|
154
|
+
const linePatch = Object.hasOwn(args, "line")
|
|
155
|
+
? validateLinePatch(args.line)
|
|
156
|
+
: undefined;
|
|
157
|
+
if (parameters.method === "loess" && bandPatch !== undefined && bandPatch !== false) {
|
|
158
|
+
throw new Error("LOESS regression does not support a band object.");
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const hadBand = current.bandId !== undefined;
|
|
162
|
+
const wantsBand = parameters.method !== "loess" &&
|
|
163
|
+
(bandPatch === false
|
|
164
|
+
? false
|
|
165
|
+
: hadBand || bandPatch !== undefined || current.parameters.method === "loess");
|
|
166
|
+
let dataId = current.dataId;
|
|
167
|
+
let next = this;
|
|
168
|
+
|
|
169
|
+
if (changesStatistics) {
|
|
170
|
+
dataId = nextRevisionId(this, owner.id);
|
|
171
|
+
next = next.createRegressionData({
|
|
172
|
+
id: dataId,
|
|
173
|
+
source: current.source,
|
|
174
|
+
x: current.x,
|
|
175
|
+
y: current.y,
|
|
176
|
+
...(current.groupBy === undefined ? {} : { groupBy: current.groupBy }),
|
|
177
|
+
...parameters
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
let bandId = current.bandId;
|
|
182
|
+
if (hadBand && !wantsBand) {
|
|
183
|
+
next = removeBand(next, current.bandId);
|
|
184
|
+
bandId = undefined;
|
|
185
|
+
} else if (!hadBand && wantsBand) {
|
|
186
|
+
bandId = `${owner.id}RegressionBands`;
|
|
187
|
+
next = next.createRegressionBand({
|
|
188
|
+
id: bandId,
|
|
189
|
+
data: dataId,
|
|
190
|
+
x: current.x,
|
|
191
|
+
lower: "__regression_ci_lower",
|
|
192
|
+
upper: "__regression_ci_upper",
|
|
193
|
+
...(current.groupBy === undefined ? {} : { groupBy: current.groupBy }),
|
|
194
|
+
coordinate: current.coordinate,
|
|
195
|
+
xScale: current.xScale,
|
|
196
|
+
yScale: current.yScale,
|
|
197
|
+
...(bandPatch === undefined || bandPatch === false ? {} : bandPatch)
|
|
198
|
+
});
|
|
199
|
+
} else if (hadBand && changesStatistics) {
|
|
200
|
+
const bandConfig = next.markConfigs[bandId];
|
|
201
|
+
next = next
|
|
202
|
+
.editSemantic({ property: `layer[${bandId}].data`, value: dataId })
|
|
203
|
+
._withMarkConfig(bandId, {
|
|
204
|
+
...bandConfig,
|
|
205
|
+
errorBand: { ...bandConfig.errorBand, data: dataId }
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (changesStatistics) {
|
|
210
|
+
next = next.editSemantic({
|
|
211
|
+
property: `layer[${current.lineId}].data`,
|
|
212
|
+
value: dataId
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (bandId !== undefined) {
|
|
217
|
+
if (
|
|
218
|
+
bandPatch !== undefined &&
|
|
219
|
+
bandPatch !== false &&
|
|
220
|
+
Object.keys(bandPatch).length > 0 &&
|
|
221
|
+
hadBand
|
|
222
|
+
) {
|
|
223
|
+
next = next.editRegressionBand({ target: bandId, ...bandPatch });
|
|
224
|
+
} else if (changesStatistics) {
|
|
225
|
+
next = next.rematerializeAreaMark({ id: bandId });
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
if (linePatch !== undefined && Object.keys(linePatch).length > 0) {
|
|
229
|
+
next = next.editRegressionLine({ target: current.lineId, ...linePatch });
|
|
230
|
+
} else if (changesStatistics) {
|
|
231
|
+
next = next.rematerializeLineMark({ id: current.lineId });
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (changesStatistics) {
|
|
235
|
+
next = next.releaseDerivedData({ id: current.dataId });
|
|
236
|
+
}
|
|
237
|
+
return next._withMarkConfig(owner.id, {
|
|
238
|
+
...next.markConfigs[owner.id],
|
|
239
|
+
regression: {
|
|
240
|
+
...current,
|
|
241
|
+
dataId,
|
|
242
|
+
bandId,
|
|
243
|
+
parameters
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
);
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
editRegressionLine
|
|
6
6
|
} from "./components.js";
|
|
7
7
|
import { createRegression } from "./create.js";
|
|
8
|
+
import { editRegression } from "./edit.js";
|
|
8
9
|
|
|
9
10
|
export {
|
|
10
11
|
createRegressionBand,
|
|
@@ -13,6 +14,7 @@ export {
|
|
|
13
14
|
editRegressionLine
|
|
14
15
|
} from "./components.js";
|
|
15
16
|
export { createRegression } from "./create.js";
|
|
17
|
+
export { editRegression } from "./edit.js";
|
|
16
18
|
|
|
17
19
|
export function registerRegressionActions(ProgramClass) {
|
|
18
20
|
ProgramClass.prototype.createRegressionBand = createRegressionBand;
|
|
@@ -20,4 +22,5 @@ export function registerRegressionActions(ProgramClass) {
|
|
|
20
22
|
ProgramClass.prototype.editRegressionBand = editRegressionBand;
|
|
21
23
|
ProgramClass.prototype.editRegressionLine = editRegressionLine;
|
|
22
24
|
ProgramClass.prototype.createRegression = createRegression;
|
|
25
|
+
ProgramClass.prototype.editRegression = editRegression;
|
|
23
26
|
}
|
|
@@ -47,7 +47,9 @@ export function inferRegressionGroup(layer, args) {
|
|
|
47
47
|
}
|
|
48
48
|
const candidates = [...new Set(
|
|
49
49
|
[layer.encoding?.color, layer.encoding?.shape]
|
|
50
|
-
.filter(encoding =>
|
|
50
|
+
.filter(encoding =>
|
|
51
|
+
["nominal", "ordinal"].includes(encoding?.fieldType)
|
|
52
|
+
)
|
|
51
53
|
.map(encoding => encoding.field)
|
|
52
54
|
)];
|
|
53
55
|
if (candidates.length > 1) {
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import {
|
|
2
|
+
readNominalField,
|
|
3
|
+
readQuantitativeField,
|
|
4
|
+
readScaleField,
|
|
5
|
+
readTemporalField
|
|
6
|
+
} from "../../../grammar/scales/index.js";
|
|
7
|
+
import { findDataset } from "../../../selectors/datasets.js";
|
|
8
|
+
import { requireSemanticScale } from "../../../selectors/scales.js";
|
|
9
|
+
import { SCALED_ENCODING_CHANNELS } from "../../../core/vocabulary.js";
|
|
10
|
+
|
|
11
|
+
export function findScale(program, id) {
|
|
12
|
+
return requireSemanticScale(program, id);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function findScaleConsumers(program, id) {
|
|
16
|
+
const consumers = [];
|
|
17
|
+
for (const layer of program.semanticSpec.layers) {
|
|
18
|
+
for (const channel of SCALED_ENCODING_CHANNELS) {
|
|
19
|
+
const encoding = layer.encoding?.[channel];
|
|
20
|
+
if (encoding?.scale === id) consumers.push({ layer, channel, encoding });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return consumers;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function requireConsumerDataset(program, consumer) {
|
|
27
|
+
const dataset = findDataset(program, consumer.layer.data);
|
|
28
|
+
if (dataset === undefined) {
|
|
29
|
+
throw new Error(
|
|
30
|
+
`Mark "${consumer.layer.id}" references unknown dataset "${consumer.layer.data}".`
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
return dataset;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function isDirectCategoricalConsumer(consumer) {
|
|
37
|
+
return ["color", "strokeDash", "xOffset", "yOffset", "shape"].includes(
|
|
38
|
+
consumer.channel
|
|
39
|
+
) && consumer.encoding.fieldType === "nominal";
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function readConsumerFieldValues(
|
|
43
|
+
program,
|
|
44
|
+
consumer,
|
|
45
|
+
dataset,
|
|
46
|
+
scale = findScale(program, consumer.encoding.scale)
|
|
47
|
+
) {
|
|
48
|
+
const allowUnknown = Object.hasOwn(scale, "unknown");
|
|
49
|
+
if (isDirectCategoricalConsumer(consumer)) {
|
|
50
|
+
return allowUnknown
|
|
51
|
+
? readScaleField(
|
|
52
|
+
dataset.values,
|
|
53
|
+
consumer.encoding.field,
|
|
54
|
+
consumer.encoding.fieldType,
|
|
55
|
+
{ allowUnknown: true }
|
|
56
|
+
)
|
|
57
|
+
: readNominalField(dataset.values, consumer.encoding.field);
|
|
58
|
+
}
|
|
59
|
+
if (consumer.encoding.fieldType === "temporal") {
|
|
60
|
+
return allowUnknown
|
|
61
|
+
? readScaleField(dataset.values, consumer.encoding.field, "temporal", {
|
|
62
|
+
allowUnknown: true
|
|
63
|
+
})
|
|
64
|
+
: readTemporalField(dataset.values, consumer.encoding.field);
|
|
65
|
+
}
|
|
66
|
+
if (["nominal", "ordinal"].includes(consumer.encoding.fieldType)) {
|
|
67
|
+
if (!["ordinal", "band", "point"].includes(scale.type)) {
|
|
68
|
+
throw new Error(
|
|
69
|
+
`Scale materialization requires a quantitative encoding on mark "${consumer.layer.id}".`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
return allowUnknown
|
|
73
|
+
? readScaleField(
|
|
74
|
+
dataset.values,
|
|
75
|
+
consumer.encoding.field,
|
|
76
|
+
consumer.encoding.fieldType,
|
|
77
|
+
{ allowUnknown: true }
|
|
78
|
+
)
|
|
79
|
+
: readNominalField(dataset.values, consumer.encoding.field);
|
|
80
|
+
}
|
|
81
|
+
if (consumer.encoding.fieldType !== "quantitative") {
|
|
82
|
+
throw new Error(
|
|
83
|
+
`Scale materialization requires a quantitative encoding on mark "${consumer.layer.id}".`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
return allowUnknown
|
|
87
|
+
? readScaleField(dataset.values, consumer.encoding.field, "quantitative", {
|
|
88
|
+
allowUnknown: true
|
|
89
|
+
})
|
|
90
|
+
: readQuantitativeField(dataset.values, consumer.encoding.field);
|
|
91
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { deriveBarAggregates } from "../../../grammar/bars/aggregate.js";
|
|
2
|
+
import {
|
|
3
|
+
BAR_GRAINS,
|
|
4
|
+
resolveBarGrain
|
|
5
|
+
} from "../../../grammar/bars/policy.js";
|
|
6
|
+
import { deriveLineSeries } from "../../../grammar/lineSeries.js";
|
|
7
|
+
import { isAggregate } from "../../../grammar/aggregate.js";
|
|
8
|
+
import {
|
|
9
|
+
resolveRectConsumerValues
|
|
10
|
+
} from "../../../materialization/rect.js";
|
|
11
|
+
|
|
12
|
+
export function resolveMarkFamilyConsumerValues(consumer, dataset) {
|
|
13
|
+
if (consumer.layer.mark?.type === "rect") {
|
|
14
|
+
return {
|
|
15
|
+
matched: true,
|
|
16
|
+
values: resolveRectConsumerValues(
|
|
17
|
+
consumer.layer,
|
|
18
|
+
dataset,
|
|
19
|
+
consumer.channel
|
|
20
|
+
)
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
if (
|
|
24
|
+
consumer.layer.mark?.type === "line" &&
|
|
25
|
+
isAggregate(consumer.layer.encoding?.y?.aggregate)
|
|
26
|
+
) {
|
|
27
|
+
const derived = deriveLineSeries(dataset.values, consumer.layer);
|
|
28
|
+
return {
|
|
29
|
+
matched: true,
|
|
30
|
+
values: consumer.channel === "x" ? derived.xValues : derived.yValues
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
if (resolveBarGrain(consumer.layer) === BAR_GRAINS.aggregate) {
|
|
34
|
+
const derived = deriveBarAggregates(dataset.values, consumer.layer);
|
|
35
|
+
if (consumer.channel === "color") {
|
|
36
|
+
return {
|
|
37
|
+
matched: true,
|
|
38
|
+
values: derived.values.map(value => value.color)
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
matched: true,
|
|
43
|
+
values: consumer.channel === "x" ? derived.xValues : derived.yValues
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return { matched: false };
|
|
47
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { normalizeRuleDatum } from "../../../grammar/rules.js";
|
|
2
|
+
import {
|
|
3
|
+
findScale,
|
|
4
|
+
isDirectCategoricalConsumer,
|
|
5
|
+
readConsumerFieldValues,
|
|
6
|
+
requireConsumerDataset
|
|
7
|
+
} from "./common.js";
|
|
8
|
+
import { resolveMarkFamilyConsumerValues } from "./families.js";
|
|
9
|
+
|
|
10
|
+
export { findScale, findScaleConsumers } from "./common.js";
|
|
11
|
+
export {
|
|
12
|
+
resolveHistogramCountValues,
|
|
13
|
+
resolveSeriesLayoutScaleValues
|
|
14
|
+
} from "./seriesLayout.js";
|
|
15
|
+
|
|
16
|
+
export function resolveConsumerValues(program, consumer) {
|
|
17
|
+
const dataset = requireConsumerDataset(program, consumer);
|
|
18
|
+
if (Object.hasOwn(consumer.encoding, "datum")) {
|
|
19
|
+
return [normalizeRuleDatum(
|
|
20
|
+
consumer.encoding.datum,
|
|
21
|
+
consumer.encoding.fieldType,
|
|
22
|
+
consumer.channel
|
|
23
|
+
)];
|
|
24
|
+
}
|
|
25
|
+
if (
|
|
26
|
+
consumer.channel === "strokeDash" &&
|
|
27
|
+
!["line", "rule"].includes(consumer.layer.mark?.type)
|
|
28
|
+
) {
|
|
29
|
+
throw new Error(
|
|
30
|
+
"strokeDash scale materialization requires a line mark or rule mark."
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
const scale = findScale(program, consumer.encoding.scale);
|
|
34
|
+
if (isDirectCategoricalConsumer(consumer)) {
|
|
35
|
+
return readConsumerFieldValues(program, consumer, dataset, scale);
|
|
36
|
+
}
|
|
37
|
+
const family = resolveMarkFamilyConsumerValues(consumer, dataset);
|
|
38
|
+
return family.matched
|
|
39
|
+
? family.values
|
|
40
|
+
: readConsumerFieldValues(program, consumer, dataset, scale);
|
|
41
|
+
}
|
|
@@ -1,138 +1,26 @@
|
|
|
1
|
-
import { deriveBarAggregates } from "
|
|
1
|
+
import { deriveBarAggregates } from "../../../grammar/bars/aggregate.js";
|
|
2
2
|
import {
|
|
3
3
|
BAR_GRAINS,
|
|
4
4
|
resolveBarChannels,
|
|
5
5
|
resolveBarColorLayout,
|
|
6
6
|
resolveBarGrain
|
|
7
|
-
} from "
|
|
7
|
+
} from "../../../grammar/bars/policy.js";
|
|
8
8
|
import {
|
|
9
9
|
countHistogramBins,
|
|
10
10
|
findHistogramBinIndex,
|
|
11
11
|
resolveHistogramBins
|
|
12
|
-
} from "
|
|
13
|
-
import { deriveDensityAreaSeries } from "
|
|
14
|
-
import {
|
|
15
|
-
|
|
12
|
+
} from "../../../grammar/histogram.js";
|
|
13
|
+
import { deriveDensityAreaSeries } from "../../../grammar/areaSeries.js";
|
|
14
|
+
import {
|
|
15
|
+
resolveSeriesLayoutDomainValues
|
|
16
|
+
} from "../../../grammar/seriesLayout.js";
|
|
16
17
|
import {
|
|
17
18
|
readNominalField,
|
|
18
19
|
readQuantitativeField,
|
|
19
|
-
readScaleField,
|
|
20
|
-
readTemporalField,
|
|
21
20
|
resolveOrdinalDomain
|
|
22
|
-
} from "
|
|
23
|
-
import { findDataset } from "
|
|
24
|
-
import {
|
|
25
|
-
import { isAggregate } from "../../grammar/aggregate.js";
|
|
26
|
-
import { normalizeRuleDatum } from "../../grammar/rules.js";
|
|
27
|
-
|
|
28
|
-
export function findScale(program, id) {
|
|
29
|
-
return requireSemanticScale(program, id);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function findScaleConsumers(program, id) {
|
|
33
|
-
const consumers = [];
|
|
34
|
-
for (const layer of program.semanticSpec.layers) {
|
|
35
|
-
for (const channel of [
|
|
36
|
-
"x", "y", "x2", "y2", "xOffset", "color", "strokeDash", "size", "shape",
|
|
37
|
-
"opacity"
|
|
38
|
-
]) {
|
|
39
|
-
const encoding = layer.encoding?.[channel];
|
|
40
|
-
if (encoding?.scale === id) consumers.push({ layer, channel, encoding });
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return consumers;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function resolveConsumerValues(program, consumer) {
|
|
47
|
-
const dataset = findDataset(program, consumer.layer.data);
|
|
48
|
-
if (dataset === undefined) {
|
|
49
|
-
throw new Error(
|
|
50
|
-
`Mark "${consumer.layer.id}" references unknown dataset "${consumer.layer.data}".`
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (Object.hasOwn(consumer.encoding, "datum")) {
|
|
55
|
-
return [normalizeRuleDatum(
|
|
56
|
-
consumer.encoding.datum,
|
|
57
|
-
consumer.encoding.fieldType,
|
|
58
|
-
consumer.channel
|
|
59
|
-
)];
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (
|
|
63
|
-
consumer.channel === "strokeDash" &&
|
|
64
|
-
!["line", "rule"].includes(consumer.layer.mark?.type)
|
|
65
|
-
) {
|
|
66
|
-
throw new Error("strokeDash scale materialization requires a line mark or rule mark.");
|
|
67
|
-
}
|
|
68
|
-
const scale = findScale(program, consumer.encoding.scale);
|
|
69
|
-
const allowUnknown = Object.hasOwn(scale, "unknown");
|
|
70
|
-
|
|
71
|
-
if (
|
|
72
|
-
["color", "strokeDash", "xOffset", "shape"].includes(consumer.channel) &&
|
|
73
|
-
consumer.encoding.fieldType === "nominal"
|
|
74
|
-
) {
|
|
75
|
-
return allowUnknown
|
|
76
|
-
? readScaleField(
|
|
77
|
-
dataset.values,
|
|
78
|
-
consumer.encoding.field,
|
|
79
|
-
consumer.encoding.fieldType,
|
|
80
|
-
{ allowUnknown: true }
|
|
81
|
-
)
|
|
82
|
-
: readNominalField(dataset.values, consumer.encoding.field);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (
|
|
86
|
-
consumer.layer.mark?.type === "line" &&
|
|
87
|
-
isAggregate(consumer.layer.encoding?.y?.aggregate)
|
|
88
|
-
) {
|
|
89
|
-
const derived = deriveLineSeries(dataset.values, consumer.layer);
|
|
90
|
-
return consumer.channel === "x" ? derived.xValues : derived.yValues;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (
|
|
94
|
-
resolveBarGrain(consumer.layer) === BAR_GRAINS.aggregate
|
|
95
|
-
) {
|
|
96
|
-
const derived = deriveBarAggregates(dataset.values, consumer.layer);
|
|
97
|
-
if (consumer.channel === "color") {
|
|
98
|
-
return derived.values.map(value => value.color);
|
|
99
|
-
}
|
|
100
|
-
return consumer.channel === "x" ? derived.xValues : derived.yValues;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (consumer.encoding.fieldType === "temporal") {
|
|
104
|
-
return allowUnknown
|
|
105
|
-
? readScaleField(dataset.values, consumer.encoding.field, "temporal", {
|
|
106
|
-
allowUnknown: true
|
|
107
|
-
})
|
|
108
|
-
: readTemporalField(dataset.values, consumer.encoding.field);
|
|
109
|
-
}
|
|
110
|
-
if (["nominal", "ordinal"].includes(consumer.encoding.fieldType)) {
|
|
111
|
-
if (!["ordinal", "band", "point"].includes(scale.type)) {
|
|
112
|
-
throw new Error(
|
|
113
|
-
`Scale materialization requires a quantitative encoding on mark "${consumer.layer.id}".`
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
return allowUnknown
|
|
117
|
-
? readScaleField(
|
|
118
|
-
dataset.values,
|
|
119
|
-
consumer.encoding.field,
|
|
120
|
-
consumer.encoding.fieldType,
|
|
121
|
-
{ allowUnknown: true }
|
|
122
|
-
)
|
|
123
|
-
: readNominalField(dataset.values, consumer.encoding.field);
|
|
124
|
-
}
|
|
125
|
-
if (consumer.encoding.fieldType !== "quantitative") {
|
|
126
|
-
throw new Error(
|
|
127
|
-
`Scale materialization requires a quantitative encoding on mark "${consumer.layer.id}".`
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
return allowUnknown
|
|
131
|
-
? readScaleField(dataset.values, consumer.encoding.field, "quantitative", {
|
|
132
|
-
allowUnknown: true
|
|
133
|
-
})
|
|
134
|
-
: readQuantitativeField(dataset.values, consumer.encoding.field);
|
|
135
|
-
}
|
|
21
|
+
} from "../../../grammar/scales/index.js";
|
|
22
|
+
import { findDataset } from "../../../selectors/datasets.js";
|
|
23
|
+
import { findScale } from "./common.js";
|
|
136
24
|
|
|
137
25
|
export function resolveHistogramCountValues(program, consumer) {
|
|
138
26
|
const xEncoding = consumer.layer.encoding?.x;
|
|
@@ -140,7 +28,6 @@ export function resolveHistogramCountValues(program, consumer) {
|
|
|
140
28
|
? undefined
|
|
141
29
|
: findScale(program, xEncoding.scale);
|
|
142
30
|
const dataset = findDataset(program, consumer.layer.data);
|
|
143
|
-
|
|
144
31
|
if (xEncoding?.bin === undefined || xScale === undefined) {
|
|
145
32
|
throw new Error(
|
|
146
33
|
`Histogram mark "${consumer.layer.id}" requires a binned x scale.`
|
|
@@ -151,7 +38,6 @@ export function resolveHistogramCountValues(program, consumer) {
|
|
|
151
38
|
`Histogram mark "${consumer.layer.id}" requires an existing dataset.`
|
|
152
39
|
);
|
|
153
40
|
}
|
|
154
|
-
|
|
155
41
|
const xValues = readQuantitativeField(dataset.values, xEncoding.field);
|
|
156
42
|
const bins = resolveHistogramBins({
|
|
157
43
|
values: xValues,
|
|
@@ -180,7 +66,6 @@ function resolveHistogramPartitions(program, consumer) {
|
|
|
180
66
|
if (colorEncoding?.scale === undefined) {
|
|
181
67
|
return countHistogramBins(xValues, bins.boundaries).map(value => [value]);
|
|
182
68
|
}
|
|
183
|
-
|
|
184
69
|
const colorScale = findScale(program, colorEncoding.scale);
|
|
185
70
|
const colorValues = readNominalField(dataset.values, colorEncoding.field);
|
|
186
71
|
const colorDomain = resolveOrdinalDomain(colorScale.domain, colorValues);
|
|
@@ -208,14 +93,16 @@ function resolveAggregatePartitions(program, consumer) {
|
|
|
208
93
|
: derived.yValues;
|
|
209
94
|
const categoryDomain = resolveOrdinalDomain(categoryScale.domain, categoryValues);
|
|
210
95
|
const colorEncoding = layer.encoding?.color;
|
|
211
|
-
if (
|
|
96
|
+
if (
|
|
97
|
+
colorEncoding?.scale === undefined ||
|
|
98
|
+
colorEncoding.fieldType === "quantitative"
|
|
99
|
+
) {
|
|
212
100
|
const byCategory = new Map(derived.values.map(value => [
|
|
213
101
|
value[channels.category],
|
|
214
102
|
value[channels.measure]
|
|
215
103
|
]));
|
|
216
104
|
return categoryDomain.map(value => [byCategory.get(value) ?? 0]);
|
|
217
105
|
}
|
|
218
|
-
|
|
219
106
|
const colorScale = findScale(program, colorEncoding.scale);
|
|
220
107
|
const colorValues = readNominalField(dataset.values, colorEncoding.field);
|
|
221
108
|
const colorDomain = resolveOrdinalDomain(colorScale.domain, colorValues);
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
isContinuousColorScaleType,
|
|
16
16
|
isDiscretizedColorScaleType,
|
|
17
17
|
normalizeScaleDefinition
|
|
18
|
-
} from "../../grammar/scales.js";
|
|
18
|
+
} from "../../grammar/scales/index.js";
|
|
19
19
|
import { findSemanticScale } from "../../selectors/scales.js";
|
|
20
20
|
|
|
21
21
|
const CREATE_SCALE_OPTIONS = Object.freeze([
|