ggaction 0.0.21 → 0.0.22
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 +73 -0
- package/README.md +3 -2
- package/knowledge/action-cards.json +1 -1
- package/knowledge/intent-taxonomy.json +1 -1
- package/knowledge/mcp-resources.json +1 -1
- package/package.json +6 -2
- package/src/BasicChartProgram.js +1 -1
- package/src/accessibility.js +1 -0
- package/src/actions/boxPlots/components.js +1 -96
- package/src/actions/boxPlots/create.js +6 -1
- package/src/actions/boxPlots/edit.js +8 -0
- package/src/actions/boxPlots/materialize.js +3 -0
- package/src/actions/boxPlots/options.js +1 -1
- package/src/actions/canvas/actions.js +2 -1
- package/src/actions/canvas/index.js +3 -0
- package/src/actions/canvas/plotBorder.js +2 -1
- package/src/actions/canvas/plotOrder.js +14 -0
- package/src/actions/charts/area.js +1 -1
- package/src/actions/charts/bar.js +4 -4
- package/src/actions/charts/density.js +1 -1
- package/src/actions/charts/ecdf.js +1 -1
- package/src/actions/charts/endpoints.js +54 -5
- package/src/actions/charts/heatmap.js +1 -1
- package/src/actions/charts/histogram.js +1 -1
- package/src/actions/charts/horizon.js +1 -1
- package/src/actions/charts/index.js +2 -1
- package/src/actions/charts/interval-regression.js +1 -1
- package/src/actions/charts/line.js +1 -1
- package/src/actions/charts/radar.js +63 -3
- package/src/actions/charts/raincloud.js +37 -6
- package/src/actions/charts/rug-strip.js +2 -2
- package/src/actions/charts/scatter.js +3 -3
- package/src/actions/charts/text.js +1 -1
- package/src/actions/composition/actions.js +10 -3
- package/src/actions/coordinates/actions.js +2 -0
- package/src/actions/data/basic.js +6 -0
- package/src/actions/data/derived.js +6 -2
- package/src/actions/data/edit.js +21 -35
- package/src/actions/data/filter.js +1 -376
- package/src/actions/data/flatten.js +19 -0
- package/src/actions/data/index.js +6 -0
- package/src/actions/data/lookup.js +50 -0
- package/src/actions/data/raincloudFilter.js +56 -0
- package/src/actions/data/shared.js +10 -0
- package/src/actions/distributions/revision.js +3 -1
- package/src/actions/encodings/angle.js +2 -1
- package/src/actions/encodings/appearance.js +38 -13
- package/src/actions/encodings/channels.js +14 -3
- package/src/actions/encodings/color/continuous.js +26 -10
- package/src/actions/encodings/color/index.js +50 -20
- package/src/actions/encodings/color/policy.js +57 -4
- package/src/actions/encodings/parallel.js +4 -0
- package/src/actions/encodings/position/policies/bar.js +10 -6
- package/src/actions/encodings/position/policies/line.js +1 -152
- package/src/actions/encodings/position/resolve.js +4 -1
- package/src/actions/encodings/ranged.js +46 -0
- package/src/actions/encodings/remove.js +1 -1
- package/src/actions/encodings/ruleAppearance.js +7 -6
- package/src/actions/encodings/shared.js +14 -2
- package/src/actions/encodings/stroke.js +20 -14
- package/src/actions/encodings/strokeDash.js +9 -11
- package/src/actions/encodings/text.js +30 -2
- package/src/actions/errorBars/edit.js +24 -4
- package/src/actions/facets/actions.js +1 -793
- package/src/actions/facets/derive.js +34 -5
- package/src/actions/facets/replay.js +1 -38
- package/src/actions/gradientPlots/components.js +21 -9
- package/src/actions/gradientPlots/create.js +4 -2
- package/src/actions/gradientPlots/edit.js +18 -1
- package/src/actions/gradientPlots/materialize.js +35 -36
- package/src/actions/gradientPlots/options.js +1 -1
- package/src/actions/gradientPlots/paint.js +13 -7
- package/src/actions/guides/applicability.js +2 -0
- package/src/actions/guides/axes/axes.js +39 -0
- package/src/actions/guides/axes/axis.js +9 -5
- package/src/actions/guides/axes/edit.js +11 -8
- package/src/actions/guides/axes/labels.js +24 -8
- package/src/actions/guides/axes/parallel/policy.js +3 -5
- package/src/actions/guides/axes/parallel/resolve.js +4 -3
- package/src/actions/guides/axes/policy.js +22 -0
- package/src/actions/guides/axes/tickGroups.js +4 -2
- package/src/actions/guides/axes/ticks.js +22 -4
- package/src/actions/guides/axes/titles.js +19 -6
- package/src/actions/guides/facadeAxes.js +3 -0
- package/src/actions/guides/grids/grid.js +3 -1
- package/src/actions/guides/grids/resolve.js +7 -11
- package/src/actions/guides/guides.js +21 -1
- package/src/actions/guides/legends/categorical/actions.js +1 -515
- package/src/actions/guides/legends/categorical/layout.js +5 -2
- package/src/actions/guides/legends/categorical/options.js +4 -0
- package/src/actions/guides/legends/categorical/resolve.js +8 -3
- package/src/actions/guides/legends/categorical/symbols.js +3 -3
- package/src/actions/guides/legends/colorSize.js +2 -0
- package/src/actions/guides/legends/continuous/common.js +1 -1
- package/src/actions/guides/legends/continuous/gradient.js +1 -360
- package/src/actions/guides/legends/continuous/interval.js +1 -1
- package/src/actions/guides/legends/continuous/opacity.js +15 -1
- package/src/actions/guides/legends/edit.js +1 -1
- package/src/actions/guides/legends/focused.js +1 -1
- package/src/actions/guides/legends/lane.js +1 -1
- package/src/actions/guides/legends/sampling.js +1 -140
- package/src/actions/guides/legends/strokeWidth.js +3 -2
- package/src/actions/guides/legends/transition.js +19 -2
- package/src/actions/guides/polar/axes/facade.js +5 -4
- package/src/actions/guides/polar/axes/labels.js +5 -4
- package/src/actions/guides/polar/axes/titles.js +5 -4
- package/src/actions/guides/polar/resolve.js +2 -1
- package/src/actions/guides/tickValues.js +7 -7
- package/src/actions/marks/arc/actions.js +5 -7
- package/src/actions/marks/area/actions.js +9 -3
- package/src/actions/marks/bar/create.js +4 -2
- package/src/actions/marks/bar/edit.js +9 -6
- package/src/actions/marks/bar/materialize.js +5 -3
- package/src/actions/marks/dependentReferences.js +87 -0
- package/src/actions/marks/index.js +2 -0
- package/src/actions/marks/lifecycle.js +2 -1
- package/src/actions/marks/line/actions.js +24 -6
- package/src/actions/marks/line/materialize.js +7 -3
- package/src/actions/marks/point/create.js +5 -4
- package/src/actions/marks/point/edit.js +6 -3
- package/src/actions/marks/point/jitter.js +6 -6
- package/src/actions/marks/point/materialize.js +36 -39
- package/src/actions/marks/rect/actions.js +16 -4
- package/src/actions/marks/references.js +183 -35
- package/src/actions/marks/rule/actions.js +20 -9
- package/src/actions/marks/shared.js +2 -1
- package/src/actions/marks/text/actions.js +10 -3
- package/src/actions/marks/tick/actions.js +11 -2
- package/src/actions/primitives/editGraphics.js +28 -3
- package/src/actions/primitives/index.js +9 -0
- package/src/actions/primitives/semanticAction.js +13 -7
- package/src/actions/primitives/semanticValidation/layer.js +20 -0
- package/src/actions/primitives/semanticValidation/scale.js +8 -1
- package/src/actions/scales/channels.js +1 -1
- package/src/actions/scales/consumers/common.js +19 -1
- package/src/actions/scales/consumers/families.js +2 -2
- package/src/actions/scales/consumers/seriesLayout.js +4 -3
- package/src/actions/scales/edit.js +11 -0
- package/src/actions/scales/editPolicy.js +5 -3
- package/src/actions/scales/preview.js +2 -1
- package/src/actions/scales/quantitativeColor.js +2 -4
- package/src/actions/selection/actions.js +10 -1
- package/src/actions/theme/reconcile.js +37 -9
- package/src/core/compositionState.js +21 -4
- package/src/core/datasetReferences.js +17 -0
- package/src/core/immutable.js +1 -0
- package/src/core/resourceReferences.js +5 -3
- package/src/core/validation.js +4 -0
- package/src/core/vocabulary.js +24 -2
- package/src/grammar/aggregate.js +1 -0
- package/src/grammar/arcs.js +1 -1
- package/src/grammar/areaSeries.js +1 -1
- package/src/grammar/axisTextPlacement.js +1 -1
- package/src/grammar/bars/policy.js +2 -2
- package/src/grammar/datasetDependencies.js +97 -0
- package/src/grammar/datasetSchema.js +31 -1
- package/src/grammar/facetHeaders.js +1 -0
- package/src/grammar/facets/dependencies.js +6 -2
- package/src/grammar/facets/legendIntent.js +6 -2
- package/src/grammar/facets/scales.js +27 -7
- package/src/grammar/flatten.js +85 -0
- package/src/grammar/histogram.js +13 -1
- package/src/grammar/horizon.js +1 -494
- package/src/grammar/jitter.js +2 -2
- package/src/grammar/legendSpacing.js +45 -0
- package/src/grammar/lineMissing.js +90 -0
- package/src/grammar/lineSeries.js +1 -376
- package/src/grammar/lookup.js +97 -0
- package/src/grammar/markFilter.js +4 -2
- package/src/grammar/markLabels.js +8 -3
- package/src/grammar/numeric.js +1 -1
- package/src/grammar/pathCommands.js +1 -1
- package/src/grammar/pathSeries.js +1 -109
- package/src/grammar/pointPolygon.js +81 -0
- package/src/grammar/pointShapes.js +15 -15
- package/src/grammar/rects.js +1 -1
- package/src/grammar/regression/derive.js +1 -195
- package/src/grammar/scales/appearance.js +1 -1
- package/src/grammar/scales/color.js +1 -1
- package/src/grammar/scales/colorConsumers.js +1 -63
- package/src/grammar/scales/continuous.js +58 -1
- package/src/grammar/scales/definition.js +1 -1
- package/src/grammar/scales/ordinal.js +5 -2
- package/src/grammar/scales/policies.js +3 -3
- package/src/grammar/schemas/graphicBounds.js +40 -12
- package/src/grammar/schemas/graphicClip.js +23 -0
- package/src/grammar/schemas/graphicTree.js +16 -0
- package/src/grammar/statisticalReference.js +22 -0
- package/src/grammar/text.js +65 -1
- package/src/grammar/ticks.js +92 -1
- package/src/grammar/transformTopology.js +3 -1
- package/src/grammar/transforms.js +24 -0
- package/src/inspection.js +1 -495
- package/src/inspectionDescriptors.js +1 -1
- package/src/layout/canvas.js +1 -1
- package/src/layout/facetContentFlow.js +101 -0
- package/src/layout/facetHeaderTitles.js +1 -0
- package/src/layout/facetTopLane.js +29 -0
- package/src/layout/facets.js +1 -1
- package/src/layout/legendGroup.js +1 -1
- package/src/layout/legendItems.js +26 -10
- package/src/layout/legendSpacing.js +66 -0
- package/src/layout/plotDrawOrder.js +17 -0
- package/src/materialization/bars/histogram.js +8 -2
- package/src/materialization/bars/resolve.js +1 -1
- package/src/materialization/composition.js +1 -0
- package/src/materialization/compositionSnapshot.js +22 -2
- package/src/materialization/dataProvenance.js +1 -1
- package/src/materialization/facetGuides/layout.js +1 -1
- package/src/materialization/facetGuides/placement.js +23 -11
- package/src/materialization/facetGuides/preparation.js +43 -24
- package/src/materialization/facetHeaders.js +1 -1
- package/src/materialization/facetTopLane.js +25 -0
- package/src/materialization/facets.js +1 -1
- package/src/materialization/graphicHierarchy.js +5 -0
- package/src/materialization/graphicTranslation.js +2 -0
- package/src/materialization/guides/layout.js +1 -1
- package/src/materialization/guides/resources.js +1 -1
- package/src/materialization/legends.js +1 -1
- package/src/materialization/markClip.js +26 -0
- package/src/materialization/marks/capabilities.js +3 -2
- package/src/materialization/marks/grouping.js +7 -5
- package/src/materialization/marks/index.js +4 -2
- package/src/materialization/marks/policies.js +4 -0
- package/src/materialization/plotDrawOrder.js +44 -0
- package/src/materialization/rect.js +11 -3
- package/src/materialization/scaleGuideDependencies.js +13 -5
- package/src/materialization/selection/items/common.js +1 -1
- package/src/materialization/selection/items/path.js +1 -0
- package/src/materialization/selection/policies/index.js +2 -1
- package/src/materialization/text.js +10 -5
- package/src/mcp/cli.js +0 -0
- package/src/persistence/validation.js +108 -18
- package/src/persistence.js +4 -2
- package/src/renderers/canvas/index.js +16 -0
- package/src/renderers/canvas/isolated.js +11 -1
- package/src/renderers/canvas/native.js +7 -0
- package/src/renderers/canvas/scene.js +66 -0
- package/src/renderers/canvas/text.js +3 -2
- package/src/renderers/svg.js +1 -617
- package/src/renderers/svgSerialization.js +643 -0
- package/src/renderers/transitionScene.js +67 -0
- package/src/scene.js +89 -0
- package/src/selectors/axes.js +1 -1
- package/src/selectors/datasets.js +1 -0
- package/src/selectors/grids.js +9 -0
- package/src/selectors/markClip.js +28 -0
- package/src/selectors/raincloud.js +7 -0
- package/src/version.js +1 -1
- package/types/basic.d.ts +7 -0
- package/types/index.d.ts +8 -0
- package/types/program.d.ts +270 -60
- package/types/scene.d.ts +35 -0
|
@@ -2,6 +2,7 @@ import { action } from "../../core/action.js";
|
|
|
2
2
|
import { noOptions } from "../../core/validation.js";
|
|
3
3
|
import { resolveGraphicBounds } from "../../layout/canvas.js";
|
|
4
4
|
import { resolvePlotGraphicPlacement } from "../../materialization/graphicHierarchy.js";
|
|
5
|
+
import { hasPlotUnderlays } from "../../materialization/plotDrawOrder.js";
|
|
5
6
|
|
|
6
7
|
export const rematerializePlotBorder = /* @__PURE__ */ action(
|
|
7
8
|
{ op: "rematerializePlotBorder", description: "Materialize the optional inset plot border." },
|
|
@@ -23,6 +24,6 @@ export const rematerializePlotBorder = /* @__PURE__ */ action(
|
|
|
23
24
|
for (const [property, value] of Object.entries(properties)) {
|
|
24
25
|
next = next.editGraphics({ target: "plotBorder", property, value });
|
|
25
26
|
}
|
|
26
|
-
return next;
|
|
27
|
+
return hasPlotUnderlays(next) ? next.rematerializePlotDrawOrder() : next;
|
|
27
28
|
}
|
|
28
29
|
);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { action } from "../../core/action.js";
|
|
2
|
+
import { noOptions } from "../../core/validation.js";
|
|
3
|
+
import { resolveProgramPlotDrawOrder } from "../../materialization/plotDrawOrder.js";
|
|
4
|
+
|
|
5
|
+
export const rematerializePlotDrawOrder = action({
|
|
6
|
+
op: "rematerializePlotDrawOrder", description: "Reconcile explicit guide underlays without changing graphic content."
|
|
7
|
+
}, function (args = {}) {
|
|
8
|
+
noOptions(args, "rematerializePlotDrawOrder");
|
|
9
|
+
const plot = this.graphicSpec.objects["plot-main"];
|
|
10
|
+
if (this.compositionSpec !== undefined || plot === undefined) return this;
|
|
11
|
+
const children = resolveProgramPlotDrawOrder(this);
|
|
12
|
+
if (children.every((id, index) => id === plot.children[index])) return this;
|
|
13
|
+
return this.editGraphics({ target: "plot-main", property: "children", value: children });
|
|
14
|
+
});
|
|
@@ -33,7 +33,7 @@ export const createAreaPlot = /* @__PURE__ */ action({ op: OPERATION, descriptio
|
|
|
33
33
|
validateAreaEndpointPair(normalizeAreaBound(lower), normalizeAreaBound(upper));
|
|
34
34
|
const groupBy = args.groupBy === undefined ? undefined : normalizeGroupFields(args.groupBy);
|
|
35
35
|
const area = omitUndefinedOptions(normalizeAppearance(args.area, [
|
|
36
|
-
"fill", "opacity", "stroke", "strokeWidth", "curve",
|
|
36
|
+
"clip", "fill", "opacity", "stroke", "strokeWidth", "curve",
|
|
37
37
|
...STROKE_STYLE_PROPERTIES
|
|
38
38
|
], `${OPERATION} area`));
|
|
39
39
|
const color = args.color === undefined ? undefined : normalizeCategoricalColor(args.color, `${OPERATION} color`);
|
|
@@ -17,10 +17,10 @@ import {
|
|
|
17
17
|
} from "./shared.js";
|
|
18
18
|
|
|
19
19
|
const OPTIONS = Object.freeze([
|
|
20
|
-
"id", "data", "coordinate", "orientation", "x", "y", "color", "width", "bar", "guides"
|
|
20
|
+
"id", "data", "coordinate", "orientation", "x", "y", "color", "width", "bar", "missing", "guides"
|
|
21
21
|
]);
|
|
22
22
|
const BAR_OPTIONS = Object.freeze([
|
|
23
|
-
"fill", "opacity", "stroke", "strokeWidth", ...RECT_STYLE_PROPERTIES
|
|
23
|
+
"clip", "fill", "opacity", "stroke", "strokeWidth", ...RECT_STYLE_PROPERTIES
|
|
24
24
|
]);
|
|
25
25
|
|
|
26
26
|
function normalizeBarPosition(value, label) {
|
|
@@ -40,7 +40,7 @@ function normalizeBarPosition(value, label) {
|
|
|
40
40
|
export const createBarPlot = /* @__PURE__ */ action(
|
|
41
41
|
{
|
|
42
42
|
op: "createBarPlot",
|
|
43
|
-
description: "Create a Cartesian bar plot from existing chart data."
|
|
43
|
+
description: "Create a Cartesian bar plot, including interval-width X bins with Y aggregates, from existing chart data."
|
|
44
44
|
},
|
|
45
45
|
function (args = {}) {
|
|
46
46
|
validateFacadeOptions(args, OPTIONS, "createBarPlot");
|
|
@@ -74,7 +74,7 @@ export const createBarPlot = /* @__PURE__ */ action(
|
|
|
74
74
|
const positions = isBarCategoryEncoding(y) || orientation === "horizontal"
|
|
75
75
|
? [["encodeY", y], [xRange ? "encodeXRange" : "encodeX", x]]
|
|
76
76
|
: [["encodeX", x], [yRange ? "encodeYRange" : "encodeY", y]];
|
|
77
|
-
let next = this.createBarMark({ id, data, ...bar, ...(orientation === undefined ? {} : { orientation }) });
|
|
77
|
+
let next = this.createBarMark({ id, data, ...bar, ...(args.missing === undefined ? {} : { missing: args.missing }), ...(orientation === undefined ? {} : { orientation }) });
|
|
78
78
|
for (const [operation, encoding] of positions) {
|
|
79
79
|
next = next[operation](positionArgs(encoding, {
|
|
80
80
|
target: id, coordinate: args.coordinate
|
|
@@ -10,7 +10,7 @@ const OPERATION = "createDensityPlot";
|
|
|
10
10
|
const OPTIONS = ["id", "data", "coordinate", "field", "groupBy", "bandwidth", "extent", "steps",
|
|
11
11
|
"kernel", "normalization", "weight", "as", "densityChannel", "valueScale", "densityScale", "color", "area", "guides"];
|
|
12
12
|
const AREA_OPTIONS = [
|
|
13
|
-
"fill", "opacity", "stroke", "strokeWidth", "curve",
|
|
13
|
+
"clip", "fill", "opacity", "stroke", "strokeWidth", "curve",
|
|
14
14
|
...STROKE_STYLE_PROPERTIES
|
|
15
15
|
];
|
|
16
16
|
|
|
@@ -23,7 +23,7 @@ const EDIT_OPTIONS = Object.freeze([
|
|
|
23
23
|
"target", "data", "coordinate", "field", "groupBy", "weight", "missing", "as", "color"
|
|
24
24
|
]);
|
|
25
25
|
const LINE_OPTIONS = Object.freeze([
|
|
26
|
-
"strokeWidth", "stroke", "opacity", ...STROKE_STYLE_PROPERTIES
|
|
26
|
+
"clip", "strokeWidth", "stroke", "opacity", ...STROKE_STYLE_PROPERTIES
|
|
27
27
|
]);
|
|
28
28
|
const LABEL_OPTIONS = Object.freeze([
|
|
29
29
|
"field", "value", "content", "normalizeBy", "format", "layout", "fill",
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
validateNonNegativeFinite,
|
|
10
10
|
validateOptionObject
|
|
11
11
|
} from "../../core/validation.js";
|
|
12
|
+
import { retainStatisticalDependents, restoreStatisticalDependents } from "../marks/dependentReferences.js";
|
|
12
13
|
import { findDataset } from "../../selectors/datasets.js";
|
|
13
14
|
import { findSemanticScale } from "../../selectors/scales.js";
|
|
14
15
|
import {
|
|
@@ -33,14 +34,14 @@ const DUMBBELL_OPTIONS = Object.freeze([
|
|
|
33
34
|
const CATEGORY_OPTIONS = Object.freeze(["field", "fieldType", "scale"]);
|
|
34
35
|
const VALUE_OPTIONS = Object.freeze(["field", "fieldType", "scale"]);
|
|
35
36
|
const POINT_OPTIONS = Object.freeze([
|
|
36
|
-
"shape", "fill", "opacity", "stroke", "strokeWidth", "radius",
|
|
37
|
+
"clip", "shape", "fill", "opacity", "stroke", "strokeWidth", "radius",
|
|
37
38
|
...STROKE_STYLE_PROPERTIES
|
|
38
39
|
]);
|
|
39
40
|
const RULE_OPTIONS = Object.freeze([
|
|
40
|
-
"stroke", "strokeWidth", "strokeDash", "opacity", ...STROKE_STYLE_PROPERTIES
|
|
41
|
+
"clip", "stroke", "strokeWidth", "strokeDash", "opacity", ...STROKE_STYLE_PROPERTIES
|
|
41
42
|
]);
|
|
42
43
|
const LABEL_OPTIONS = Object.freeze([
|
|
43
|
-
"endpoint", "field", "value", "content", "normalizeBy", "format", "layout",
|
|
44
|
+
"clip", "endpoint", "field", "value", "content", "normalizeBy", "format", "layout",
|
|
44
45
|
"fill", "opacity", "fontSize", "fontFamily", "fontWeight", "align", "baseline",
|
|
45
46
|
"rotation", "dx", "dy"
|
|
46
47
|
]);
|
|
@@ -435,6 +436,49 @@ function reviseRequestedScales(program, ownerId, revised, changes) {
|
|
|
435
436
|
return next;
|
|
436
437
|
}
|
|
437
438
|
|
|
439
|
+
function reviseRoleGuideSamples(program, owner, current, revised, changes) {
|
|
440
|
+
const categoryAxis = current.orientation === "vertical" ? "x" : "y";
|
|
441
|
+
const valueAxis = categoryAxis === "x" ? "y" : "x";
|
|
442
|
+
const field = value => typeof value === "string" ? value : value?.field;
|
|
443
|
+
const axes = new Set();
|
|
444
|
+
for (const key of changes) {
|
|
445
|
+
if (["data", "orientation"].includes(key) && revised[key] !== current.options[key]) {
|
|
446
|
+
axes.add("x"); axes.add("y");
|
|
447
|
+
} else if (key === "category" &&
|
|
448
|
+
(field(revised.category) !== current.roles.category.field || revised.category?.scale)) {
|
|
449
|
+
axes.add(categoryAxis);
|
|
450
|
+
} else if (["value", "start", "end"].includes(key) &&
|
|
451
|
+
(field(revised[key]) !== current.roles[key]?.field || revised[key]?.scale) ||
|
|
452
|
+
["summary", "baseline"].includes(key) && revised[key] !== current.options[key]) {
|
|
453
|
+
axes.add(valueAxis);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
let next = program;
|
|
457
|
+
for (const axis of axes) {
|
|
458
|
+
const saved = revised.guides?.axes?.[axis]?.ticksAndLabels;
|
|
459
|
+
if (saved?.values) {
|
|
460
|
+
const { values, ...rest } = saved;
|
|
461
|
+
revised.guides = { ...revised.guides, axes: { ...revised.guides.axes,
|
|
462
|
+
[axis]: { ...revised.guides.axes[axis], ticksAndLabels: {
|
|
463
|
+
...rest, ...(axis === categoryAxis ? {} : { count: Math.max(2, values.length) })
|
|
464
|
+
} }
|
|
465
|
+
} };
|
|
466
|
+
}
|
|
467
|
+
const scale = owner.encoding[axis]?.scale;
|
|
468
|
+
for (const [id, config] of Object.entries(next.guideConfigs.axis ?? {})) {
|
|
469
|
+
if (config.ticks?.scale !== scale || config.ticks.mode !== "values") continue;
|
|
470
|
+
const refresh = part => {
|
|
471
|
+
if (axis === categoryAxis) return { ...part, inferredValues: true };
|
|
472
|
+
const { values, ...rest } = part;
|
|
473
|
+
return { ...rest, mode: "count", count: Math.max(2, values?.length ?? 5), inferredValues: false };
|
|
474
|
+
};
|
|
475
|
+
next = next._withGuideConfig(id, "ticks", refresh(config.ticks));
|
|
476
|
+
if (config.labels) next = next._withGuideConfig(id, "labels", refresh(config.labels));
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
return next;
|
|
480
|
+
}
|
|
481
|
+
|
|
438
482
|
export const editEndpointPlot = /* @__PURE__ */ action(
|
|
439
483
|
{ op: "editEndpointPlot", description: "Atomically revise an endpoint plot's semantic roles." },
|
|
440
484
|
function (args = {}) {
|
|
@@ -452,8 +496,13 @@ export const editEndpointPlot = /* @__PURE__ */ action(
|
|
|
452
496
|
}
|
|
453
497
|
const revised = { ...current.options };
|
|
454
498
|
for (const key of changes) revised[key] = args[key];
|
|
455
|
-
|
|
499
|
+
const axes = { fromAxis: current.orientation === "vertical" ? "y" : "x",
|
|
500
|
+
toAxis: revised.orientation === "vertical" ? "y" : "x" };
|
|
501
|
+
const retained = retainStatisticalDependents(this, owner.id);
|
|
502
|
+
let next = reviseRoleGuideSamples(retained.program, owner, current, revised, changes);
|
|
503
|
+
next = next.removeMark({ target: owner.id });
|
|
456
504
|
next = reviseRequestedScales(next, owner.id, revised, changes);
|
|
457
|
-
|
|
505
|
+
const rebuilt = next[KIND_METHOD[current.kind]](revised);
|
|
506
|
+
return restoreStatisticalDependents(rebuilt, retained.references, { ...axes, fallbackSource: owner.id });
|
|
458
507
|
}
|
|
459
508
|
);
|
|
@@ -23,7 +23,7 @@ const OPTIONS = [
|
|
|
23
23
|
"id", "data", "coordinate", "x", "y", "bin", "color", "rect", "guides"
|
|
24
24
|
];
|
|
25
25
|
const RECT_OPTIONS = [
|
|
26
|
-
"opacity", "stroke", "strokeWidth", ...RECT_STYLE_PROPERTIES
|
|
26
|
+
"clip", "opacity", "stroke", "strokeWidth", ...RECT_STYLE_PROPERTIES
|
|
27
27
|
];
|
|
28
28
|
const BIN_OPTIONS = [
|
|
29
29
|
"bins", "extent", "includeEmpty"
|
|
@@ -17,7 +17,7 @@ const OPTIONS = Object.freeze([
|
|
|
17
17
|
"binBoundaries", "stack", "xScale", "yScale", "weight", "color", "bar", "guides"
|
|
18
18
|
]);
|
|
19
19
|
const BAR_OPTIONS = Object.freeze([
|
|
20
|
-
"fill", "opacity", "stroke", "strokeWidth", ...RECT_STYLE_PROPERTIES
|
|
20
|
+
"clip", "fill", "opacity", "stroke", "strokeWidth", ...RECT_STYLE_PROPERTIES
|
|
21
21
|
]);
|
|
22
22
|
const HISTOGRAM_OPTIONS = Object.freeze([
|
|
23
23
|
"maxBins", "binStep", "binBoundaries", "stack", "xScale", "yScale", "weight"
|
|
@@ -52,7 +52,7 @@ export const createHorizonPlot = /* @__PURE__ */ action({
|
|
|
52
52
|
const { id: requestedId, data: requestedData, coordinate, x: requestedX, y: requestedY,
|
|
53
53
|
area: requestedArea, guides: requestedGuides, ...horizon } = omitUndefinedOptions(args);
|
|
54
54
|
const { opacity, ...area } = omitUndefinedOptions(normalizeAppearance(requestedArea,
|
|
55
|
-
["opacity", "stroke", "strokeWidth", "curve", ...STROKE_STYLE_PROPERTIES],
|
|
55
|
+
["clip", "opacity", "stroke", "strokeWidth", "curve", ...STROKE_STYLE_PROPERTIES],
|
|
56
56
|
`${OPERATION} area`));
|
|
57
57
|
for (const [key, value] of Object.entries({ ...horizon, ...area })) {
|
|
58
58
|
if (value === null) throw new TypeError(`${OPERATION} ${key} cannot be null.`);
|
|
@@ -11,7 +11,7 @@ import { createPiePlot } from "./pie.js";
|
|
|
11
11
|
import { createDensityPlot } from "./density.js";
|
|
12
12
|
import { createHorizonPlot } from "./horizon.js";
|
|
13
13
|
import { createPolarLinePlot, createPolarScatterPlot } from "./polar.js";
|
|
14
|
-
import { createRadarPlot } from "./radar.js";
|
|
14
|
+
import { createRadarPlot, editRadarPlot } from "./radar.js";
|
|
15
15
|
import { createRugPlot, createStripPlot } from "./rug-strip.js";
|
|
16
16
|
import { createIntervalPlot, createRegressionPlot } from "./interval-regression.js";
|
|
17
17
|
import {
|
|
@@ -38,6 +38,7 @@ export function registerChartActions(ProgramClass) {
|
|
|
38
38
|
ProgramClass.prototype.createPolarScatterPlot = createPolarScatterPlot;
|
|
39
39
|
ProgramClass.prototype.createPolarLinePlot = createPolarLinePlot;
|
|
40
40
|
ProgramClass.prototype.createRadarPlot = createRadarPlot;
|
|
41
|
+
ProgramClass.prototype.editRadarPlot = editRadarPlot;
|
|
41
42
|
ProgramClass.prototype.createRugPlot = createRugPlot;
|
|
42
43
|
ProgramClass.prototype.createStripPlot = createStripPlot;
|
|
43
44
|
ProgramClass.prototype.createIntervalPlot = createIntervalPlot;
|
|
@@ -19,7 +19,7 @@ const INTERVAL_OPTIONS = Object.freeze([
|
|
|
19
19
|
"color", "point", "errorBar", "guides"
|
|
20
20
|
]);
|
|
21
21
|
const POINT_OPTIONS = Object.freeze([
|
|
22
|
-
"shape", "fill", "opacity", "stroke", "strokeWidth", "radius",
|
|
22
|
+
"clip", "shape", "fill", "opacity", "stroke", "strokeWidth", "radius",
|
|
23
23
|
...STROKE_STYLE_PROPERTIES
|
|
24
24
|
]);
|
|
25
25
|
const ERROR_BAR_OPTIONS = Object.freeze([
|
|
@@ -20,7 +20,7 @@ const OPTIONS = Object.freeze([
|
|
|
20
20
|
"strokeDash", "line", "guides"
|
|
21
21
|
]);
|
|
22
22
|
const LINE_OPTIONS = Object.freeze([
|
|
23
|
-
"strokeWidth", "curve", "tension", "stroke", "opacity", "closed",
|
|
23
|
+
"clip", "missing", "strokeWidth", "curve", "tension", "stroke", "opacity", "closed",
|
|
24
24
|
...STROKE_STYLE_PROPERTIES
|
|
25
25
|
]);
|
|
26
26
|
|
|
@@ -7,6 +7,10 @@ import { normalizeGroupFields } from "../../grammar/pathSeries.js";
|
|
|
7
7
|
import { readNominalField, readQuantitativeField } from
|
|
8
8
|
"../../grammar/scales/fields.js";
|
|
9
9
|
import { findDataset } from "../../selectors/datasets.js";
|
|
10
|
+
import { resolveEligibleLayer } from "../../selectors/layers.js";
|
|
11
|
+
import { planDerivedDataRevision } from "../../materialization/dataProvenance.js";
|
|
12
|
+
import { applyLayerDataRematerialization } from "../../materialization/dependencies.js";
|
|
13
|
+
import { deriveFoldRows, normalizeFoldTransform } from "../../grammar/fold.js";
|
|
10
14
|
import {
|
|
11
15
|
normalizeAppearance,
|
|
12
16
|
normalizeEncoding,
|
|
@@ -76,13 +80,13 @@ function normalizeValue(value, operation) {
|
|
|
76
80
|
return { ...omitUndefinedOptions(result), fieldType: "quantitative" };
|
|
77
81
|
}
|
|
78
82
|
|
|
79
|
-
function normalizeWide(value, id, operation) {
|
|
83
|
+
function normalizeWide(value, id, operation, minimum = 3) {
|
|
80
84
|
if (!isPlainObject(value)) {
|
|
81
85
|
throw new TypeError(`${operation} wide must be a plain object.`);
|
|
82
86
|
}
|
|
83
87
|
validateOptionObject(value, WIDE_OPTIONS, `${operation} wide`);
|
|
84
|
-
if (!Array.isArray(value.fields) || value.fields.length <
|
|
85
|
-
throw new Error(`${operation} wide.fields must contain at least three fields.`);
|
|
88
|
+
if (!Array.isArray(value.fields) || value.fields.length < minimum) {
|
|
89
|
+
throw new Error(`${operation} wide.fields must contain at least ${minimum === 3 ? "three" : "two"} fields.`);
|
|
86
90
|
}
|
|
87
91
|
const fields = [...value.fields];
|
|
88
92
|
for (const field of fields) validateNonEmptyString(field, `${operation} wide field`);
|
|
@@ -303,3 +307,59 @@ export const createRadarPlot = /* @__PURE__ */ action(
|
|
|
303
307
|
});
|
|
304
308
|
}
|
|
305
309
|
);
|
|
310
|
+
|
|
311
|
+
export const editRadarPlot = /* @__PURE__ */ action(
|
|
312
|
+
{
|
|
313
|
+
op: "editRadarPlot",
|
|
314
|
+
description: "Revise a wide Radar plot's dimensions and order while preserving its series and appearance."
|
|
315
|
+
},
|
|
316
|
+
function (args = {}) {
|
|
317
|
+
const operation = "editRadarPlot";
|
|
318
|
+
validateFacadeOptions(args, ["target", "wide"], operation);
|
|
319
|
+
validateOptionObject(args.wide, ["fields"], `${operation} wide`);
|
|
320
|
+
const owner = resolveEligibleLayer(this, {
|
|
321
|
+
target: args.target,
|
|
322
|
+
label: "wide Radar plot",
|
|
323
|
+
predicate: layer => this.markConfigs[layer.id]?.compositionRole === "radar" &&
|
|
324
|
+
findDataset(this, layer.data)?.transform?.[0]?.type === "fold"
|
|
325
|
+
});
|
|
326
|
+
const previous = findDataset(this, owner.data);
|
|
327
|
+
const prior = previous.transform[0];
|
|
328
|
+
const source = findDataset(this, previous.source);
|
|
329
|
+
const wide = normalizeWide({ ...args.wide, as: prior.as }, owner.id, operation, 2);
|
|
330
|
+
for (const field of wide.fields) readQuantitativeField(source.values, field);
|
|
331
|
+
const transform = normalizeFoldTransform(wide, previous.id);
|
|
332
|
+
const rows = deriveFoldRows(source.values, transform);
|
|
333
|
+
const group = owner.encoding.group;
|
|
334
|
+
const groupBy = group?.fields ?? (group?.field ? [group.field] : []);
|
|
335
|
+
validateRadarRows(rows, { category: prior.as.key, value: prior.as.value,
|
|
336
|
+
groupBy, order: wide.fields }, operation);
|
|
337
|
+
const revision = planDerivedDataRevision(this, {
|
|
338
|
+
owner: owner.id, role: "RadarData", previous: previous.id, consumers: [owner.id]
|
|
339
|
+
});
|
|
340
|
+
let next = this.createFoldData({
|
|
341
|
+
id: revision.id, source: source.id, fields: wide.fields, as: prior.as
|
|
342
|
+
}).rebindLayerData(revision.rebinds[0]);
|
|
343
|
+
const theta = owner.encoding.theta.scale;
|
|
344
|
+
const revisedValues = config => {
|
|
345
|
+
const full = config.inferredValues || !Array.isArray(config.values) ||
|
|
346
|
+
config.values.length === prior.fields.length && prior.fields.every(field => config.values.includes(field));
|
|
347
|
+
const retained = full ? wide.fields : config.values.filter(field => wide.fields.includes(field));
|
|
348
|
+
return { ...config, mode: "values", values: retained.length ? retained : wide.fields };
|
|
349
|
+
};
|
|
350
|
+
for (const [id, axis] of Object.entries(next.semanticSpec.guides.axis ?? {})) {
|
|
351
|
+
if (axis.scale !== theta) continue;
|
|
352
|
+
for (const role of ["ticks", "labels"]) {
|
|
353
|
+
const config = next.guideConfigs.axis?.[id]?.[role];
|
|
354
|
+
if (config) next = next._withGuideConfig(id, role, revisedValues(config));
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
const thetaGrid = next.guideConfigs.grid?.theta;
|
|
358
|
+
if (thetaGrid?.scale === theta) next = next._withGridConfig("theta", revisedValues(thetaGrid));
|
|
359
|
+
next = next.editThetaScale({ target: owner.id, domain: wide.fields });
|
|
360
|
+
next = applyLayerDataRematerialization(next, owner.id);
|
|
361
|
+
if (next.markConfigs[owner.id]?.closed !== true) next = next.editLineMark({ target: owner.id, closed: true });
|
|
362
|
+
return next.releaseDerivedData(revision.release)
|
|
363
|
+
._withContext({ currentMark: owner.id, currentData: source.id });
|
|
364
|
+
}
|
|
365
|
+
);
|
|
@@ -5,6 +5,7 @@ import { validateOptionObject } from "../../core/validation.js";
|
|
|
5
5
|
import { findDataset } from "../../selectors/datasets.js";
|
|
6
6
|
import { findLayer } from "../../selectors/layers.js";
|
|
7
7
|
import { findSemanticScale } from "../../selectors/scales.js";
|
|
8
|
+
import { retainStatisticalDependents, restoreStatisticalDependents } from "../marks/dependentReferences.js";
|
|
8
9
|
import { resolveViolinRoles } from "../violinPlots/create.js";
|
|
9
10
|
import {
|
|
10
11
|
applyFacadeGuides,
|
|
@@ -111,6 +112,13 @@ function roleScale(encoding, fallbackId, label, defaults = {}) {
|
|
|
111
112
|
|
|
112
113
|
function normalizeColor(value, category, id) {
|
|
113
114
|
if (value === undefined || value === false) return undefined;
|
|
115
|
+
if (isPlainObject(value) && Object.hasOwn(value, "value")) {
|
|
116
|
+
validateOptionObject(value, ["value"], "Raincloud fixed color");
|
|
117
|
+
if (typeof value.value !== "string" || value.value.length === 0) {
|
|
118
|
+
throw new TypeError("Raincloud fixed color requires a non-empty value.");
|
|
119
|
+
}
|
|
120
|
+
return { value: value.value };
|
|
121
|
+
}
|
|
114
122
|
const color = normalizeEncoding(value, "Raincloud color");
|
|
115
123
|
if (color.field !== category.field) {
|
|
116
124
|
throw new Error("Raincloud color must encode its category field.");
|
|
@@ -194,6 +202,9 @@ function addSummary(program, config, positions) {
|
|
|
194
202
|
y: positions.y,
|
|
195
203
|
width: options.width ?? { band: 0.24 },
|
|
196
204
|
...options,
|
|
205
|
+
...(config.color?.value === undefined ? {} : {
|
|
206
|
+
box: { ...(options.box ?? {}), fill: config.color.value }
|
|
207
|
+
}),
|
|
197
208
|
guides: false
|
|
198
209
|
});
|
|
199
210
|
if (config.color !== undefined) next = next.encodeColor({ target: id, ...config.color });
|
|
@@ -238,7 +249,7 @@ function addPoints(program, config, positions) {
|
|
|
238
249
|
coordinate: config.coordinate,
|
|
239
250
|
x: positions.x,
|
|
240
251
|
y: positions.y,
|
|
241
|
-
...(config.color === undefined ? {} : { color: config.color }),
|
|
252
|
+
...(config.color?.field === undefined ? {} : { color: config.color }),
|
|
242
253
|
...(size === undefined ? {} : { size }),
|
|
243
254
|
...(shape === undefined ? {} : { shape }),
|
|
244
255
|
...(point === undefined ? {} : { point }),
|
|
@@ -274,7 +285,7 @@ function buildRaincloud(program, config) {
|
|
|
274
285
|
coordinate: config.coordinate,
|
|
275
286
|
x: positions.x,
|
|
276
287
|
y: positions.y,
|
|
277
|
-
...(config.color === undefined ? {} : { color: config.color }),
|
|
288
|
+
...(config.color?.field === undefined ? {} : { color: config.color }),
|
|
278
289
|
density: { ...density, side: densitySide(config.orientation, config.side) },
|
|
279
290
|
...(area === undefined ? {} : { area }),
|
|
280
291
|
guides: false
|
|
@@ -282,6 +293,11 @@ function buildRaincloud(program, config) {
|
|
|
282
293
|
}
|
|
283
294
|
next = addSummary(next, config, positions);
|
|
284
295
|
next = addPoints(next, config, positions);
|
|
296
|
+
if (config.color?.value !== undefined) {
|
|
297
|
+
for (const id of [config.childIds.cloud, config.childIds.points]) {
|
|
298
|
+
if (findLayer(next, id) !== undefined) next = next.encodeColor({ target: id, value: config.color.value });
|
|
299
|
+
}
|
|
300
|
+
}
|
|
285
301
|
const ownerId = [config.childIds.cloud, config.childIds.summary, config.childIds.points]
|
|
286
302
|
.find(id => findLayer(next, id) !== undefined);
|
|
287
303
|
if (ownerId === undefined) throw new Error("Raincloud requires at least one enabled component.");
|
|
@@ -395,11 +411,16 @@ export const editRaincloudPlot = /* @__PURE__ */ action(
|
|
|
395
411
|
}
|
|
396
412
|
const ownerId = raincloudOwner(this, args.target);
|
|
397
413
|
const current = this.markConfigs[ownerId].raincloudPlot;
|
|
414
|
+
const category = Object.hasOwn(args, "category") ? args.category : current.category;
|
|
415
|
+
const color = Object.hasOwn(args, "color") ? args.color
|
|
416
|
+
: Object.hasOwn(args, "category") && current.color?.field === current.category.field
|
|
417
|
+
? { ...current.color, field: normalizeEncoding(category, "Raincloud category").field }
|
|
418
|
+
: current.color;
|
|
398
419
|
const candidateArgs = {
|
|
399
420
|
id: current.id,
|
|
400
421
|
data: Object.hasOwn(args, "data") ? args.data : current.source,
|
|
401
422
|
...(current.coordinate === undefined ? {} : { coordinate: current.coordinate }),
|
|
402
|
-
category
|
|
423
|
+
category,
|
|
403
424
|
value: Object.hasOwn(args, "value") ? args.value : current.value,
|
|
404
425
|
orientation: args.orientation ?? current.orientation,
|
|
405
426
|
side: args.side ?? current.side,
|
|
@@ -412,11 +433,21 @@ export const editRaincloudPlot = /* @__PURE__ */ action(
|
|
|
412
433
|
points: Object.hasOwn(args, "points")
|
|
413
434
|
? normalizePoints(args.points, current.points)
|
|
414
435
|
: current.points,
|
|
415
|
-
color
|
|
436
|
+
color,
|
|
416
437
|
guides: current.guides
|
|
417
438
|
};
|
|
418
|
-
const
|
|
439
|
+
const axes = { fromAxis: current.orientation === "vertical" ? "y" : "x",
|
|
440
|
+
toAxis: candidateArgs.orientation === "vertical" ? "y" : "x" };
|
|
441
|
+
const retained = retainStatisticalDependents(this, ownerId);
|
|
442
|
+
const withoutCurrent = retained.program.removeMark({ target: ownerId });
|
|
419
443
|
const revised = normalizeCreate(withoutCurrent, candidateArgs, operation);
|
|
420
|
-
|
|
444
|
+
const rebuilt = buildRaincloud(alignExistingRoleScales(withoutCurrent, revised), {
|
|
445
|
+
...revised,
|
|
446
|
+
...(!Object.hasOwn(args, "data") && current.sourceFilter !== undefined
|
|
447
|
+
? { sourceFilter: current.sourceFilter } : {})
|
|
448
|
+
});
|
|
449
|
+
return restoreStatisticalDependents(rebuilt, retained.references, {
|
|
450
|
+
...axes, fallbackSource: raincloudOwner(rebuilt, current.id)
|
|
451
|
+
});
|
|
421
452
|
}
|
|
422
453
|
);
|
|
@@ -21,13 +21,13 @@ import {
|
|
|
21
21
|
const RUG_OPTIONS = Object.freeze(["id", "data", "coordinate", "x", "y", "edge", "tick", "guides"]);
|
|
22
22
|
const MEASURE_OPTIONS = Object.freeze(["field", "fieldType", "temporalUnit", "scale"]);
|
|
23
23
|
const TICK_OPTIONS = Object.freeze([
|
|
24
|
-
"length", "stroke", "strokeWidth", "opacity", ...STROKE_STYLE_PROPERTIES
|
|
24
|
+
"clip", "length", "stroke", "strokeWidth", "opacity", ...STROKE_STYLE_PROPERTIES
|
|
25
25
|
]);
|
|
26
26
|
const STRIP_OPTIONS = Object.freeze([
|
|
27
27
|
"id", "data", "coordinate", "x", "y", "color", "size", "shape", "point", "jitter", "guides"
|
|
28
28
|
]);
|
|
29
29
|
const POINT_OPTIONS = Object.freeze([
|
|
30
|
-
"radius", "shape", "fill", "opacity", "stroke", "strokeWidth",
|
|
30
|
+
"clip", "radius", "shape", "fill", "opacity", "stroke", "strokeWidth",
|
|
31
31
|
...STROKE_STYLE_PROPERTIES
|
|
32
32
|
]);
|
|
33
33
|
const JITTER_OPTIONS = Object.freeze(["maxOffset", "seed", "key"]);
|
|
@@ -17,10 +17,10 @@ import {
|
|
|
17
17
|
|
|
18
18
|
const OPTIONS = Object.freeze([
|
|
19
19
|
"id", "data", "coordinate", "x", "y", "color", "stroke", "size", "shape",
|
|
20
|
-
"point", "guides"
|
|
20
|
+
"point", "missing", "guides"
|
|
21
21
|
]);
|
|
22
22
|
const POINT_OPTIONS = Object.freeze([
|
|
23
|
-
"shape", "fill", "opacity", "stroke", "strokeWidth", "radius",
|
|
23
|
+
"clip", "shape", "fill", "opacity", "stroke", "strokeWidth", "radius",
|
|
24
24
|
...STROKE_STYLE_PROPERTIES
|
|
25
25
|
]);
|
|
26
26
|
|
|
@@ -62,7 +62,7 @@ export const createScatterPlot = /* @__PURE__ */ action(
|
|
|
62
62
|
const initialPoint = { ...point };
|
|
63
63
|
if (stroke !== undefined) delete initialPoint.strokeWidth;
|
|
64
64
|
let next = this
|
|
65
|
-
.createPointMark({ id, data, ...initialPoint })
|
|
65
|
+
.createPointMark({ id, data, ...initialPoint, ...(args.missing === undefined ? {} : { missing: args.missing }) })
|
|
66
66
|
.encodeX(positionArgs(x, { target: id, coordinate: args.coordinate }))
|
|
67
67
|
.encodeY(positionArgs(y, { target: id, coordinate: args.coordinate }));
|
|
68
68
|
if (radius !== undefined) next = next.encodePointRadius({ target: id, value: radius });
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from "./shared.js";
|
|
8
8
|
|
|
9
9
|
const OPTIONS = Object.freeze(["id", "data", "coordinate", "x", "y", "text", "color", "style", "guides"]);
|
|
10
|
-
const STYLE_OPTIONS = Object.freeze(["missing", ...TEXT_MARK_STYLE_OPTIONS.filter(key => key !== "inheritColor")]);
|
|
10
|
+
const STYLE_OPTIONS = Object.freeze(["clip", "missing", ...TEXT_MARK_STYLE_OPTIONS.filter(key => key !== "inheritColor")]);
|
|
11
11
|
|
|
12
12
|
export const createTextPlot = /* @__PURE__ */ action({
|
|
13
13
|
op: "createTextPlot", description: "Create a Cartesian text plot from existing chart data."
|
|
@@ -20,7 +20,7 @@ const CONCAT_OPTIONS = Object.freeze([
|
|
|
20
20
|
"id", "programs", "gap", "align", "padding"
|
|
21
21
|
]);
|
|
22
22
|
const LAYOUT_EDIT_OPTIONS = Object.freeze([
|
|
23
|
-
"columns", "gap", "spacing", "align", "padding"
|
|
23
|
+
"columns", "gap", "spacing", "topLane", "align", "padding"
|
|
24
24
|
]);
|
|
25
25
|
const REPLACEMENT_OPTIONS = Object.freeze(["target", "program"]);
|
|
26
26
|
const INSERTION_OPTIONS = Object.freeze(["id", "program", "before", "after"]);
|
|
@@ -181,6 +181,9 @@ const editCompositionLayout = /* @__PURE__ */ closedAction(
|
|
|
181
181
|
);
|
|
182
182
|
}
|
|
183
183
|
if (current.type !== "facet" && Object.hasOwn(args, "spacing")) throw new Error("Plot spacing requires a facet composition.");
|
|
184
|
+
if (current.type !== "facet" && Object.hasOwn(args, "topLane")) {
|
|
185
|
+
throw new Error("topLane requires a facet composition.");
|
|
186
|
+
}
|
|
184
187
|
const padding = Object.hasOwn(args, "padding")
|
|
185
188
|
? normalizeCompositionPadding(args.padding, current.padding)
|
|
186
189
|
: current.padding;
|
|
@@ -191,6 +194,7 @@ const editCompositionLayout = /* @__PURE__ */ closedAction(
|
|
|
191
194
|
);
|
|
192
195
|
layout = resolveFacetLayout({
|
|
193
196
|
spacing: option(args, "spacing", current.spacing),
|
|
197
|
+
topLane: args.topLane === undefined ? current.topLane : args.topLane,
|
|
194
198
|
plots: current.children.map(id => ({ id, ...resolveGraphicBounds(this.children[id]) })),
|
|
195
199
|
children: current.children.map((id, index) => ({
|
|
196
200
|
...childDescriptor({ id, program: this.children[id] }),
|
|
@@ -218,11 +222,14 @@ const editCompositionLayout = /* @__PURE__ */ closedAction(
|
|
|
218
222
|
padding
|
|
219
223
|
});
|
|
220
224
|
}
|
|
225
|
+
const { topLane: _previousTopLane, ...currentLayoutSpec } = current;
|
|
221
226
|
return applyCompositionState(this, {
|
|
222
227
|
children: this.children,
|
|
223
228
|
compositionSpec: {
|
|
224
|
-
...
|
|
225
|
-
...(current.type === "facet" ? { columns: layout.columns,
|
|
229
|
+
...currentLayoutSpec,
|
|
230
|
+
...(current.type === "facet" ? { columns: layout.columns,
|
|
231
|
+
...(layout.spacing !== undefined ? { spacing: layout.spacing } : current.spacing !== undefined ? { spacing: "canvas" } : {}),
|
|
232
|
+
...(layout.topLane === undefined ? {} : { topLane: layout.topLane }) } : {}),
|
|
226
233
|
gap: layout.gap,
|
|
227
234
|
align: layout.align,
|
|
228
235
|
padding: layout.padding
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { action } from "../../core/action.js";
|
|
2
|
+
import { validateMarkClipCoordinate } from "../../selectors/markClip.js";
|
|
2
3
|
import { validateCoordinateType } from "../../grammar/coordinates.js";
|
|
3
4
|
import { validateUserId } from "../../core/identifiers.js";
|
|
4
5
|
import { findCoordinate } from "../../selectors/coordinates.js";
|
|
@@ -51,6 +52,7 @@ export const createCoordinate = /* @__PURE__ */ action(
|
|
|
51
52
|
|
|
52
53
|
for (const layerId of layers) {
|
|
53
54
|
const layer = findLayer(this, layerId);
|
|
55
|
+
validateMarkClipCoordinate(this, layer, this.markConfigs[layerId]?.clip, type);
|
|
54
56
|
|
|
55
57
|
if (layer.coordinate !== undefined && layer.coordinate !== id) {
|
|
56
58
|
throw new Error(
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { createFlattenData, materializeFlattenData } from "./flatten.js";
|
|
2
|
+
import {createLookupData,materializeLookupData} from "./lookup.js";
|
|
1
3
|
import { createData } from "./create.js";
|
|
2
4
|
import { createDerivedData } from "./derived.js";
|
|
3
5
|
import { createBasicBin2DData } from "./basicBin2d.js";
|
|
@@ -5,6 +7,10 @@ import { materializeBin2DData } from "./bin2dMaterialize.js";
|
|
|
5
7
|
|
|
6
8
|
export function registerBasicDataActions(ProgramClass) {
|
|
7
9
|
ProgramClass.prototype.createData = createData;
|
|
10
|
+
ProgramClass.prototype.createFlattenData = createFlattenData;
|
|
11
|
+
ProgramClass.prototype.materializeFlattenData = materializeFlattenData;
|
|
12
|
+
ProgramClass.prototype.createLookupData=createLookupData;
|
|
13
|
+
ProgramClass.prototype.materializeLookupData=materializeLookupData;
|
|
8
14
|
ProgramClass.prototype.createDerivedData = createDerivedData;
|
|
9
15
|
ProgramClass.prototype.createBin2DData = createBasicBin2DData;
|
|
10
16
|
ProgramClass.prototype.materializeBin2DData = materializeBin2DData;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {resolveDatasetTransformInputs} from "./shared.js";
|
|
1
2
|
import { closedAction } from "../../core/action.js";
|
|
2
3
|
import { validateGraphicItemLimit } from "../../core/validation.js";
|
|
3
4
|
import { resolveGraphicItemCapacity } from "../../selectors/graphicCapacity.js";
|
|
@@ -49,11 +50,14 @@ export const createDerivedData = /* @__PURE__ */ closedAction(
|
|
|
49
50
|
if (!hasDataset(this, source)) {
|
|
50
51
|
throw new Error(`Unknown source dataset "${source}".`);
|
|
51
52
|
}
|
|
53
|
+
const transforms=args.transform?.[0]?.type==="lookup"
|
|
54
|
+
? [resolveDatasetTransformInputs(this,args.transform[0])]
|
|
55
|
+
: args.transform;
|
|
52
56
|
const created = this
|
|
53
57
|
.editSemantic({ property: `dataset[${id}].source`, value: source })
|
|
54
|
-
.editSemantic({ property: `dataset[${id}].transform`, value:
|
|
58
|
+
.editSemantic({ property: `dataset[${id}].transform`, value: transforms });
|
|
55
59
|
const input = resolveDatasetReference(created, source, "Source dataset");
|
|
56
|
-
const transform =
|
|
60
|
+
const transform = transforms[0];
|
|
57
61
|
assertFieldsAvailable(input.schema, transformInputFields(transform), {
|
|
58
62
|
data: input.id,
|
|
59
63
|
operation: "createDerivedData"
|