ggaction 0.0.15 → 0.0.17
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 +88 -0
- package/README.md +23 -2
- package/knowledge/action-cards.json +1 -1
- package/knowledge/intent-taxonomy.json +1 -1
- package/knowledge/mcp-resources.json +1 -1
- package/knowledge/task-packet.schema.json +1 -1
- package/knowledge/task-resolver.js +1 -1
- package/package.json +40 -7
- package/src/BasicChartProgram.js +3 -1
- package/src/ChartProgram.js +2 -0
- package/src/accessibility.js +157 -0
- package/src/actions/boxPlots/components.js +6 -8
- package/src/actions/boxPlots/create.js +4 -5
- package/src/actions/boxPlots/edit.js +3 -4
- package/src/actions/boxPlots/materialize.js +1 -1
- package/src/actions/canvas/actions.js +3 -3
- package/src/actions/canvas/fitting.js +1 -1
- package/src/actions/categoryOrder/index.js +6 -8
- package/src/actions/charts/area.js +1 -1
- package/src/actions/charts/bar.js +1 -1
- package/src/actions/charts/beeswarm.js +1 -1
- package/src/actions/charts/density.js +1 -1
- package/src/actions/charts/ecdf.js +2 -2
- package/src/actions/charts/endpoints.js +4 -4
- package/src/actions/charts/heatmap.js +1 -1
- package/src/actions/charts/histogram.js +1 -1
- package/src/actions/charts/horizon.js +1 -1
- package/src/actions/charts/interval-regression.js +2 -2
- package/src/actions/charts/line.js +1 -1
- package/src/actions/charts/parallel.js +1 -1
- package/src/actions/charts/pie.js +1 -1
- package/src/actions/charts/polar.js +2 -2
- package/src/actions/charts/radar.js +1 -1
- package/src/actions/charts/radial.js +2 -2
- package/src/actions/charts/raincloud.js +2 -2
- package/src/actions/charts/rug-strip.js +2 -2
- package/src/actions/charts/scatter.js +1 -1
- package/src/actions/composition/actions.js +20 -24
- package/src/actions/coordinates/actions.js +1 -1
- package/src/actions/coordinates/edit.js +1 -1
- package/src/actions/data/basicBin2d.js +4 -5
- package/src/actions/data/bin.js +3 -3
- package/src/actions/data/bin2d.js +6 -8
- package/src/actions/data/bin2dMaterialize.js +4 -5
- package/src/actions/data/box.js +4 -4
- package/src/actions/data/complete.js +2 -2
- package/src/actions/data/computed.js +2 -2
- package/src/actions/data/create.js +23 -17
- package/src/actions/data/density.js +4 -4
- package/src/actions/data/derived.js +25 -15
- package/src/actions/data/ecdf.js +2 -2
- package/src/actions/data/edit.js +54 -29
- package/src/actions/data/filter.js +29 -24
- package/src/actions/data/fold.js +2 -2
- package/src/actions/data/gradientProfile.js +2 -2
- package/src/actions/data/horizon.js +2 -2
- package/src/actions/data/impute.js +2 -2
- package/src/actions/data/index.js +58 -54
- package/src/actions/data/interval.js +4 -2
- package/src/actions/data/intervalEdit.js +26 -18
- package/src/actions/data/normalize.js +2 -2
- package/src/actions/data/regression.js +9 -7
- package/src/actions/data/revise.js +80 -0
- package/src/actions/data/revisionBindings.js +13 -33
- package/src/actions/data/shared.js +30 -2
- package/src/actions/data/sort.js +21 -0
- package/src/actions/data/stack.js +2 -2
- package/src/actions/data/summary.js +3 -3
- package/src/actions/data/timeUnit.js +2 -2
- package/src/actions/data/window.js +2 -2
- package/src/actions/encodings/angle.js +5 -2
- package/src/actions/encodings/appearance.js +10 -6
- package/src/actions/encodings/barWidth.js +1 -1
- package/src/actions/encodings/channels.js +2 -2
- package/src/actions/encodings/color/continuous.js +4 -1
- package/src/actions/encodings/color/index.js +5 -2
- package/src/actions/encodings/density.js +2 -2
- package/src/actions/encodings/histogram.js +1 -1
- package/src/actions/encodings/horizon.js +6 -8
- package/src/actions/encodings/offset.js +6 -3
- package/src/actions/encodings/parallel.js +4 -5
- package/src/actions/encodings/pathOrder.js +6 -11
- package/src/actions/encodings/position/index.js +4 -4
- package/src/actions/encodings/position/resolve.js +6 -1
- package/src/actions/encodings/ranged.js +11 -6
- package/src/actions/encodings/remove.js +4 -5
- package/src/actions/encodings/ruleAppearance.js +5 -2
- package/src/actions/encodings/seriesLayout.js +1 -1
- package/src/actions/encodings/stroke.js +5 -2
- package/src/actions/encodings/strokeDash.js +8 -3
- package/src/actions/encodings/text.js +7 -2
- package/src/actions/errorBands/create.js +11 -17
- package/src/actions/errorBands/edit.js +13 -131
- package/src/actions/errorBars/create.js +8 -13
- package/src/actions/errorBars/edit.js +10 -121
- package/src/actions/facets/actions.js +30 -16
- package/src/actions/facets/derive.js +8 -2
- package/src/actions/facets/guides.js +4 -5
- package/src/actions/facets/replay.js +4 -5
- package/src/actions/gradientPlots/components.js +5 -6
- package/src/actions/gradientPlots/create.js +4 -5
- package/src/actions/gradientPlots/edit.js +4 -5
- package/src/actions/gradientPlots/materialize.js +2 -2
- package/src/actions/gradientPlots/rebind.js +4 -5
- package/src/actions/guides/axes/axes.js +23 -4
- package/src/actions/guides/axes/axis.js +2 -2
- package/src/actions/guides/axes/edit.js +2 -2
- package/src/actions/guides/axes/labels.js +9 -9
- package/src/actions/guides/axes/lines.js +9 -7
- package/src/actions/guides/axes/parallel/lifecycle.js +13 -13
- package/src/actions/guides/axes/parallel.js +5 -5
- package/src/actions/guides/axes/remove.js +4 -4
- package/src/actions/guides/axes/tickGroups.js +4 -4
- package/src/actions/guides/axes/ticks.js +13 -4
- package/src/actions/guides/axes/titles.js +10 -10
- package/src/actions/guides/grids/grid.js +18 -29
- package/src/actions/guides/guides.js +1 -1
- package/src/actions/guides/legends/blocks.js +1 -1
- package/src/actions/guides/legends/categorical/actions.js +4 -4
- package/src/actions/guides/legends/categorical/components.js +38 -33
- package/src/actions/guides/legends/categorical/layout.js +1 -1
- package/src/actions/guides/legends/categorical/symbols.js +27 -30
- package/src/actions/guides/legends/continuous/common.js +46 -8
- package/src/actions/guides/legends/continuous/gradient.js +89 -155
- package/src/actions/guides/legends/continuous/interval.js +13 -13
- package/src/actions/guides/legends/continuous/opacity.js +30 -79
- package/src/actions/guides/legends/continuous/stroke.js +22 -322
- package/src/actions/guides/legends/edit.js +1 -1
- package/src/actions/guides/legends/focused.js +5 -5
- package/src/actions/guides/legends/lane.js +6 -6
- package/src/actions/guides/legends/remove.js +4 -5
- package/src/actions/guides/legends/size.js +21 -82
- package/src/actions/guides/legends/strokeWidth.js +17 -77
- package/src/actions/guides/polar/axes/facade.js +4 -4
- package/src/actions/guides/polar/axes/labels.js +5 -5
- package/src/actions/guides/polar/axes/lines.js +9 -15
- package/src/actions/guides/polar/axes/ticks.js +9 -15
- package/src/actions/guides/polar/axes/titles.js +5 -5
- package/src/actions/guides/polar/grids.js +11 -13
- package/src/actions/index.js +2 -0
- package/src/actions/intervals/revision.js +126 -0
- package/src/actions/marks/arc/actions.js +3 -3
- package/src/actions/marks/area/actions.js +4 -4
- package/src/actions/marks/bar/create.js +9 -2
- package/src/actions/marks/bar/edit.js +13 -6
- package/src/actions/marks/bar/materialize.js +12 -38
- package/src/actions/marks/line/actions.js +3 -3
- package/src/actions/marks/point/create.js +9 -2
- package/src/actions/marks/point/edit.js +13 -6
- package/src/actions/marks/point/jitter.js +6 -8
- package/src/actions/marks/point/materialize.js +20 -26
- package/src/actions/marks/point/packing.js +6 -8
- package/src/actions/marks/rect/actions.js +26 -11
- package/src/actions/marks/references.js +8 -10
- package/src/actions/marks/remove.js +5 -49
- package/src/actions/marks/rule/actions.js +28 -12
- package/src/actions/marks/text/actions.js +30 -11
- package/src/actions/marks/text/layout.js +12 -20
- package/src/actions/marks/text/removal.js +1 -1
- package/src/actions/marks/text/selection.js +4 -5
- package/src/actions/marks/tick/actions.js +26 -11
- package/src/actions/primitives/createGraphics.js +5 -4
- package/src/actions/primitives/editGraphics.js +5 -4
- package/src/actions/primitives/graphicProperties.js +6 -0
- package/src/actions/primitives/semantic.js +10 -3
- package/src/actions/primitives/semanticAction.js +44 -7
- package/src/actions/primitives/semanticValidation/dataset.js +14 -4
- package/src/actions/primitives/semanticValidation/layer.js +22 -2
- package/src/actions/primitives/semanticValidation/scale.js +6 -0
- package/src/actions/regression/components.js +10 -14
- package/src/actions/regression/create.js +28 -8
- package/src/actions/regression/edit.js +50 -16
- package/src/actions/regression/follow.js +22 -0
- package/src/actions/resources/remove.js +12 -11
- package/src/actions/scales/channels.js +11 -11
- package/src/actions/scales/consumers/common.js +2 -1
- package/src/actions/scales/create.js +3 -2
- package/src/actions/scales/definitions.js +1 -1
- package/src/actions/scales/edit.js +2 -2
- package/src/actions/scales/materialize.js +1 -1
- package/src/actions/scales/offset.js +2 -2
- package/src/actions/scales/parallel.js +2 -2
- package/src/actions/scales/patch.js +1 -1
- package/src/actions/scales/preview.js +28 -1
- package/src/actions/scales/quantitativeColor.js +4 -5
- package/src/actions/selection/actions.js +25 -36
- package/src/actions/textMetrics/index.js +56 -0
- package/src/actions/theme/actions.js +2 -2
- package/src/actions/theme/reconcile.js +67 -121
- package/src/actions/titles/actions.js +8 -8
- package/src/actions/titles/resolve.js +3 -3
- package/src/actions/violinPlots/create.js +1 -1
- package/src/actions/violinPlots/edit.js +1 -1
- package/src/core/action.js +109 -36
- package/src/core/diagnostics.js +16 -0
- package/src/core/extensionRegistry.js +27 -0
- package/src/core/font.js +18 -0
- package/src/core/identifiers.js +5 -4
- package/src/core/immutable.js +10 -3
- package/src/core/optionRequirements.js +8 -0
- package/src/core/programState.js +6 -2
- package/src/core/resourceReferences.js +15 -6
- package/src/core/textMetricProfile.js +28 -0
- package/src/core/textMetrics.js +24 -3
- package/src/core/validation.js +22 -10
- package/src/diagnostics.js +1 -0
- package/src/grammar/bin.js +39 -10
- package/src/grammar/datasetSchema.js +386 -0
- package/src/grammar/density.js +53 -5
- package/src/grammar/filter.js +133 -39
- package/src/grammar/impute.js +3 -2
- package/src/grammar/interval.js +32 -1
- package/src/grammar/itemMissing.js +59 -0
- package/src/grammar/regression/derive.js +57 -16
- package/src/grammar/regression/index.js +1 -0
- package/src/grammar/regression/models.js +51 -22
- package/src/grammar/regression/parameters.js +56 -4
- package/src/grammar/scales/definition.js +7 -0
- package/src/grammar/scales/types.js +8 -0
- package/src/grammar/schemas/graphicBounds.js +11 -11
- package/src/grammar/schemas/semanticPath.js +3 -2
- package/src/grammar/sort.js +88 -0
- package/src/grammar/summary.js +117 -19
- package/src/grammar/transformTopology.js +1 -0
- package/src/grammar/transforms.js +21 -11
- package/src/inspection.js +495 -0
- package/src/inspectionDescriptors.js +3 -0
- package/src/layout/labels.js +11 -10
- package/src/layout/legend.js +4 -4
- package/src/layout/legendItems.js +6 -6
- package/src/layout/text.js +10 -9
- package/src/layout/title.js +9 -9
- package/src/materialization/bars/resolve.js +4 -2
- package/src/materialization/facetGuides/placement.js +1 -1
- package/src/materialization/facetGuides/preparation.js +1 -1
- package/src/materialization/facetHeaders.js +11 -10
- package/src/materialization/guides/layout.js +3 -3
- package/src/materialization/revisionIdentity.js +19 -0
- package/src/materialization/scaleGuideDependencies.js +10 -0
- package/src/materialization/scales/resolve.js +67 -4
- package/src/materialization/selection/items/common.js +1 -1
- package/src/materialization/text.js +6 -4
- package/src/materialization/typography.js +31 -0
- package/src/mcp/cli.js +5 -3
- package/src/persistence/codec.js +65 -0
- package/src/persistence/validation.js +185 -0
- package/src/persistence.js +147 -0
- package/src/renderers/canvas/index.js +5 -4
- package/src/renderers/nativeBackend.js +10 -0
- package/src/renderers/options.js +13 -0
- package/src/renderers/pdf.js +25 -54
- package/src/renderers/png.js +22 -17
- package/src/renderers/svg.js +10 -14
- package/src/renderers/text.js +1 -11
- package/src/selectors/coordinates.js +3 -1
- package/src/selectors/datasets.js +8 -6
- package/src/selectors/layers.js +6 -4
- package/src/selectors/markOwners.js +46 -0
- package/src/selectors/scales.js +6 -4
- package/src/theme/defaults.js +2 -1
- package/src/version.js +2 -0
- package/types/accessibility.d.ts +37 -0
- package/types/basic.d.ts +4 -2
- package/types/diagnostics.d.ts +15 -0
- package/types/index.d.ts +5 -0
- package/types/inspection.d.ts +17 -0
- package/types/pdf.d.ts +9 -0
- package/types/persistence.d.ts +7 -0
- package/types/png.d.ts +9 -0
- package/types/program.d.ts +181 -28
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { hasSemanticScaleReferences } from "../../selectors/scales.js";
|
|
2
|
-
import {
|
|
2
|
+
import { closedAction } from "../../core/action.js";
|
|
3
3
|
import {
|
|
4
4
|
cloneAndFreeze,
|
|
5
5
|
freezeOwned,
|
|
@@ -7,6 +7,8 @@ import {
|
|
|
7
7
|
removeOwnedPath
|
|
8
8
|
} from "../../core/immutable.js";
|
|
9
9
|
import { parseSemanticPath } from "../../grammar/schemas/semanticPath.js";
|
|
10
|
+
import { deriveTransformSchema, inferDatasetSchema, validateRowsAgainstSchema } from "../../grammar/datasetSchema.js";
|
|
11
|
+
|
|
10
12
|
|
|
11
13
|
const CONTEXT_KEYS = Object.freeze({
|
|
12
14
|
dataset: "currentData",
|
|
@@ -43,7 +45,39 @@ function updateEntity(spec, parsed, value) {
|
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
const current = index === -1 ? { id: parsed.id } : collection[index];
|
|
46
|
-
|
|
48
|
+
let updated = setNestedProperty(current, parsed.path, value);
|
|
49
|
+
if (
|
|
50
|
+
parsed.kind === "dataset" && parsed.path.length === 1 &&
|
|
51
|
+
parsed.path[0] === "transform" && current.schema === undefined &&
|
|
52
|
+
current.source !== undefined && value.length === 1
|
|
53
|
+
) {
|
|
54
|
+
const source = collection.find(dataset => dataset.id === current.source);
|
|
55
|
+
if (source?.schema !== undefined) {
|
|
56
|
+
updated = setNestedProperty(updated, ["schema"], deriveTransformSchema(
|
|
57
|
+
source.schema,
|
|
58
|
+
value[0],
|
|
59
|
+
undefined,
|
|
60
|
+
{ sourceId: source.id, ownerId: parsed.id }
|
|
61
|
+
));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (
|
|
65
|
+
parsed.kind === "dataset" && parsed.path.length === 1 &&
|
|
66
|
+
parsed.path[0] === "values" &&
|
|
67
|
+
(current.schema === undefined || current.schema.origin === "derived")
|
|
68
|
+
) {
|
|
69
|
+
const source = current.source === undefined
|
|
70
|
+
? undefined
|
|
71
|
+
: collection.find(dataset => dataset.id === current.source);
|
|
72
|
+
const schema = source?.schema !== undefined && current.transform?.length === 1
|
|
73
|
+
? deriveTransformSchema(source.schema, current.transform[0], value, {
|
|
74
|
+
sourceId: source.id,
|
|
75
|
+
ownerId: parsed.id
|
|
76
|
+
})
|
|
77
|
+
: inferDatasetSchema(value);
|
|
78
|
+
validateRowsAgainstSchema(value, schema, `Dataset "${parsed.id}"`);
|
|
79
|
+
updated = setNestedProperty(updated, ["schema"], schema);
|
|
80
|
+
}
|
|
47
81
|
const nextCollection = [...collection];
|
|
48
82
|
|
|
49
83
|
if (index === -1) {
|
|
@@ -154,13 +188,14 @@ export function withRematerializedDerivedDataset(program, {
|
|
|
154
188
|
id,
|
|
155
189
|
source,
|
|
156
190
|
transform,
|
|
157
|
-
values
|
|
191
|
+
values,
|
|
192
|
+
schema
|
|
158
193
|
}) {
|
|
159
194
|
const semanticSpec = {
|
|
160
195
|
...program.semanticSpec,
|
|
161
196
|
datasets: program.semanticSpec.datasets.map(dataset =>
|
|
162
197
|
dataset.id === id
|
|
163
|
-
? { ...dataset, source, transform: [transform], values }
|
|
198
|
+
? { ...dataset, source, transform: [transform], values, ...(schema === undefined ? {} : { schema }) }
|
|
164
199
|
: dataset
|
|
165
200
|
)
|
|
166
201
|
};
|
|
@@ -191,13 +226,15 @@ export function withoutPreviewLayerEncodings(program, { id, channels }) {
|
|
|
191
226
|
}
|
|
192
227
|
|
|
193
228
|
export function createSemanticPrimitiveAction(validateSemanticValue, planNamedRemoval) {
|
|
194
|
-
return
|
|
229
|
+
return closedAction(
|
|
195
230
|
{
|
|
196
231
|
op: "editSemantic",
|
|
197
232
|
description: "Create, replace, or remove one semantic property.",
|
|
198
233
|
scope: "any"
|
|
199
|
-
},
|
|
200
|
-
function (
|
|
234
|
+
}, ["property", "value", "remove"],
|
|
235
|
+
function (args = {}) {
|
|
236
|
+
|
|
237
|
+
const { property, value, remove = false } = args;
|
|
201
238
|
if (typeof remove !== "boolean") {
|
|
202
239
|
throw new TypeError("editSemantic remove must be a boolean.");
|
|
203
240
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { validateUserId } from "../../../core/identifiers.js";
|
|
2
|
-
import {
|
|
3
|
-
import { hasDataset } from "../../../selectors/datasets.js";
|
|
2
|
+
import { validateDataRows } from "../../../core/validation.js";
|
|
3
|
+
import { findDataset, hasDataset } from "../../../selectors/datasets.js";
|
|
4
|
+
import {
|
|
5
|
+
validateDatasetSchema,
|
|
6
|
+
validateRowsAgainstSchema
|
|
7
|
+
} from "../../../grammar/datasetSchema.js";
|
|
4
8
|
|
|
5
9
|
export function validateDatasetSemanticValue(
|
|
6
10
|
program,
|
|
@@ -10,11 +14,17 @@ export function validateDatasetSemanticValue(
|
|
|
10
14
|
) {
|
|
11
15
|
const property = parsed.path[0];
|
|
12
16
|
if (property === "values") {
|
|
13
|
-
|
|
14
|
-
|
|
17
|
+
validateDataRows(value, `Dataset "${parsed.id}"`);
|
|
18
|
+
const schema = findDataset(program, parsed.id)?.schema;
|
|
19
|
+
if (schema !== undefined && schema.origin !== "derived") {
|
|
20
|
+
validateRowsAgainstSchema(value, schema, `Dataset "${parsed.id}"`);
|
|
15
21
|
}
|
|
16
22
|
return;
|
|
17
23
|
}
|
|
24
|
+
if (property === "schema") {
|
|
25
|
+
validateDatasetSchema(value);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
18
28
|
if (property === "source") {
|
|
19
29
|
validateUserId(value, "Dataset source id");
|
|
20
30
|
if (!hasDataset(program, value)) {
|
|
@@ -19,6 +19,8 @@ import { findLayer } from "../../../selectors/layers.js";
|
|
|
19
19
|
import { validateNonEmptySemanticString } from "./shared.js";
|
|
20
20
|
import { normalizeStatisticalWeight } from
|
|
21
21
|
"../../../grammar/weightedStatistics.js";
|
|
22
|
+
import { ITEM_MISSING_MARK_TYPES, validateItemMissing } from
|
|
23
|
+
"../../../grammar/itemMissing.js";
|
|
22
24
|
|
|
23
25
|
function validateLayerSource(program, parsed, value, sourceMarkTypes) {
|
|
24
26
|
validateUserId(value, "Layer source id");
|
|
@@ -52,8 +54,26 @@ export function validateLayerSemanticValue(
|
|
|
52
54
|
if (property === "mark.type" && !MARK_TYPES.includes(value)) {
|
|
53
55
|
throw new Error(`Unknown mark type "${value}".`);
|
|
54
56
|
}
|
|
55
|
-
if (property === "mark.missing"
|
|
56
|
-
|
|
57
|
+
if (property === "mark.missing") {
|
|
58
|
+
const markType = findLayer(program, parsed.id)?.mark?.type;
|
|
59
|
+
if (markType === "area") {
|
|
60
|
+
if (!["error", "break"].includes(value)) {
|
|
61
|
+
throw new Error(`Unsupported area missing policy "${value}".`);
|
|
62
|
+
}
|
|
63
|
+
} else if (ITEM_MISSING_MARK_TYPES.includes(markType)) {
|
|
64
|
+
validateItemMissing(value, `${markType} missing`);
|
|
65
|
+
} else {
|
|
66
|
+
throw new Error(`Mark type "${markType}" does not support a missing policy.`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (property === "derivedBindings.regression") {
|
|
70
|
+
if (!value || typeof value !== "object" || Array.isArray(value) ||
|
|
71
|
+
Object.keys(value).length !== 2 || value.mode !== "follow" ||
|
|
72
|
+
!Array.isArray(value.roles) || value.roles.length !== 3 ||
|
|
73
|
+
value.roles.join(",") !== "data,x,y") {
|
|
74
|
+
throw new Error("Regression derived binding must follow data, x, and y roles.");
|
|
75
|
+
}
|
|
76
|
+
return;
|
|
57
77
|
}
|
|
58
78
|
if (property === "layout.mode" && !COLOR_LAYOUTS.includes(value)) {
|
|
59
79
|
throw new Error(`Unsupported series layout "${value}".`);
|
|
@@ -55,6 +55,12 @@ export function validateScaleSemanticValue(program, parsed, value) {
|
|
|
55
55
|
return;
|
|
56
56
|
}
|
|
57
57
|
if (property === "domain") return validateSemanticScaleDomain(value);
|
|
58
|
+
if (property === "emptyDomain") {
|
|
59
|
+
if (!["preserve", "require-explicit"].includes(value)) {
|
|
60
|
+
throw new Error('Scale emptyDomain must be "preserve" or "require-explicit".');
|
|
61
|
+
}
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
58
64
|
if (property === "range") return validateSemanticScaleRange(value);
|
|
59
65
|
if (["nice", "zero", "clamp", "reverse"].includes(property)) {
|
|
60
66
|
if (typeof value !== "boolean") {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { closedAction } from "../../core/action.js";
|
|
2
2
|
import { validateUserId } from "../../core/identifiers.js";
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
import { DEFAULT_COLORS } from "../../theme/defaults.js";
|
|
5
5
|
import { findDataset } from "../../selectors/datasets.js";
|
|
6
6
|
import { resolveEligibleLayer } from "../../selectors/layers.js";
|
|
@@ -72,13 +72,12 @@ function requireRegressionBandDataset(program, args) {
|
|
|
72
72
|
return { dataset, transform };
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
export const createRegressionBand =
|
|
75
|
+
export const createRegressionBand = /* @__PURE__ */ closedAction(
|
|
76
76
|
{
|
|
77
77
|
op: "createRegressionBand",
|
|
78
78
|
description: "Create and encode a grouped regression confidence band."
|
|
79
|
-
},
|
|
79
|
+
}, BAND_OPTIONS,
|
|
80
80
|
function (args = {}) {
|
|
81
|
-
validateKeys(args, BAND_OPTIONS, "createRegressionBand");
|
|
82
81
|
const id = validateUserId(args.id, "Regression band id");
|
|
83
82
|
const { transform } = requireRegressionBandDataset(this, args);
|
|
84
83
|
validateAreaCreateOutline(args, "createRegressionBand");
|
|
@@ -121,13 +120,12 @@ export const createRegressionBand = action(
|
|
|
121
120
|
}
|
|
122
121
|
);
|
|
123
122
|
|
|
124
|
-
export const editRegressionBand =
|
|
123
|
+
export const editRegressionBand = /* @__PURE__ */ closedAction(
|
|
125
124
|
{
|
|
126
125
|
op: "editRegressionBand",
|
|
127
126
|
description: "Edit regression-band fill, opacity, and outline."
|
|
128
|
-
},
|
|
127
|
+
}, EDIT_BAND_OPTIONS,
|
|
129
128
|
function (args = {}) {
|
|
130
|
-
validateKeys(args, EDIT_BAND_OPTIONS, "editRegressionBand");
|
|
131
129
|
const changes = [
|
|
132
130
|
"color", "opacity", "stroke", "strokeWidth", "curve",
|
|
133
131
|
...STROKE_STYLE_PROPERTIES
|
|
@@ -157,13 +155,12 @@ export const editRegressionBand = action(
|
|
|
157
155
|
}
|
|
158
156
|
);
|
|
159
157
|
|
|
160
|
-
export const editRegressionLine =
|
|
158
|
+
export const editRegressionLine = /* @__PURE__ */ closedAction(
|
|
161
159
|
{
|
|
162
160
|
op: "editRegressionLine",
|
|
163
161
|
description: "Edit regression-line width or curve."
|
|
164
|
-
},
|
|
162
|
+
}, EDIT_LINE_OPTIONS,
|
|
165
163
|
function (args = {}) {
|
|
166
|
-
validateKeys(args, EDIT_LINE_OPTIONS, "editRegressionLine");
|
|
167
164
|
if (
|
|
168
165
|
!["strokeWidth", "curve", ...STROKE_STYLE_PROPERTIES]
|
|
169
166
|
.some(property => Object.hasOwn(args, property))
|
|
@@ -187,13 +184,12 @@ export const editRegressionLine = action(
|
|
|
187
184
|
}
|
|
188
185
|
);
|
|
189
186
|
|
|
190
|
-
export const createRegressionLine =
|
|
187
|
+
export const createRegressionLine = /* @__PURE__ */ closedAction(
|
|
191
188
|
{
|
|
192
189
|
op: "createRegressionLine",
|
|
193
190
|
description: "Create and encode grouped regression line paths."
|
|
194
|
-
},
|
|
191
|
+
}, LINE_OPTIONS,
|
|
195
192
|
function (args = {}) {
|
|
196
|
-
validateKeys(args, LINE_OPTIONS, "createRegressionLine");
|
|
197
193
|
const id = validateUserId(args.id, "Regression line id");
|
|
198
194
|
let next = this
|
|
199
195
|
.createLineMark({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { closedAction } from "../../core/action.js";
|
|
2
2
|
import { validateKeys } from "../../core/validation.js";
|
|
3
|
-
import { normalizeRegressionParameters } from "../../grammar/regression/index.js";
|
|
3
|
+
import { normalizeRegressionParameters, normalizeRegressionPredict } from "../../grammar/regression/index.js";
|
|
4
4
|
import { STROKE_STYLE_PROPERTIES } from "../../grammar/strokeStyle.js";
|
|
5
5
|
import {
|
|
6
6
|
findRegressionPoint,
|
|
@@ -12,15 +12,19 @@ import {
|
|
|
12
12
|
const REGRESSION_OPTIONS = Object.freeze([
|
|
13
13
|
"target", "x", "y", "groupBy", "method", "degree", "span",
|
|
14
14
|
"confidenceMethod", "level", "confidence", "interval", "band", "line"
|
|
15
|
+
, "predict", "sourceBinding", "missing"
|
|
15
16
|
]);
|
|
16
17
|
|
|
17
|
-
export const createRegression =
|
|
18
|
+
export const createRegression = /* @__PURE__ */ closedAction(
|
|
18
19
|
{
|
|
19
20
|
op: "createRegression",
|
|
20
21
|
description: "Fit and layer regression lines with optional interval bands."
|
|
21
|
-
},
|
|
22
|
+
}, REGRESSION_OPTIONS,
|
|
22
23
|
function (args = {}) {
|
|
23
|
-
|
|
24
|
+
const sourceBinding = args.sourceBinding ?? "fixed";
|
|
25
|
+
if (!["fixed", "follow"].includes(sourceBinding)) {
|
|
26
|
+
throw new Error('Regression sourceBinding must be "fixed" or "follow".');
|
|
27
|
+
}
|
|
24
28
|
const point = findRegressionPoint(this, args.target);
|
|
25
29
|
const x = args.x === undefined
|
|
26
30
|
? point.encoding.x.field
|
|
@@ -38,11 +42,21 @@ export const createRegression = action(
|
|
|
38
42
|
);
|
|
39
43
|
}
|
|
40
44
|
const parameters = normalizeRegressionParameters(args);
|
|
45
|
+
const predict = normalizeRegressionPredict(args.predict);
|
|
46
|
+
const regressionDefinition = {
|
|
47
|
+
...parameters,
|
|
48
|
+
...(predict === undefined ? {} : { predict }),
|
|
49
|
+
...(args.missing === undefined ? {} : { missing: args.missing })
|
|
50
|
+
};
|
|
41
51
|
let band = false;
|
|
42
52
|
if (parameters.method === "loess") {
|
|
43
53
|
if (args.band !== undefined && args.band !== false) {
|
|
44
54
|
throw new Error("LOESS regression does not support a band object.");
|
|
45
55
|
}
|
|
56
|
+
} else if (parameters.interval === false) {
|
|
57
|
+
if (args.band !== undefined && args.band !== false) {
|
|
58
|
+
throw new Error("Regression interval false cannot include a band object.");
|
|
59
|
+
}
|
|
46
60
|
} else if (args.band !== false) {
|
|
47
61
|
band = requireRegressionObject(args.band ?? {}, "Regression band");
|
|
48
62
|
}
|
|
@@ -79,7 +93,7 @@ export const createRegression = action(
|
|
|
79
93
|
x,
|
|
80
94
|
y,
|
|
81
95
|
...(groupBy === undefined ? {} : { groupBy }),
|
|
82
|
-
...
|
|
96
|
+
...regressionDefinition
|
|
83
97
|
});
|
|
84
98
|
if (band !== false) {
|
|
85
99
|
next = next.createRegressionBand({
|
|
@@ -106,7 +120,7 @@ export const createRegression = action(
|
|
|
106
120
|
yScale,
|
|
107
121
|
...line
|
|
108
122
|
});
|
|
109
|
-
|
|
123
|
+
next = next._withMarkConfig(point.id, {
|
|
110
124
|
...next.markConfigs[point.id],
|
|
111
125
|
regression: {
|
|
112
126
|
source: point.data,
|
|
@@ -120,8 +134,14 @@ export const createRegression = action(
|
|
|
120
134
|
dataId,
|
|
121
135
|
bandId: band === false ? undefined : bandId,
|
|
122
136
|
lineId,
|
|
123
|
-
parameters
|
|
137
|
+
parameters: regressionDefinition
|
|
124
138
|
}
|
|
125
139
|
});
|
|
140
|
+
return sourceBinding === "follow"
|
|
141
|
+
? next.editSemantic({
|
|
142
|
+
property: `layer[${point.id}].derivedBindings.regression`,
|
|
143
|
+
value: { mode: "follow", roles: ["data", "x", "y"] }
|
|
144
|
+
})
|
|
145
|
+
: next;
|
|
126
146
|
}
|
|
127
147
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { closedAction } from "../../core/action.js";
|
|
2
2
|
import { isPlainObject } from "../../core/immutable.js";
|
|
3
3
|
import { validateUserId } from "../../core/identifiers.js";
|
|
4
4
|
import {
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
validateNonNegativeFinite,
|
|
8
8
|
validateUnitInterval
|
|
9
9
|
} from "../../core/validation.js";
|
|
10
|
-
import { normalizeRegressionParameters } from "../../grammar/regression/index.js";
|
|
10
|
+
import { normalizeRegressionParameters, normalizeRegressionPredict } from "../../grammar/regression/index.js";
|
|
11
11
|
import { validateCurveInterpolation } from "../../grammar/curveCommands.js";
|
|
12
12
|
import {
|
|
13
13
|
requestedStrokeDetails,
|
|
@@ -23,6 +23,7 @@ import { requireRegressionField } from "./resolve.js";
|
|
|
23
23
|
const OPTIONS = Object.freeze([
|
|
24
24
|
"target", "data", "x", "y", "groupBy", "method", "degree", "span",
|
|
25
25
|
"confidenceMethod", "level", "confidence", "interval", "band", "line"
|
|
26
|
+
, "predict", "sourceBinding", "missing"
|
|
26
27
|
]);
|
|
27
28
|
const BAND_OPTIONS = Object.freeze([
|
|
28
29
|
"color", "opacity", "stroke", "strokeWidth", "curve",
|
|
@@ -115,7 +116,7 @@ function resolveParameters(previous, args) {
|
|
|
115
116
|
if (Object.hasOwn(args, key)) raw[key] = args[key];
|
|
116
117
|
}
|
|
117
118
|
const inheritsLevel = !Object.hasOwn(raw, "confidence");
|
|
118
|
-
if (method === previous.method) {
|
|
119
|
+
if (method === previous.method && args.interval !== false) {
|
|
119
120
|
for (const key of [
|
|
120
121
|
"degree", "span", "confidenceMethod", "level", "interval"
|
|
121
122
|
]) {
|
|
@@ -127,7 +128,7 @@ function resolveParameters(previous, args) {
|
|
|
127
128
|
raw[key] = previous[key];
|
|
128
129
|
}
|
|
129
130
|
}
|
|
130
|
-
} else if (method !== "loess" && previous.method !== "loess") {
|
|
131
|
+
} else if (method !== "loess" && previous.method !== "loess" && args.interval !== false) {
|
|
131
132
|
for (const key of ["confidenceMethod", "level", "interval"]) {
|
|
132
133
|
if (
|
|
133
134
|
!Object.hasOwn(raw, key) &&
|
|
@@ -138,7 +139,19 @@ function resolveParameters(previous, args) {
|
|
|
138
139
|
}
|
|
139
140
|
}
|
|
140
141
|
}
|
|
141
|
-
|
|
142
|
+
const parameters = normalizeRegressionParameters(raw);
|
|
143
|
+
const predict = Object.hasOwn(args, "predict")
|
|
144
|
+
? args.predict === false ? undefined : normalizeRegressionPredict(args.predict)
|
|
145
|
+
: previous.predict;
|
|
146
|
+
const missing = Object.hasOwn(args, "missing") ? args.missing : previous.missing;
|
|
147
|
+
if (missing !== undefined && !["error", "drop"].includes(missing)) {
|
|
148
|
+
throw new Error('Regression missing must be "error" or "drop".');
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
...parameters,
|
|
152
|
+
...(predict === undefined ? {} : { predict }),
|
|
153
|
+
...(missing === undefined ? {} : { missing })
|
|
154
|
+
};
|
|
142
155
|
}
|
|
143
156
|
|
|
144
157
|
function regressionColorScale(owner, current, groupBy) {
|
|
@@ -234,27 +247,42 @@ function updateRegressionBandSemantics(program, bandId, { x, groupBy }) {
|
|
|
234
247
|
});
|
|
235
248
|
}
|
|
236
249
|
|
|
237
|
-
export const editRegression =
|
|
250
|
+
export const editRegression = /* @__PURE__ */ closedAction(
|
|
238
251
|
{
|
|
239
252
|
op: "editRegression",
|
|
240
253
|
description: "Revise a regression model and its owned visible components."
|
|
241
|
-
},
|
|
254
|
+
}, OPTIONS,
|
|
242
255
|
function (args = {}) {
|
|
243
|
-
validateKeys(args, OPTIONS, "editRegression");
|
|
244
256
|
if (!OPTIONS.slice(1).some(key => Object.hasOwn(args, key))) {
|
|
245
257
|
throw new Error("editRegression requires a statistical or component option.");
|
|
246
258
|
}
|
|
247
259
|
const owner = resolveRegressionOwner(this, args.target);
|
|
248
260
|
const current = this.markConfigs[owner.id].regression;
|
|
249
|
-
const
|
|
261
|
+
const currentBinding = owner.derivedBindings?.regression?.mode === "follow" ? "follow" : "fixed";
|
|
262
|
+
const sourceBinding = args.sourceBinding ?? currentBinding;
|
|
263
|
+
if (!["fixed", "follow"].includes(sourceBinding)) throw new Error('Regression sourceBinding must be "fixed" or "follow".');
|
|
264
|
+
const followed = sourceBinding === "follow" ? {
|
|
265
|
+
data: owner.data,
|
|
266
|
+
x: owner.encoding?.x?.fieldType === "quantitative" ? owner.encoding.x.field : undefined,
|
|
267
|
+
y: owner.encoding?.y?.fieldType === "quantitative" ? owner.encoding.y.field : undefined
|
|
268
|
+
} : undefined;
|
|
269
|
+
if (sourceBinding === "follow" && (!followed.data || !followed.x || !followed.y)) {
|
|
270
|
+
throw new Error(`Following regression source "${owner.id}" requires quantitative x/y fields and data.`);
|
|
271
|
+
}
|
|
272
|
+
for (const key of ["data", "x", "y"]) {
|
|
273
|
+
if (followed !== undefined && Object.hasOwn(args, key) && args[key] !== followed[key]) {
|
|
274
|
+
throw new Error(`Following regression ${key} must match source mark "${owner.id}".`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
const source = followed?.data ?? (Object.hasOwn(args, "data")
|
|
250
278
|
? validateUserId(args.data, "Regression data id")
|
|
251
|
-
: current.source;
|
|
252
|
-
const x = Object.hasOwn(args, "x")
|
|
279
|
+
: current.source);
|
|
280
|
+
const x = followed?.x ?? (Object.hasOwn(args, "x")
|
|
253
281
|
? requireRegressionField(args.x, "Regression x")
|
|
254
|
-
: current.x;
|
|
255
|
-
const y = Object.hasOwn(args, "y")
|
|
282
|
+
: current.x);
|
|
283
|
+
const y = followed?.y ?? (Object.hasOwn(args, "y")
|
|
256
284
|
? requireRegressionField(args.y, "Regression y")
|
|
257
|
-
: current.y;
|
|
285
|
+
: current.y);
|
|
258
286
|
const groupBy = Object.hasOwn(args, "groupBy")
|
|
259
287
|
? args.groupBy === false
|
|
260
288
|
? undefined
|
|
@@ -273,12 +301,12 @@ export const editRegression = action(
|
|
|
273
301
|
const linePatch = Object.hasOwn(args, "line")
|
|
274
302
|
? validateLinePatch(args.line)
|
|
275
303
|
: undefined;
|
|
276
|
-
if (parameters.method === "loess" && bandPatch !== undefined && bandPatch !== false) {
|
|
304
|
+
if ((parameters.method === "loess" || parameters.interval === false) && bandPatch !== undefined && bandPatch !== false) {
|
|
277
305
|
throw new Error("LOESS regression does not support a band object.");
|
|
278
306
|
}
|
|
279
307
|
|
|
280
308
|
const hadBand = current.bandId !== undefined;
|
|
281
|
-
const wantsBand = parameters.method !== "loess" &&
|
|
309
|
+
const wantsBand = parameters.method !== "loess" && parameters.interval !== false &&
|
|
282
310
|
(bandPatch === false
|
|
283
311
|
? false
|
|
284
312
|
: hadBand || bandPatch !== undefined || current.parameters.method === "loess");
|
|
@@ -386,6 +414,12 @@ export const editRegression = action(
|
|
|
386
414
|
if (changesStatistics) {
|
|
387
415
|
next = next.releaseDerivedData(revision.release);
|
|
388
416
|
}
|
|
417
|
+
const binding = findLayer(next, owner.id)?.derivedBindings?.regression;
|
|
418
|
+
if (sourceBinding === "follow" && binding?.mode !== "follow") {
|
|
419
|
+
next = next.editSemantic({ property: `layer[${owner.id}].derivedBindings.regression`, value: { mode: "follow", roles: ["data", "x", "y"] } });
|
|
420
|
+
} else if (sourceBinding === "fixed" && binding !== undefined) {
|
|
421
|
+
next = next.editSemantic({ property: `layer[${owner.id}].derivedBindings.regression`, remove: true });
|
|
422
|
+
}
|
|
389
423
|
return next;
|
|
390
424
|
};
|
|
391
425
|
return applyEdit(this);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export function reconcileFollowingRegressions(program) {
|
|
2
|
+
let next = program;
|
|
3
|
+
for (const layer of program.semanticSpec.layers) {
|
|
4
|
+
if (layer.derivedBindings?.regression?.mode !== "follow") continue;
|
|
5
|
+
const config = next.markConfigs[layer.id]?.regression;
|
|
6
|
+
if (config === undefined) continue;
|
|
7
|
+
const x = layer.encoding?.x;
|
|
8
|
+
const y = layer.encoding?.y;
|
|
9
|
+
if (typeof layer.data !== "string" || x?.fieldType !== "quantitative" || y?.fieldType !== "quantitative" ||
|
|
10
|
+
typeof x.field !== "string" || typeof y.field !== "string") {
|
|
11
|
+
throw new Error(`Following regression source "${layer.id}" requires quantitative x/y fields and data.`);
|
|
12
|
+
}
|
|
13
|
+
if (config.source === layer.data && config.x === x.field && config.y === y.field) continue;
|
|
14
|
+
next = next.editRegression({
|
|
15
|
+
target: layer.id,
|
|
16
|
+
data: layer.data,
|
|
17
|
+
x: x.field,
|
|
18
|
+
y: y.field
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
return next;
|
|
22
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { annotateError } from "../../core/diagnostics.js";
|
|
1
2
|
import { action } from "../../core/action.js";
|
|
2
3
|
import { validateUserId } from "../../core/identifiers.js";
|
|
3
4
|
import { validateOptionObject } from "../../core/validation.js";
|
|
@@ -70,20 +71,20 @@ export function resolveResourceOwnership(program, { kind, id }) {
|
|
|
70
71
|
if (resource !== undefined) return { ownership: "named", resource };
|
|
71
72
|
const other = existingKind(program, id);
|
|
72
73
|
if (other !== undefined) {
|
|
73
|
-
throw new Error(`Resource "${id}" exists as ${other}, not ${kind}.`);
|
|
74
|
+
throw annotateError(new Error(`Resource "${id}" exists as ${other}, not ${kind}.`), { code: "incompatible-resource", resourceId: id });
|
|
74
75
|
}
|
|
75
|
-
throw new Error(`Unknown ${kind} "${id}".`);
|
|
76
|
+
throw annotateError(new Error(`Unknown ${kind} "${id}".`), { code: "missing-resource", resourceId: id });
|
|
76
77
|
}
|
|
77
78
|
|
|
78
79
|
const owners = dataOwners(program).filter(owner => owner.owner === id);
|
|
79
80
|
if (owners.length > 1) {
|
|
80
|
-
throw new Error(`Data resource "${id}" has ambiguous logical ownership.`);
|
|
81
|
+
throw annotateError(new Error(`Data resource "${id}" has ambiguous logical ownership.`), { code: "ambiguous-resource", resourceId: id });
|
|
81
82
|
}
|
|
82
83
|
if (owners.length === 1) {
|
|
83
84
|
const owner = owners[0];
|
|
84
85
|
const current = exactResource(program, "data", owner.current);
|
|
85
86
|
if (current === undefined) {
|
|
86
|
-
throw new Error(`Data owner "${id}" has no current dataset.`);
|
|
87
|
+
throw annotateError(new Error(`Data owner "${id}" has no current dataset.`), { code: "missing-resource", resourceId: id });
|
|
87
88
|
}
|
|
88
89
|
return { ownership: "standalone", resource: current, dataOwner: owner };
|
|
89
90
|
}
|
|
@@ -98,9 +99,9 @@ export function resolveResourceOwnership(program, { kind, id }) {
|
|
|
98
99
|
}
|
|
99
100
|
const other = existingKind(program, id);
|
|
100
101
|
if (other !== undefined) {
|
|
101
|
-
throw new Error(`Resource "${id}" exists as ${other}, not data.`);
|
|
102
|
+
throw annotateError(new Error(`Resource "${id}" exists as ${other}, not data.`), { code: "incompatible-resource", resourceId: id });
|
|
102
103
|
}
|
|
103
|
-
throw new Error(`Unknown data "${id}".`);
|
|
104
|
+
throw annotateError(new Error(`Unknown data "${id}".`), { code: "missing-resource", resourceId: id });
|
|
104
105
|
}
|
|
105
106
|
|
|
106
107
|
function assertSupportedProgram(program, operation) {
|
|
@@ -126,10 +127,10 @@ export function planResourceRemoval(program, { kind, id, operation }) {
|
|
|
126
127
|
value.path.at(-1) === "current"
|
|
127
128
|
));
|
|
128
129
|
if (live.length > 0) {
|
|
129
|
-
throw new Error(
|
|
130
|
+
throw annotateError(new Error(
|
|
130
131
|
`Cannot remove ${kind} "${id}"; live references: ` +
|
|
131
132
|
live.map(formatReference).join("; ")
|
|
132
|
-
);
|
|
133
|
+
), { code: "resource-in-use", resourceId: id, candidates: [...new Set(live.map(value => value.ownerId))] });
|
|
133
134
|
}
|
|
134
135
|
return Object.freeze({
|
|
135
136
|
kind,
|
|
@@ -161,12 +162,12 @@ function removeResource(kind, operation, description) {
|
|
|
161
162
|
);
|
|
162
163
|
}
|
|
163
164
|
|
|
164
|
-
export const removeData = removeResource(
|
|
165
|
+
export const removeData = /* @__PURE__ */ removeResource(
|
|
165
166
|
"data", "removeData", "Remove one unreferenced named dataset."
|
|
166
167
|
);
|
|
167
|
-
export const removeScale = removeResource(
|
|
168
|
+
export const removeScale = /* @__PURE__ */ removeResource(
|
|
168
169
|
"scale", "removeScale", "Remove one unreferenced named scale."
|
|
169
170
|
);
|
|
170
|
-
export const removeCoordinate = removeResource(
|
|
171
|
+
export const removeCoordinate = /* @__PURE__ */ removeResource(
|
|
171
172
|
"coordinate", "removeCoordinate", "Remove one unreferenced named coordinate."
|
|
172
173
|
);
|
|
@@ -10,7 +10,7 @@ const DEFINITIONS = Object.freeze({
|
|
|
10
10
|
editXScale: Object.freeze({
|
|
11
11
|
channel: "x",
|
|
12
12
|
options: Object.freeze([
|
|
13
|
-
"type", "domain", "range", "nice", "zero", "clamp", "reverse",
|
|
13
|
+
"type", "domain", "range", "emptyDomain", "nice", "zero", "clamp", "reverse",
|
|
14
14
|
"base", "exponent", "constant", "paddingInner", "paddingOuter",
|
|
15
15
|
"padding", "align", "unknown"
|
|
16
16
|
])
|
|
@@ -18,7 +18,7 @@ const DEFINITIONS = Object.freeze({
|
|
|
18
18
|
editYScale: Object.freeze({
|
|
19
19
|
channel: "y",
|
|
20
20
|
options: Object.freeze([
|
|
21
|
-
"type", "domain", "range", "nice", "zero", "clamp", "reverse",
|
|
21
|
+
"type", "domain", "range", "emptyDomain", "nice", "zero", "clamp", "reverse",
|
|
22
22
|
"base", "exponent", "constant", "paddingInner", "paddingOuter",
|
|
23
23
|
"padding", "align", "unknown"
|
|
24
24
|
])
|
|
@@ -26,21 +26,21 @@ const DEFINITIONS = Object.freeze({
|
|
|
26
26
|
editThetaScale: Object.freeze({
|
|
27
27
|
channel: "theta",
|
|
28
28
|
options: Object.freeze([
|
|
29
|
-
"type", "domain", "range", "nice", "zero", "clamp", "reverse",
|
|
29
|
+
"type", "domain", "range", "emptyDomain", "nice", "zero", "clamp", "reverse",
|
|
30
30
|
"paddingInner", "paddingOuter", "padding", "align"
|
|
31
31
|
])
|
|
32
32
|
}),
|
|
33
33
|
editRScale: Object.freeze({
|
|
34
34
|
channel: "radius",
|
|
35
35
|
options: Object.freeze([
|
|
36
|
-
"type", "domain", "range", "nice", "zero", "clamp", "reverse",
|
|
36
|
+
"type", "domain", "range", "emptyDomain", "nice", "zero", "clamp", "reverse",
|
|
37
37
|
"base", "exponent", "constant", "radialMapping"
|
|
38
38
|
])
|
|
39
39
|
}),
|
|
40
40
|
editColorScale: Object.freeze({
|
|
41
41
|
channel: "color",
|
|
42
42
|
options: Object.freeze([
|
|
43
|
-
"type", "domain", "range", "clamp", "reverse", "palette",
|
|
43
|
+
"type", "domain", "range", "emptyDomain", "clamp", "reverse", "palette",
|
|
44
44
|
"interpolate", "midpoint", "unknown"
|
|
45
45
|
])
|
|
46
46
|
}),
|
|
@@ -48,37 +48,37 @@ const DEFINITIONS = Object.freeze({
|
|
|
48
48
|
channel: "stroke",
|
|
49
49
|
targetOnly: true,
|
|
50
50
|
options: Object.freeze([
|
|
51
|
-
"type", "domain", "range", "clamp", "reverse", "palette",
|
|
51
|
+
"type", "domain", "range", "emptyDomain", "clamp", "reverse", "palette",
|
|
52
52
|
"interpolate", "midpoint", "unknown"
|
|
53
53
|
])
|
|
54
54
|
}),
|
|
55
55
|
editSizeScale: Object.freeze({
|
|
56
56
|
channel: "size",
|
|
57
57
|
options: Object.freeze([
|
|
58
|
-
"type", "domain", "range", "unknown", "clamp", "reverse", "base",
|
|
58
|
+
"type", "domain", "range", "emptyDomain", "unknown", "clamp", "reverse", "base",
|
|
59
59
|
"exponent"
|
|
60
60
|
])
|
|
61
61
|
}),
|
|
62
62
|
editOpacityScale: Object.freeze({
|
|
63
63
|
channel: "opacity",
|
|
64
64
|
options: Object.freeze([
|
|
65
|
-
"type", "domain", "range", "nice", "zero", "clamp", "reverse", "unknown"
|
|
65
|
+
"type", "domain", "range", "emptyDomain", "nice", "zero", "clamp", "reverse", "unknown"
|
|
66
66
|
])
|
|
67
67
|
}),
|
|
68
68
|
editShapeScale: Object.freeze({
|
|
69
69
|
channel: "shape",
|
|
70
|
-
options: Object.freeze(["type", "domain", "range", "unknown"])
|
|
70
|
+
options: Object.freeze(["type", "domain", "range", "emptyDomain", "unknown"])
|
|
71
71
|
}),
|
|
72
72
|
editStrokeWidthScale: Object.freeze({
|
|
73
73
|
channel: "strokeWidth",
|
|
74
74
|
options: Object.freeze([
|
|
75
|
-
"type", "domain", "range", "nice", "zero", "clamp", "reverse",
|
|
75
|
+
"type", "domain", "range", "emptyDomain", "nice", "zero", "clamp", "reverse",
|
|
76
76
|
"base", "exponent", "constant"
|
|
77
77
|
])
|
|
78
78
|
}),
|
|
79
79
|
editStrokeDashScale: Object.freeze({
|
|
80
80
|
channel: "strokeDash",
|
|
81
|
-
options: Object.freeze(["type", "domain", "range"])
|
|
81
|
+
options: Object.freeze(["type", "domain", "range", "emptyDomain"])
|
|
82
82
|
})
|
|
83
83
|
});
|
|
84
84
|
|