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
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { action } from "../../core/action.js";
|
|
2
|
+
import { validateUserId } from "../../core/identifiers.js";
|
|
3
|
+
import { validateOptionObject } from "../../core/validation.js";
|
|
4
|
+
import { normalizeCoordinateAspect } from "../../grammar/coordinates.js";
|
|
5
|
+
import { normalizePolarFrameOptions } from "../../grammar/polar.js";
|
|
6
|
+
import {
|
|
7
|
+
applyMaterializationPlan,
|
|
8
|
+
planCoordinateRematerialization
|
|
9
|
+
} from "../../materialization/dependencies.js";
|
|
10
|
+
import { requireCoordinate } from "../../selectors/coordinates.js";
|
|
11
|
+
|
|
12
|
+
const EDIT_COORDINATE_OPTIONS = Object.freeze(["target", "aspect", "polarFrame"]);
|
|
13
|
+
|
|
14
|
+
function applyCoordinatePatch(program, target, property, value) {
|
|
15
|
+
const coordinate = requireCoordinate(program, target);
|
|
16
|
+
if (value === "auto") {
|
|
17
|
+
return coordinate[property] === undefined
|
|
18
|
+
? program
|
|
19
|
+
: program.editSemantic({
|
|
20
|
+
property: `coordinate[${target}].${property}`,
|
|
21
|
+
remove: true
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
return program.editSemantic({
|
|
25
|
+
property: `coordinate[${target}].${property}`,
|
|
26
|
+
value
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const editCoordinate = action(
|
|
31
|
+
{
|
|
32
|
+
op: "editCoordinate",
|
|
33
|
+
description: "Edit coordinate layout constraints and rematerialize its consumers."
|
|
34
|
+
},
|
|
35
|
+
function (args = {}) {
|
|
36
|
+
validateOptionObject(args, EDIT_COORDINATE_OPTIONS, "editCoordinate", {
|
|
37
|
+
allowEmpty: false,
|
|
38
|
+
emptyMessage: "editCoordinate requires aspect or polarFrame changes.",
|
|
39
|
+
emptyError: Error
|
|
40
|
+
});
|
|
41
|
+
const target = validateUserId(args.target, "Coordinate id");
|
|
42
|
+
const coordinate = requireCoordinate(this, target);
|
|
43
|
+
const hasAspect = Object.hasOwn(args, "aspect");
|
|
44
|
+
const hasPolarFrame = Object.hasOwn(args, "polarFrame");
|
|
45
|
+
if (!hasAspect && !hasPolarFrame) {
|
|
46
|
+
throw new Error("editCoordinate requires aspect or polarFrame changes.");
|
|
47
|
+
}
|
|
48
|
+
const aspect = hasAspect ? normalizeCoordinateAspect(args.aspect) : undefined;
|
|
49
|
+
if (hasPolarFrame && coordinate.type !== "polar") {
|
|
50
|
+
throw new Error("editCoordinate polarFrame requires a Polar coordinate.");
|
|
51
|
+
}
|
|
52
|
+
const polarFrame = hasPolarFrame
|
|
53
|
+
? normalizePolarFrameOptions(args.polarFrame)
|
|
54
|
+
: undefined;
|
|
55
|
+
let proposed = this;
|
|
56
|
+
if (hasAspect) {
|
|
57
|
+
proposed = applyCoordinatePatch(proposed, target, "aspect", aspect);
|
|
58
|
+
}
|
|
59
|
+
if (hasPolarFrame) {
|
|
60
|
+
proposed = applyCoordinatePatch(
|
|
61
|
+
proposed,
|
|
62
|
+
target,
|
|
63
|
+
"polarFrame",
|
|
64
|
+
polarFrame
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
const plan = planCoordinateRematerialization(proposed, target);
|
|
68
|
+
// Validate the complete dependent geometry on a discarded immutable branch.
|
|
69
|
+
applyMaterializationPlan(proposed, plan);
|
|
70
|
+
return applyMaterializationPlan(proposed, plan);
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
export function registerCoordinateEditActions(ProgramClass) {
|
|
75
|
+
ProgramClass.prototype.editCoordinate = editCoordinate;
|
|
76
|
+
}
|
package/src/actions/data/bin.js
CHANGED
|
@@ -7,7 +7,7 @@ import { derivedCreator, derivedMaterializer } from "./shared.js";
|
|
|
7
7
|
|
|
8
8
|
const OPTIONS = Object.freeze([
|
|
9
9
|
"id", "source", "field", "maxBins", "step", "boundaries", "extent",
|
|
10
|
-
"nice", "zero", "includeEmpty", "members", "as"
|
|
10
|
+
"nice", "zero", "includeEmpty", "members", "as", "weight"
|
|
11
11
|
]);
|
|
12
12
|
|
|
13
13
|
export const materializeBinData = derivedMaterializer(
|
|
@@ -6,24 +6,28 @@ import {
|
|
|
6
6
|
normalizeBin2DTransform,
|
|
7
7
|
requestedBin2DTransform
|
|
8
8
|
} from "../../grammar/bin2d.js";
|
|
9
|
-
import { applyLayerDataRematerialization } from
|
|
10
|
-
"../../materialization/dependencies.js";
|
|
11
|
-
import { planDerivedDataRevision } from
|
|
12
|
-
"../../materialization/dataProvenance.js";
|
|
13
9
|
import {
|
|
14
10
|
findDataset,
|
|
15
|
-
|
|
11
|
+
resolveDatasetReference
|
|
16
12
|
} from "../../selectors/datasets.js";
|
|
17
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
normalizeDerivedDependentPolicy,
|
|
15
|
+
resolveDerivedDataOwner,
|
|
16
|
+
reviseDerivedData
|
|
17
|
+
} from "./edit.js";
|
|
18
|
+
import { normalizeDatasetTransformEdit } from "../../grammar/transforms.js";
|
|
18
19
|
export { materializeBin2DData } from "./bin2dMaterialize.js";
|
|
19
20
|
|
|
20
21
|
const OPTIONS = Object.freeze([
|
|
21
22
|
"id", "source", "x", "y", "bins", "extent", "includeEmpty", "members", "as"
|
|
22
23
|
]);
|
|
23
24
|
const EDIT_OPTIONS = Object.freeze([
|
|
24
|
-
"target", "source", "x", "y", "bins", "extent", "includeEmpty",
|
|
25
|
+
"target", "source", "x", "y", "bins", "extent", "includeEmpty",
|
|
26
|
+
"members", "as", "dependents"
|
|
25
27
|
]);
|
|
26
|
-
const EDITABLE = Object.freeze(EDIT_OPTIONS.
|
|
28
|
+
const EDITABLE = Object.freeze(EDIT_OPTIONS.filter(option =>
|
|
29
|
+
!["target", "dependents"].includes(option)
|
|
30
|
+
));
|
|
27
31
|
const OUTPUT_FIELDS = Object.freeze([
|
|
28
32
|
"x0", "x1", "y0", "y1", "count", "members"
|
|
29
33
|
]);
|
|
@@ -69,122 +73,6 @@ function requireCurrentBin2D(program, id, config) {
|
|
|
69
73
|
return current;
|
|
70
74
|
}
|
|
71
75
|
|
|
72
|
-
function directLayerConsumers(program, data) {
|
|
73
|
-
return program.semanticSpec.layers
|
|
74
|
-
.filter(layer => layer.data === data)
|
|
75
|
-
.map(layer => layer.id);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function outputFieldChanges(previous, next) {
|
|
79
|
-
return new Map(OUTPUT_FIELDS.flatMap(role => {
|
|
80
|
-
const from = previous.as[role];
|
|
81
|
-
const to = next.as[role];
|
|
82
|
-
return from !== undefined && from !== to
|
|
83
|
-
? [[from, [role, to]]]
|
|
84
|
-
: [];
|
|
85
|
-
}));
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function changedConsumerField(field, changes) {
|
|
89
|
-
const change = changes.get(field);
|
|
90
|
-
if (change === undefined) return field;
|
|
91
|
-
const [role, next] = change;
|
|
92
|
-
if (next === undefined) {
|
|
93
|
-
throw new Error(
|
|
94
|
-
`Cannot remove referenced 2D bin ${role} output field "${field}".`
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
return next;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function rebindLayerOutputFields(program, id, changes) {
|
|
101
|
-
const layer = requireLayer(program, id);
|
|
102
|
-
let next = program;
|
|
103
|
-
const changed = field => changedConsumerField(field, changes);
|
|
104
|
-
const editField = (property, field) => {
|
|
105
|
-
if (field === undefined) return;
|
|
106
|
-
const value = changed(field);
|
|
107
|
-
if (value !== field) next = next.editSemantic({ property, value });
|
|
108
|
-
};
|
|
109
|
-
for (const [channel, encoding] of Object.entries(layer.encoding ?? {})) {
|
|
110
|
-
editField(
|
|
111
|
-
`layer[${id}].encoding.${channel}.field`,
|
|
112
|
-
encoding?.field
|
|
113
|
-
);
|
|
114
|
-
const summary = encoding?.categoryOrder?.by;
|
|
115
|
-
if (summary?.field !== undefined) {
|
|
116
|
-
const field = changed(summary.field);
|
|
117
|
-
if (field !== summary.field) {
|
|
118
|
-
next = next.editSemantic({
|
|
119
|
-
property: `layer[${id}].encoding.${channel}.categoryOrder`,
|
|
120
|
-
value: { ...encoding.categoryOrder, by: { ...summary, field } }
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
editField(
|
|
126
|
-
`layer[${id}].encoding.theta.weight`,
|
|
127
|
-
layer.encoding?.theta?.weight
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
const parallel = layer.encoding?.parallel;
|
|
131
|
-
if (parallel?.dimensions !== undefined) {
|
|
132
|
-
const dimensions = parallel.dimensions.map(dimension => {
|
|
133
|
-
const field = changed(dimension.field);
|
|
134
|
-
return { ...dimension, field };
|
|
135
|
-
});
|
|
136
|
-
if (dimensions.some((dimension, index) =>
|
|
137
|
-
dimension.field !== parallel.dimensions[index].field
|
|
138
|
-
)) {
|
|
139
|
-
next = next.editSemantic({
|
|
140
|
-
property: `layer[${id}].encoding.parallel.dimensions`,
|
|
141
|
-
value: dimensions
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
editField(
|
|
146
|
-
`layer[${id}].encoding.parallel.key`,
|
|
147
|
-
parallel?.key
|
|
148
|
-
);
|
|
149
|
-
|
|
150
|
-
for (const [selectionId, config] of Object.entries(
|
|
151
|
-
program.materializationConfigs.selections ?? {}
|
|
152
|
-
)) {
|
|
153
|
-
if (config.target !== id) continue;
|
|
154
|
-
const selector = { ...config.selector };
|
|
155
|
-
if (selector.field !== undefined) {
|
|
156
|
-
selector.field = changed(selector.field);
|
|
157
|
-
}
|
|
158
|
-
if (selector.groupBy !== undefined) {
|
|
159
|
-
selector.groupBy = selector.groupBy.map(changed);
|
|
160
|
-
}
|
|
161
|
-
if (JSON.stringify(selector) !== JSON.stringify(config.selector)) {
|
|
162
|
-
next = next._withSelectionConfig(selectionId, { ...config, selector });
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const jitter = program.materializationConfigs.jitters?.[id];
|
|
167
|
-
const key = jitter?.key === undefined
|
|
168
|
-
? undefined
|
|
169
|
-
: changed(jitter.key);
|
|
170
|
-
if (key !== undefined && key !== jitter.key) {
|
|
171
|
-
next = next._withMaterializationConfig(
|
|
172
|
-
["jitters", id], { ...jitter, key }
|
|
173
|
-
);
|
|
174
|
-
}
|
|
175
|
-
return next;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
function rejectDerivedConsumers(program, data) {
|
|
179
|
-
const dependent = findDatasetConsumer(program, data);
|
|
180
|
-
if (dependent !== undefined) {
|
|
181
|
-
throw new Error(
|
|
182
|
-
`Cannot replace 2D bin dataset "${data}" while derived dataset ` +
|
|
183
|
-
`"${dependent.id}" depends on it.`
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
76
|
function preflight(program, sourceId, transform) {
|
|
189
77
|
const source = findDataset(program, sourceId);
|
|
190
78
|
if (source?.values === undefined) {
|
|
@@ -204,32 +92,18 @@ function requireCompleteEditOutputFields(value, members) {
|
|
|
204
92
|
}
|
|
205
93
|
|
|
206
94
|
function editedTransform(owner, previous, args) {
|
|
207
|
-
const
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
} else if (!members) {
|
|
218
|
-
delete as.members;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
const transform = normalizeBin2DTransform({
|
|
222
|
-
id: owner,
|
|
223
|
-
x: option("x"),
|
|
224
|
-
y: option("y"),
|
|
225
|
-
bins: option("bins"),
|
|
226
|
-
extent: option("extent"),
|
|
227
|
-
includeEmpty: option("includeEmpty"),
|
|
228
|
-
members,
|
|
229
|
-
as
|
|
230
|
-
});
|
|
95
|
+
const patch = Object.fromEntries(EDITABLE.flatMap(property =>
|
|
96
|
+
property !== "source" && Object.hasOwn(args, property)
|
|
97
|
+
? [[property, args[property]]]
|
|
98
|
+
: []
|
|
99
|
+
));
|
|
100
|
+
const transform = normalizeDatasetTransformEdit(
|
|
101
|
+
previous.transform[0],
|
|
102
|
+
patch,
|
|
103
|
+
owner
|
|
104
|
+
);
|
|
231
105
|
if (Object.hasOwn(args, "as")) {
|
|
232
|
-
requireCompleteEditOutputFields(args.as, members);
|
|
106
|
+
requireCompleteEditOutputFields(args.as, transform.members);
|
|
233
107
|
}
|
|
234
108
|
return transform;
|
|
235
109
|
}
|
|
@@ -238,29 +112,18 @@ function sameRequestedTransform(left, right) {
|
|
|
238
112
|
return JSON.stringify(left) === JSON.stringify(right);
|
|
239
113
|
}
|
|
240
114
|
|
|
241
|
-
function applyBin2DRevision(program, {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
115
|
+
function applyBin2DRevision(program, {
|
|
116
|
+
owner,
|
|
117
|
+
source,
|
|
118
|
+
transform,
|
|
119
|
+
dependents = "reject"
|
|
120
|
+
}) {
|
|
121
|
+
return reviseDerivedData(program, {
|
|
122
|
+
resolved: resolveDerivedDataOwner(program, owner, "bin2d"),
|
|
123
|
+
definition: transform,
|
|
124
|
+
dependents,
|
|
125
|
+
source
|
|
250
126
|
});
|
|
251
|
-
let next = program
|
|
252
|
-
.createDerivedData({ id: revision.id, source, transform: [transform] })
|
|
253
|
-
.materializeBin2DData({ id: revision.id });
|
|
254
|
-
for (const rebind of revision.rebinds) {
|
|
255
|
-
next = next.rebindLayerData(rebind);
|
|
256
|
-
next = rebindLayerOutputFields(next, rebind.id, changes);
|
|
257
|
-
next = applyLayerDataRematerialization(next, rebind.id);
|
|
258
|
-
}
|
|
259
|
-
next = next.releaseDerivedData(revision.release);
|
|
260
|
-
return next._withMaterializationConfig(
|
|
261
|
-
["data", "bin2d", owner],
|
|
262
|
-
{ current: revision.id }
|
|
263
|
-
);
|
|
264
127
|
}
|
|
265
128
|
|
|
266
129
|
export const createBin2DData = action(
|
|
@@ -275,10 +138,14 @@ export const createBin2DData = action(
|
|
|
275
138
|
const previous = config === undefined
|
|
276
139
|
? undefined
|
|
277
140
|
: requireCurrentBin2D(this, owner, config);
|
|
278
|
-
const source =
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
141
|
+
const source = resolveDatasetReference(
|
|
142
|
+
this,
|
|
143
|
+
validateUserId(
|
|
144
|
+
args.source ?? previous?.source ?? this.context.currentData,
|
|
145
|
+
"Source dataset id"
|
|
146
|
+
),
|
|
147
|
+
"Source dataset"
|
|
148
|
+
).id;
|
|
282
149
|
const transform = normalizeBin2DTransform({ ...args, id: owner });
|
|
283
150
|
preflight(this, source, transform);
|
|
284
151
|
|
|
@@ -313,10 +180,15 @@ export const editBin2DData = action(
|
|
|
313
180
|
}
|
|
314
181
|
const owner = resolveBin2DOwner(this, args.target);
|
|
315
182
|
const previous = requireCurrentBin2D(this, owner, ownerConfig(this, owner));
|
|
316
|
-
const
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
183
|
+
const dependents = normalizeDerivedDependentPolicy(args.dependents);
|
|
184
|
+
const source = resolveDatasetReference(
|
|
185
|
+
this,
|
|
186
|
+
validateUserId(
|
|
187
|
+
args.source ?? previous.source,
|
|
188
|
+
"2D bin source dataset id"
|
|
189
|
+
),
|
|
190
|
+
"2D bin source dataset"
|
|
191
|
+
).id;
|
|
320
192
|
const transform = editedTransform(owner, previous, args);
|
|
321
193
|
if (
|
|
322
194
|
source === previous.source &&
|
|
@@ -328,11 +200,11 @@ export const editBin2DData = action(
|
|
|
328
200
|
throw new Error("editBin2DData requires an actual transform or source change.");
|
|
329
201
|
}
|
|
330
202
|
preflight(this, source, transform);
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
203
|
+
return applyBin2DRevision(this, {
|
|
204
|
+
owner,
|
|
205
|
+
source,
|
|
206
|
+
transform,
|
|
207
|
+
dependents
|
|
208
|
+
});
|
|
337
209
|
}
|
|
338
210
|
);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {
|
|
2
|
+
deriveCompleteRows,
|
|
3
|
+
normalizeCompleteTransform
|
|
4
|
+
} from "../../grammar/complete.js";
|
|
5
|
+
import { derivedCreator, derivedMaterializer } from "./shared.js";
|
|
6
|
+
|
|
7
|
+
const OPTIONS = Object.freeze([
|
|
8
|
+
"id", "source", "key", "groupBy", "values", "sequence", "fill", "members"
|
|
9
|
+
]);
|
|
10
|
+
|
|
11
|
+
export const materializeCompleteData = derivedMaterializer(
|
|
12
|
+
"materializeCompleteData",
|
|
13
|
+
"Materialize one immutable completed-key dataset.",
|
|
14
|
+
"complete",
|
|
15
|
+
deriveCompleteRows
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
export const createCompleteData = derivedCreator(
|
|
19
|
+
"createCompleteData",
|
|
20
|
+
"Complete one key domain independently within observed groups.",
|
|
21
|
+
OPTIONS,
|
|
22
|
+
"Complete dataset id",
|
|
23
|
+
"Complete source dataset id",
|
|
24
|
+
normalizeCompleteTransform,
|
|
25
|
+
"materializeCompleteData"
|
|
26
|
+
);
|
|
@@ -8,14 +8,14 @@ const OPTIONS = Object.freeze(["id", "source", "as", "expression"]);
|
|
|
8
8
|
|
|
9
9
|
export const materializeComputedData = derivedMaterializer(
|
|
10
10
|
"materializeComputedData",
|
|
11
|
-
"Materialize one immutable row-level
|
|
11
|
+
"Materialize one immutable row-level typed expression dataset.",
|
|
12
12
|
"computed",
|
|
13
13
|
deriveComputedRows
|
|
14
14
|
);
|
|
15
15
|
|
|
16
16
|
export const createComputedData = derivedCreator(
|
|
17
17
|
"createComputedData",
|
|
18
|
-
"Create a
|
|
18
|
+
"Create a typed computed field from a closed expression.",
|
|
19
19
|
OPTIONS,
|
|
20
20
|
"Computed dataset id",
|
|
21
21
|
"Computed source dataset id",
|
|
@@ -2,7 +2,7 @@ import { action } from "../../core/action.js";
|
|
|
2
2
|
import { resolveOptionalUserId } from "../../core/identifiers.js";
|
|
3
3
|
import { isPlainObject } from "../../core/immutable.js";
|
|
4
4
|
import { validateKeys } from "../../core/validation.js";
|
|
5
|
-
import { hasDataset } from "../../selectors/index.js";
|
|
5
|
+
import { hasDataset, hasDatasetOwner } from "../../selectors/index.js";
|
|
6
6
|
|
|
7
7
|
const OPTIONS = Object.freeze(["id", "values"]);
|
|
8
8
|
|
|
@@ -22,7 +22,7 @@ export const createData = action(
|
|
|
22
22
|
if (!args.values.every(isPlainObject)) {
|
|
23
23
|
throw new TypeError("createData requires every row to be a plain object.");
|
|
24
24
|
}
|
|
25
|
-
if (hasDataset(this, id)) {
|
|
25
|
+
if (hasDataset(this, id) || hasDatasetOwner(this, id)) {
|
|
26
26
|
throw new Error(`Dataset "${id}" already exists.`);
|
|
27
27
|
}
|
|
28
28
|
return this.editSemantic({
|
|
@@ -1,28 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
deriveKernelDensity,
|
|
3
|
+
normalizeDensityTransform
|
|
4
|
+
} from "../../grammar/density.js";
|
|
2
5
|
import { derivedCreator, derivedMaterializer } from "./shared.js";
|
|
3
6
|
|
|
4
7
|
const OPTIONS = Object.freeze([
|
|
5
8
|
"id", "source", "field", "groupBy", "bandwidth", "extent", "steps",
|
|
6
|
-
"kernel", "normalization", "as"
|
|
9
|
+
"kernel", "normalization", "as", "weight"
|
|
7
10
|
]);
|
|
8
11
|
const CATEGORICAL_OPTIONS = Object.freeze([...OPTIONS, "placement"]);
|
|
9
12
|
|
|
10
|
-
function densityTransform(args, placement) {
|
|
11
|
-
return {
|
|
12
|
-
type: "density",
|
|
13
|
-
field: args.field,
|
|
14
|
-
...(args.groupBy === undefined ? {} : { groupBy: args.groupBy }),
|
|
15
|
-
bandwidth: args.bandwidth ?? "auto",
|
|
16
|
-
extent: args.extent ?? "auto",
|
|
17
|
-
steps: args.steps ?? 100,
|
|
18
|
-
kernel: args.kernel ?? "gaussian",
|
|
19
|
-
normalization: args.normalization ?? "unit",
|
|
20
|
-
as: args.as ?? [`${args.field}_value`, `${args.field}_density`],
|
|
21
|
-
resolve: "shared",
|
|
22
|
-
...(placement === undefined ? {} : { placement })
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
13
|
function requestedTransform(args, op, categorical = false) {
|
|
27
14
|
if (typeof args.field !== "string" || args.field.length === 0) {
|
|
28
15
|
throw new TypeError(`${op} requires a non-empty field string.`);
|
|
@@ -32,7 +19,10 @@ function requestedTransform(args, op, categorical = false) {
|
|
|
32
19
|
"createCategoricalDensityData requires normalized category placement."
|
|
33
20
|
);
|
|
34
21
|
}
|
|
35
|
-
return
|
|
22
|
+
return normalizeDensityTransform({
|
|
23
|
+
...args,
|
|
24
|
+
...(categorical ? { placement: args.placement } : {})
|
|
25
|
+
});
|
|
36
26
|
}
|
|
37
27
|
|
|
38
28
|
export const materializeDensityData = derivedMaterializer(
|
|
@@ -43,7 +33,9 @@ export const materializeDensityData = derivedMaterializer(
|
|
|
43
33
|
(result, transform) => [{
|
|
44
34
|
...transform,
|
|
45
35
|
resolved: {
|
|
46
|
-
|
|
36
|
+
...(result.bandwidth === undefined
|
|
37
|
+
? { bandwidths: result.bandwidths }
|
|
38
|
+
: { bandwidth: result.bandwidth }),
|
|
47
39
|
extent: result.extent,
|
|
48
40
|
...(result.splitDomain === undefined
|
|
49
41
|
? {}
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { action } from "../../core/action.js";
|
|
2
2
|
import { validateUserId } from "../../core/identifiers.js";
|
|
3
3
|
import { validateKeys } from "../../core/validation.js";
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import {
|
|
5
|
+
findDataset,
|
|
6
|
+
hasDataset,
|
|
7
|
+
hasDatasetOwner,
|
|
8
|
+
resolveDatasetReference
|
|
9
|
+
} from "../../selectors/datasets.js";
|
|
6
10
|
import { requireLayer } from "../../selectors/layers.js";
|
|
7
11
|
import { applyLayerDataRematerialization } from
|
|
8
12
|
"../../materialization/dependencies.js";
|
|
13
|
+
import { collectResourceReferences } from "../../core/resourceReferences.js";
|
|
9
14
|
|
|
10
15
|
const OPTIONS = Object.freeze(["id", "source", "transform"]);
|
|
11
16
|
const RELEASE_OPTIONS = Object.freeze(["id"]);
|
|
@@ -18,7 +23,8 @@ const OWNED_MARK_ROLES = Object.freeze([
|
|
|
18
23
|
"errorBar",
|
|
19
24
|
"gradientPlot",
|
|
20
25
|
"ecdfPlot",
|
|
21
|
-
"regression"
|
|
26
|
+
"regression",
|
|
27
|
+
"statisticalReference"
|
|
22
28
|
]);
|
|
23
29
|
|
|
24
30
|
export const createDerivedData = action(
|
|
@@ -26,8 +32,13 @@ export const createDerivedData = action(
|
|
|
26
32
|
function (args = {}) {
|
|
27
33
|
validateKeys(args, OPTIONS, "createDerivedData");
|
|
28
34
|
const id = validateUserId(args.id, "Derived dataset id");
|
|
29
|
-
const
|
|
30
|
-
|
|
35
|
+
const requestedSource = validateUserId(args.source, "Source dataset id");
|
|
36
|
+
const source = resolveDatasetReference(
|
|
37
|
+
this,
|
|
38
|
+
requestedSource,
|
|
39
|
+
"Source dataset"
|
|
40
|
+
).id;
|
|
41
|
+
if (hasDataset(this, id) || hasDatasetOwner(this, id)) {
|
|
31
42
|
throw new Error(`Dataset "${id}" already exists.`);
|
|
32
43
|
}
|
|
33
44
|
if (!hasDataset(this, source)) {
|
|
@@ -51,17 +62,26 @@ export const releaseDerivedData = action(
|
|
|
51
62
|
if (dataset === undefined || dataset.source === undefined) {
|
|
52
63
|
throw new Error(`Unknown derived dataset "${validatedId}".`);
|
|
53
64
|
}
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
65
|
+
const references = collectResourceReferences(this, {
|
|
66
|
+
kind: "data",
|
|
67
|
+
id: validatedId
|
|
68
|
+
});
|
|
69
|
+
const selfOwners = references.filter(reference =>
|
|
70
|
+
reference.ownerKind === "dataOwner" &&
|
|
71
|
+
reference.path.at(-1) === "current"
|
|
58
72
|
);
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
73
|
+
if (references.some(reference =>
|
|
74
|
+
reference.strength === "live" && !selfOwners.includes(reference)
|
|
75
|
+
)) return this;
|
|
76
|
+
let next = this.editSemantic({
|
|
77
|
+
property: `dataset[${validatedId}]`,
|
|
78
|
+
remove: true
|
|
79
|
+
});
|
|
80
|
+
for (const owner of selfOwners) {
|
|
81
|
+
const [, family, ownerId] = owner.path;
|
|
82
|
+
next = next._withoutMaterializationConfig(["data", family, ownerId]);
|
|
83
|
+
}
|
|
84
|
+
return next;
|
|
65
85
|
}
|
|
66
86
|
);
|
|
67
87
|
|
|
@@ -73,7 +93,12 @@ export const rebindLayerData = action(
|
|
|
73
93
|
function (args = {}) {
|
|
74
94
|
validateKeys(args, REBIND_OPTIONS, "rebindLayerData");
|
|
75
95
|
const id = validateUserId(args.id, "Layer id");
|
|
76
|
-
const
|
|
96
|
+
const requestedData = validateUserId(args.data, "Layer dataset id");
|
|
97
|
+
const data = resolveDatasetReference(
|
|
98
|
+
this,
|
|
99
|
+
requestedData,
|
|
100
|
+
"Layer dataset"
|
|
101
|
+
).id;
|
|
77
102
|
requireLayer(this, id);
|
|
78
103
|
if (!hasDataset(this, data)) {
|
|
79
104
|
throw new Error(`Layer dataset "${data}" does not exist.`);
|
|
@@ -117,7 +142,12 @@ export const bindMarkData = action(
|
|
|
117
142
|
function (args = {}) {
|
|
118
143
|
validateKeys(args, BIND_OPTIONS, "bindMarkData");
|
|
119
144
|
const target = validateUserId(args.target, "Mark target id");
|
|
120
|
-
const
|
|
145
|
+
const requestedData = validateUserId(args.data, "Mark dataset id");
|
|
146
|
+
const data = resolveDatasetReference(
|
|
147
|
+
this,
|
|
148
|
+
requestedData,
|
|
149
|
+
"Mark dataset"
|
|
150
|
+
).id;
|
|
121
151
|
const layer = requireLayer(this, target);
|
|
122
152
|
const dataset = findDataset(this, data);
|
|
123
153
|
if (dataset === undefined) {
|