ggaction 0.0.13 → 0.0.15
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 +78 -0
- package/README.md +20 -11
- package/knowledge/action-cards.json +1 -1
- package/knowledge/intent-taxonomy.json +1 -1
- package/knowledge/mcp-resources.json +1 -1
- package/package.json +8 -3
- package/src/actions/basic.js +2 -2
- package/src/actions/boxPlots/components.js +14 -4
- package/src/actions/boxPlots/edit.js +31 -5
- package/src/actions/boxPlots/materialize.js +11 -3
- package/src/actions/boxPlots/options.js +48 -16
- package/src/actions/categoryOrder/index.js +15 -4
- package/src/actions/charts/area.js +5 -1
- package/src/actions/charts/bar.js +2 -1
- package/src/actions/charts/density.js +6 -2
- package/src/actions/charts/ecdf.js +4 -1
- package/src/actions/charts/endpoints.js +25 -3
- package/src/actions/charts/heatmap.js +2 -1
- package/src/actions/charts/histogram.js +4 -3
- package/src/actions/charts/horizon.js +3 -1
- package/src/actions/charts/interval-regression.js +5 -2
- package/src/actions/charts/line.js +3 -1
- package/src/actions/charts/parallel.js +8 -2
- package/src/actions/charts/pie.js +10 -2
- package/src/actions/charts/polar.js +15 -4
- package/src/actions/charts/radar.js +8 -2
- package/src/actions/charts/radial.js +10 -2
- package/src/actions/charts/rug-strip.js +6 -2
- package/src/actions/charts/scatter.js +3 -1
- package/src/actions/composition/actions.js +13 -4
- package/src/actions/coordinates/actions.js +1 -1
- package/src/actions/coordinates/edit.js +76 -0
- package/src/actions/data/bin.js +1 -1
- package/src/actions/data/bin2d.js +57 -185
- package/src/actions/data/complete.js +26 -0
- package/src/actions/data/computed.js +2 -2
- package/src/actions/data/create.js +2 -2
- package/src/actions/data/density.js +12 -20
- package/src/actions/data/derived.js +47 -17
- package/src/actions/data/edit.js +539 -0
- package/src/actions/data/filter.js +14 -2
- package/src/actions/data/impute.js +26 -0
- package/src/actions/data/index.js +14 -0
- package/src/actions/data/normalize.js +27 -0
- package/src/actions/data/regression.js +16 -21
- package/src/actions/data/revisionBindings.js +145 -0
- package/src/actions/data/shared.js +20 -4
- package/src/actions/data/summary.js +1 -1
- package/src/actions/data/timeUnit.js +4 -1
- package/src/actions/data/window.js +1 -1
- package/src/actions/encodings/channels.js +415 -0
- package/src/actions/encodings/color/index.js +2 -1
- package/src/actions/encodings/density.js +5 -2
- package/src/actions/encodings/histogram.js +3 -2
- package/src/actions/encodings/index.js +4 -0
- package/src/actions/encodings/offset.js +20 -13
- package/src/actions/encodings/position/apply.js +53 -7
- package/src/actions/encodings/position/index.js +10 -2
- package/src/actions/encodings/position/policies/bar.js +9 -0
- package/src/actions/encodings/position/resolve.js +24 -7
- package/src/actions/encodings/remove.js +9 -4
- package/src/actions/encodings/ruleAppearance.js +1 -23
- package/src/actions/encodings/seriesLayout.js +1 -0
- package/src/actions/encodings/shared.js +82 -14
- package/src/actions/encodings/stroke.js +226 -0
- package/src/actions/errorBands/create.js +23 -3
- package/src/actions/errorBands/edit.js +21 -6
- package/src/actions/errorBars/create.js +35 -7
- package/src/actions/errorBars/edit.js +19 -4
- package/src/actions/facets/actions.js +237 -57
- package/src/actions/facets/derive.js +91 -26
- package/src/actions/gradientPlots/components.js +10 -2
- package/src/actions/gradientPlots/edit.js +14 -4
- package/src/actions/gradientPlots/materialize.js +3 -1
- package/src/actions/gradientPlots/options.js +10 -2
- package/src/actions/guides/applicability.js +8 -2
- package/src/actions/guides/axes/labels.js +58 -12
- package/src/actions/guides/axes/lines.js +6 -2
- package/src/actions/guides/axes/parallel/resolve.js +6 -2
- package/src/actions/guides/axes/tickGroups.js +2 -1
- package/src/actions/guides/axes/ticks.js +6 -2
- package/src/actions/guides/axes/titles.js +11 -3
- package/src/actions/guides/grids/resolve.js +7 -2
- package/src/actions/guides/guides.js +19 -3
- package/src/actions/guides/legends/blocks.js +426 -0
- package/src/actions/guides/legends/categorical/actions.js +134 -48
- package/src/actions/guides/legends/categorical/components.js +17 -12
- package/src/actions/guides/legends/categorical/index.js +37 -33
- package/src/actions/guides/legends/categorical/layout.js +97 -15
- 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 +85 -30
- package/src/actions/guides/legends/continuous/common.js +30 -12
- package/src/actions/guides/legends/continuous/gradient.js +10 -7
- package/src/actions/guides/legends/continuous/index.js +2 -0
- package/src/actions/guides/legends/continuous/interval.js +8 -3
- package/src/actions/guides/legends/continuous/opacity.js +8 -5
- package/src/actions/guides/legends/continuous/stroke.js +525 -0
- package/src/actions/guides/legends/creation.js +14 -1
- package/src/actions/guides/legends/edit.js +158 -59
- package/src/actions/guides/legends/index.js +2 -0
- package/src/actions/guides/legends/lane.js +54 -19
- package/src/actions/guides/legends/lifecycle.js +19 -8
- package/src/actions/guides/legends/remove.js +13 -3
- package/src/actions/guides/legends/sampling.js +140 -0
- package/src/actions/guides/legends/size.js +93 -40
- package/src/actions/guides/legends/strokeWidth.js +34 -28
- 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 +4 -4
- package/src/actions/guides/polar/axes/labels.js +24 -5
- package/src/actions/guides/polar/axes/lines.js +10 -4
- package/src/actions/guides/polar/axes/shared.js +16 -0
- package/src/actions/guides/polar/axes/ticks.js +1 -1
- package/src/actions/guides/polar/axes/titles.js +1 -1
- package/src/actions/guides/polar/grids.js +1 -1
- package/src/actions/guides/polar/resolve.js +12 -8
- package/src/actions/index.js +14 -3
- package/src/actions/marks/arc/actions.js +77 -19
- package/src/actions/marks/area/actions.js +34 -9
- package/src/actions/marks/area/materialize.js +17 -1
- package/src/actions/marks/bar/create.js +11 -2
- package/src/actions/marks/bar/edit.js +20 -3
- package/src/actions/marks/bar/materialize.js +22 -2
- package/src/actions/marks/index.js +10 -1
- package/src/actions/marks/line/actions.js +37 -14
- package/src/actions/marks/line/materialize.js +29 -10
- package/src/actions/marks/point/create.js +8 -2
- package/src/actions/marks/point/edit.js +18 -6
- package/src/actions/marks/point/materialize.js +49 -15
- package/src/actions/marks/rect/actions.js +33 -12
- package/src/actions/marks/references.js +601 -30
- package/src/actions/marks/remove.js +71 -1
- package/src/actions/marks/rule/actions.js +47 -10
- package/src/actions/marks/shared.js +1 -1
- package/src/actions/marks/text/actions.js +74 -9
- package/src/actions/marks/text/index.js +4 -0
- package/src/actions/marks/text/layout.js +154 -6
- package/src/actions/marks/text/removal.js +173 -0
- package/src/actions/marks/text/selection.js +73 -0
- package/src/actions/marks/tick/actions.js +22 -5
- package/src/actions/primitives/editGraphics.js +26 -0
- package/src/actions/primitives/semantic.js +2 -1
- package/src/actions/primitives/semanticAction.js +83 -10
- 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 +26 -11
- package/src/actions/regression/create.js +10 -2
- package/src/actions/regression/edit.js +21 -7
- package/src/actions/resources/index.js +7 -0
- package/src/actions/resources/remove.js +172 -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 +54 -22
- package/src/actions/scales/definitions.js +94 -40
- package/src/actions/scales/edit.js +66 -11
- package/src/actions/scales/editPolicy.js +81 -11
- package/src/actions/scales/index.js +6 -0
- package/src/actions/scales/materialize.js +4 -3
- 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/selection/actions.js +154 -30
- package/src/actions/selection/index.js +3 -0
- package/src/actions/theme/actions.js +68 -13
- package/src/actions/theme/composition.js +238 -0
- package/src/actions/theme/index.js +9 -2
- package/src/actions/theme/reconcile.js +315 -67
- package/src/actions/theme/state.js +160 -0
- package/src/actions/violinPlots/create.js +5 -2
- package/src/actions/violinPlots/edit.js +1 -0
- package/src/core/action.js +10 -0
- package/src/core/compositionState.js +6 -1
- package/src/core/programState.js +20 -0
- package/src/core/resourceReferences.js +332 -0
- package/src/core/vocabulary.js +16 -3
- 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 +340 -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/schemas/concreteGraphic.js +14 -2
- package/src/grammar/schemas/graphic.js +15 -0
- package/src/grammar/schemas/graphicBounds.js +179 -30
- 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 +343 -0
- 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 +8 -2
- package/src/materialization/facetGuides/preparation.js +12 -7
- package/src/materialization/facetHeaders.js +346 -0
- package/src/materialization/facets.js +15 -65
- 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/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 +19 -4
- 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/renderers/canvas/circle.js +2 -3
- 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/svg.js +19 -0
- package/src/selectors/datasets.js +32 -1
- package/src/selectors/layers.js +4 -0
- package/src/theme/defaults.js +101 -0
- package/types/basic.d.ts +6 -0
- package/types/index.d.ts +85 -0
- package/types/program.d.ts +910 -117
|
@@ -1,15 +1,56 @@
|
|
|
1
1
|
import { isSourceOwnedText } from "../../grammar/text.js";
|
|
2
2
|
import { action } from "../../core/action.js";
|
|
3
|
+
import { isPlainObject } from "../../core/immutable.js";
|
|
3
4
|
import { validateUserId } from "../../core/identifiers.js";
|
|
5
|
+
import { validateKeys } from "../../core/validation.js";
|
|
4
6
|
import { findCoordinate } from "../../selectors/coordinates.js";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
+
import {
|
|
8
|
+
findDataset,
|
|
9
|
+
hasDataset,
|
|
10
|
+
hasDatasetOwner
|
|
11
|
+
} from "../../selectors/datasets.js";
|
|
12
|
+
import { findLayer, resolveEligibleLayer } from "../../selectors/layers.js";
|
|
13
|
+
import { resolveConsumerValuesForDataset } from
|
|
14
|
+
"../scales/consumers/index.js";
|
|
15
|
+
import { resolveMarkItems } from
|
|
16
|
+
"../../materialization/selection/policies/index.js";
|
|
17
|
+
import { getMarkMaterializationPolicy } from
|
|
18
|
+
"../../materialization/marks/policies.js";
|
|
19
|
+
import { requireDerivedDataset } from "../data/shared.js";
|
|
20
|
+
import { withRematerializedDerivedDataset } from
|
|
21
|
+
"../primitives/semanticAction.js";
|
|
22
|
+
import {
|
|
23
|
+
deriveStatisticalReferenceValues,
|
|
24
|
+
normalizeReferenceField,
|
|
25
|
+
normalizeReferencePopulation,
|
|
26
|
+
normalizeReferenceStatistics,
|
|
27
|
+
normalizeStatisticalReferenceTransform,
|
|
28
|
+
validateStatisticalReferenceTransform
|
|
29
|
+
} from "../../grammar/statisticalReference.js";
|
|
30
|
+
import {
|
|
31
|
+
resolveFacadeData,
|
|
32
|
+
resolveFacadeId,
|
|
33
|
+
validateFacadeOptions
|
|
34
|
+
} from "../charts/shared.js";
|
|
35
|
+
import { RECT_STYLE_PROPERTIES } from "../../grammar/roundedRect.js";
|
|
36
|
+
import { STROKE_STYLE_PROPERTIES } from "../../grammar/strokeStyle.js";
|
|
7
37
|
|
|
8
|
-
const COMMON_OPTIONS = [
|
|
9
|
-
|
|
10
|
-
|
|
38
|
+
const COMMON_OPTIONS = Object.freeze([
|
|
39
|
+
"id", "x", "y", "space", "source", "data", "coordinate", "temporalUnit"
|
|
40
|
+
]);
|
|
41
|
+
const DYNAMIC_OPTIONS = Object.freeze([
|
|
42
|
+
"id", "source", "axis", "population", "field", "statistic", "statistics"
|
|
43
|
+
]);
|
|
44
|
+
const LINE_STYLE = Object.freeze([
|
|
45
|
+
"stroke", "strokeWidth", "strokeDash", "opacity", ...STROKE_STYLE_PROPERTIES
|
|
46
|
+
]);
|
|
47
|
+
const BAND_STYLE = Object.freeze([
|
|
48
|
+
"fill", "opacity", "stroke", "strokeWidth", ...RECT_STYLE_PROPERTIES
|
|
49
|
+
]);
|
|
50
|
+
const MATERIALIZE_OPTIONS = Object.freeze(["id"]);
|
|
51
|
+
const SERIES_MARKS = new Set(["line", "area"]);
|
|
11
52
|
|
|
12
|
-
function
|
|
53
|
+
function resolveLiteralBinding(program, args, axis, operation, band) {
|
|
13
54
|
const space = args.space === undefined ? "data" : args.space;
|
|
14
55
|
if (space !== "data" && space !== "plot") {
|
|
15
56
|
throw new Error(`${operation} space must be data or plot.`);
|
|
@@ -18,70 +59,600 @@ function resolveBinding(program, args, axis, operation, band) {
|
|
|
18
59
|
if (Object.hasOwn(args, "source") || Object.hasOwn(args, "temporalUnit")) {
|
|
19
60
|
throw new Error(`${operation} plot space does not accept source or temporalUnit.`);
|
|
20
61
|
}
|
|
21
|
-
return {
|
|
22
|
-
|
|
62
|
+
return {
|
|
63
|
+
data: resolveFacadeData(program, args.data, operation),
|
|
64
|
+
fieldType: "quantitative",
|
|
65
|
+
coordinate: args.coordinate,
|
|
66
|
+
plot: true
|
|
67
|
+
};
|
|
23
68
|
}
|
|
24
69
|
if (Object.hasOwn(args, "data") || Object.hasOwn(args, "coordinate")) {
|
|
25
70
|
throw new Error(`${operation} data space uses source data and coordinate.`);
|
|
26
71
|
}
|
|
27
72
|
const source = resolveEligibleLayer(program, {
|
|
28
|
-
target: args.source === undefined
|
|
29
|
-
|
|
73
|
+
target: args.source === undefined
|
|
74
|
+
? undefined
|
|
75
|
+
: validateUserId(args.source, `${operation} source`),
|
|
76
|
+
predicate: layer =>
|
|
77
|
+
!isSourceOwnedText(layer) &&
|
|
78
|
+
layer.data !== undefined &&
|
|
79
|
+
layer.encoding?.[axis]?.scale !== undefined &&
|
|
30
80
|
findCoordinate(program, layer.coordinate)?.type === "cartesian" &&
|
|
31
|
-
(!band || ["quantitative", "temporal"].includes(
|
|
81
|
+
(!band || ["quantitative", "temporal"].includes(
|
|
82
|
+
layer.encoding[axis].fieldType
|
|
83
|
+
)),
|
|
32
84
|
label: `${operation} Cartesian layer`,
|
|
33
85
|
targetOption: "source"
|
|
34
86
|
});
|
|
35
87
|
const encoding = source.encoding[axis];
|
|
36
|
-
return {
|
|
37
|
-
|
|
88
|
+
return {
|
|
89
|
+
data: source.data,
|
|
90
|
+
coordinate: source.coordinate,
|
|
91
|
+
scale: encoding.scale,
|
|
92
|
+
fieldType: encoding.fieldType,
|
|
93
|
+
temporalUnit: args.temporalUnit === undefined
|
|
94
|
+
? encoding.temporalUnit
|
|
95
|
+
: args.temporalUnit
|
|
96
|
+
};
|
|
38
97
|
}
|
|
39
98
|
|
|
40
|
-
function
|
|
99
|
+
function createLiteralReference(program, args, band) {
|
|
41
100
|
const operation = band ? "createReferenceBand" : "createReferenceLine";
|
|
42
101
|
const styleOptions = band ? BAND_STYLE : LINE_STYLE;
|
|
43
102
|
validateFacadeOptions(args, [...COMMON_OPTIONS, ...styleOptions], operation);
|
|
44
103
|
const axes = ["x", "y"].filter(axis => Object.hasOwn(args, axis));
|
|
45
|
-
if (axes.length !== 1)
|
|
104
|
+
if (axes.length !== 1) {
|
|
105
|
+
throw new Error(`${operation} requires exactly one of x or y.`);
|
|
106
|
+
}
|
|
46
107
|
const axis = axes[0];
|
|
47
108
|
const values = band ? args[axis] : [args[axis]];
|
|
48
109
|
if (!Array.isArray(values) || values.length !== (band ? 2 : 1)) {
|
|
49
110
|
throw new Error(`${operation} ${axis} requires a two-value interval.`);
|
|
50
111
|
}
|
|
51
112
|
const id = resolveFacadeId(program, args.id, {
|
|
52
|
-
defaultId: band ? "referenceBand" : "referenceLine",
|
|
113
|
+
defaultId: band ? "referenceBand" : "referenceLine",
|
|
114
|
+
operation
|
|
53
115
|
});
|
|
54
|
-
const binding =
|
|
55
|
-
if (
|
|
56
|
-
|
|
116
|
+
const binding = resolveLiteralBinding(program, args, axis, operation, band);
|
|
117
|
+
if (
|
|
118
|
+
binding.plot &&
|
|
119
|
+
!values.every(value =>
|
|
120
|
+
Number.isFinite(value) && value >= 0 && value <= 1
|
|
121
|
+
)
|
|
122
|
+
) {
|
|
123
|
+
throw new Error(
|
|
124
|
+
`${operation} plot coordinates must be finite numbers in [0, 1].`
|
|
125
|
+
);
|
|
57
126
|
}
|
|
58
127
|
const scale = binding.plot ? `${id}-${axis}` : binding.scale;
|
|
59
|
-
const style = Object.fromEntries(
|
|
128
|
+
const style = Object.fromEntries(
|
|
129
|
+
styleOptions
|
|
130
|
+
.filter(key => args[key] !== undefined)
|
|
131
|
+
.map(key => [key, args[key]])
|
|
132
|
+
);
|
|
60
133
|
const encode = axis === "x" ? "encodeX" : "encodeY";
|
|
61
|
-
const options = {
|
|
62
|
-
|
|
63
|
-
|
|
134
|
+
const options = {
|
|
135
|
+
target: id,
|
|
136
|
+
fieldType: binding.fieldType,
|
|
137
|
+
scale: { id: scale },
|
|
138
|
+
...(binding.coordinate === undefined
|
|
139
|
+
? {}
|
|
140
|
+
: { coordinate: binding.coordinate }),
|
|
141
|
+
...(binding.temporalUnit === undefined
|
|
142
|
+
? {}
|
|
143
|
+
: { temporalUnit: binding.temporalUnit })
|
|
144
|
+
};
|
|
64
145
|
const apply = initial => {
|
|
65
146
|
let next = binding.plot
|
|
66
147
|
? initial.createScale({ id: scale, type: "linear", domain: [0, 1] })
|
|
67
148
|
: initial;
|
|
68
149
|
next = band
|
|
69
|
-
? next.createRectMark({
|
|
70
|
-
|
|
150
|
+
? next.createRectMark({
|
|
151
|
+
id,
|
|
152
|
+
data: binding.data,
|
|
153
|
+
fill: "#94a3b8",
|
|
154
|
+
opacity: 0.15,
|
|
155
|
+
stroke: false,
|
|
156
|
+
...style
|
|
157
|
+
})
|
|
158
|
+
: next.createRuleMark({
|
|
159
|
+
id,
|
|
160
|
+
data: binding.data,
|
|
161
|
+
stroke: "#64748b",
|
|
162
|
+
strokeWidth: 1,
|
|
163
|
+
strokeDash: "dashed",
|
|
164
|
+
...style
|
|
165
|
+
});
|
|
71
166
|
next = next[encode]({ ...options, datum: values[0] });
|
|
72
|
-
|
|
167
|
+
if (band) next = next[`${encode}2`]({ ...options, datum: values[1] });
|
|
168
|
+
return next._withMarkConfig(id, {
|
|
169
|
+
...next.markConfigs[id],
|
|
170
|
+
referenceAuthoring: { kind: "literal" }
|
|
171
|
+
});
|
|
73
172
|
};
|
|
74
173
|
// Validate the complete lower-action chain on a discarded immutable branch.
|
|
75
174
|
apply(program);
|
|
76
175
|
return apply(program);
|
|
77
176
|
}
|
|
78
177
|
|
|
178
|
+
function requireStatisticalSource(program, config, referenceId) {
|
|
179
|
+
if (!isPlainObject(config)) {
|
|
180
|
+
throw new TypeError(
|
|
181
|
+
`Statistical reference "${referenceId}" requires materialization config.`
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
const sourceId = validateUserId(
|
|
185
|
+
config.source,
|
|
186
|
+
`Statistical reference "${referenceId}" source`
|
|
187
|
+
);
|
|
188
|
+
const source = findLayer(program, sourceId);
|
|
189
|
+
if (source === undefined) {
|
|
190
|
+
throw new Error(
|
|
191
|
+
`Statistical reference "${referenceId}" source "${sourceId}" does not exist.`
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
if (
|
|
195
|
+
sourceId === referenceId ||
|
|
196
|
+
program.markConfigs[sourceId]?.referenceAuthoring !== undefined ||
|
|
197
|
+
program.markConfigs[sourceId]?.statisticalReference !== undefined
|
|
198
|
+
) {
|
|
199
|
+
throw new Error(
|
|
200
|
+
`Statistical reference "${referenceId}" source must be a non-reference mark.`
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
if (findCoordinate(program, source.coordinate)?.type !== "cartesian") {
|
|
204
|
+
throw new Error(
|
|
205
|
+
`Statistical reference "${referenceId}" source must use Cartesian coordinates.`
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
if (!["x", "y"].includes(config.axis)) {
|
|
209
|
+
throw new Error(
|
|
210
|
+
`Statistical reference "${referenceId}" axis must be x or y.`
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
const encoding = source.encoding?.[config.axis];
|
|
214
|
+
if (
|
|
215
|
+
encoding?.fieldType !== "quantitative" ||
|
|
216
|
+
typeof encoding.scale !== "string" ||
|
|
217
|
+
encoding.scale.length === 0
|
|
218
|
+
) {
|
|
219
|
+
throw new Error(
|
|
220
|
+
`Statistical reference "${referenceId}" source axis must have a quantitative scaled encoding.`
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
if (
|
|
224
|
+
!isPlainObject(config.field) ||
|
|
225
|
+
!["axis", "explicit"].includes(config.field.kind) ||
|
|
226
|
+
(config.field.kind === "explicit" &&
|
|
227
|
+
(typeof config.field.field !== "string" || config.field.field.length === 0))
|
|
228
|
+
) {
|
|
229
|
+
throw new Error(
|
|
230
|
+
`Statistical reference "${referenceId}" has an invalid field binding.`
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
return { source, encoding };
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function resolvePopulationDataset(program, source, population, referenceId) {
|
|
237
|
+
let dataset = findDataset(program, source.data);
|
|
238
|
+
if (dataset === undefined || !Array.isArray(dataset.values)) {
|
|
239
|
+
throw new Error(
|
|
240
|
+
`Statistical reference "${referenceId}" source requires materialized data.`
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
if (population === "visibleItems") return dataset;
|
|
244
|
+
while (
|
|
245
|
+
dataset.transform?.length === 1 &&
|
|
246
|
+
dataset.transform[0].type === "markFilter" &&
|
|
247
|
+
dataset.transform[0].target === source.id
|
|
248
|
+
) {
|
|
249
|
+
const parent = findDataset(program, dataset.source);
|
|
250
|
+
if (parent === undefined || !Array.isArray(parent.values)) {
|
|
251
|
+
throw new Error(
|
|
252
|
+
`Statistical reference "${referenceId}" bound data is unavailable.`
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
dataset = parent;
|
|
256
|
+
}
|
|
257
|
+
return dataset;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function strictFieldValues(rows, field, label) {
|
|
261
|
+
return rows.map((row, index) => {
|
|
262
|
+
if (!isPlainObject(row) || !Object.hasOwn(row, field)) {
|
|
263
|
+
throw new Error(`${label} field "${field}" is missing at item ${index}.`);
|
|
264
|
+
}
|
|
265
|
+
const value = row[field];
|
|
266
|
+
if (!Number.isFinite(value)) {
|
|
267
|
+
throw new TypeError(
|
|
268
|
+
`${label} field "${field}" must contain finite numbers; item ${index} is invalid.`
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
return value;
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function visibleExplicitValues(program, source, dataset, field, referenceId) {
|
|
276
|
+
if (SERIES_MARKS.has(source.mark?.type) || source.encoding?.parallel !== undefined) {
|
|
277
|
+
throw new Error(
|
|
278
|
+
`Statistical reference "${referenceId}" visibleItems population is ambiguous for series marks.`
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
let resolvedProgram = program;
|
|
282
|
+
if (source.data !== dataset.id) {
|
|
283
|
+
const policy = getMarkMaterializationPolicy(source);
|
|
284
|
+
if (typeof policy?.op !== "string") {
|
|
285
|
+
throw new Error(
|
|
286
|
+
`Statistical reference "${referenceId}" cannot resolve visible items for its source mark.`
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
resolvedProgram = program
|
|
290
|
+
.editSemantic({
|
|
291
|
+
property: `layer[${source.id}].data`,
|
|
292
|
+
value: dataset.id
|
|
293
|
+
})
|
|
294
|
+
[policy.op]({ id: source.id });
|
|
295
|
+
}
|
|
296
|
+
const items = resolveMarkItems(resolvedProgram, source.id);
|
|
297
|
+
return items.map((item, index) => {
|
|
298
|
+
if (!Object.hasOwn(item.fields, field)) {
|
|
299
|
+
throw new Error(
|
|
300
|
+
`Statistical reference "${referenceId}" field "${field}" is not scalar at visible item ${index}.`
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
const value = item.fields[field];
|
|
304
|
+
if (!Number.isFinite(value)) {
|
|
305
|
+
throw new TypeError(
|
|
306
|
+
`Statistical reference "${referenceId}" field "${field}" must be finite at visible item ${index}.`
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
return value;
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function resolvePopulationValues(
|
|
314
|
+
program,
|
|
315
|
+
source,
|
|
316
|
+
encoding,
|
|
317
|
+
config,
|
|
318
|
+
dataset,
|
|
319
|
+
referenceId
|
|
320
|
+
) {
|
|
321
|
+
if (
|
|
322
|
+
config.population === "visibleItems" &&
|
|
323
|
+
(SERIES_MARKS.has(source.mark?.type) || source.encoding?.parallel !== undefined)
|
|
324
|
+
) {
|
|
325
|
+
throw new Error(
|
|
326
|
+
`Statistical reference "${referenceId}" visibleItems population is ambiguous for series marks.`
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
if (config.field.kind === "explicit") {
|
|
330
|
+
return config.population === "visibleItems"
|
|
331
|
+
? visibleExplicitValues(
|
|
332
|
+
program,
|
|
333
|
+
source,
|
|
334
|
+
dataset,
|
|
335
|
+
config.field.field,
|
|
336
|
+
referenceId
|
|
337
|
+
)
|
|
338
|
+
: strictFieldValues(
|
|
339
|
+
dataset.values,
|
|
340
|
+
config.field.field,
|
|
341
|
+
`Statistical reference "${referenceId}" boundData`
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
return resolveConsumerValuesForDataset(program, {
|
|
345
|
+
layer: source,
|
|
346
|
+
channel: config.axis,
|
|
347
|
+
encoding
|
|
348
|
+
}, dataset);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function statisticalRows(program, referenceId, dataset) {
|
|
352
|
+
const config = program.markConfigs[referenceId]?.statisticalReference;
|
|
353
|
+
const { source, encoding } = requireStatisticalSource(
|
|
354
|
+
program,
|
|
355
|
+
config,
|
|
356
|
+
referenceId
|
|
357
|
+
);
|
|
358
|
+
if (!Array.isArray(config.statistics) || ![1, 2].includes(config.statistics.length)) {
|
|
359
|
+
throw new Error(
|
|
360
|
+
`Statistical reference "${referenceId}" requires one or two statistics.`
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
const statistics = normalizeReferenceStatistics(
|
|
364
|
+
config.statistics,
|
|
365
|
+
config.statistics.length,
|
|
366
|
+
`Statistical reference "${referenceId}"`
|
|
367
|
+
);
|
|
368
|
+
const population = normalizeReferencePopulation(
|
|
369
|
+
config.population,
|
|
370
|
+
`Statistical reference "${referenceId}" population`
|
|
371
|
+
);
|
|
372
|
+
const values = resolvePopulationValues(
|
|
373
|
+
program,
|
|
374
|
+
source,
|
|
375
|
+
encoding,
|
|
376
|
+
{ ...config, population, statistics },
|
|
377
|
+
dataset,
|
|
378
|
+
referenceId
|
|
379
|
+
);
|
|
380
|
+
const resolved = deriveStatisticalReferenceValues(
|
|
381
|
+
values,
|
|
382
|
+
statistics,
|
|
383
|
+
`Statistical reference "${referenceId}"`
|
|
384
|
+
);
|
|
385
|
+
if (resolved.length === 2 && resolved[0] > resolved[1]) {
|
|
386
|
+
throw new Error(
|
|
387
|
+
`Statistical reference band "${referenceId}" lower statistic exceeds its upper statistic.`
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
return resolved.length === 1
|
|
391
|
+
? [{ value: resolved[0] }]
|
|
392
|
+
: [{ lower: resolved[0], upper: resolved[1] }];
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function replaceStatisticalDataset(program, id, source, transform, values) {
|
|
396
|
+
const dataset = findDataset(program, id);
|
|
397
|
+
if (dataset === undefined || dataset.source === undefined) {
|
|
398
|
+
throw new Error(`Unknown statistical reference dataset "${id}".`);
|
|
399
|
+
}
|
|
400
|
+
validateStatisticalReferenceTransform(transform);
|
|
401
|
+
return withRematerializedDerivedDataset(program, {
|
|
402
|
+
id,
|
|
403
|
+
source,
|
|
404
|
+
transform,
|
|
405
|
+
values
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function syncReferenceEncoding(program, id, source, config) {
|
|
410
|
+
const layer = findLayer(program, id);
|
|
411
|
+
if (layer === undefined) {
|
|
412
|
+
throw new Error(`Unknown statistical reference mark "${id}".`);
|
|
413
|
+
}
|
|
414
|
+
const axis = config.axis;
|
|
415
|
+
const secondary = `${axis}2`;
|
|
416
|
+
const retained = new Set(
|
|
417
|
+
config.statistics.length === 1 ? [axis] : [axis, secondary]
|
|
418
|
+
);
|
|
419
|
+
let next = program;
|
|
420
|
+
for (const channel of ["x", "y", "x2", "y2"]) {
|
|
421
|
+
if (!retained.has(channel) && layer.encoding?.[channel] !== undefined) {
|
|
422
|
+
next = next.editSemantic({
|
|
423
|
+
property: `layer[${id}].encoding.${channel}`,
|
|
424
|
+
remove: true
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
const scale = source.encoding[axis].scale;
|
|
429
|
+
const fields = config.statistics.length === 1
|
|
430
|
+
? [[axis, "value"]]
|
|
431
|
+
: [[axis, "lower"], [secondary, "upper"]];
|
|
432
|
+
for (const [channel, field] of fields) {
|
|
433
|
+
const current = findLayer(next, id).encoding?.[channel];
|
|
434
|
+
if (current?.datum !== undefined) {
|
|
435
|
+
next = next.editSemantic({
|
|
436
|
+
property: `layer[${id}].encoding.${channel}.datum`,
|
|
437
|
+
remove: true
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
for (const [property, value] of Object.entries({
|
|
441
|
+
field,
|
|
442
|
+
fieldType: "quantitative",
|
|
443
|
+
scale
|
|
444
|
+
})) {
|
|
445
|
+
if (findLayer(next, id).encoding?.[channel]?.[property] !== value) {
|
|
446
|
+
next = next.editSemantic({
|
|
447
|
+
property: `layer[${id}].encoding.${channel}.${property}`,
|
|
448
|
+
value
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
const currentCoordinate = findLayer(next, id).coordinate;
|
|
454
|
+
if (source.coordinate === undefined && currentCoordinate !== undefined) {
|
|
455
|
+
next = next.editSemantic({
|
|
456
|
+
property: `layer[${id}].coordinate`,
|
|
457
|
+
remove: true
|
|
458
|
+
});
|
|
459
|
+
} else if (source.coordinate !== undefined && source.coordinate !== currentCoordinate) {
|
|
460
|
+
next = next.editSemantic({
|
|
461
|
+
property: `layer[${id}].coordinate`,
|
|
462
|
+
value: source.coordinate
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
return next;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
export const materializeStatisticalReferenceData = action(
|
|
469
|
+
{
|
|
470
|
+
op: "materializeStatisticalReferenceData",
|
|
471
|
+
description: "Materialize one owned statistical reference value dataset."
|
|
472
|
+
},
|
|
473
|
+
function (args = {}) {
|
|
474
|
+
validateKeys(args, MATERIALIZE_OPTIONS, "materializeStatisticalReferenceData");
|
|
475
|
+
const { id, source, transform } = requireDerivedDataset(
|
|
476
|
+
this,
|
|
477
|
+
args.id,
|
|
478
|
+
"statisticalReference"
|
|
479
|
+
);
|
|
480
|
+
const values = statisticalRows(this, transform.target, source);
|
|
481
|
+
return this.editSemantic({
|
|
482
|
+
property: `dataset[${id}].values`,
|
|
483
|
+
value: values
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
);
|
|
487
|
+
|
|
488
|
+
export const rematerializeStatisticalReference = action(
|
|
489
|
+
{
|
|
490
|
+
op: "rematerializeStatisticalReference",
|
|
491
|
+
description: "Recompute one source-dependent statistical reference."
|
|
492
|
+
},
|
|
493
|
+
function (args = {}) {
|
|
494
|
+
validateKeys(args, MATERIALIZE_OPTIONS, "rematerializeStatisticalReference");
|
|
495
|
+
const id = validateUserId(args.id, "Statistical reference mark id");
|
|
496
|
+
const config = this.markConfigs[id]?.statisticalReference;
|
|
497
|
+
const { source } = requireStatisticalSource(this, config, id);
|
|
498
|
+
const population = normalizeReferencePopulation(config.population);
|
|
499
|
+
const dataset = resolvePopulationDataset(this, source, population, id);
|
|
500
|
+
const values = statisticalRows(this, id, dataset);
|
|
501
|
+
const transform = normalizeStatisticalReferenceTransform({ target: id });
|
|
502
|
+
let next = replaceStatisticalDataset(
|
|
503
|
+
this,
|
|
504
|
+
config.dataId,
|
|
505
|
+
dataset.id,
|
|
506
|
+
transform,
|
|
507
|
+
values
|
|
508
|
+
);
|
|
509
|
+
if (findLayer(next, id)?.data !== config.dataId) {
|
|
510
|
+
next = next.editSemantic({
|
|
511
|
+
property: `layer[${id}].data`,
|
|
512
|
+
value: config.dataId
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
next = syncReferenceEncoding(next, id, source, config);
|
|
516
|
+
next = config.statistics.length === 1
|
|
517
|
+
? next.rematerializeRuleMark({ id })
|
|
518
|
+
: next.rematerializeRectMark({ id });
|
|
519
|
+
return next._withContext(this.context);
|
|
520
|
+
}
|
|
521
|
+
);
|
|
522
|
+
|
|
523
|
+
function isDynamicReference(args) {
|
|
524
|
+
return ["axis", "population", "field", "statistic", "statistics"]
|
|
525
|
+
.some(key => Object.hasOwn(args, key));
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
function normalizeDynamicReference(program, args, band) {
|
|
529
|
+
const operation = band ? "createReferenceBand" : "createReferenceLine";
|
|
530
|
+
const styleOptions = band ? BAND_STYLE : LINE_STYLE;
|
|
531
|
+
validateFacadeOptions(
|
|
532
|
+
args,
|
|
533
|
+
[...DYNAMIC_OPTIONS, ...styleOptions],
|
|
534
|
+
operation
|
|
535
|
+
);
|
|
536
|
+
if (typeof args.source !== "string") {
|
|
537
|
+
throw new TypeError(`${operation} statistical source must be a mark id.`);
|
|
538
|
+
}
|
|
539
|
+
const sourceId = validateUserId(args.source, `${operation} source`);
|
|
540
|
+
if (!["x", "y"].includes(args.axis)) {
|
|
541
|
+
throw new Error(`${operation} statistical axis must be x or y.`);
|
|
542
|
+
}
|
|
543
|
+
if (band && Object.hasOwn(args, "statistic")) {
|
|
544
|
+
throw new Error(`${operation} uses statistics, not statistic.`);
|
|
545
|
+
}
|
|
546
|
+
if (!band && Object.hasOwn(args, "statistics")) {
|
|
547
|
+
throw new Error(`${operation} uses statistic, not statistics.`);
|
|
548
|
+
}
|
|
549
|
+
const statistics = normalizeReferenceStatistics(
|
|
550
|
+
band ? args.statistics : [args.statistic],
|
|
551
|
+
band ? 2 : 1,
|
|
552
|
+
operation
|
|
553
|
+
);
|
|
554
|
+
const id = resolveFacadeId(program, args.id, {
|
|
555
|
+
defaultId: band ? "referenceBand" : "referenceLine",
|
|
556
|
+
operation
|
|
557
|
+
});
|
|
558
|
+
const config = {
|
|
559
|
+
source: sourceId,
|
|
560
|
+
axis: args.axis,
|
|
561
|
+
population: normalizeReferencePopulation(args.population, `${operation} population`),
|
|
562
|
+
field: normalizeReferenceField(args.field, `${operation} field`),
|
|
563
|
+
statistics,
|
|
564
|
+
dataId: `${id}-statistical-reference-data`
|
|
565
|
+
};
|
|
566
|
+
const preview = program._withMarkConfig(id, { statisticalReference: config });
|
|
567
|
+
const { source } = requireStatisticalSource(preview, config, id);
|
|
568
|
+
const dataset = resolvePopulationDataset(
|
|
569
|
+
program,
|
|
570
|
+
source,
|
|
571
|
+
config.population,
|
|
572
|
+
id
|
|
573
|
+
);
|
|
574
|
+
statisticalRows(preview, id, dataset);
|
|
575
|
+
if (hasDataset(program, config.dataId) || hasDatasetOwner(program, config.dataId)) {
|
|
576
|
+
throw new Error(`Dataset "${config.dataId}" already exists.`);
|
|
577
|
+
}
|
|
578
|
+
return { id, config, dataset, styleOptions };
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
function createDynamicReference(program, args, band) {
|
|
582
|
+
const { id, config, dataset, styleOptions } = normalizeDynamicReference(
|
|
583
|
+
program,
|
|
584
|
+
args,
|
|
585
|
+
band
|
|
586
|
+
);
|
|
587
|
+
const style = Object.fromEntries(
|
|
588
|
+
styleOptions
|
|
589
|
+
.filter(key => args[key] !== undefined)
|
|
590
|
+
.map(key => [key, args[key]])
|
|
591
|
+
);
|
|
592
|
+
const transform = normalizeStatisticalReferenceTransform({ target: id });
|
|
593
|
+
const apply = initial => {
|
|
594
|
+
const originalContext = initial.context;
|
|
595
|
+
let next = initial
|
|
596
|
+
.createDerivedData({
|
|
597
|
+
id: config.dataId,
|
|
598
|
+
source: dataset.id,
|
|
599
|
+
transform: [transform]
|
|
600
|
+
})
|
|
601
|
+
._withMarkConfig(id, { statisticalReference: config })
|
|
602
|
+
.materializeStatisticalReferenceData({ id: config.dataId });
|
|
603
|
+
next = band
|
|
604
|
+
? next.createRectMark({
|
|
605
|
+
id,
|
|
606
|
+
data: config.dataId,
|
|
607
|
+
fill: "#94a3b8",
|
|
608
|
+
opacity: 0.15,
|
|
609
|
+
stroke: false,
|
|
610
|
+
...style
|
|
611
|
+
})
|
|
612
|
+
: next.createRuleMark({
|
|
613
|
+
id,
|
|
614
|
+
data: config.dataId,
|
|
615
|
+
stroke: "#64748b",
|
|
616
|
+
strokeWidth: 1,
|
|
617
|
+
strokeDash: "dashed",
|
|
618
|
+
...style
|
|
619
|
+
});
|
|
620
|
+
next = next._withMarkConfig(id, {
|
|
621
|
+
...next.markConfigs[id],
|
|
622
|
+
itemFilterable: false,
|
|
623
|
+
statisticalReference: config
|
|
624
|
+
});
|
|
625
|
+
return next
|
|
626
|
+
.rematerializeStatisticalReference({ id })
|
|
627
|
+
._withContext({ ...originalContext, currentMark: id });
|
|
628
|
+
};
|
|
629
|
+
// Validate every owned data, semantic, scale, and renderer step atomically.
|
|
630
|
+
apply(program);
|
|
631
|
+
return apply(program);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
function createReference(program, args, band) {
|
|
635
|
+
return isDynamicReference(args)
|
|
636
|
+
? createDynamicReference(program, args, band)
|
|
637
|
+
: createLiteralReference(program, args, band);
|
|
638
|
+
}
|
|
639
|
+
|
|
79
640
|
export const createReferenceLine = action(
|
|
80
|
-
{
|
|
81
|
-
|
|
641
|
+
{
|
|
642
|
+
op: "createReferenceLine",
|
|
643
|
+
description: "Create a constant or statistical reference line."
|
|
644
|
+
},
|
|
645
|
+
function (args = {}) {
|
|
646
|
+
return createReference(this, args, false);
|
|
647
|
+
}
|
|
82
648
|
);
|
|
83
649
|
|
|
84
650
|
export const createReferenceBand = action(
|
|
85
|
-
{
|
|
86
|
-
|
|
651
|
+
{
|
|
652
|
+
op: "createReferenceBand",
|
|
653
|
+
description: "Create a constant or statistical reference interval."
|
|
654
|
+
},
|
|
655
|
+
function (args = {}) {
|
|
656
|
+
return createReference(this, args, true);
|
|
657
|
+
}
|
|
87
658
|
);
|