ggaction 0.0.12 → 0.0.13
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 +49 -0
- package/README.md +2 -2
- package/knowledge/action-card.schema.json +1 -1
- package/knowledge/action-cards.json +1 -1
- package/knowledge/action-cards.schema.json +1 -1
- package/knowledge/extension-authoring.md +2 -1
- package/knowledge/intent-taxonomy.json +1 -1
- package/knowledge/mcp-resources.json +1 -1
- package/knowledge/task-resolver.js +1 -1
- package/package.json +4 -2
- package/src/actions/basic.js +2 -0
- package/src/actions/boxPlots/materialize.js +2 -1
- package/src/actions/canvas/actions.js +3 -1
- package/src/actions/canvas/fitting.js +211 -0
- package/src/actions/canvas/index.js +2 -0
- package/src/actions/categoryOrder/index.js +3 -2
- package/src/actions/charts/area.js +47 -0
- package/src/actions/charts/bar.js +11 -5
- package/src/actions/charts/beeswarm.js +70 -0
- package/src/actions/charts/density.js +44 -0
- package/src/actions/charts/ecdf.js +183 -0
- package/src/actions/charts/endpoints.js +451 -0
- package/src/actions/charts/heatmap.js +2 -2
- package/src/actions/charts/histogram.js +1 -1
- package/src/actions/charts/horizon.js +71 -0
- package/src/actions/charts/index.js +37 -0
- package/src/actions/charts/interval-regression.js +169 -0
- package/src/actions/charts/line.js +5 -5
- package/src/actions/charts/parallel.js +1 -1
- package/src/actions/charts/pie.js +44 -0
- package/src/actions/charts/polar.js +123 -0
- package/src/actions/charts/radar.js +299 -0
- package/src/actions/charts/radial.js +42 -0
- package/src/actions/charts/raincloud.js +422 -0
- package/src/actions/charts/rug-strip.js +279 -0
- package/src/actions/charts/scatter.js +9 -3
- package/src/actions/charts/shared.js +69 -10
- package/src/actions/composition/actions.js +118 -1
- package/src/actions/data/bin.js +29 -0
- package/src/actions/data/computed.js +24 -0
- package/src/actions/data/derived.js +66 -0
- package/src/actions/data/ecdf.js +38 -0
- package/src/actions/data/filter.js +212 -28
- package/src/actions/data/fold.js +24 -0
- package/src/actions/data/index.js +24 -0
- package/src/actions/data/interval.js +2 -0
- package/src/actions/data/intervalEdit.js +86 -4
- package/src/actions/data/regression.js +5 -2
- package/src/actions/data/stack.js +26 -0
- package/src/actions/data/summary.js +26 -0
- package/src/actions/data/timeUnit.js +1 -1
- package/src/actions/encodings/appearance.js +32 -13
- package/src/actions/encodings/barWidth.js +8 -0
- package/src/actions/encodings/basic.js +2 -0
- package/src/actions/encodings/color/continuous.js +19 -59
- package/src/actions/encodings/color/index.js +28 -22
- package/src/actions/encodings/color/layout.js +3 -97
- package/src/actions/encodings/color/policy.js +5 -8
- package/src/actions/encodings/density/resolve.js +37 -5
- package/src/actions/encodings/density.js +120 -33
- package/src/actions/encodings/horizon/resolve.js +8 -4
- package/src/actions/encodings/horizon.js +18 -8
- package/src/actions/encodings/index.js +2 -0
- package/src/actions/encodings/offset.js +10 -16
- package/src/actions/encodings/parallel.js +2 -8
- package/src/actions/encodings/position/apply.js +10 -4
- package/src/actions/encodings/position/index.js +43 -5
- package/src/actions/encodings/position/policies/arc.js +14 -0
- package/src/actions/encodings/position/policies/area.js +4 -42
- package/src/actions/encodings/position/policies/bar.js +48 -13
- package/src/actions/encodings/position/resolve.js +67 -22
- package/src/actions/encodings/ranged.js +123 -97
- package/src/actions/encodings/remove.js +37 -32
- package/src/actions/encodings/ruleAppearance.js +23 -9
- package/src/actions/encodings/seriesLayout.js +104 -0
- package/src/actions/encodings/shared.js +25 -23
- package/src/actions/encodings/strokeDash.js +9 -6
- package/src/actions/encodings/temporal.js +7 -0
- package/src/actions/encodings/text.js +30 -15
- package/src/actions/errorBands/create.js +18 -5
- package/src/actions/errorBands/edit.js +341 -21
- package/src/actions/errorBars/create.js +21 -10
- package/src/actions/errorBars/edit.js +355 -19
- package/src/actions/facets/actions.js +410 -12
- package/src/actions/facets/derive.js +57 -8
- package/src/actions/gradientPlots/components.js +33 -11
- package/src/actions/gradientPlots/materialize.js +5 -7
- package/src/actions/guides/applicability.js +20 -17
- package/src/actions/guides/axes/axes.js +4 -3
- package/src/actions/guides/axes/axis.js +18 -18
- package/src/actions/guides/axes/components.js +43 -0
- package/src/actions/guides/axes/edit.js +16 -51
- package/src/actions/guides/axes/labels.js +129 -19
- package/src/actions/guides/axes/lines.js +7 -5
- package/src/actions/guides/axes/parallel/lifecycle.js +117 -0
- package/src/actions/guides/axes/parallel/policy.js +137 -0
- package/src/actions/guides/axes/parallel/resolve.js +44 -23
- package/src/actions/guides/axes/parallel.js +93 -217
- package/src/actions/guides/axes/policy.js +21 -67
- package/src/actions/guides/axes/tickGroups.js +14 -8
- package/src/actions/guides/axes/ticks.js +5 -4
- package/src/actions/guides/axes/titles.js +21 -8
- package/src/actions/guides/basic.js +2 -0
- package/src/actions/guides/facade.js +106 -0
- package/src/actions/guides/facadeAxes.js +200 -0
- package/src/actions/guides/facadeLegend.js +63 -0
- package/src/actions/guides/grids/grid.js +37 -33
- package/src/actions/guides/grids/resolve.js +10 -2
- package/src/actions/guides/guides.js +35 -28
- package/src/actions/guides/legends/categorical/actions.js +193 -249
- package/src/actions/guides/legends/categorical/components.js +4 -5
- package/src/actions/guides/legends/categorical/layout.js +36 -349
- package/src/actions/guides/legends/categorical/options.js +30 -14
- package/src/actions/guides/legends/categorical/recipes.js +14 -0
- package/src/actions/guides/legends/categorical/resolve.js +21 -10
- package/src/actions/guides/legends/categorical/symbols.js +2 -3
- package/src/actions/guides/legends/continuous/common.js +69 -14
- package/src/actions/guides/legends/continuous/gradient.js +111 -83
- package/src/actions/guides/legends/continuous/index.js +6 -2
- package/src/actions/guides/legends/continuous/interval.js +71 -92
- package/src/actions/guides/legends/continuous/opacity.js +105 -84
- package/src/actions/guides/legends/creation.js +27 -0
- package/src/actions/guides/legends/edit.js +198 -66
- package/src/actions/guides/legends/focused.js +2 -2
- package/src/actions/guides/legends/lane.js +98 -86
- package/src/actions/guides/legends/lifecycle.js +132 -0
- package/src/actions/guides/legends/remove.js +31 -76
- package/src/actions/guides/legends/size.js +149 -105
- package/src/actions/guides/legends/strokeWidth.js +106 -64
- package/src/actions/guides/legends/target.js +12 -0
- package/src/actions/guides/legends/transition.js +43 -0
- package/src/actions/guides/polar/axes/facade.js +77 -62
- package/src/actions/guides/polar/axes/labels.js +5 -4
- package/src/actions/guides/polar/axes/lines.js +2 -1
- package/src/actions/guides/polar/axes/shared.js +6 -0
- package/src/actions/guides/polar/axes/ticks.js +5 -4
- package/src/actions/guides/polar/axes/titles.js +5 -4
- package/src/actions/guides/polar/grids.js +7 -7
- package/src/actions/guides/reuse.js +44 -0
- package/src/actions/guides/tickValues.js +19 -21
- package/src/actions/index.js +2 -0
- package/src/actions/intervals/resolve.js +35 -15
- package/src/actions/marks/arc/actions.js +1 -1
- package/src/actions/marks/area/actions.js +18 -4
- package/src/actions/marks/area/materialize.js +5 -2
- package/src/actions/marks/bar/materialize.js +11 -7
- package/src/actions/marks/index.js +5 -0
- package/src/actions/marks/line/actions.js +43 -108
- package/src/actions/marks/line/materialize.js +34 -52
- package/src/actions/marks/point/edit.js +11 -15
- package/src/actions/marks/point/index.js +1 -0
- package/src/actions/marks/point/jitter.js +3 -0
- package/src/actions/marks/point/materialize.js +106 -2
- package/src/actions/marks/point/packing.js +68 -0
- package/src/actions/marks/references.js +87 -0
- package/src/actions/marks/remove.js +17 -4
- package/src/actions/marks/rule/actions.js +34 -3
- package/src/actions/marks/rule/appearance.js +26 -0
- package/src/actions/marks/shared.js +12 -12
- package/src/actions/marks/text/actions.js +224 -6
- package/src/actions/marks/text/layout.js +2 -2
- package/src/actions/primitives/createGraphics.js +3 -1
- package/src/actions/primitives/semantic.js +1 -1
- package/src/actions/primitives/semanticAction.js +39 -2
- package/src/actions/primitives/semanticValidation/guide.js +10 -0
- package/src/actions/primitives/semanticValidation/layer.js +18 -1
- package/src/actions/primitives/semanticValidation/scale.js +10 -1
- package/src/actions/regression/create.js +1 -1
- package/src/actions/regression/edit.js +19 -6
- package/src/actions/regression/resolve.js +1 -1
- package/src/actions/scales/consumers/common.js +20 -53
- package/src/actions/scales/consumers/families.js +27 -14
- package/src/actions/scales/consumers/index.js +23 -2
- package/src/actions/scales/consumers/seriesLayout.js +33 -2
- package/src/actions/scales/create.js +4 -4
- package/src/actions/scales/definitions.js +19 -3
- package/src/actions/scales/edit.js +46 -34
- package/src/actions/scales/editPolicy.js +21 -31
- package/src/actions/scales/materialize.js +10 -46
- package/src/actions/scales/patch.js +1 -1
- package/src/actions/scales/preview.js +39 -0
- package/src/actions/scales/quantitativeColor.js +9 -5
- package/src/actions/theme/actions.js +43 -0
- package/src/actions/theme/index.js +9 -0
- package/src/actions/theme/reconcile.js +882 -0
- package/src/actions/titles/actions.js +11 -10
- package/src/actions/titles/resolve.js +1 -40
- package/src/actions/violinPlots/create.js +86 -42
- package/src/actions/violinPlots/edit.js +191 -0
- package/src/actions/violinPlots/index.js +2 -0
- package/src/core/ChartProgram.js +7 -0
- package/src/core/action.js +22 -2
- package/src/core/compositionState.js +136 -8
- package/src/grammar/aggregate.js +66 -23
- package/src/grammar/arcs.js +58 -1
- package/src/grammar/areaEndpoints.js +46 -0
- package/src/grammar/areaSeries.js +87 -41
- package/src/grammar/bars/aggregate.js +33 -12
- package/src/grammar/bars/policy.js +9 -7
- package/src/grammar/bin.js +181 -0
- package/src/grammar/categoryOrder.js +34 -0
- package/src/grammar/computed.js +150 -0
- package/src/grammar/ecdf.js +198 -0
- package/src/grammar/facets/index.js +117 -6
- package/src/grammar/fold.js +123 -0
- package/src/grammar/horizon.js +6 -4
- package/src/grammar/interval.js +37 -20
- package/src/grammar/lineSeries.js +20 -63
- package/src/grammar/markFilter.js +22 -4
- package/src/grammar/markLabels.js +93 -0
- package/src/grammar/parallelAxisTitles.js +16 -0
- package/src/grammar/pathSeries.js +91 -0
- package/src/grammar/pointPacking.js +183 -0
- package/src/grammar/positionDatum.js +12 -0
- package/src/grammar/rects.js +9 -1
- package/src/grammar/regression/derive.js +4 -0
- package/src/grammar/regression/index.js +7 -2
- package/src/grammar/regression/models.js +22 -7
- package/src/grammar/regression/parameters.js +40 -13
- package/src/grammar/rotation.js +29 -0
- package/src/grammar/rules.js +7 -21
- package/src/grammar/scales/color.js +23 -1
- package/src/grammar/scales/colorConsumers.js +38 -0
- package/src/grammar/scales/definition.js +15 -1
- package/src/grammar/scales/discretized.js +11 -5
- package/src/grammar/scales/fields.js +38 -8
- package/src/grammar/scales/mapping.js +2 -0
- package/src/grammar/scales/radial.js +55 -0
- package/src/grammar/scales/types.js +1 -0
- package/src/grammar/schemas/semanticPath.js +17 -3
- package/src/grammar/stack.js +170 -0
- package/src/grammar/statistics/confidenceInterval.js +101 -0
- package/src/grammar/summary.js +183 -0
- package/src/grammar/text.js +22 -16
- package/src/grammar/timeUnit.js +21 -11
- package/src/grammar/transformTopology.js +6 -0
- package/src/grammar/transforms.js +36 -0
- package/src/grammar/valueFormat.js +112 -0
- package/src/grammar/window.js +13 -7
- package/src/layout/facets.js +41 -7
- package/src/layout/guideCollisions.js +12 -0
- package/src/layout/legend.js +2 -10
- package/src/layout/legendItems.js +102 -0
- package/src/layout/legendLane.js +100 -11
- package/src/materialization/bars/aggregate.js +38 -152
- package/src/materialization/bars/histogram.js +24 -0
- package/src/materialization/categorySlotOffset.js +40 -0
- package/src/materialization/compositionSnapshot.js +1 -1
- package/src/materialization/dependencies.js +57 -16
- package/src/materialization/encodings.js +1 -1
- package/src/materialization/facets.js +8 -1
- package/src/materialization/guides/layout.js +57 -0
- package/src/materialization/guides/resources.js +2 -2
- package/src/materialization/legends.js +10 -1
- package/src/materialization/marks/capabilities.js +20 -5
- package/src/materialization/marks/grouping.js +52 -0
- package/src/materialization/marks/index.js +58 -23
- package/src/materialization/marks/policies.js +2 -0
- package/src/materialization/rect.js +33 -33
- package/src/materialization/rowEncoding.js +13 -13
- package/src/materialization/scaleGuideDependencies.js +8 -5
- package/src/materialization/scales/map.js +1 -0
- package/src/materialization/scales/policies/arc.js +42 -0
- package/src/materialization/scales/policies/binnedPosition.js +7 -4
- package/src/materialization/scales/policies/series.js +2 -1
- package/src/materialization/scales/resolve.js +46 -14
- package/src/materialization/selection/compatibility.js +11 -0
- package/src/materialization/selection/items/bar.js +12 -68
- package/src/materialization/selection/items/common.js +8 -2
- package/src/materialization/selection/items/path.js +3 -13
- package/src/materialization/selection/items/rect.js +7 -4
- package/src/materialization/text.js +64 -5
- package/src/mcp/adapter.js +2 -2
- package/src/selectors/datasets.js +13 -0
- package/src/selectors/layers.js +3 -2
- package/src/selectors/scales.js +6 -0
- package/src/theme/defaults.js +39 -0
- package/types/basic.d.ts +11 -2
- package/types/index.d.ts +126 -0
- package/types/program.d.ts +1320 -135
- package/src/materialization/bars/grouped.js +0 -144
|
@@ -1,15 +1,13 @@
|
|
|
1
|
+
import { isSourceOwnedText } from "../../grammar/text.js";
|
|
1
2
|
import { validateUserId } from "../../core/identifiers.js";
|
|
2
3
|
import { findDataset } from "../../selectors/datasets.js";
|
|
3
4
|
import { resolveEligibleLayer } from "../../selectors/layers.js";
|
|
4
5
|
import { hasMaterializedLegend } from "../../materialization/legends.js";
|
|
5
|
-
import { applyMaterializationPlan } from "../../materialization/dependencies.js";
|
|
6
|
+
import { applyDetachedScaleRematerialization, applyMaterializationPlan } from "../../materialization/dependencies.js";
|
|
6
7
|
import { planEncodingRematerialization } from "../../materialization/encodings.js";
|
|
7
8
|
import { findSemanticScale } from "../../selectors/scales.js";
|
|
8
9
|
import { validateOptionObject } from "../../core/validation.js";
|
|
9
|
-
import {
|
|
10
|
-
getMarkGraphicTypes,
|
|
11
|
-
getPositionChannelDefinition
|
|
12
|
-
} from "../../core/vocabulary.js";
|
|
10
|
+
import { getMarkGraphicTypes, getPositionChannelDefinition } from "../../core/vocabulary.js";
|
|
13
11
|
|
|
14
12
|
export function validateOptions(args, supported, operation) {
|
|
15
13
|
validateOptionObject(args, supported, operation);
|
|
@@ -31,11 +29,16 @@ export function setEncodingProperties(
|
|
|
31
29
|
return next;
|
|
32
30
|
}
|
|
33
31
|
|
|
34
|
-
export
|
|
35
|
-
|
|
32
|
+
export { applyDetachedScaleRematerialization };
|
|
33
|
+
|
|
34
|
+
export function rematerializeEncoding(program, target, channel, scale, previousLayer) {
|
|
35
|
+
const next = applyMaterializationPlan(
|
|
36
36
|
program,
|
|
37
37
|
planEncodingRematerialization(program, { target, channel, scale })
|
|
38
38
|
);
|
|
39
|
+
return previousLayer === undefined
|
|
40
|
+
? next
|
|
41
|
+
: applyDetachedScaleRematerialization(next, [previousLayer]);
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
export function clearMarkGraphic(program, target) {
|
|
@@ -50,19 +53,6 @@ export function clearMarkGraphic(program, target) {
|
|
|
50
53
|
}
|
|
51
54
|
|
|
52
55
|
|
|
53
|
-
export function validateLineSeriesCompatibility(layer, channel, field) {
|
|
54
|
-
if (layer.mark?.type !== "line") return;
|
|
55
|
-
for (const companion of ["group", "color", "strokeDash"]) {
|
|
56
|
-
if (companion === channel) continue;
|
|
57
|
-
const companionField = layer.encoding?.[companion]?.field;
|
|
58
|
-
if (companionField !== undefined && companionField !== field) {
|
|
59
|
-
throw new Error(
|
|
60
|
-
`Line ${channel} field "${field}" must match ${companion} field "${companionField}".`
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
56
|
export function resolveReassignmentScaleOptions(encoding, options) {
|
|
67
57
|
if (encoding?.scale === undefined || options?.id !== undefined) return options;
|
|
68
58
|
return { ...options, id: encoding.scale };
|
|
@@ -72,13 +62,14 @@ export function applyEncodingScale(
|
|
|
72
62
|
program,
|
|
73
63
|
definition,
|
|
74
64
|
options = {},
|
|
75
|
-
{ reassignment = false } = {}
|
|
65
|
+
{ reassignment = false, allowTypeChange = false } = {}
|
|
76
66
|
) {
|
|
77
67
|
const existing = findSemanticScale(program, definition.id);
|
|
78
68
|
if (existing === undefined) {
|
|
79
69
|
return program.createScale(definition);
|
|
80
70
|
}
|
|
81
71
|
if (existing.type !== definition.type) {
|
|
72
|
+
if (reassignment && allowTypeChange) return program.editScale({ ...definition });
|
|
82
73
|
throw new Error(
|
|
83
74
|
`Scale "${definition.id}" cannot change type from "${existing.type}" to "${definition.type}".`
|
|
84
75
|
);
|
|
@@ -88,7 +79,7 @@ export function applyEncodingScale(
|
|
|
88
79
|
for (const property of [
|
|
89
80
|
"domain", "range", "nice", "zero", "clamp", "reverse",
|
|
90
81
|
"base", "exponent", "constant", "paddingInner", "paddingOuter",
|
|
91
|
-
"padding", "align", "unknown", "interpolate"
|
|
82
|
+
"padding", "align", "unknown", "interpolate", "radialMapping"
|
|
92
83
|
]) {
|
|
93
84
|
if (Object.hasOwn(options, property)) patch[property] = definition[property];
|
|
94
85
|
}
|
|
@@ -118,7 +109,7 @@ export function rebindPositionGuides(
|
|
|
118
109
|
if (!ownsAxis && !ownsGrid) return program;
|
|
119
110
|
|
|
120
111
|
const remaining = program.semanticSpec.layers.some(layer =>
|
|
121
|
-
layer.id !== target && layer.encoding?.[channel]?.scale === previousScale
|
|
112
|
+
layer.id !== target && !isSourceOwnedText(layer) && layer.encoding?.[channel]?.scale === previousScale
|
|
122
113
|
);
|
|
123
114
|
if (remaining) {
|
|
124
115
|
throw new Error(
|
|
@@ -195,3 +186,14 @@ export function resolveTarget(
|
|
|
195
186
|
|
|
196
187
|
return { id, dataset, layer };
|
|
197
188
|
}
|
|
189
|
+
|
|
190
|
+
export function inferSeriesGroup(program, layer, field, origin) {
|
|
191
|
+
const group = layer.encoding?.group;
|
|
192
|
+
if (group !== undefined && group.inferredFrom !== origin) {
|
|
193
|
+
if (origin === "offset" && (group.fields !== undefined || group.field !== field)) {
|
|
194
|
+
throw new Error("Offset field conflicts with the stored series group.");
|
|
195
|
+
}
|
|
196
|
+
return program;
|
|
197
|
+
}
|
|
198
|
+
return setEncodingProperties(program, layer.id, "group", { field, fieldType: "nominal", inferredFrom: origin });
|
|
199
|
+
}
|
|
@@ -11,10 +11,10 @@ import {
|
|
|
11
11
|
resolveReassignmentScaleOptions,
|
|
12
12
|
resolveTarget,
|
|
13
13
|
setEncodingProperties,
|
|
14
|
-
validateLineSeriesCompatibility,
|
|
15
14
|
validateOptions
|
|
16
15
|
} from "./shared.js";
|
|
17
16
|
import { findLayer } from "../../selectors/layers.js";
|
|
17
|
+
import { validatePathSeriesAppearance } from "../../grammar/pathSeries.js";
|
|
18
18
|
|
|
19
19
|
const STROKE_DASH_ENCODING_OPTIONS = Object.freeze([
|
|
20
20
|
"field", "value", "target", "fieldType", "scale"
|
|
@@ -81,6 +81,9 @@ const encodeStrokeDash = action(
|
|
|
81
81
|
);
|
|
82
82
|
if (hasValue) {
|
|
83
83
|
normalizeStrokeDashPattern(args.value);
|
|
84
|
+
validatePathSeriesAppearance(dataset.values, {
|
|
85
|
+
...layer, encoding: { ...layer.encoding, strokeDash: { datum: args.value } }
|
|
86
|
+
});
|
|
84
87
|
let next = layer.encoding?.strokeDash === undefined
|
|
85
88
|
? this
|
|
86
89
|
: this.clearStrokeDashEncoding({ target });
|
|
@@ -89,13 +92,13 @@ const encodeStrokeDash = action(
|
|
|
89
92
|
value: args.value
|
|
90
93
|
});
|
|
91
94
|
next = reconcileLegendAfterDashRemoval(next, target);
|
|
92
|
-
return
|
|
93
|
-
? next.rematerializeRuleMark({ id: target })
|
|
94
|
-
: next.rematerializeLineMark({ id: target });
|
|
95
|
+
return rematerializeEncoding(next, target, "strokeDash", undefined, layer);
|
|
95
96
|
}
|
|
96
97
|
|
|
97
98
|
const fieldType = validateNominalFieldType(args.fieldType ?? "nominal");
|
|
98
|
-
|
|
99
|
+
validatePathSeriesAppearance(dataset.values, {
|
|
100
|
+
...layer, encoding: { ...layer.encoding, strokeDash: { field: args.field, fieldType } }
|
|
101
|
+
});
|
|
99
102
|
const previous = layer.encoding?.strokeDash;
|
|
100
103
|
const requestedScale = previous?.field === args.field
|
|
101
104
|
? resolveReassignmentScaleOptions(previous, args.scale ?? {})
|
|
@@ -120,7 +123,7 @@ const encodeStrokeDash = action(
|
|
|
120
123
|
reassignment: previous?.scale === scale.id
|
|
121
124
|
});
|
|
122
125
|
|
|
123
|
-
return rematerializeEncoding(next, target, "strokeDash", scale.id);
|
|
126
|
+
return rematerializeEncoding(next, target, "strokeDash", scale.id, layer);
|
|
124
127
|
}
|
|
125
128
|
);
|
|
126
129
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export function applyTemporalUnit(program, target, channel, unit, previous) {
|
|
2
|
+
if (unit === previous?.temporalUnit) return program;
|
|
3
|
+
return program.editSemantic({
|
|
4
|
+
property: `layer[${target}].encoding.${channel}.temporalUnit`,
|
|
5
|
+
...(unit === undefined ? { remove: true } : { value: unit })
|
|
6
|
+
});
|
|
7
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { action } from "../../core/action.js";
|
|
2
2
|
import { formatTextValue, validateTextFormat } from "../../grammar/text.js";
|
|
3
|
+
import { normalizeMarkLabelContent, resolveMarkLabelValues } from "../../grammar/markLabels.js";
|
|
3
4
|
import { canMaterializeText } from "../../materialization/marks/index.js";
|
|
5
|
+
import { resolveMarkItems } from "../../materialization/selection/policies/index.js";
|
|
4
6
|
import { findLayer } from "../../selectors/layers.js";
|
|
5
7
|
import {
|
|
6
8
|
resolveTarget,
|
|
@@ -8,7 +10,7 @@ import {
|
|
|
8
10
|
validateOptions
|
|
9
11
|
} from "./shared.js";
|
|
10
12
|
|
|
11
|
-
const OPTIONS = Object.freeze(["target", "field", "value", "format"]);
|
|
13
|
+
const OPTIONS = Object.freeze(["target", "field", "value", "content", "normalizeBy", "format"]);
|
|
12
14
|
|
|
13
15
|
function validateTextField(rows, field, format) {
|
|
14
16
|
if (typeof field !== "string" || field.length === 0) {
|
|
@@ -26,14 +28,18 @@ function validateTextField(rows, field, format) {
|
|
|
26
28
|
export const encodeText = action(
|
|
27
29
|
{
|
|
28
30
|
op: "encodeText",
|
|
29
|
-
description: "Assign field
|
|
31
|
+
description: "Assign field, constant, or source semantic text content."
|
|
30
32
|
},
|
|
31
33
|
function (args = {}) {
|
|
32
34
|
validateOptions(args, OPTIONS, "encodeText");
|
|
33
35
|
const hasField = Object.hasOwn(args, "field");
|
|
34
36
|
const hasValue = Object.hasOwn(args, "value");
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
const hasContent = Object.hasOwn(args, "content");
|
|
38
|
+
if ([hasField, hasValue, hasContent].filter(Boolean).length !== 1) {
|
|
39
|
+
throw new Error("encodeText requires exactly one of field, value, or content.");
|
|
40
|
+
}
|
|
41
|
+
if (Object.hasOwn(args, "normalizeBy") && (!hasContent || args.content !== "share")) {
|
|
42
|
+
throw new Error("Text normalizeBy is only supported with share content.");
|
|
37
43
|
}
|
|
38
44
|
const { id: target, dataset, layer } = resolveTarget(
|
|
39
45
|
this,
|
|
@@ -43,23 +49,32 @@ export const encodeText = action(
|
|
|
43
49
|
);
|
|
44
50
|
const previous = layer.encoding?.text;
|
|
45
51
|
const format = validateTextFormat(args.format ?? previous?.format ?? "auto");
|
|
52
|
+
const content = hasContent
|
|
53
|
+
? normalizeMarkLabelContent(findLayer(this, layer.source), args)
|
|
54
|
+
: undefined;
|
|
46
55
|
if (hasField) validateTextField(dataset.values, args.field, format);
|
|
47
|
-
else if (formatTextValue(args.value, format) === undefined) {
|
|
56
|
+
else if (hasValue && formatTextValue(args.value, format) === undefined) {
|
|
48
57
|
throw new Error("encodeText value must produce non-empty text.");
|
|
49
58
|
}
|
|
50
59
|
|
|
60
|
+
const properties = {
|
|
61
|
+
...(hasContent ? content : { [hasField ? "field" : "datum"]: hasField ? args.field : args.value }),
|
|
62
|
+
format
|
|
63
|
+
};
|
|
64
|
+
const proposed = { ...layer, encoding: { ...layer.encoding, text: properties } };
|
|
65
|
+
if (hasContent && canMaterializeText(this, proposed)) {
|
|
66
|
+
const source = findLayer(this, layer.source);
|
|
67
|
+
for (const value of resolveMarkLabelValues(source, resolveMarkItems(this, source.id), content)) {
|
|
68
|
+
formatTextValue(value, format);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
51
71
|
let next = this;
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
remove: true
|
|
57
|
-
});
|
|
72
|
+
for (const property of ["field", "datum", "content", "normalizeBy"]) {
|
|
73
|
+
if (Object.hasOwn(previous ?? {}, property) && !Object.hasOwn(properties, property)) {
|
|
74
|
+
next = next.editSemantic({ property: `layer[${target}].encoding.text.${property}`, remove: true });
|
|
75
|
+
}
|
|
58
76
|
}
|
|
59
|
-
next = setEncodingProperties(next, target, "text",
|
|
60
|
-
[hasField ? "field" : "datum"]: hasField ? args.field : args.value,
|
|
61
|
-
format
|
|
62
|
-
});
|
|
77
|
+
next = setEncodingProperties(next, target, "text", properties);
|
|
63
78
|
const updated = findLayer(next, target);
|
|
64
79
|
return canMaterializeText(next, updated)
|
|
65
80
|
? next.rematerializeTextMark({ id: target })
|
|
@@ -2,6 +2,7 @@ import { action } from "../../core/action.js";
|
|
|
2
2
|
import { isPlainObject } from "../../core/immutable.js";
|
|
3
3
|
import {
|
|
4
4
|
validateKeys,
|
|
5
|
+
validateNonEmptyString,
|
|
5
6
|
} from "../../core/validation.js";
|
|
6
7
|
import { DEFAULT_COLORS } from "../../theme/defaults.js";
|
|
7
8
|
import { validateCurveInterpolation } from "../../grammar/curveCommands.js";
|
|
@@ -23,7 +24,7 @@ const OPTIONS = Object.freeze([
|
|
|
23
24
|
"boundaries"
|
|
24
25
|
]);
|
|
25
26
|
|
|
26
|
-
const ERROR_BAND_POLICY = Object.freeze({
|
|
27
|
+
export const ERROR_BAND_POLICY = Object.freeze({
|
|
27
28
|
operation: "createErrorBand",
|
|
28
29
|
resourceLabel: "error-band",
|
|
29
30
|
defaultId: "errorBand",
|
|
@@ -40,8 +41,8 @@ const ERROR_BAND_POLICY = Object.freeze({
|
|
|
40
41
|
"createErrorBand cannot infer the interval axis when both positions are quantitative; provide an interval option."
|
|
41
42
|
});
|
|
42
43
|
|
|
43
|
-
function resolveErrorBand(program, args) {
|
|
44
|
-
const resolved = resolveIntervalComposite(program, args,
|
|
44
|
+
export function resolveErrorBand(program, args, policy = ERROR_BAND_POLICY) {
|
|
45
|
+
const resolved = resolveIntervalComposite(program, args, policy);
|
|
45
46
|
if (resolved.groupField === resolved.position.field) {
|
|
46
47
|
throw new Error(
|
|
47
48
|
"createErrorBand groupBy must differ from the independent position field."
|
|
@@ -71,8 +72,9 @@ function resolveBoundaries(value, areaCurve) {
|
|
|
71
72
|
});
|
|
72
73
|
}
|
|
73
74
|
|
|
74
|
-
function positionOptions({ target, field, fieldType, coordinate, scale }) {
|
|
75
|
-
return { target, field, fieldType, coordinate, scale: { id: scale }
|
|
75
|
+
function positionOptions({ target, field, fieldType, coordinate, scale, temporalUnit }) {
|
|
76
|
+
return { target, field, fieldType, coordinate, scale: { id: scale },
|
|
77
|
+
...(temporalUnit === undefined ? {} : { temporalUnit }) };
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
export const createErrorBandBoundary = action(
|
|
@@ -103,6 +105,7 @@ export const createErrorBandBoundary = action(
|
|
|
103
105
|
target: id,
|
|
104
106
|
field: vertical ? bound : position.field,
|
|
105
107
|
fieldType: vertical ? "quantitative" : position.fieldType,
|
|
108
|
+
temporalUnit: vertical ? undefined : position.temporalUnit,
|
|
106
109
|
coordinate,
|
|
107
110
|
scale: vertical ? intervalScale : positionScale
|
|
108
111
|
}))
|
|
@@ -110,6 +113,7 @@ export const createErrorBandBoundary = action(
|
|
|
110
113
|
target: id,
|
|
111
114
|
field: vertical ? position.field : bound,
|
|
112
115
|
fieldType: vertical ? position.fieldType : "quantitative",
|
|
116
|
+
temporalUnit: vertical ? position.temporalUnit : undefined,
|
|
113
117
|
coordinate,
|
|
114
118
|
scale: vertical ? positionScale : intervalScale
|
|
115
119
|
}));
|
|
@@ -132,6 +136,7 @@ function positionArgs(resolved) {
|
|
|
132
136
|
target: resolved.id,
|
|
133
137
|
field: resolved.position.field,
|
|
134
138
|
fieldType: resolved.position.fieldType,
|
|
139
|
+
...(resolved.position.temporalUnit === undefined ? {} : { temporalUnit: resolved.position.temporalUnit }),
|
|
135
140
|
coordinate: resolved.coordinate,
|
|
136
141
|
scale: resolved.position.scale
|
|
137
142
|
};
|
|
@@ -158,6 +163,7 @@ export const createErrorBand = action(
|
|
|
158
163
|
const resolved = resolveErrorBand(this, args);
|
|
159
164
|
const curve = validateCurveInterpolation(args.curve ?? "linear");
|
|
160
165
|
const boundaries = resolveBoundaries(args.boundaries, curve);
|
|
166
|
+
if (args.fill !== undefined) validateNonEmptyString(args.fill, "Error-band fill");
|
|
161
167
|
let next = createResolvedIntervalData(this, resolved);
|
|
162
168
|
next = next.createAreaMark({
|
|
163
169
|
id: resolved.id,
|
|
@@ -216,6 +222,13 @@ export const createErrorBand = action(
|
|
|
216
222
|
return next._withMarkConfig(resolved.id, {
|
|
217
223
|
...next.markConfigs[resolved.id],
|
|
218
224
|
errorBand: {
|
|
225
|
+
...(args.fill === undefined ? {} : { fill: args.fill }),
|
|
226
|
+
source: resolved.source,
|
|
227
|
+
intervalMode: resolved.interval.mode,
|
|
228
|
+
...(resolved.interval.mode === "statistical"
|
|
229
|
+
? { intervalField: resolved.interval.field }
|
|
230
|
+
: { centerField: resolved.fields.center }),
|
|
231
|
+
transformGroupBy: resolved.groupBy,
|
|
219
232
|
data: resolved.dataId,
|
|
220
233
|
orientation: resolved.orientation,
|
|
221
234
|
position: resolved.position,
|