ggaction 0.0.9 → 0.0.11
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 +84 -0
- package/README.md +5 -4
- package/knowledge/action-card.schema.json +1 -0
- package/knowledge/action-cards.json +1 -10941
- package/knowledge/action-cards.schema.json +1 -0
- package/knowledge/extension-authoring.md +248 -0
- package/knowledge/intent-taxonomy.json +1 -183
- package/knowledge/intent-taxonomy.schema.json +1 -0
- package/knowledge/mcp-resources.json +1 -95
- package/knowledge/mcp-resources.schema.json +1 -0
- package/knowledge/task-packet.schema.json +1 -159
- package/knowledge/task-resolver.js +1 -1230
- package/package.json +19 -2
- package/src/actions/boxPlots/edit.js +45 -298
- package/src/actions/boxPlots/options.js +46 -77
- package/src/actions/boxPlots/resolve.js +1 -1
- package/src/actions/charts/bar.js +3 -0
- package/src/actions/charts/heatmap.js +73 -83
- package/src/actions/charts/index.js +1 -1
- package/src/actions/charts/parallel.js +35 -1
- package/src/actions/charts/shared.js +20 -0
- package/src/actions/composition/actions.js +46 -49
- package/src/actions/data/bin2d.js +105 -2
- package/src/actions/data/box.js +17 -17
- package/src/actions/data/density.js +42 -78
- package/src/actions/data/gradientProfile.js +22 -52
- package/src/actions/data/horizon.js +16 -41
- package/src/actions/data/index.js +10 -10
- package/src/actions/data/interval.js +16 -38
- package/src/actions/data/intervalEdit.js +55 -0
- package/src/actions/data/regression.js +7 -17
- package/src/actions/data/shared.js +47 -0
- package/src/actions/data/timeUnit.js +14 -38
- package/src/actions/data/window.js +14 -38
- package/src/actions/distributions/revision.js +154 -34
- package/src/actions/encodings/angle.js +9 -10
- package/src/actions/encodings/appearance.js +17 -51
- package/src/actions/encodings/density/resolve.js +3 -1
- package/src/actions/encodings/density.js +1 -15
- package/src/actions/encodings/horizon/resolve.js +13 -3
- package/src/actions/encodings/horizon.js +8 -7
- package/src/actions/encodings/index.js +9 -9
- package/src/actions/encodings/offset.js +8 -24
- package/src/actions/encodings/parallel.js +9 -10
- package/src/actions/encodings/pathOrder.js +6 -13
- package/src/actions/encodings/position/policies/index.js +4 -4
- package/src/actions/encodings/position/policies/line.js +47 -17
- package/src/actions/encodings/position/resolve.js +24 -5
- package/src/actions/encodings/ranged.js +18 -23
- package/src/actions/encodings/remove.js +15 -25
- package/src/actions/encodings/ruleAppearance.js +9 -24
- package/src/actions/encodings/shared.js +37 -0
- package/src/actions/encodings/strokeDash.js +8 -23
- package/src/actions/encodings/text.js +9 -10
- package/src/actions/errorBands/create.js +105 -39
- package/src/actions/errorBands/edit.js +89 -93
- package/src/actions/errorBands/index.js +1 -2
- package/src/actions/errorBars/create.js +78 -27
- package/src/actions/errorBars/edit.js +81 -48
- package/src/actions/errorBars/index.js +1 -2
- package/src/actions/facets/actions.js +45 -69
- package/src/actions/facets/derive.js +38 -53
- package/src/actions/facets/replay.js +0 -1
- package/src/actions/gradientPlots/components.js +59 -48
- package/src/actions/gradientPlots/edit.js +35 -216
- package/src/actions/gradientPlots/index.js +11 -10
- package/src/actions/gradientPlots/materialize.js +21 -35
- package/src/actions/gradientPlots/options.js +5 -7
- package/src/actions/gradientPlots/paint.js +9 -6
- package/src/actions/gradientPlots/resolve.js +1 -1
- package/src/actions/guides/axes/index.js +3 -3
- package/src/actions/guides/axes/labels.js +68 -26
- package/src/actions/guides/axes/lines.js +22 -2
- package/src/actions/guides/axes/policy.js +28 -8
- package/src/actions/guides/axes/ticks.js +27 -9
- package/src/actions/guides/axes/titles.js +113 -65
- package/src/actions/guides/grids/resolve.js +14 -0
- package/src/actions/guides/guides.js +2 -4
- package/src/actions/guides/index.js +2 -2
- package/src/actions/guides/legends/categorical/actions.js +44 -68
- package/src/actions/guides/legends/categorical/components.js +6 -1
- package/src/actions/guides/legends/categorical/index.js +2 -2
- package/src/actions/guides/legends/categorical/layout.js +148 -175
- package/src/actions/guides/legends/categorical/recipes.js +5 -0
- package/src/actions/guides/legends/categorical/resolve.js +8 -1
- package/src/actions/guides/legends/continuous/common.js +117 -66
- package/src/actions/guides/legends/continuous/gradient.js +38 -37
- package/src/actions/guides/legends/continuous/interval.js +97 -76
- package/src/actions/guides/legends/continuous/opacity.js +28 -38
- package/src/actions/guides/legends/edit.js +14 -1
- package/src/actions/guides/legends/index.js +1 -1
- package/src/actions/guides/legends/lane.js +2 -1
- package/src/actions/guides/legends/remove.js +8 -0
- package/src/actions/guides/legends/size.js +36 -43
- package/src/actions/guides/legends/strokeWidth.js +20 -26
- package/src/actions/guides/polar/axes/labels.js +17 -1
- package/src/actions/guides/polar/axes/shared.js +7 -1
- package/src/actions/guides/polar/axes/titles.js +19 -2
- package/src/actions/guides/polar/grids.js +4 -0
- package/src/actions/guides/polar/resolve.js +6 -0
- package/src/actions/index.js +13 -13
- package/src/actions/intervals/resolve.js +87 -117
- package/src/actions/marks/arc/actions.js +31 -36
- package/src/actions/marks/area/actions.js +23 -31
- package/src/actions/marks/index.js +6 -6
- package/src/actions/marks/line/actions.js +33 -52
- package/src/actions/marks/line/materialize.js +7 -5
- package/src/actions/marks/point/materialize.js +5 -3
- package/src/actions/marks/remove.js +21 -0
- package/src/actions/marks/rule/actions.js +53 -53
- package/src/actions/marks/shared.js +8 -4
- package/src/actions/marks/text/actions.js +14 -6
- package/src/actions/marks/text/layout.js +21 -45
- package/src/actions/marks/tick/actions.js +22 -21
- package/src/actions/primitives/createGraphics.js +4 -0
- package/src/actions/primitives/editGraphics.js +4 -0
- package/src/actions/primitives/index.js +3 -3
- package/src/actions/primitives/semantic.js +1 -1
- package/src/actions/primitives/semanticValidation/index.js +2 -2
- package/src/actions/primitives/semanticValidation/layer.js +1 -1
- package/src/actions/regression/edit.js +3 -43
- package/src/actions/scales/consumers/families.js +24 -4
- package/src/actions/scales/consumers/index.js +1 -1
- package/src/actions/scales/consumers/seriesLayout.js +17 -0
- package/src/actions/scales/definitions.js +100 -103
- package/src/actions/scales/materialize.js +5 -0
- package/src/actions/selection/actions.js +79 -121
- package/src/actions/titles/actions.js +48 -94
- package/src/actions/titles/resolve.js +14 -27
- package/src/actions/violinPlots/create.js +37 -44
- package/src/core/action.js +20 -5
- package/src/core/extensionRegistry.js +104 -0
- package/src/core/textMetrics.js +74 -37
- package/src/core/validation.js +18 -0
- package/src/extension.js +8 -1
- package/src/grammar/aggregate.js +48 -28
- package/src/grammar/arcs.js +58 -11
- package/src/grammar/areaSeries.js +14 -16
- package/src/grammar/bin2d.js +37 -23
- package/src/grammar/boxPlot.js +14 -13
- package/src/grammar/categoricalDensity.js +14 -14
- package/src/grammar/categoryOrder.js +8 -14
- package/src/grammar/curveCommands.js +87 -20
- package/src/grammar/density.js +162 -141
- package/src/grammar/facets/index.js +14 -0
- package/src/grammar/facets/scales.js +7 -4
- package/src/grammar/gradientProfile.js +12 -15
- package/src/grammar/histogram.js +145 -83
- package/src/grammar/horizon.js +60 -23
- package/src/grammar/interval.js +14 -13
- package/src/grammar/lineSeries.js +91 -61
- package/src/grammar/numeric.js +290 -0
- package/src/grammar/paint.js +3 -4
- package/src/grammar/palettes.js +21 -32
- package/src/grammar/pathCommands.js +6 -0
- package/src/grammar/polarPaths.js +5 -5
- package/src/grammar/regression/derive.js +48 -9
- package/src/grammar/regression/models.js +248 -69
- package/src/grammar/regression/parameters.js +8 -0
- package/src/grammar/scales/color.js +35 -26
- package/src/grammar/scales/continuous.js +71 -24
- package/src/grammar/scales/definition.js +1 -1
- package/src/grammar/scales/discretized.js +42 -12
- package/src/grammar/scales/fields.js +21 -4
- package/src/grammar/scales/ordinal.js +117 -61
- package/src/grammar/scales/temporal.js +40 -11
- package/src/grammar/scales/transformed.js +199 -52
- package/src/grammar/schemas/graphicBounds.js +270 -79
- package/src/grammar/seriesLayout.js +50 -18
- package/src/grammar/ticks.js +123 -53
- package/src/grammar/timeUnit.js +18 -8
- package/src/grammar/transforms.js +4 -1
- package/src/grammar/window.js +70 -57
- package/src/index.js +1 -1
- package/src/layout/canvas.js +4 -8
- package/src/layout/composition.js +39 -40
- package/src/layout/facets.js +10 -14
- package/src/layout/labels.js +91 -15
- package/src/layout/legend.js +22 -20
- package/src/layout/legendLane.js +54 -40
- package/src/layout/title.js +7 -7
- package/src/materialization/bars/aggregate.js +14 -40
- package/src/materialization/bars/grouped.js +7 -18
- package/src/materialization/bars/histogram.js +2 -19
- package/src/materialization/bars/ranged.js +20 -15
- package/src/materialization/bars/resolve.js +21 -0
- package/src/materialization/facetGuides/legacyCategorical.js +2 -1
- package/src/materialization/facetGuides/placement.js +34 -19
- package/src/materialization/facetGuides/preparation.js +9 -5
- package/src/materialization/facets.js +39 -27
- package/src/materialization/guides/resources.js +2 -1
- package/src/materialization/marks/capabilities.js +5 -2
- package/src/materialization/marks/index.js +24 -4
- package/src/materialization/scales/policies/bar.js +61 -59
- package/src/materialization/scales/policies/binnedPosition.js +34 -0
- package/src/materialization/scales/policies/series.js +13 -7
- package/src/materialization/scales/resolve.js +4 -5
- package/src/materialization/selection/items/arc.js +16 -2
- package/src/materialization/selection/items/bar.js +4 -2
- package/src/materialization/selection/items/common.js +21 -1
- package/src/materialization/selection/items/path.js +19 -2
- package/src/materialization/selection/items/point.js +4 -16
- package/src/materialization/selection/items/tick.js +13 -21
- package/src/materialization/selection/point.js +11 -4
- package/src/materialization/selection/styles.js +19 -27
- package/src/materialization/text.js +4 -1
- package/src/mcp/adapter.js +8 -3
- package/src/renderers/canvas/fill.js +2 -2
- package/src/renderers/canvas/index.js +35 -2
- package/src/renderers/canvas/native.js +160 -0
- package/src/renderers/pdf.js +14 -0
- package/src/renderers/svg.js +37 -4
- package/types/extension.d.ts +19 -0
- package/types/index.d.ts +3 -0
- package/types/program.d.ts +509 -131
- package/types/svg.d.ts +1 -0
- package/src/actions/errorBands/components.js +0 -81
- package/src/actions/errorBands/options.js +0 -39
- package/src/actions/errorBands/resolve.js +0 -28
- package/src/actions/errorBars/components.js +0 -62
- package/src/actions/errorBars/options.js +0 -58
- package/src/actions/errorBars/resolve.js +0 -25
|
@@ -15,7 +15,7 @@ import { planDerivedDataRevision } from
|
|
|
15
15
|
import { validateOptions } from "./shared.js";
|
|
16
16
|
import { normalizeDensityPlacement } from "../../grammar/density.js";
|
|
17
17
|
import { scaleEditPatch } from "../scales/patch.js";
|
|
18
|
-
import {
|
|
18
|
+
import { removeOwnedColorLegends } from "../guides/legends/remove.js";
|
|
19
19
|
import {
|
|
20
20
|
requireDensityField,
|
|
21
21
|
resolveDensityCategoryScaleOptions,
|
|
@@ -215,19 +215,6 @@ function assertGroupingSelectionCompatibility(program, layer, changesGroup) {
|
|
|
215
215
|
}
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
-
function removeOwnedColorLegends(program, target) {
|
|
219
|
-
const kinds = Object.entries(program.guideConfigs.legend ?? {})
|
|
220
|
-
.filter(([kind, config]) =>
|
|
221
|
-
config?.target === target &&
|
|
222
|
-
(
|
|
223
|
-
config.channels?.includes("color") ||
|
|
224
|
-
["gradient", "interval"].includes(kind)
|
|
225
|
-
)
|
|
226
|
-
)
|
|
227
|
-
.map(([kind]) => kind);
|
|
228
|
-
return kinds.length === 0 ? program : removeLegendKinds(program, kinds);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
218
|
const editDensity = action(
|
|
232
219
|
{
|
|
233
220
|
op: "editDensity",
|
|
@@ -454,7 +441,6 @@ const editDensity = action(
|
|
|
454
441
|
}
|
|
455
442
|
return next;
|
|
456
443
|
};
|
|
457
|
-
applyEdit(this);
|
|
458
444
|
return applyEdit(this);
|
|
459
445
|
}
|
|
460
446
|
);
|
|
@@ -167,7 +167,11 @@ export function resolveHorizonPaletteColors(transform) {
|
|
|
167
167
|
for (const sign of ["negative", "positive"]) {
|
|
168
168
|
const palette = transform.palette[sign];
|
|
169
169
|
const dense = palette.count === undefined && transform.bands > 1
|
|
170
|
-
? resolvePalette(
|
|
170
|
+
? resolvePalette(
|
|
171
|
+
{ ...palette, count: transform.bands * 2 },
|
|
172
|
+
transform.bands * 2,
|
|
173
|
+
transform.bands * 2
|
|
174
|
+
)
|
|
171
175
|
: resolvePalette(palette, transform.bands);
|
|
172
176
|
const colors = palette.count === undefined && transform.bands > 1
|
|
173
177
|
? Array.from({ length: transform.bands }, (_, index) =>
|
|
@@ -181,11 +185,17 @@ export function resolveHorizonPaletteColors(transform) {
|
|
|
181
185
|
return { domain, range };
|
|
182
186
|
}
|
|
183
187
|
|
|
184
|
-
export function resolveFoldedHorizonScaleOptions(target, requested) {
|
|
188
|
+
export function resolveFoldedHorizonScaleOptions(target, requested, existing = {}) {
|
|
185
189
|
if (requested !== undefined && !isPlainObject(requested)) {
|
|
186
190
|
throw new TypeError("Horizon y scale must be a plain object.");
|
|
187
191
|
}
|
|
188
|
-
const
|
|
192
|
+
const patch = requested ?? {};
|
|
193
|
+
validateOptionObject(
|
|
194
|
+
patch,
|
|
195
|
+
["id", "type", "domain", "range", "clamp", "reverse"],
|
|
196
|
+
"Horizon y scale"
|
|
197
|
+
);
|
|
198
|
+
const options = { ...existing, ...patch };
|
|
189
199
|
if (
|
|
190
200
|
options.domain !== undefined &&
|
|
191
201
|
(!Array.isArray(options.domain) ||
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
deriveHorizon,
|
|
6
6
|
validateHorizonTransform
|
|
7
7
|
} from "../../grammar/horizon.js";
|
|
8
|
+
import { numericExtent } from "../../grammar/numeric.js";
|
|
8
9
|
import {
|
|
9
10
|
normalizeTemporalValue,
|
|
10
11
|
readQuantitativeField
|
|
@@ -217,7 +218,7 @@ const editHorizon = action(
|
|
|
217
218
|
id: currentX.id,
|
|
218
219
|
...(emptyXDomain === undefined
|
|
219
220
|
? {}
|
|
220
|
-
: { domain:
|
|
221
|
+
: { domain: numericExtent(emptyXDomain) }),
|
|
221
222
|
...(xTypeChanged && requestedXScale.type === undefined
|
|
222
223
|
? { type: x.fieldType === "temporal" ? "time" : "linear" }
|
|
223
224
|
: {})
|
|
@@ -233,11 +234,11 @@ const editHorizon = action(
|
|
|
233
234
|
if (requestedYScale.id !== undefined && requestedYScale.id !== currentY.id) {
|
|
234
235
|
throw new Error("editHorizon y scale cannot change its id.");
|
|
235
236
|
}
|
|
236
|
-
const nextY = resolveFoldedHorizonScaleOptions(
|
|
237
|
-
|
|
238
|
-
...requestedYScale,
|
|
239
|
-
|
|
240
|
-
|
|
237
|
+
const nextY = resolveFoldedHorizonScaleOptions(
|
|
238
|
+
layer.id,
|
|
239
|
+
{ ...requestedYScale, id: currentY.id },
|
|
240
|
+
currentY
|
|
241
|
+
);
|
|
241
242
|
next = applyScaleDefinition(next, currentY, nextY);
|
|
242
243
|
|
|
243
244
|
const colors = resolveHorizonPaletteColors(candidate);
|
|
@@ -314,7 +315,7 @@ const encodeHorizon = action(
|
|
|
314
315
|
: {})
|
|
315
316
|
};
|
|
316
317
|
if (Array.isArray(xScale.domain) && xScale.domain.length > 2) {
|
|
317
|
-
xScale.domain =
|
|
318
|
+
xScale.domain = numericExtent(xScale.domain);
|
|
318
319
|
}
|
|
319
320
|
const yScale = resolveFoldedHorizonScaleOptions(layer.id, y.scale);
|
|
320
321
|
const colors = resolveHorizonPaletteColors(transform);
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { registerAppearanceEncodingAction } from "./appearance.js";
|
|
2
|
-
import { registerAngleEncodingAction } from "./angle.js";
|
|
3
|
-
import { registerBarWidthEncodingAction } from "./barWidth.js";
|
|
4
|
-
import { registerColorEncodingAction } from "./color/index.js";
|
|
5
1
|
import { registerDensityEncodingAction } from "./density.js";
|
|
6
|
-
import { registerHistogramEncodingAction } from "./histogram.js";
|
|
7
|
-
import { registerHorizonEncodingAction } from "./horizon.js";
|
|
8
|
-
import { registerOffsetEncodingAction } from "./offset.js";
|
|
9
2
|
import { registerPathOrderEncodingActions } from "./pathOrder.js";
|
|
3
|
+
import { registerHorizonEncodingAction } from "./horizon.js";
|
|
4
|
+
import { registerHistogramEncodingAction } from "./histogram.js";
|
|
10
5
|
import { registerPositionEncodingActions } from "./position/index.js";
|
|
11
6
|
import { registerRangedEncodingActions } from "./ranged.js";
|
|
7
|
+
import { registerAngleEncodingAction } from "./angle.js";
|
|
8
|
+
import { registerOffsetEncodingAction } from "./offset.js";
|
|
9
|
+
import { registerParallelEncodingAction } from "./parallel.js";
|
|
10
|
+
import { registerColorEncodingAction } from "./color/index.js";
|
|
11
|
+
import { registerTextEncodingAction } from "./text.js";
|
|
12
|
+
import { registerAppearanceEncodingAction } from "./appearance.js";
|
|
12
13
|
import { registerStrokeDashEncodingActions } from "./strokeDash.js";
|
|
13
14
|
import { registerRuleAppearanceEncodingActions } from "./ruleAppearance.js";
|
|
14
|
-
import {
|
|
15
|
-
import { registerParallelEncodingAction } from "./parallel.js";
|
|
15
|
+
import { registerBarWidthEncodingAction } from "./barWidth.js";
|
|
16
16
|
import { registerEncodingRemovalAction } from "./remove.js";
|
|
17
17
|
|
|
18
18
|
export function registerEncodingActions(ProgramClass) {
|
|
@@ -6,8 +6,10 @@ import {
|
|
|
6
6
|
import { resolveOffsetScaleDefinition } from "../scales/definitions.js";
|
|
7
7
|
import {
|
|
8
8
|
applyEncodingScale,
|
|
9
|
+
rematerializeEncoding,
|
|
9
10
|
resolveReassignmentScaleOptions,
|
|
10
11
|
resolveTarget,
|
|
12
|
+
setEncodingProperties,
|
|
11
13
|
validateOptions
|
|
12
14
|
} from "./shared.js";
|
|
13
15
|
import {
|
|
@@ -16,8 +18,6 @@ import {
|
|
|
16
18
|
resolveBarGrain
|
|
17
19
|
} from "../../grammar/bars/policy.js";
|
|
18
20
|
import { normalizeOffsetPadding } from "../../grammar/bars/geometry.js";
|
|
19
|
-
import { applyMaterializationPlan } from "../../materialization/dependencies.js";
|
|
20
|
-
import { planEncodingRematerialization } from "../../materialization/encodings.js";
|
|
21
21
|
|
|
22
22
|
const ENCODING_OPTIONS = Object.freeze([
|
|
23
23
|
"field", "target", "fieldType", "scale", "paddingInner", "paddingOuter"
|
|
@@ -76,20 +76,11 @@ function createOffsetEncoding(channel) {
|
|
|
76
76
|
channel
|
|
77
77
|
);
|
|
78
78
|
|
|
79
|
-
let next = this
|
|
80
|
-
.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
.editSemantic({
|
|
85
|
-
property: `layer[${target}].encoding.${channel}.fieldType`,
|
|
86
|
-
value: fieldType
|
|
87
|
-
})
|
|
88
|
-
.editSemantic({
|
|
89
|
-
property: `layer[${target}].encoding.${channel}.scale`,
|
|
90
|
-
value: scale.id
|
|
91
|
-
})
|
|
92
|
-
._withMarkConfig(target, {
|
|
79
|
+
let next = setEncodingProperties(this, target, channel, {
|
|
80
|
+
field: args.field,
|
|
81
|
+
fieldType,
|
|
82
|
+
scale: scale.id
|
|
83
|
+
})._withMarkConfig(target, {
|
|
93
84
|
...this.markConfigs[target],
|
|
94
85
|
[channel]: padding
|
|
95
86
|
});
|
|
@@ -101,14 +92,7 @@ function createOffsetEncoding(channel) {
|
|
|
101
92
|
.rematerializeScale({ id: scale.id })
|
|
102
93
|
.editGraphics({ target, property: "length", value: 0 });
|
|
103
94
|
}
|
|
104
|
-
return
|
|
105
|
-
next,
|
|
106
|
-
planEncodingRematerialization(next, {
|
|
107
|
-
target,
|
|
108
|
-
channel,
|
|
109
|
-
scale: scale.id
|
|
110
|
-
})
|
|
111
|
-
);
|
|
95
|
+
return rematerializeEncoding(next, target, channel, scale.id);
|
|
112
96
|
}
|
|
113
97
|
);
|
|
114
98
|
}
|
|
@@ -7,7 +7,11 @@ import {
|
|
|
7
7
|
validateParallelRows
|
|
8
8
|
} from "../../grammar/parallelCoordinates.js";
|
|
9
9
|
import { resolvePositionScaleDefinition } from "../scales/definitions.js";
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
applyEncodingScale,
|
|
12
|
+
resolveTarget,
|
|
13
|
+
setEncodingProperties
|
|
14
|
+
} from "./shared.js";
|
|
11
15
|
import { resolveParallelCoordinate } from "../coordinates/parallel.js";
|
|
12
16
|
|
|
13
17
|
const OPTIONS = Object.freeze([
|
|
@@ -76,15 +80,10 @@ export const encodeParallelCoordinates = action(
|
|
|
76
80
|
value: coordinate.id
|
|
77
81
|
});
|
|
78
82
|
}
|
|
79
|
-
next = next
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
})
|
|
84
|
-
.editSemantic({
|
|
85
|
-
property: `layer[${target}].encoding.parallel.missing`,
|
|
86
|
-
value: missing
|
|
87
|
-
});
|
|
83
|
+
next = setEncodingProperties(next, target, "parallel", {
|
|
84
|
+
dimensions: storedDimensions,
|
|
85
|
+
missing
|
|
86
|
+
});
|
|
88
87
|
if (key === undefined && layer.encoding?.parallel?.key !== undefined) {
|
|
89
88
|
next = next.editSemantic({
|
|
90
89
|
property: `layer[${target}].encoding.parallel.key`,
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
canMaterializeLine
|
|
16
16
|
} from "../../materialization/marks/index.js";
|
|
17
17
|
import { findLayer } from "../../selectors/layers.js";
|
|
18
|
+
import { setEncodingProperties } from "./shared.js";
|
|
18
19
|
|
|
19
20
|
const ENCODE_OPTIONS = Object.freeze([
|
|
20
21
|
"target", "field", "fieldType", "order"
|
|
@@ -92,19 +93,11 @@ const encodePathOrder = action(
|
|
|
92
93
|
const dataset = assertPathOrderCompatible(this, layer, "encodePathOrder");
|
|
93
94
|
readQuantitativeField(dataset.values, field);
|
|
94
95
|
|
|
95
|
-
const next = this
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
.editSemantic({
|
|
101
|
-
property: `layer[${layer.id}].encoding.pathOrder.fieldType`,
|
|
102
|
-
value: fieldType
|
|
103
|
-
})
|
|
104
|
-
.editSemantic({
|
|
105
|
-
property: `layer[${layer.id}].encoding.pathOrder.order`,
|
|
106
|
-
value: order
|
|
107
|
-
});
|
|
96
|
+
const next = setEncodingProperties(this, layer.id, "pathOrder", {
|
|
97
|
+
field,
|
|
98
|
+
fieldType,
|
|
99
|
+
order
|
|
100
|
+
});
|
|
108
101
|
return rematerializePath(next, findLayer(next, layer.id));
|
|
109
102
|
}
|
|
110
103
|
);
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
"../../../../grammar/positionCompatibility.js";
|
|
1
|
+
import { resolveTickPositionPolicy } from "./tick.js";
|
|
3
2
|
import {
|
|
4
3
|
isCategoricalDensityPosition,
|
|
5
4
|
resolveAreaPositionPolicy
|
|
6
5
|
} from "./area.js";
|
|
7
|
-
import { resolveArcPositionPolicy } from "./arc.js";
|
|
8
6
|
import { resolveBarPositionPolicy } from "./bar.js";
|
|
9
7
|
import { resolveLinePositionPolicy } from "./line.js";
|
|
10
8
|
import { resolvePointPositionPolicy } from "./point.js";
|
|
11
9
|
import { resolveRulePositionPolicy } from "./rule.js";
|
|
12
|
-
import {
|
|
10
|
+
import { resolveArcPositionPolicy } from "./arc.js";
|
|
11
|
+
import { validatePositionFieldCompatibility } from
|
|
12
|
+
"../../../../grammar/positionCompatibility.js";
|
|
13
13
|
|
|
14
14
|
const POSITION_POLICIES = Object.freeze({
|
|
15
15
|
area: resolveAreaPositionPolicy,
|
|
@@ -2,17 +2,20 @@ import {
|
|
|
2
2
|
validateAggregate,
|
|
3
3
|
validateAggregateFieldType
|
|
4
4
|
} from "../../../../grammar/aggregate.js";
|
|
5
|
-
import { emptyPositionPolicy } from "./common.js";
|
|
5
|
+
import { emptyPositionPolicy, resolveBin } from "./common.js";
|
|
6
6
|
|
|
7
|
-
function
|
|
8
|
-
if (args.bin !== undefined) {
|
|
9
|
-
throw new Error(`Line ${channel} encoding does not support bin.`);
|
|
10
|
-
}
|
|
7
|
+
function rejectStack(args, channel) {
|
|
11
8
|
if (args.stack !== undefined) {
|
|
12
9
|
throw new Error(`Line ${channel} encoding does not support stack.`);
|
|
13
10
|
}
|
|
14
11
|
}
|
|
15
12
|
|
|
13
|
+
function rejectBin(args, channel) {
|
|
14
|
+
if (args.bin !== undefined) {
|
|
15
|
+
throw new Error(`Line ${channel} encoding does not support bin.`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
16
19
|
export function resolveLinePositionPolicy({
|
|
17
20
|
program,
|
|
18
21
|
layer,
|
|
@@ -27,7 +30,8 @@ export function resolveLinePositionPolicy({
|
|
|
27
30
|
if (config.curve !== undefined && config.curve !== "linear") {
|
|
28
31
|
throw new Error("Polar line position currently requires curve \"linear\".");
|
|
29
32
|
}
|
|
30
|
-
|
|
33
|
+
rejectBin(args, channel);
|
|
34
|
+
rejectStack(args, channel);
|
|
31
35
|
if (args.aggregate !== undefined) {
|
|
32
36
|
throw new Error(`Line ${channel} encoding does not support aggregate.`);
|
|
33
37
|
}
|
|
@@ -44,6 +48,26 @@ export function resolveLinePositionPolicy({
|
|
|
44
48
|
);
|
|
45
49
|
|
|
46
50
|
if (channel === "x") {
|
|
51
|
+
rejectStack(args, "x");
|
|
52
|
+
if (args.aggregate !== undefined) {
|
|
53
|
+
throw new Error("Line x encoding does not support aggregate.");
|
|
54
|
+
}
|
|
55
|
+
if (args.bin !== undefined) {
|
|
56
|
+
if (fieldType !== "quantitative") {
|
|
57
|
+
throw new Error("Binned line x encoding requires a quantitative field.");
|
|
58
|
+
}
|
|
59
|
+
if (
|
|
60
|
+
layer.encoding?.y !== undefined &&
|
|
61
|
+
layer.encoding.y.aggregate === undefined
|
|
62
|
+
) {
|
|
63
|
+
throw new Error("Binned line x encoding requires an aggregate y encoding.");
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
bin: resolveBin(args.bin),
|
|
67
|
+
aggregate: undefined,
|
|
68
|
+
stack: undefined
|
|
69
|
+
};
|
|
70
|
+
}
|
|
47
71
|
const directPair =
|
|
48
72
|
layer.encoding?.y?.aggregate === undefined &&
|
|
49
73
|
["quantitative", "temporal"].includes(layer.encoding?.y?.fieldType) &&
|
|
@@ -61,17 +85,18 @@ export function resolveLinePositionPolicy({
|
|
|
61
85
|
"Line x encoding requires a temporal field or a compatible derived quantitative field."
|
|
62
86
|
);
|
|
63
87
|
}
|
|
64
|
-
if (args.aggregate !== undefined) {
|
|
65
|
-
throw new Error("Line x encoding does not support aggregate.");
|
|
66
|
-
}
|
|
67
|
-
rejectSharedOptions(args, "x");
|
|
68
88
|
return emptyPositionPolicy();
|
|
69
89
|
}
|
|
70
90
|
|
|
71
|
-
|
|
91
|
+
rejectBin(args, "y");
|
|
92
|
+
rejectStack(args, "y");
|
|
93
|
+
if (layer.encoding?.x?.bin !== undefined && args.aggregate === undefined) {
|
|
94
|
+
throw new Error("Binned line x encoding requires an aggregate y encoding.");
|
|
95
|
+
}
|
|
72
96
|
const quantitativePair =
|
|
73
97
|
fieldType === "quantitative" &&
|
|
74
|
-
layer.encoding?.x?.fieldType === "quantitative"
|
|
98
|
+
layer.encoding?.x?.fieldType === "quantitative" &&
|
|
99
|
+
layer.encoding.x.bin === undefined;
|
|
75
100
|
const prospectiveDirect =
|
|
76
101
|
args.aggregate === undefined &&
|
|
77
102
|
(fieldType === "temporal" ||
|
|
@@ -98,11 +123,16 @@ export function resolveLinePositionPolicy({
|
|
|
98
123
|
return emptyPositionPolicy();
|
|
99
124
|
}
|
|
100
125
|
|
|
101
|
-
if (
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
126
|
+
if (layer.encoding?.x !== undefined) {
|
|
127
|
+
const compatibleAggregateX =
|
|
128
|
+
layer.encoding.x.fieldType === "temporal" ||
|
|
129
|
+
(layer.encoding.x.fieldType === "quantitative" &&
|
|
130
|
+
layer.encoding.x.bin !== undefined);
|
|
131
|
+
if (!compatibleAggregateX) {
|
|
132
|
+
throw new Error(
|
|
133
|
+
"Aggregate line y encoding requires a temporal or binned quantitative x encoding."
|
|
134
|
+
);
|
|
135
|
+
}
|
|
106
136
|
}
|
|
107
137
|
|
|
108
138
|
const aggregate = validateAggregate(args.aggregate);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { validateUserId } from "../../../core/identifiers.js";
|
|
2
2
|
import { getPositionCoordinateDefaults } from "../../../grammar/coordinates.js";
|
|
3
3
|
import {
|
|
4
|
+
isNominalValue,
|
|
4
5
|
readNominalField,
|
|
5
6
|
readQuantitativeField,
|
|
6
7
|
readScaleField,
|
|
@@ -33,6 +34,12 @@ const POSITION_ENCODING_OPTIONS = Object.freeze([
|
|
|
33
34
|
"aggregate", "bin", "stack", "weight"
|
|
34
35
|
]);
|
|
35
36
|
|
|
37
|
+
function inferRuleDatumFieldType(datum, operation) {
|
|
38
|
+
if (Number.isFinite(datum)) return "quantitative";
|
|
39
|
+
if (isNominalValue(datum)) return "nominal";
|
|
40
|
+
throw new Error(`${operation} datum requires an explicit fieldType.`);
|
|
41
|
+
}
|
|
42
|
+
|
|
36
43
|
function validateCoordinateFamily(layer, channel, operation) {
|
|
37
44
|
const family = getPositionChannelDefinition(channel).family;
|
|
38
45
|
const incompatible = positionChannelsForFamily(
|
|
@@ -96,7 +103,7 @@ export function resolvePositionEncoding(program, channel, args, operation) {
|
|
|
96
103
|
if (hasField === hasDatum) {
|
|
97
104
|
throw new Error(`${operation} requires exactly one of field or datum for a rule mark.`);
|
|
98
105
|
}
|
|
99
|
-
if (args.fieldType === undefined) {
|
|
106
|
+
if (hasField && args.fieldType === undefined) {
|
|
100
107
|
throw new Error(`${operation} requires fieldType for a rule mark.`);
|
|
101
108
|
}
|
|
102
109
|
} else if (hasDatum) {
|
|
@@ -104,10 +111,12 @@ export function resolvePositionEncoding(program, channel, args, operation) {
|
|
|
104
111
|
}
|
|
105
112
|
const previous = layer.encoding?.[channel];
|
|
106
113
|
const requestedFieldType = args.fieldType ?? previous?.fieldType ?? (
|
|
107
|
-
layer.mark.type === "
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
114
|
+
layer.mark.type === "rule" && hasDatum
|
|
115
|
+
? inferRuleDatumFieldType(args.datum, operation)
|
|
116
|
+
: layer.mark.type === "arc" && channel === "theta" &&
|
|
117
|
+
["count", "sum"].includes(args.aggregate)
|
|
118
|
+
? "nominal"
|
|
119
|
+
: "quantitative"
|
|
111
120
|
);
|
|
112
121
|
const fieldType = requestedFieldType === "nominal"
|
|
113
122
|
? "nominal"
|
|
@@ -169,6 +178,8 @@ export function resolvePositionEncoding(program, channel, args, operation) {
|
|
|
169
178
|
: fieldType === "temporal"
|
|
170
179
|
? { nice: true }
|
|
171
180
|
: { discreteType: "band" }
|
|
181
|
+
: layer.mark.type === "line" && channel === "x" && policy.bin !== undefined
|
|
182
|
+
? { nice: true, zero: false }
|
|
172
183
|
: ["ordinal", "nominal"].includes(fieldType)
|
|
173
184
|
? {
|
|
174
185
|
discreteType: ["arc", "rect"].includes(layer.mark.type)
|
|
@@ -177,6 +188,14 @@ export function resolvePositionEncoding(program, channel, args, operation) {
|
|
|
177
188
|
}
|
|
178
189
|
: {}
|
|
179
190
|
);
|
|
191
|
+
if (
|
|
192
|
+
layer.mark.type === "bar" &&
|
|
193
|
+
program.markConfigs[target]?.boxPlot === undefined &&
|
|
194
|
+
scale.type === "log" &&
|
|
195
|
+
policy.bin === undefined
|
|
196
|
+
) {
|
|
197
|
+
throw new Error('Bar scale type "log" does not support zero baselines.');
|
|
198
|
+
}
|
|
180
199
|
if (
|
|
181
200
|
layer.mark.type === "arc" &&
|
|
182
201
|
channel === "theta" &&
|
|
@@ -11,11 +11,13 @@ import {
|
|
|
11
11
|
import { normalizeRuleDatum } from "../../grammar/rules.js";
|
|
12
12
|
import {
|
|
13
13
|
canMaterializeArea,
|
|
14
|
-
canMaterializeLine
|
|
14
|
+
canMaterializeLine,
|
|
15
|
+
getPositionEncodingMaterializationSteps
|
|
15
16
|
} from "../../materialization/marks/index.js";
|
|
16
17
|
import { findLayer } from "../../selectors/layers.js";
|
|
17
18
|
import {
|
|
18
19
|
resolveTarget,
|
|
20
|
+
setEncodingProperties,
|
|
19
21
|
validateLineSeriesCompatibility,
|
|
20
22
|
validateOptions
|
|
21
23
|
} from "./shared.js";
|
|
@@ -138,28 +140,21 @@ function encodeSecondaryPosition(program, channel, args, operation, types) {
|
|
|
138
140
|
});
|
|
139
141
|
}
|
|
140
142
|
}
|
|
141
|
-
next = next
|
|
142
|
-
.
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
return layer.mark.type === "bar"
|
|
157
|
-
? next.rematerializeBarMark({ id: target })
|
|
158
|
-
: layer.mark.type === "rect"
|
|
159
|
-
? next.rematerializeRectMark({ id: target })
|
|
160
|
-
: canMaterializeArea(next, findLayer(next, target))
|
|
161
|
-
? next.rematerializeAreaMark({ id: target })
|
|
162
|
-
: next;
|
|
143
|
+
next = setEncodingProperties(next, target, channel, {
|
|
144
|
+
[hasField ? "field" : "datum"]: hasField ? args.field : args.datum,
|
|
145
|
+
fieldType,
|
|
146
|
+
scale: primary.scale
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
const updated = findLayer(next, target);
|
|
150
|
+
for (const step of getPositionEncodingMaterializationSteps(
|
|
151
|
+
next,
|
|
152
|
+
updated,
|
|
153
|
+
primary.scale
|
|
154
|
+
)) {
|
|
155
|
+
next = next[step.op](step.args);
|
|
156
|
+
}
|
|
157
|
+
return next;
|
|
163
158
|
}
|
|
164
159
|
|
|
165
160
|
const encodeX2 = action(
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
} from "../../materialization/marks/index.js";
|
|
17
17
|
import { findLayer } from "../../selectors/layers.js";
|
|
18
18
|
import { removeLegendKinds } from "../guides/legends/remove.js";
|
|
19
|
+
import { clearMarkGraphic } from "./shared.js";
|
|
19
20
|
|
|
20
21
|
const OPTIONS = Object.freeze(["target", "channel"]);
|
|
21
22
|
const REMOVABLE_CHANNELS = Object.freeze([
|
|
@@ -35,6 +36,10 @@ const SPECIALIZED_LEGEND_KIND = Object.freeze({
|
|
|
35
36
|
opacity: Object.freeze(["opacity"]),
|
|
36
37
|
strokeWidth: Object.freeze(["strokeWidth"])
|
|
37
38
|
});
|
|
39
|
+
const LEGEND_OPTION_KEYS = Object.freeze([
|
|
40
|
+
"position", "align", "direction", "columns", "offset", "titlePosition",
|
|
41
|
+
"title", "symbol", "labels", "titleStyle", "itemGap", "border"
|
|
42
|
+
]);
|
|
38
43
|
|
|
39
44
|
function resolveTarget(program, requested, channel) {
|
|
40
45
|
const candidates = program.semanticSpec.layers.filter(
|
|
@@ -178,22 +183,15 @@ function reconcileCategoricalLegend(program, target, channels) {
|
|
|
178
183
|
return removeLegendKinds(program, [kind]);
|
|
179
184
|
}
|
|
180
185
|
const next = removeLegendKinds(program, [kind]);
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
...(config.inferredTitle ? {} : { title: config.title }),
|
|
191
|
-
symbol: config.symbol,
|
|
192
|
-
labels: config.labels,
|
|
193
|
-
titleStyle: config.titleStyle,
|
|
194
|
-
itemGap: config.itemGap,
|
|
195
|
-
border: config.border
|
|
196
|
-
});
|
|
186
|
+
const options = { target, channels: remaining };
|
|
187
|
+
for (const property of LEGEND_OPTION_KEYS) {
|
|
188
|
+
if (
|
|
189
|
+
(property === "columns" && config[property] === undefined) ||
|
|
190
|
+
(property === "title" && config.inferredTitle)
|
|
191
|
+
) continue;
|
|
192
|
+
options[property] = config[property];
|
|
193
|
+
}
|
|
194
|
+
return next.createLegend(options);
|
|
197
195
|
}
|
|
198
196
|
|
|
199
197
|
function cleanupLegends(program, target, channels) {
|
|
@@ -204,18 +202,10 @@ function cleanupLegends(program, target, channels) {
|
|
|
204
202
|
return kinds.length === 0 ? next : removeLegendKinds(next, kinds);
|
|
205
203
|
}
|
|
206
204
|
|
|
207
|
-
function clearGraphic(program, target) {
|
|
208
|
-
const graphic = program.graphicSpec.objects[target];
|
|
209
|
-
if (graphic === undefined) return program;
|
|
210
|
-
return graphic.type === "collection"
|
|
211
|
-
? program.editGraphics({ target, property: "items", value: [] })
|
|
212
|
-
: program.editGraphics({ target, property: "length", value: 0 });
|
|
213
|
-
}
|
|
214
|
-
|
|
215
205
|
function rematerializeTarget(program, target) {
|
|
216
206
|
const layer = findLayer(program, target);
|
|
217
207
|
const step = getMarkMaterializationStep(program, layer);
|
|
218
|
-
const baseline =
|
|
208
|
+
const baseline = clearMarkGraphic(program, target);
|
|
219
209
|
let next = step === undefined
|
|
220
210
|
? baseline
|
|
221
211
|
: baseline[step.op](step.args);
|
|
@@ -7,12 +7,12 @@ import { readQuantitativeField } from "../../grammar/scales/index.js";
|
|
|
7
7
|
import { resolveStrokeWidthScaleDefinition } from "../scales/definitions.js";
|
|
8
8
|
import {
|
|
9
9
|
applyEncodingScale,
|
|
10
|
+
rematerializeEncoding,
|
|
10
11
|
resolveReassignmentScaleOptions,
|
|
11
12
|
resolveTarget,
|
|
13
|
+
setEncodingProperties,
|
|
12
14
|
validateOptions
|
|
13
15
|
} from "./shared.js";
|
|
14
|
-
import { applyMaterializationPlan } from "../../materialization/dependencies.js";
|
|
15
|
-
import { planEncodingRematerialization } from "../../materialization/encodings.js";
|
|
16
16
|
import { findLayer } from "../../selectors/layers.js";
|
|
17
17
|
|
|
18
18
|
const STROKE_OPTIONS = Object.freeze(["target", "value"]);
|
|
@@ -91,31 +91,16 @@ const encodeStrokeWidth = action(
|
|
|
91
91
|
const scale = resolveStrokeWidthScaleDefinition(this, requestedScale);
|
|
92
92
|
const { strokeWidth, ...config } = this.markConfigs[id] ?? {};
|
|
93
93
|
void strokeWidth;
|
|
94
|
-
let next =
|
|
95
|
-
._withMarkConfig(id, config)
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
.editSemantic({
|
|
101
|
-
property: `layer[${id}].encoding.strokeWidth.fieldType`,
|
|
102
|
-
value: fieldType
|
|
103
|
-
})
|
|
104
|
-
.editSemantic({
|
|
105
|
-
property: `layer[${id}].encoding.strokeWidth.scale`,
|
|
106
|
-
value: scale.id
|
|
107
|
-
});
|
|
94
|
+
let next = setEncodingProperties(
|
|
95
|
+
this._withMarkConfig(id, config),
|
|
96
|
+
id,
|
|
97
|
+
"strokeWidth",
|
|
98
|
+
{ field: args.field, fieldType, scale: scale.id }
|
|
99
|
+
);
|
|
108
100
|
next = applyEncodingScale(next, scale, requestedScale, {
|
|
109
101
|
reassignment: previous?.scale === scale.id
|
|
110
102
|
});
|
|
111
|
-
return
|
|
112
|
-
next,
|
|
113
|
-
planEncodingRematerialization(next, {
|
|
114
|
-
target: id,
|
|
115
|
-
channel: "strokeWidth",
|
|
116
|
-
scale: scale.id
|
|
117
|
-
})
|
|
118
|
-
);
|
|
103
|
+
return rematerializeEncoding(next, id, "strokeWidth", scale.id);
|
|
119
104
|
}
|
|
120
105
|
);
|
|
121
106
|
|