ggaction 0.0.13 → 0.0.16
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 +146 -0
- package/README.md +41 -12
- 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 +39 -7
- package/src/BasicChartProgram.js +3 -1
- package/src/ChartProgram.js +2 -0
- package/src/accessibility.js +157 -0
- package/src/actions/basic.js +2 -2
- package/src/actions/boxPlots/components.js +20 -12
- package/src/actions/boxPlots/create.js +4 -5
- package/src/actions/boxPlots/edit.js +34 -9
- package/src/actions/boxPlots/materialize.js +12 -4
- package/src/actions/boxPlots/options.js +48 -16
- package/src/actions/canvas/actions.js +3 -3
- package/src/actions/canvas/fitting.js +1 -1
- package/src/actions/categoryOrder/index.js +21 -12
- package/src/actions/charts/area.js +6 -2
- package/src/actions/charts/bar.js +3 -2
- package/src/actions/charts/beeswarm.js +1 -1
- package/src/actions/charts/density.js +7 -3
- package/src/actions/charts/ecdf.js +6 -3
- package/src/actions/charts/endpoints.js +29 -7
- package/src/actions/charts/heatmap.js +3 -2
- package/src/actions/charts/histogram.js +5 -4
- package/src/actions/charts/horizon.js +4 -2
- package/src/actions/charts/interval-regression.js +7 -4
- package/src/actions/charts/line.js +4 -2
- package/src/actions/charts/parallel.js +9 -3
- package/src/actions/charts/pie.js +11 -3
- package/src/actions/charts/polar.js +17 -6
- package/src/actions/charts/radar.js +9 -3
- package/src/actions/charts/radial.js +12 -4
- package/src/actions/charts/raincloud.js +2 -2
- package/src/actions/charts/rug-strip.js +8 -4
- package/src/actions/charts/scatter.js +4 -2
- package/src/actions/composition/actions.js +29 -24
- package/src/actions/coordinates/actions.js +2 -2
- package/src/actions/coordinates/edit.js +76 -0
- package/src/actions/data/basicBin2d.js +4 -5
- package/src/actions/data/bin.js +3 -3
- package/src/actions/data/bin2d.js +63 -193
- package/src/actions/data/bin2dMaterialize.js +4 -5
- package/src/actions/data/box.js +4 -4
- package/src/actions/data/complete.js +26 -0
- package/src/actions/data/computed.js +4 -4
- package/src/actions/data/create.js +7 -14
- package/src/actions/data/density.js +15 -23
- package/src/actions/data/derived.js +57 -31
- package/src/actions/data/ecdf.js +2 -2
- package/src/actions/data/edit.js +551 -0
- package/src/actions/data/filter.js +28 -22
- 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 +26 -0
- package/src/actions/data/index.js +62 -47
- package/src/actions/data/interval.js +2 -2
- package/src/actions/data/intervalEdit.js +26 -18
- package/src/actions/data/normalize.js +27 -0
- package/src/actions/data/regression.js +21 -27
- package/src/actions/data/revise.js +48 -0
- package/src/actions/data/revisionBindings.js +125 -0
- package/src/actions/data/shared.js +20 -4
- package/src/actions/data/stack.js +2 -2
- package/src/actions/data/summary.js +3 -3
- package/src/actions/data/timeUnit.js +6 -3
- package/src/actions/data/window.js +3 -3
- package/src/actions/encodings/angle.js +1 -1
- package/src/actions/encodings/appearance.js +4 -4
- package/src/actions/encodings/barWidth.js +1 -1
- package/src/actions/encodings/channels.js +415 -0
- package/src/actions/encodings/color/index.js +3 -2
- package/src/actions/encodings/density.js +7 -4
- package/src/actions/encodings/histogram.js +4 -3
- package/src/actions/encodings/horizon.js +6 -8
- package/src/actions/encodings/index.js +4 -0
- package/src/actions/encodings/offset.js +22 -15
- package/src/actions/encodings/parallel.js +4 -5
- package/src/actions/encodings/pathOrder.js +6 -11
- package/src/actions/encodings/position/apply.js +53 -7
- package/src/actions/encodings/position/index.js +14 -6
- package/src/actions/encodings/position/policies/bar.js +9 -0
- package/src/actions/encodings/position/resolve.js +24 -7
- package/src/actions/encodings/ranged.js +5 -5
- package/src/actions/encodings/remove.js +13 -9
- package/src/actions/encodings/ruleAppearance.js +2 -24
- package/src/actions/encodings/seriesLayout.js +2 -1
- package/src/actions/encodings/shared.js +82 -14
- package/src/actions/encodings/stroke.js +226 -0
- package/src/actions/encodings/strokeDash.js +2 -2
- package/src/actions/encodings/text.js +1 -1
- package/src/actions/errorBands/create.js +34 -20
- package/src/actions/errorBands/edit.js +34 -137
- package/src/actions/errorBars/create.js +43 -20
- package/src/actions/errorBars/edit.js +29 -125
- package/src/actions/facets/actions.js +267 -73
- package/src/actions/facets/derive.js +99 -28
- package/src/actions/facets/guides.js +4 -5
- package/src/actions/facets/replay.js +4 -5
- package/src/actions/gradientPlots/components.js +15 -8
- package/src/actions/gradientPlots/create.js +4 -5
- package/src/actions/gradientPlots/edit.js +18 -9
- package/src/actions/gradientPlots/materialize.js +5 -3
- package/src/actions/gradientPlots/options.js +10 -2
- package/src/actions/gradientPlots/rebind.js +4 -5
- package/src/actions/guides/applicability.js +8 -2
- 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 +67 -21
- package/src/actions/guides/axes/lines.js +15 -9
- package/src/actions/guides/axes/parallel/lifecycle.js +13 -13
- package/src/actions/guides/axes/parallel/resolve.js +6 -2
- 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 +6 -5
- package/src/actions/guides/axes/ticks.js +19 -6
- package/src/actions/guides/axes/titles.js +21 -13
- package/src/actions/guides/grids/grid.js +18 -29
- package/src/actions/guides/grids/resolve.js +7 -2
- package/src/actions/guides/guides.js +20 -4
- package/src/actions/guides/legends/blocks.js +426 -0
- package/src/actions/guides/legends/categorical/actions.js +138 -52
- package/src/actions/guides/legends/categorical/components.js +55 -45
- package/src/actions/guides/legends/categorical/index.js +37 -33
- package/src/actions/guides/legends/categorical/layout.js +98 -16
- package/src/actions/guides/legends/categorical/options.js +2 -2
- package/src/actions/guides/legends/categorical/recipes.js +111 -20
- package/src/actions/guides/legends/categorical/resolve.js +12 -8
- package/src/actions/guides/legends/categorical/symbols.js +104 -52
- package/src/actions/guides/legends/continuous/common.js +76 -20
- package/src/actions/guides/legends/continuous/gradient.js +95 -158
- package/src/actions/guides/legends/continuous/index.js +2 -0
- package/src/actions/guides/legends/continuous/interval.js +21 -16
- package/src/actions/guides/legends/continuous/opacity.js +37 -83
- package/src/actions/guides/legends/continuous/stroke.js +225 -0
- package/src/actions/guides/legends/creation.js +14 -1
- package/src/actions/guides/legends/edit.js +159 -60
- package/src/actions/guides/legends/focused.js +5 -5
- package/src/actions/guides/legends/index.js +2 -0
- package/src/actions/guides/legends/lane.js +59 -24
- package/src/actions/guides/legends/lifecycle.js +19 -8
- package/src/actions/guides/legends/remove.js +17 -8
- package/src/actions/guides/legends/sampling.js +140 -0
- package/src/actions/guides/legends/size.js +100 -108
- package/src/actions/guides/legends/strokeWidth.js +38 -92
- package/src/actions/guides/legends/target.js +112 -1
- package/src/actions/guides/legends/transition.js +165 -16
- package/src/actions/guides/polar/axes/facade.js +8 -8
- package/src/actions/guides/polar/axes/labels.js +29 -10
- package/src/actions/guides/polar/axes/lines.js +19 -19
- package/src/actions/guides/polar/axes/shared.js +16 -0
- package/src/actions/guides/polar/axes/ticks.js +10 -16
- package/src/actions/guides/polar/axes/titles.js +6 -6
- package/src/actions/guides/polar/grids.js +12 -14
- package/src/actions/guides/polar/resolve.js +12 -8
- package/src/actions/index.js +16 -3
- package/src/actions/intervals/revision.js +126 -0
- package/src/actions/marks/arc/actions.js +80 -22
- package/src/actions/marks/area/actions.js +38 -13
- package/src/actions/marks/area/materialize.js +17 -1
- package/src/actions/marks/bar/create.js +12 -3
- package/src/actions/marks/bar/edit.js +21 -4
- package/src/actions/marks/bar/materialize.js +34 -40
- package/src/actions/marks/index.js +10 -1
- package/src/actions/marks/line/actions.js +40 -17
- package/src/actions/marks/line/materialize.js +29 -10
- package/src/actions/marks/point/create.js +9 -3
- package/src/actions/marks/point/edit.js +19 -7
- package/src/actions/marks/point/jitter.js +6 -8
- package/src/actions/marks/point/materialize.js +48 -22
- package/src/actions/marks/point/packing.js +6 -8
- package/src/actions/marks/rect/actions.js +36 -15
- package/src/actions/marks/references.js +602 -33
- package/src/actions/marks/remove.js +67 -41
- package/src/actions/marks/rule/actions.js +51 -14
- package/src/actions/marks/shared.js +1 -1
- package/src/actions/marks/text/actions.js +79 -14
- package/src/actions/marks/text/index.js +4 -0
- package/src/actions/marks/text/layout.js +157 -17
- package/src/actions/marks/text/removal.js +173 -0
- package/src/actions/marks/text/selection.js +72 -0
- package/src/actions/marks/tick/actions.js +25 -8
- package/src/actions/primitives/createGraphics.js +5 -4
- package/src/actions/primitives/editGraphics.js +31 -4
- package/src/actions/primitives/graphicProperties.js +6 -0
- package/src/actions/primitives/semantic.js +11 -3
- package/src/actions/primitives/semanticAction.js +90 -14
- package/src/actions/primitives/semanticValidation/dataset.js +2 -4
- package/src/actions/primitives/semanticValidation/guide.js +1 -1
- package/src/actions/primitives/semanticValidation/index.js +9 -1
- package/src/actions/primitives/semanticValidation/layer.js +5 -0
- package/src/actions/primitives/semanticValidation/scale.js +28 -7
- package/src/actions/regression/components.js +36 -25
- package/src/actions/regression/create.js +13 -6
- package/src/actions/regression/edit.js +24 -11
- package/src/actions/resources/index.js +7 -0
- package/src/actions/resources/remove.js +173 -0
- package/src/actions/scales/channels.js +212 -0
- package/src/actions/scales/consumers/common.js +1 -1
- package/src/actions/scales/consumers/families.js +3 -2
- package/src/actions/scales/consumers/index.js +19 -2
- package/src/actions/scales/consumers/seriesLayout.js +28 -14
- package/src/actions/scales/create.js +55 -23
- package/src/actions/scales/definitions.js +94 -40
- package/src/actions/scales/edit.js +67 -12
- package/src/actions/scales/editPolicy.js +81 -11
- package/src/actions/scales/index.js +6 -0
- package/src/actions/scales/materialize.js +5 -4
- package/src/actions/scales/offset.js +48 -0
- package/src/actions/scales/parallel.js +71 -0
- package/src/actions/scales/preview.js +111 -10
- package/src/actions/scales/quantitativeColor.js +4 -5
- package/src/actions/selection/actions.js +179 -66
- package/src/actions/selection/index.js +3 -0
- package/src/actions/textMetrics/index.js +56 -0
- package/src/actions/theme/actions.js +70 -15
- package/src/actions/theme/composition.js +238 -0
- package/src/actions/theme/index.js +9 -2
- package/src/actions/theme/reconcile.js +313 -121
- package/src/actions/theme/state.js +160 -0
- package/src/actions/titles/actions.js +8 -8
- package/src/actions/titles/resolve.js +3 -3
- package/src/actions/violinPlots/create.js +6 -3
- package/src/actions/violinPlots/edit.js +2 -1
- package/src/core/action.js +117 -35
- package/src/core/compositionState.js +6 -1
- 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 +21 -1
- package/src/core/resourceReferences.js +341 -0
- package/src/core/textMetricProfile.js +28 -0
- package/src/core/textMetrics.js +24 -3
- package/src/core/validation.js +22 -10
- package/src/core/vocabulary.js +16 -3
- package/src/diagnostics.js +1 -0
- package/src/grammar/bars/aggregate.js +4 -1
- package/src/grammar/bars/geometry.js +44 -0
- package/src/grammar/bin.js +54 -9
- package/src/grammar/complete.js +279 -0
- package/src/grammar/computed.js +265 -64
- package/src/grammar/coordinates.js +37 -0
- package/src/grammar/density.js +239 -37
- package/src/grammar/displayLabels.js +57 -0
- package/src/grammar/facets/dependencies.js +133 -1
- package/src/grammar/facets/guides.js +3 -0
- package/src/grammar/facets/index.js +7 -47
- package/src/grammar/facets/scales.js +15 -18
- package/src/grammar/impute.js +341 -0
- package/src/grammar/markLabelSelection.js +57 -0
- package/src/grammar/markLabels.js +18 -1
- package/src/grammar/normalize.js +366 -0
- package/src/grammar/pathSeries.js +26 -8
- package/src/grammar/pointShapes.js +13 -4
- package/src/grammar/polar.js +90 -8
- package/src/grammar/regression/index.js +1 -0
- package/src/grammar/regression/parameters.js +23 -0
- package/src/grammar/roundedRect.js +180 -0
- package/src/grammar/rules.js +1 -0
- package/src/grammar/scales/colorConsumers.js +20 -1
- package/src/grammar/scales/continuous.js +2 -2
- package/src/grammar/scales/definition.js +27 -4
- package/src/grammar/scales/index.js +1 -0
- package/src/grammar/scales/ordinal.js +12 -3
- package/src/grammar/scales/policies.js +2 -2
- package/src/grammar/scales/size.js +456 -0
- package/src/grammar/scales/types.js +8 -0
- package/src/grammar/schemas/concreteGraphic.js +14 -2
- package/src/grammar/schemas/graphic.js +15 -0
- package/src/grammar/schemas/graphicBounds.js +190 -41
- package/src/grammar/schemas/semanticPath.js +7 -2
- package/src/grammar/statisticalReference.js +103 -0
- package/src/grammar/strokeStyle.js +77 -0
- package/src/grammar/summary.js +78 -16
- package/src/grammar/timeUnit.js +216 -5
- package/src/grammar/transformTopology.js +4 -0
- package/src/grammar/transforms.js +394 -28
- package/src/grammar/weightedStatistics.js +374 -0
- package/src/grammar/window.js +221 -16
- package/src/layout/aspect.js +80 -0
- package/src/layout/facets.js +59 -5
- package/src/layout/labels.js +351 -7
- 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/aggregate.js +25 -2
- package/src/materialization/bars/histogram.js +84 -24
- package/src/materialization/bars/ranged.js +19 -3
- package/src/materialization/bars/resolve.js +7 -4
- package/src/materialization/composition.js +3 -1
- package/src/materialization/coordinateBounds.js +204 -0
- package/src/materialization/dependencies.js +36 -0
- package/src/materialization/facetGuides/legacyCategorical.js +3 -0
- package/src/materialization/facetGuides/placement.js +9 -3
- package/src/materialization/facetGuides/preparation.js +13 -8
- package/src/materialization/facetHeaders.js +347 -0
- package/src/materialization/facets.js +15 -65
- package/src/materialization/guides/layout.js +3 -3
- package/src/materialization/guides/resources.js +26 -0
- package/src/materialization/legends.js +1 -1
- package/src/materialization/marks/index.js +11 -5
- package/src/materialization/marks/policies.js +2 -1
- package/src/materialization/rect.js +25 -12
- package/src/materialization/rectConfig.js +5 -1
- package/src/materialization/scaleGuideDependencies.js +10 -0
- package/src/materialization/scales/map.js +5 -3
- package/src/materialization/scales/policies/binnedPosition.js +2 -2
- package/src/materialization/scales/policies/offset.js +50 -8
- package/src/materialization/scales/policies/series.js +4 -1
- package/src/materialization/scales/resolve.js +22 -6
- package/src/materialization/selection/items/arc.js +28 -4
- package/src/materialization/selection/items/bar.js +30 -3
- package/src/materialization/selection/items/common.js +20 -5
- package/src/materialization/selection/items/rect.js +28 -4
- package/src/materialization/selection/path.js +1 -1
- package/src/materialization/selection/point.js +3 -1
- package/src/materialization/text.js +265 -14
- 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 +74 -0
- package/src/renderers/canvas/circle.js +2 -3
- package/src/renderers/canvas/index.js +5 -4
- package/src/renderers/canvas/line.js +2 -3
- package/src/renderers/canvas/native.js +4 -4
- package/src/renderers/canvas/path.js +2 -3
- package/src/renderers/canvas/rect.js +2 -3
- package/src/renderers/canvas/stroke.js +11 -0
- 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 +29 -14
- package/src/renderers/text.js +1 -11
- package/src/selectors/coordinates.js +3 -1
- package/src/selectors/datasets.js +38 -5
- package/src/selectors/layers.js +10 -4
- package/src/selectors/markOwners.js +46 -0
- package/src/selectors/scales.js +6 -4
- package/src/theme/defaults.js +103 -1
- package/src/version.js +2 -0
- package/types/accessibility.d.ts +37 -0
- package/types/basic.d.ts +10 -2
- package/types/diagnostics.d.ts +15 -0
- package/types/index.d.ts +90 -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 +944 -118
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { closedAction } from "../../core/action.js";
|
|
2
2
|
import { cloneAndFreeze, freezeOwned, isPlainObject } from "../../core/immutable.js";
|
|
3
3
|
import { validateGeneratedItemLimit } from "../../core/validation.js";
|
|
4
4
|
import {
|
|
@@ -63,6 +63,32 @@ function replaceDrawableItems(value, id, type) {
|
|
|
63
63
|
});
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
export function replaceGraphicItems(program, target, baseType, items) {
|
|
67
|
+
let next = program.editGraphics({ target, property: "items", value: items });
|
|
68
|
+
const graphic = next.graphicSpec.objects[target];
|
|
69
|
+
if (
|
|
70
|
+
graphic.type !== "collection" ||
|
|
71
|
+
!graphic.items.every(item => item.type === baseType)
|
|
72
|
+
) return next;
|
|
73
|
+
const normalized = freezeOwned({
|
|
74
|
+
...graphic,
|
|
75
|
+
type: baseType,
|
|
76
|
+
items: freezeOwned(graphic.items.map(item => freezeOwned({
|
|
77
|
+
id: item.id,
|
|
78
|
+
properties: item.properties
|
|
79
|
+
})))
|
|
80
|
+
});
|
|
81
|
+
return next._clone({
|
|
82
|
+
graphicSpec: freezeOwned({
|
|
83
|
+
...next.graphicSpec,
|
|
84
|
+
objects: freezeOwned({
|
|
85
|
+
...next.graphicSpec.objects,
|
|
86
|
+
[target]: normalized
|
|
87
|
+
})
|
|
88
|
+
})
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
66
92
|
function editGeneratedItem(owner, itemIndex, property, value) {
|
|
67
93
|
const items = [...owner.items];
|
|
68
94
|
const item = items[itemIndex];
|
|
@@ -136,13 +162,14 @@ function removeGraphicTree(graphicSpec, id) {
|
|
|
136
162
|
return freezeOwned({ objects: freezeOwned(objects), order });
|
|
137
163
|
}
|
|
138
164
|
|
|
139
|
-
const editGraphics =
|
|
165
|
+
const editGraphics = /* @__PURE__ */ closedAction(
|
|
140
166
|
{
|
|
141
167
|
op: "editGraphics",
|
|
142
168
|
description: "Replace or remove concrete graphic state.",
|
|
143
169
|
scope: "any"
|
|
144
|
-
},
|
|
145
|
-
function (
|
|
170
|
+
}, ["target", "property", "value", "remove"],
|
|
171
|
+
function (args = {}) {
|
|
172
|
+
const { target, property, value, remove = false } = args;
|
|
146
173
|
if (typeof target !== "string" || target.length === 0) {
|
|
147
174
|
throw new TypeError("editGraphics requires a non-empty target string.");
|
|
148
175
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createSemanticPrimitiveAction } from "./semanticAction.js";
|
|
2
|
+
import { planResourceRemoval } from "../resources/remove.js";
|
|
2
3
|
import { validateDatasetTransforms } from "../../grammar/transforms.js";
|
|
3
4
|
import {
|
|
4
5
|
validateParallelDimensions,
|
|
@@ -17,12 +18,19 @@ function validateParallel(property, value) {
|
|
|
17
18
|
}
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
function fullSemanticValidator() {
|
|
22
|
+
return createSemanticValueValidator({
|
|
22
23
|
validateDatasetTransforms,
|
|
23
24
|
validateParallel,
|
|
24
25
|
sourceMarkTypes: ["point", "bar", "line", "rule", "rect", "arc"]
|
|
25
26
|
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function validateStoredSemanticValue(program, parsed, value) {
|
|
30
|
+
return fullSemanticValidator()(program, parsed, value);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function registerSemanticPrimitiveAction(ProgramClass) {
|
|
26
34
|
ProgramClass.prototype.editSemantic =
|
|
27
|
-
createSemanticPrimitiveAction(
|
|
35
|
+
createSemanticPrimitiveAction(fullSemanticValidator(), planResourceRemoval);
|
|
28
36
|
}
|
|
@@ -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,
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
} from "../../core/immutable.js";
|
|
9
9
|
import { parseSemanticPath } from "../../grammar/schemas/semanticPath.js";
|
|
10
10
|
|
|
11
|
+
|
|
11
12
|
const CONTEXT_KEYS = Object.freeze({
|
|
12
13
|
dataset: "currentData",
|
|
13
14
|
layer: "currentMark",
|
|
@@ -79,7 +80,7 @@ function removeEntity(spec, parsed) {
|
|
|
79
80
|
if (parsed.kind === "scale" && parsed.path.length === 0) {
|
|
80
81
|
if (hasSemanticScaleReferences(spec, parsed.id)) throw new Error(`Scale "${parsed.id}" is still referenced.`);
|
|
81
82
|
}
|
|
82
|
-
if (["layer", "scale"].includes(parsed.kind) && parsed.path.length === 0) {
|
|
83
|
+
if (["layer", "scale", "coordinate"].includes(parsed.kind) && parsed.path.length === 0) {
|
|
83
84
|
const nextCollection = collection.filter((_, itemIndex) => itemIndex !== index);
|
|
84
85
|
return freezeOwned({
|
|
85
86
|
...spec,
|
|
@@ -87,10 +88,6 @@ function removeEntity(spec, parsed) {
|
|
|
87
88
|
});
|
|
88
89
|
}
|
|
89
90
|
if (parsed.kind === "dataset" && parsed.path.length === 0) {
|
|
90
|
-
const dataset = collection[index];
|
|
91
|
-
if (dataset.source === undefined) {
|
|
92
|
-
throw new Error(`Source dataset "${parsed.id}" is immutable after creation.`);
|
|
93
|
-
}
|
|
94
91
|
const referenced = spec.layers.some(layer => layer.data === parsed.id) ||
|
|
95
92
|
spec.datasets.some(candidate => candidate.source === parsed.id);
|
|
96
93
|
if (referenced) {
|
|
@@ -151,14 +148,59 @@ export function withPreviewDatasetValues(program, {
|
|
|
151
148
|
return program._clone({ semanticSpec });
|
|
152
149
|
}
|
|
153
150
|
|
|
154
|
-
|
|
155
|
-
|
|
151
|
+
// Owned materializers may refresh a generated derived dataset at a stable ID.
|
|
152
|
+
// Keep that privileged immutable transition inside the semantic primitive
|
|
153
|
+
// boundary; public editSemantic still rejects every post-creation dataset edit.
|
|
154
|
+
export function withRematerializedDerivedDataset(program, {
|
|
155
|
+
id,
|
|
156
|
+
source,
|
|
157
|
+
transform,
|
|
158
|
+
values
|
|
159
|
+
}) {
|
|
160
|
+
const semanticSpec = {
|
|
161
|
+
...program.semanticSpec,
|
|
162
|
+
datasets: program.semanticSpec.datasets.map(dataset =>
|
|
163
|
+
dataset.id === id
|
|
164
|
+
? { ...dataset, source, transform: [transform], values }
|
|
165
|
+
: dataset
|
|
166
|
+
)
|
|
167
|
+
};
|
|
168
|
+
return program._clone({ semanticSpec });
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Final-state planners may need to remove mutually constrained roles before
|
|
172
|
+
// replaying their canonical primitive owners. Keep that speculative clone in
|
|
173
|
+
// the primitive boundary and preserve the caller's layer for later dependency
|
|
174
|
+
// and guide reconciliation.
|
|
175
|
+
export function withoutPreviewLayerEncodings(program, { id, channels }) {
|
|
176
|
+
const removed = new Set(channels);
|
|
177
|
+
const semanticSpec = {
|
|
178
|
+
...program.semanticSpec,
|
|
179
|
+
layers: program.semanticSpec.layers.map(layer => {
|
|
180
|
+
if (layer.id !== id) return layer;
|
|
181
|
+
return {
|
|
182
|
+
...layer,
|
|
183
|
+
encoding: Object.fromEntries(
|
|
184
|
+
Object.entries(layer.encoding ?? {}).filter(
|
|
185
|
+
([channel]) => !removed.has(channel)
|
|
186
|
+
)
|
|
187
|
+
)
|
|
188
|
+
};
|
|
189
|
+
})
|
|
190
|
+
};
|
|
191
|
+
return program._clone({ semanticSpec });
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export function createSemanticPrimitiveAction(validateSemanticValue, planNamedRemoval) {
|
|
195
|
+
return closedAction(
|
|
156
196
|
{
|
|
157
197
|
op: "editSemantic",
|
|
158
198
|
description: "Create, replace, or remove one semantic property.",
|
|
159
199
|
scope: "any"
|
|
160
|
-
},
|
|
161
|
-
function (
|
|
200
|
+
}, ["property", "value", "remove"],
|
|
201
|
+
function (args = {}) {
|
|
202
|
+
|
|
203
|
+
const { property, value, remove = false } = args;
|
|
162
204
|
if (typeof remove !== "boolean") {
|
|
163
205
|
throw new TypeError("editSemantic remove must be a boolean.");
|
|
164
206
|
}
|
|
@@ -170,14 +212,37 @@ export function createSemanticPrimitiveAction(validateSemanticValue) {
|
|
|
170
212
|
}
|
|
171
213
|
|
|
172
214
|
const parsed = parseSemanticPath(property, { allowContainer: remove });
|
|
215
|
+
const removesNamedResource = remove && parsed.path.length === 0 &&
|
|
216
|
+
["dataset", "scale", "coordinate"].includes(parsed.kind);
|
|
173
217
|
if (this.compositionSpec !== undefined && !(
|
|
174
|
-
this.compositionSpec.type === "facet" &&
|
|
218
|
+
this.compositionSpec.type === "facet" &&
|
|
219
|
+
(parsed.kind === "title" || removesNamedResource)
|
|
175
220
|
)) {
|
|
176
221
|
throw new Error(
|
|
177
|
-
"editSemantic on a composition parent
|
|
222
|
+
"editSemantic on a composition parent supports only facet title state and unreferenced named resource removal."
|
|
178
223
|
);
|
|
179
224
|
}
|
|
180
225
|
if (remove) {
|
|
226
|
+
// Source/coordinate removal and facet-parent removal use the same full
|
|
227
|
+
// dependency policy as the domain lifecycle. Existing unit derived-data
|
|
228
|
+
// teardown retains its semantic-only primitive contract; its owning
|
|
229
|
+
// action coordinates configuration and graphics cleanup separately.
|
|
230
|
+
const resource = removesNamedResource
|
|
231
|
+
? this.semanticSpec[parsed.collection].find(item => item.id === parsed.id)
|
|
232
|
+
: undefined;
|
|
233
|
+
if (resource !== undefined && (
|
|
234
|
+
parsed.kind === "coordinate" || this.compositionSpec?.type === "facet" ||
|
|
235
|
+
(parsed.kind === "dataset" && resource.source === undefined)
|
|
236
|
+
)) {
|
|
237
|
+
if (planNamedRemoval === undefined) {
|
|
238
|
+
throw new Error("Named resource removal requires the full ChartProgram.");
|
|
239
|
+
}
|
|
240
|
+
planNamedRemoval(this, {
|
|
241
|
+
kind: parsed.kind === "dataset" ? "data" : parsed.kind,
|
|
242
|
+
id: parsed.id,
|
|
243
|
+
operation: "editSemantic"
|
|
244
|
+
});
|
|
245
|
+
}
|
|
181
246
|
const semanticSpec = parsed.kind === "guide"
|
|
182
247
|
? removeRootProperty(this.semanticSpec, "guides", parsed.path)
|
|
183
248
|
: parsed.kind === "title"
|
|
@@ -192,17 +257,28 @@ export function createSemanticPrimitiveAction(validateSemanticValue) {
|
|
|
192
257
|
parsed.kind === "layer" &&
|
|
193
258
|
parsed.path.length === 0 &&
|
|
194
259
|
this.context.currentMark === parsed.id;
|
|
260
|
+
const clearsCurrentCoordinate =
|
|
261
|
+
parsed.kind === "coordinate" &&
|
|
262
|
+
parsed.path.length === 0 &&
|
|
263
|
+
this.context.currentCoordinate === parsed.id;
|
|
264
|
+
const clearsCurrentGuide =
|
|
265
|
+
parsed.kind === "guide" &&
|
|
266
|
+
parsed.path.length === 2 &&
|
|
267
|
+
this.context.currentGuide === parsed.id;
|
|
195
268
|
const removesScale = parsed.kind === "scale" && parsed.path.length === 0;
|
|
196
269
|
const resolvedScales = removesScale ? Object.fromEntries(Object.entries(this.resolvedScales).filter(([id]) => id !== parsed.id)) : this.resolvedScales;
|
|
197
270
|
return this._clone({
|
|
198
271
|
semanticSpec,
|
|
199
272
|
...(removesScale ? { resolvedScales: freezeOwned(resolvedScales) } : {}),
|
|
200
|
-
...(clearsCurrentData || clearsCurrentMark ||
|
|
273
|
+
...(clearsCurrentData || clearsCurrentMark || clearsCurrentGuide || clearsCurrentCoordinate ||
|
|
274
|
+
(removesScale && this.context.currentScale === parsed.id)
|
|
201
275
|
? { context: freezeOwned({
|
|
202
276
|
...this.context,
|
|
203
277
|
...(removesScale && this.context.currentScale === parsed.id ? { currentScale: undefined } : {}),
|
|
204
278
|
...(clearsCurrentData ? { currentData: undefined } : {}),
|
|
205
|
-
...(clearsCurrentMark ? { currentMark: undefined } : {})
|
|
279
|
+
...(clearsCurrentMark ? { currentMark: undefined } : {}),
|
|
280
|
+
...(clearsCurrentCoordinate ? { currentCoordinate: undefined } : {}),
|
|
281
|
+
...(clearsCurrentGuide ? { currentGuide: undefined } : {})
|
|
206
282
|
}) }
|
|
207
283
|
: {})
|
|
208
284
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { validateUserId } from "../../../core/identifiers.js";
|
|
2
|
-
import {
|
|
2
|
+
import { validateDataRows } from "../../../core/validation.js";
|
|
3
3
|
import { hasDataset } from "../../../selectors/datasets.js";
|
|
4
4
|
|
|
5
5
|
export function validateDatasetSemanticValue(
|
|
@@ -10,9 +10,7 @@ export function validateDatasetSemanticValue(
|
|
|
10
10
|
) {
|
|
11
11
|
const property = parsed.path[0];
|
|
12
12
|
if (property === "values") {
|
|
13
|
-
|
|
14
|
-
throw new TypeError("Dataset values must be an array of plain row objects.");
|
|
15
|
-
}
|
|
13
|
+
validateDataRows(value, `Dataset "${parsed.id}"`);
|
|
16
14
|
return;
|
|
17
15
|
}
|
|
18
16
|
if (property === "source") {
|
|
@@ -30,7 +30,7 @@ export function validateGuideSemanticValue(_program, parsed, value) {
|
|
|
30
30
|
validateParallelAxisTitles(value);
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
|
-
if (["legend.series", "legend.color"].includes(parsed.id) && property === "order") {
|
|
33
|
+
if (["legend.series", "legend.color", "legend.stroke"].includes(parsed.id) && property === "order") {
|
|
34
34
|
normalizeLegendOrder(value);
|
|
35
35
|
return;
|
|
36
36
|
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
normalizeCoordinateAspect,
|
|
3
|
+
validateCoordinateType
|
|
4
|
+
} from "../../../grammar/coordinates.js";
|
|
5
|
+
import { normalizePolarFrameOptions } from "../../../grammar/polar.js";
|
|
2
6
|
import { validateScaleSemanticValue } from "./scale.js";
|
|
3
7
|
import { validateDatasetSemanticValue } from "./dataset.js";
|
|
4
8
|
import { validateLayerSemanticValue } from "./layer.js";
|
|
@@ -27,6 +31,10 @@ export function createSemanticValueValidator({
|
|
|
27
31
|
validateScaleSemanticValue(program, parsed, value);
|
|
28
32
|
} else if (parsed.kind === "coordinate" && parsed.path[0] === "type") {
|
|
29
33
|
validateCoordinateType(value);
|
|
34
|
+
} else if (parsed.kind === "coordinate" && parsed.path[0] === "aspect") {
|
|
35
|
+
normalizeCoordinateAspect(value);
|
|
36
|
+
} else if (parsed.kind === "coordinate" && parsed.path[0] === "polarFrame") {
|
|
37
|
+
normalizePolarFrameOptions(value);
|
|
30
38
|
} else if (parsed.kind === "guide") {
|
|
31
39
|
validateGuideSemanticValue(program, parsed, value);
|
|
32
40
|
} else if (parsed.kind === "title") {
|
|
@@ -17,6 +17,8 @@ import { normalizeCategoryOrder } from "../../../grammar/categoryOrder.js";
|
|
|
17
17
|
import { validateSemanticFieldType } from "../../../grammar/scales/index.js";
|
|
18
18
|
import { findLayer } from "../../../selectors/layers.js";
|
|
19
19
|
import { validateNonEmptySemanticString } from "./shared.js";
|
|
20
|
+
import { normalizeStatisticalWeight } from
|
|
21
|
+
"../../../grammar/weightedStatistics.js";
|
|
20
22
|
|
|
21
23
|
function validateLayerSource(program, parsed, value, sourceMarkTypes) {
|
|
22
24
|
validateUserId(value, "Layer source id");
|
|
@@ -81,6 +83,9 @@ export function validateLayerSemanticValue(
|
|
|
81
83
|
validateParallel?.(property, value);
|
|
82
84
|
}
|
|
83
85
|
if (property.endsWith(".aggregate")) validateAggregate(value);
|
|
86
|
+
if (property === "encoding.x.weight") {
|
|
87
|
+
normalizeStatisticalWeight(value, "Histogram weight");
|
|
88
|
+
}
|
|
84
89
|
if (property.endsWith(".bin.maxBins")) normalizeHistogramBin({ maxBins: value });
|
|
85
90
|
if (property.endsWith(".bin.step")) validateHistogramBinStep(value);
|
|
86
91
|
if (property.endsWith(".bin.boundaries")) validateHistogramBinBoundaries(value);
|
|
@@ -8,9 +8,22 @@ import {
|
|
|
8
8
|
validateSemanticScaleType
|
|
9
9
|
} from "../../../grammar/scales/index.js";
|
|
10
10
|
import { findSemanticScale } from "../../../selectors/scales.js";
|
|
11
|
+
import { findScaleConsumers } from "../../scales/consumers/index.js";
|
|
11
12
|
|
|
12
|
-
function
|
|
13
|
+
function isOffsetScale(program, id, existing) {
|
|
14
|
+
if (existing?.type !== "ordinal") return false;
|
|
15
|
+
const consumers = findScaleConsumers(program, id);
|
|
16
|
+
return consumers.length > 0 && consumers.every(
|
|
17
|
+
consumer => ["xOffset", "yOffset"].includes(consumer.channel)
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function validateOwnedProperty(program, id, existing, property) {
|
|
13
22
|
if (existing?.type !== undefined) {
|
|
23
|
+
if (
|
|
24
|
+
isOffsetScale(program, id, existing) &&
|
|
25
|
+
["paddingInner", "paddingOuter", "align"].includes(property)
|
|
26
|
+
) return;
|
|
14
27
|
validateScalePropertyForType(existing.type, property);
|
|
15
28
|
}
|
|
16
29
|
}
|
|
@@ -31,7 +44,13 @@ export function validateScaleSemanticValue(program, parsed, value) {
|
|
|
31
44
|
"nice", "zero", "clamp", "base", "exponent", "constant", "midpoint",
|
|
32
45
|
"paddingInner", "paddingOuter", "padding", "align"
|
|
33
46
|
]) {
|
|
34
|
-
if (existing?.[owned]
|
|
47
|
+
if (existing?.[owned] === undefined) continue;
|
|
48
|
+
if (
|
|
49
|
+
value === "ordinal" &&
|
|
50
|
+
isOffsetScale(program, parsed.id, existing) &&
|
|
51
|
+
["paddingInner", "paddingOuter", "align"].includes(owned)
|
|
52
|
+
) continue;
|
|
53
|
+
validateScalePropertyForType(value, owned);
|
|
35
54
|
}
|
|
36
55
|
return;
|
|
37
56
|
}
|
|
@@ -41,7 +60,9 @@ export function validateScaleSemanticValue(program, parsed, value) {
|
|
|
41
60
|
if (typeof value !== "boolean") {
|
|
42
61
|
throw new TypeError(`Scale ${property} must be a boolean.`);
|
|
43
62
|
}
|
|
44
|
-
if (property !== "reverse")
|
|
63
|
+
if (property !== "reverse") {
|
|
64
|
+
validateOwnedProperty(program, parsed.id, existing, property);
|
|
65
|
+
}
|
|
45
66
|
return;
|
|
46
67
|
}
|
|
47
68
|
if (["base", "exponent", "constant"].includes(property)) {
|
|
@@ -51,7 +72,7 @@ export function validateScaleSemanticValue(program, parsed, value) {
|
|
|
51
72
|
if (property === "base" && value === 1) {
|
|
52
73
|
throw new RangeError("Scale base must not equal 1.");
|
|
53
74
|
}
|
|
54
|
-
validateOwnedProperty(existing, property);
|
|
75
|
+
validateOwnedProperty(program, parsed.id, existing, property);
|
|
55
76
|
return;
|
|
56
77
|
}
|
|
57
78
|
if (property === "interpolate") {
|
|
@@ -64,20 +85,20 @@ export function validateScaleSemanticValue(program, parsed, value) {
|
|
|
64
85
|
"Scale paddingInner must be from 0 (inclusive) to 1 (exclusive)."
|
|
65
86
|
);
|
|
66
87
|
}
|
|
67
|
-
validateOwnedProperty(existing, property);
|
|
88
|
+
validateOwnedProperty(program, parsed.id, existing, property);
|
|
68
89
|
return;
|
|
69
90
|
}
|
|
70
91
|
if (property === "paddingOuter" || property === "padding") {
|
|
71
92
|
if (!Number.isFinite(value) || value < 0) {
|
|
72
93
|
throw new RangeError(`Scale ${property} must be a non-negative finite number.`);
|
|
73
94
|
}
|
|
74
|
-
validateOwnedProperty(existing, property);
|
|
95
|
+
validateOwnedProperty(program, parsed.id, existing, property);
|
|
75
96
|
return;
|
|
76
97
|
}
|
|
77
98
|
if (property === "align") {
|
|
78
99
|
if (!Number.isFinite(value) || value < 0 || value > 1) {
|
|
79
100
|
throw new RangeError("Scale align must be between 0 and 1.");
|
|
80
101
|
}
|
|
81
|
-
validateOwnedProperty(existing, property);
|
|
102
|
+
validateOwnedProperty(program, parsed.id, existing, property);
|
|
82
103
|
}
|
|
83
104
|
}
|
|
@@ -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";
|
|
@@ -9,19 +9,27 @@ import {
|
|
|
9
9
|
REGRESSION_UPPER_FIELD
|
|
10
10
|
} from "../../grammar/regression/index.js";
|
|
11
11
|
import { validateAreaCreateOutline } from "../marks/area/index.js";
|
|
12
|
+
import {
|
|
13
|
+
requestedStrokeDetails,
|
|
14
|
+
STROKE_STYLE_PROPERTIES
|
|
15
|
+
} from "../../grammar/strokeStyle.js";
|
|
12
16
|
|
|
13
17
|
const BAND_OPTIONS = Object.freeze([
|
|
14
18
|
"id", "data", "x", "lower", "upper", "groupBy", "coordinate", "xScale", "yScale",
|
|
15
|
-
"color", "opacity", "stroke", "strokeWidth", "curve"
|
|
19
|
+
"color", "opacity", "stroke", "strokeWidth", "curve",
|
|
20
|
+
...STROKE_STYLE_PROPERTIES
|
|
16
21
|
]);
|
|
17
22
|
const LINE_OPTIONS = Object.freeze([
|
|
18
23
|
"id", "data", "x", "y", "groupBy", "coordinate", "xScale", "yScale", "colorScale",
|
|
19
|
-
"strokeWidth", "curve"
|
|
24
|
+
"strokeWidth", "curve", ...STROKE_STYLE_PROPERTIES
|
|
20
25
|
]);
|
|
21
26
|
const EDIT_BAND_OPTIONS = Object.freeze([
|
|
22
|
-
"target", "color", "opacity", "stroke", "strokeWidth", "curve"
|
|
27
|
+
"target", "color", "opacity", "stroke", "strokeWidth", "curve",
|
|
28
|
+
...STROKE_STYLE_PROPERTIES
|
|
29
|
+
]);
|
|
30
|
+
const EDIT_LINE_OPTIONS = Object.freeze([
|
|
31
|
+
"target", "strokeWidth", "curve", ...STROKE_STYLE_PROPERTIES
|
|
23
32
|
]);
|
|
24
|
-
const EDIT_LINE_OPTIONS = Object.freeze(["target", "strokeWidth", "curve"]);
|
|
25
33
|
|
|
26
34
|
function isRegressionLayer(program, layer, type) {
|
|
27
35
|
const dataset = findDataset(program, layer.data);
|
|
@@ -64,13 +72,12 @@ function requireRegressionBandDataset(program, args) {
|
|
|
64
72
|
return { dataset, transform };
|
|
65
73
|
}
|
|
66
74
|
|
|
67
|
-
export const createRegressionBand =
|
|
75
|
+
export const createRegressionBand = /* @__PURE__ */ closedAction(
|
|
68
76
|
{
|
|
69
77
|
op: "createRegressionBand",
|
|
70
78
|
description: "Create and encode a grouped regression confidence band."
|
|
71
|
-
},
|
|
79
|
+
}, BAND_OPTIONS,
|
|
72
80
|
function (args = {}) {
|
|
73
|
-
validateKeys(args, BAND_OPTIONS, "createRegressionBand");
|
|
74
81
|
const id = validateUserId(args.id, "Regression band id");
|
|
75
82
|
const { transform } = requireRegressionBandDataset(this, args);
|
|
76
83
|
validateAreaCreateOutline(args, "createRegressionBand");
|
|
@@ -93,7 +100,8 @@ export const createRegressionBand = action(
|
|
|
93
100
|
coordinate: args.coordinate,
|
|
94
101
|
fill: args.color ?? DEFAULT_COLORS.regressionBand,
|
|
95
102
|
opacity: args.opacity ?? 0.18,
|
|
96
|
-
...(args.curve === undefined ? {} : { curve: args.curve })
|
|
103
|
+
...(args.curve === undefined ? {} : { curve: args.curve }),
|
|
104
|
+
...requestedStrokeDetails(args, "createRegressionBand")
|
|
97
105
|
})
|
|
98
106
|
.editSemantic({
|
|
99
107
|
property: `layer[${id}].encoding.y.title`,
|
|
@@ -112,14 +120,16 @@ export const createRegressionBand = action(
|
|
|
112
120
|
}
|
|
113
121
|
);
|
|
114
122
|
|
|
115
|
-
export const editRegressionBand =
|
|
123
|
+
export const editRegressionBand = /* @__PURE__ */ closedAction(
|
|
116
124
|
{
|
|
117
125
|
op: "editRegressionBand",
|
|
118
126
|
description: "Edit regression-band fill, opacity, and outline."
|
|
119
|
-
},
|
|
127
|
+
}, EDIT_BAND_OPTIONS,
|
|
120
128
|
function (args = {}) {
|
|
121
|
-
|
|
122
|
-
|
|
129
|
+
const changes = [
|
|
130
|
+
"color", "opacity", "stroke", "strokeWidth", "curve",
|
|
131
|
+
...STROKE_STYLE_PROPERTIES
|
|
132
|
+
];
|
|
123
133
|
if (!changes.some(key => Object.hasOwn(args, key))) {
|
|
124
134
|
throw new Error(
|
|
125
135
|
"editRegressionBand requires color, opacity, stroke, strokeWidth, or curve."
|
|
@@ -139,21 +149,21 @@ export const editRegressionBand = action(
|
|
|
139
149
|
...(Object.hasOwn(args, "strokeWidth")
|
|
140
150
|
? { strokeWidth: args.strokeWidth }
|
|
141
151
|
: {}),
|
|
142
|
-
...(Object.hasOwn(args, "curve") ? { curve: args.curve } : {})
|
|
152
|
+
...(Object.hasOwn(args, "curve") ? { curve: args.curve } : {}),
|
|
153
|
+
...requestedStrokeDetails(args, "editRegressionBand")
|
|
143
154
|
});
|
|
144
155
|
}
|
|
145
156
|
);
|
|
146
157
|
|
|
147
|
-
export const editRegressionLine =
|
|
158
|
+
export const editRegressionLine = /* @__PURE__ */ closedAction(
|
|
148
159
|
{
|
|
149
160
|
op: "editRegressionLine",
|
|
150
161
|
description: "Edit regression-line width or curve."
|
|
151
|
-
},
|
|
162
|
+
}, EDIT_LINE_OPTIONS,
|
|
152
163
|
function (args = {}) {
|
|
153
|
-
validateKeys(args, EDIT_LINE_OPTIONS, "editRegressionLine");
|
|
154
164
|
if (
|
|
155
|
-
!
|
|
156
|
-
|
|
165
|
+
!["strokeWidth", "curve", ...STROKE_STYLE_PROPERTIES]
|
|
166
|
+
.some(property => Object.hasOwn(args, property))
|
|
157
167
|
) {
|
|
158
168
|
throw new Error("editRegressionLine requires strokeWidth or curve.");
|
|
159
169
|
}
|
|
@@ -168,25 +178,26 @@ export const editRegressionLine = action(
|
|
|
168
178
|
...(Object.hasOwn(args, "strokeWidth")
|
|
169
179
|
? { strokeWidth: args.strokeWidth }
|
|
170
180
|
: {}),
|
|
171
|
-
...(Object.hasOwn(args, "curve") ? { curve: args.curve } : {})
|
|
181
|
+
...(Object.hasOwn(args, "curve") ? { curve: args.curve } : {}),
|
|
182
|
+
...requestedStrokeDetails(args, "editRegressionLine")
|
|
172
183
|
});
|
|
173
184
|
}
|
|
174
185
|
);
|
|
175
186
|
|
|
176
|
-
export const createRegressionLine =
|
|
187
|
+
export const createRegressionLine = /* @__PURE__ */ closedAction(
|
|
177
188
|
{
|
|
178
189
|
op: "createRegressionLine",
|
|
179
190
|
description: "Create and encode grouped regression line paths."
|
|
180
|
-
},
|
|
191
|
+
}, LINE_OPTIONS,
|
|
181
192
|
function (args = {}) {
|
|
182
|
-
validateKeys(args, LINE_OPTIONS, "createRegressionLine");
|
|
183
193
|
const id = validateUserId(args.id, "Regression line id");
|
|
184
194
|
let next = this
|
|
185
195
|
.createLineMark({
|
|
186
196
|
id,
|
|
187
197
|
data: args.data,
|
|
188
198
|
strokeWidth: args.strokeWidth ?? 3,
|
|
189
|
-
...(args.curve === undefined ? {} : { curve: args.curve })
|
|
199
|
+
...(args.curve === undefined ? {} : { curve: args.curve }),
|
|
200
|
+
...requestedStrokeDetails(args, "createRegressionLine")
|
|
190
201
|
})
|
|
191
202
|
.encodeX({
|
|
192
203
|
target: id,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { closedAction } from "../../core/action.js";
|
|
2
2
|
import { validateKeys } from "../../core/validation.js";
|
|
3
3
|
import { normalizeRegressionParameters } from "../../grammar/regression/index.js";
|
|
4
|
+
import { STROKE_STYLE_PROPERTIES } from "../../grammar/strokeStyle.js";
|
|
4
5
|
import {
|
|
5
6
|
findRegressionPoint,
|
|
6
7
|
inferRegressionGroup,
|
|
@@ -13,13 +14,12 @@ const REGRESSION_OPTIONS = Object.freeze([
|
|
|
13
14
|
"confidenceMethod", "level", "confidence", "interval", "band", "line"
|
|
14
15
|
]);
|
|
15
16
|
|
|
16
|
-
export const createRegression =
|
|
17
|
+
export const createRegression = /* @__PURE__ */ closedAction(
|
|
17
18
|
{
|
|
18
19
|
op: "createRegression",
|
|
19
20
|
description: "Fit and layer regression lines with optional interval bands."
|
|
20
|
-
},
|
|
21
|
+
}, REGRESSION_OPTIONS,
|
|
21
22
|
function (args = {}) {
|
|
22
|
-
validateKeys(args, REGRESSION_OPTIONS, "createRegression");
|
|
23
23
|
const point = findRegressionPoint(this, args.target);
|
|
24
24
|
const x = args.x === undefined
|
|
25
25
|
? point.encoding.x.field
|
|
@@ -49,11 +49,18 @@ export const createRegression = action(
|
|
|
49
49
|
if (band !== false) {
|
|
50
50
|
validateKeys(
|
|
51
51
|
band,
|
|
52
|
-
[
|
|
52
|
+
[
|
|
53
|
+
"color", "opacity", "stroke", "strokeWidth", "curve",
|
|
54
|
+
...STROKE_STYLE_PROPERTIES
|
|
55
|
+
],
|
|
53
56
|
"regression band"
|
|
54
57
|
);
|
|
55
58
|
}
|
|
56
|
-
validateKeys(
|
|
59
|
+
validateKeys(
|
|
60
|
+
line,
|
|
61
|
+
["strokeWidth", "curve", ...STROKE_STYLE_PROPERTIES],
|
|
62
|
+
"regression line"
|
|
63
|
+
);
|
|
57
64
|
const colorEncoding = point.encoding?.color;
|
|
58
65
|
const namespace = point.id;
|
|
59
66
|
const dataId = `${namespace}RegressionData`;
|