ggaction 0.0.17 → 0.0.19
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 +96 -0
- package/README.md +6 -2
- package/knowledge/action-card.schema.json +1 -1
- package/knowledge/action-cards.json +1 -1
- package/knowledge/intent-taxonomy.json +1 -1
- package/knowledge/mcp-resources.json +1 -1
- package/knowledge/task-resolver.js +1 -1
- package/package.json +3 -3
- package/src/BasicChartProgram.js +1 -1
- package/src/accessibility.js +3 -2
- package/src/actions/boxPlots/create.js +14 -4
- package/src/actions/boxPlots/edit.js +39 -33
- package/src/actions/boxPlots/materialize.js +7 -3
- package/src/actions/boxPlots/options.js +37 -11
- package/src/actions/canvas/actions.js +70 -95
- package/src/actions/canvas/fitting.js +20 -1
- package/src/actions/canvas/index.js +3 -0
- package/src/actions/canvas/plotBorder.js +28 -0
- package/src/actions/charts/area.js +2 -2
- package/src/actions/charts/bar.js +34 -7
- package/src/actions/charts/ecdf.js +4 -18
- package/src/actions/charts/endpoints.js +4 -18
- package/src/actions/charts/heatmap.js +8 -7
- package/src/actions/charts/index.js +2 -0
- package/src/actions/charts/interval-regression.js +2 -2
- package/src/actions/charts/line.js +1 -1
- package/src/actions/charts/pie.js +3 -47
- package/src/actions/charts/radial.js +34 -12
- package/src/actions/charts/scatter.js +16 -2
- package/src/actions/charts/shared.js +2 -2
- package/src/actions/charts/text.js +35 -0
- package/src/actions/composition/actions.js +6 -2
- package/src/actions/data/box.js +2 -1
- package/src/actions/data/derived.js +11 -1
- package/src/actions/data/edit.js +3 -1
- package/src/actions/data/index.js +4 -0
- package/src/actions/data/regression.js +25 -16
- package/src/actions/data/regressionStatistics.js +73 -0
- package/src/actions/data/shared.js +8 -4
- package/src/actions/data/stack.js +3 -1
- package/src/actions/distributions/revision.js +24 -18
- package/src/actions/encodings/appearance.js +37 -29
- package/src/actions/encodings/barWidth.js +36 -11
- package/src/actions/encodings/channels.js +0 -1
- package/src/actions/encodings/color/continuous.js +1 -1
- package/src/actions/encodings/color/index.js +1 -1
- package/src/actions/encodings/color/policy.js +10 -3
- package/src/actions/encodings/density/resolve.js +1 -6
- package/src/actions/encodings/position/policies/arc.js +12 -10
- package/src/actions/encodings/position/policies/area.js +3 -3
- package/src/actions/encodings/position/policies/bar.js +15 -6
- package/src/actions/encodings/position/policies/line.js +17 -6
- package/src/actions/encodings/position/resolve.js +3 -2
- package/src/actions/encodings/ranged.js +17 -0
- package/src/actions/encodings/remove.js +14 -8
- package/src/actions/encodings/seriesLayout.js +1 -0
- package/src/actions/encodings/shared.js +26 -24
- package/src/actions/encodings/text.js +6 -3
- package/src/actions/errorBands/create.js +2 -2
- package/src/actions/errorBands/edit.js +2 -1
- package/src/actions/facets/actions.js +176 -247
- package/src/actions/facets/guides.js +2 -1
- package/src/actions/gradientPlots/resolve.js +2 -17
- package/src/actions/guides/applicability.js +1 -1
- package/src/actions/guides/axes/axes.js +30 -11
- package/src/actions/guides/axes/axis.js +72 -10
- package/src/actions/guides/axes/components.js +13 -13
- package/src/actions/guides/axes/edit.js +36 -24
- package/src/actions/guides/axes/labels.js +155 -71
- package/src/actions/guides/axes/lines.js +27 -24
- package/src/actions/guides/axes/parallel/lifecycle.js +1 -1
- package/src/actions/guides/axes/parallel/policy.js +8 -7
- package/src/actions/guides/axes/remove.js +13 -8
- package/src/actions/guides/axes/tickGroups.js +11 -7
- package/src/actions/guides/axes/ticks.js +36 -24
- package/src/actions/guides/axes/titles.js +107 -69
- package/src/actions/guides/basic.js +2 -0
- package/src/actions/guides/facadeAxes.js +33 -24
- package/src/actions/guides/facadeLegend.js +12 -4
- package/src/actions/guides/grids/grid.js +8 -2
- package/src/actions/guides/grids/resolve.js +102 -58
- package/src/actions/guides/legends/blocks.js +46 -20
- package/src/actions/guides/legends/categorical/actions.js +95 -19
- package/src/actions/guides/legends/categorical/components.js +15 -18
- package/src/actions/guides/legends/categorical/index.js +8 -0
- package/src/actions/guides/legends/categorical/layout.js +45 -20
- package/src/actions/guides/legends/categorical/options.js +39 -22
- package/src/actions/guides/legends/categorical/recipes.js +7 -3
- package/src/actions/guides/legends/categorical/resolve.js +11 -4
- package/src/actions/guides/legends/categorical/symbols.js +38 -18
- package/src/actions/guides/legends/categorical/validation.js +1 -6
- package/src/actions/guides/legends/colorSize.js +110 -0
- package/src/actions/guides/legends/combine.js +37 -0
- package/src/actions/guides/legends/continuous/colorSymbols.js +1 -0
- package/src/actions/guides/legends/continuous/common.js +1 -447
- package/src/actions/guides/legends/continuous/gradient.js +73 -46
- package/src/actions/guides/legends/continuous/interval.js +4 -4
- package/src/actions/guides/legends/continuous/opacity.js +33 -21
- package/src/actions/guides/legends/creation.js +2 -0
- package/src/actions/guides/legends/edit.js +1 -604
- package/src/actions/guides/legends/focused.js +8 -7
- package/src/actions/guides/legends/group.js +1 -0
- package/src/actions/guides/legends/lane.js +1 -516
- package/src/actions/guides/legends/lifecycle.js +2 -1
- package/src/actions/guides/legends/remove.js +9 -3
- package/src/actions/guides/legends/sampling.js +1 -1
- package/src/actions/guides/legends/size.js +65 -47
- package/src/actions/guides/legends/strokeWidth.js +13 -29
- package/src/actions/guides/legends/target.js +2 -79
- package/src/actions/guides/legends/transition.js +44 -11
- package/src/actions/guides/polar/axes/labels.js +4 -2
- package/src/actions/guides/polar/axes/titles.js +7 -5
- package/src/actions/guides/polar/resolve.js +6 -14
- package/src/actions/guides/tickValues.js +8 -5
- package/src/actions/index.js +16 -16
- package/src/actions/marks/arc/actions.js +3 -10
- package/src/actions/marks/area/actions.js +8 -5
- package/src/actions/marks/area/materialize.js +8 -9
- package/src/actions/marks/bar/create.js +10 -4
- package/src/actions/marks/bar/edit.js +29 -14
- package/src/actions/marks/bar/materialize.js +15 -7
- package/src/actions/marks/line/actions.js +11 -4
- package/src/actions/marks/line/materialize.js +9 -5
- package/src/actions/marks/point/edit.js +1 -1
- package/src/actions/marks/point/materialize.js +5 -1
- package/src/actions/marks/rect/actions.js +3 -3
- package/src/actions/marks/remove.js +12 -10
- package/src/actions/marks/rule/actions.js +7 -4
- package/src/actions/marks/text/actions.js +17 -5
- package/src/actions/marks/text/layout.js +3 -0
- package/src/actions/primitives/createGraphics.js +3 -2
- package/src/actions/primitives/editGraphics.js +15 -11
- package/src/actions/primitives/graphicProperties.js +1 -6
- package/src/actions/primitives/semanticAction.js +27 -1
- package/src/actions/primitives/semanticValidation/guide.js +11 -1
- package/src/actions/primitives/semanticValidation/layer.js +8 -0
- package/src/actions/regression/create.js +1 -1
- package/src/actions/regression/edit.js +18 -6
- package/src/actions/regression/resolve.js +2 -6
- package/src/actions/scales/channels.js +9 -4
- package/src/actions/scales/consumers/families.js +16 -5
- package/src/actions/scales/create.js +10 -5
- package/src/actions/scales/definitions.js +1 -425
- package/src/actions/scales/edit.js +3 -3
- package/src/actions/scales/editPolicy.js +12 -3
- package/src/actions/scales/materialize.js +1 -1
- package/src/actions/scales/patch.js +1 -1
- package/src/actions/scales/preview.js +21 -1
- package/src/actions/scales/quantitativeColor.js +8 -3
- package/src/actions/selection/actions.js +1 -13
- package/src/actions/theme/reconcile.js +126 -45
- package/src/actions/theme/state.js +12 -0
- package/src/actions/titles/actions.js +5 -18
- package/src/actions/titles/resolve.js +41 -19
- package/src/actions/violinPlots/edit.js +3 -20
- package/src/core/compositionState.js +6 -3
- package/src/core/font.js +9 -2
- package/src/core/graphicProperties.js +1 -0
- package/src/core/optionRequirements.js +1 -0
- package/src/core/programState.js +4 -0
- package/src/core/resourceReferences.js +5 -2
- package/src/core/textMetricProfile.js +3 -2
- package/src/core/textMetrics.js +41 -4
- package/src/core/validation.js +35 -0
- package/src/core/vocabulary.js +7 -0
- package/src/grammar/aggregate.js +4 -18
- package/src/grammar/arcs.js +1 -386
- package/src/grammar/areaPaint.js +10 -0
- package/src/grammar/areaSeries.js +18 -10
- package/src/grammar/axisTextPlacement.js +1 -0
- package/src/grammar/bars/geometry.js +30 -3
- package/src/grammar/bars/policy.js +12 -1
- package/src/grammar/bin.js +2 -12
- package/src/grammar/bin2d.js +1 -6
- package/src/grammar/boxPlot.js +56 -9
- package/src/grammar/categoryOrder.js +1 -6
- package/src/grammar/colorSizeLegend.js +39 -0
- package/src/grammar/complete.js +15 -19
- package/src/grammar/computed.js +115 -26
- package/src/grammar/curveCommands.js +29 -16
- package/src/grammar/datasetSchema.js +13 -9
- package/src/grammar/displayLabels.js +36 -0
- package/src/grammar/ecdf.js +2 -9
- package/src/grammar/facets/dependencies.js +6 -2
- package/src/grammar/facets/guides.js +58 -30
- package/src/grammar/facets/index.js +2 -5
- package/src/grammar/facets/legendIntent.js +65 -0
- package/src/grammar/fold.js +2 -12
- package/src/grammar/gradientProfile.js +1 -6
- package/src/grammar/guideDash.js +1 -0
- package/src/grammar/impute.js +21 -48
- package/src/grammar/interval.js +2 -9
- package/src/grammar/legendBlocks.js +1 -0
- package/src/grammar/legendBorder.js +9 -0
- package/src/grammar/legendClip.js +19 -0
- package/src/grammar/legendCombinations.js +45 -0
- package/src/grammar/legendGradient.js +27 -0
- package/src/grammar/legendGroups.js +1 -0
- package/src/grammar/legendOpacity.js +6 -0
- package/src/grammar/legendTitleStyle.js +22 -0
- package/src/grammar/lineSeries.js +32 -17
- package/src/grammar/markLabels.js +5 -2
- package/src/grammar/normalize.js +4 -54
- package/src/grammar/numeric.js +1 -290
- package/src/grammar/parallelCoordinates.js +1 -6
- package/src/grammar/parseTime.js +41 -0
- package/src/grammar/pathCommands.js +11 -4
- package/src/grammar/pointShapes.js +16 -2
- package/src/grammar/polar.js +1 -184
- package/src/grammar/positionCompatibility.js +3 -3
- package/src/grammar/regression/derive.js +16 -2
- package/src/grammar/regression/models.js +142 -54
- package/src/grammar/regression/parameters.js +23 -4
- package/src/grammar/regression/statistics.js +64 -0
- package/src/grammar/roundedRect.js +42 -54
- package/src/grammar/scales/appearance.js +1 -206
- package/src/grammar/scales/color.js +1 -382
- package/src/grammar/scales/colorConsumers.js +5 -2
- package/src/grammar/scales/definition.js +1 -197
- package/src/grammar/scales/discretized.js +1 -195
- package/src/grammar/scales/size.js +1 -456
- package/src/grammar/scales/temporal.js +2 -13
- package/src/grammar/scales/transformed.js +1 -383
- package/src/grammar/scales/types.js +1 -1
- package/src/grammar/scales/validation.js +1 -66
- package/src/grammar/schemas/concreteGraphic.js +14 -0
- package/src/grammar/schemas/graphic.js +6 -0
- package/src/grammar/schemas/graphicBounds.js +31 -7
- package/src/grammar/schemas/semanticPath.js +19 -3
- package/src/grammar/stack.js +2 -10
- package/src/grammar/statisticalReference.js +1 -6
- package/src/grammar/summary.js +4 -27
- package/src/grammar/text.js +19 -0
- package/src/grammar/timeUnit.js +22 -11
- package/src/grammar/transformKeys.js +47 -0
- package/src/grammar/transformTopology.js +1 -0
- package/src/grammar/transforms.js +15 -2
- package/src/grammar/valueFormat.js +17 -5
- package/src/grammar/weightedStatistics.js +1 -6
- package/src/grammar/window.js +4 -58
- package/src/inspectionDescriptors.js +1 -1
- package/src/layout/canvas.js +1 -110
- package/src/layout/facets.js +1 -244
- package/src/layout/guideCollisions.js +9 -1
- package/src/layout/labels.js +1 -0
- package/src/layout/legend.js +13 -0
- package/src/layout/legendGroup.js +1 -0
- package/src/layout/legendItems.js +59 -15
- package/src/layout/legendLane.js +1 -441
- package/src/layout/legendText.js +1 -0
- package/src/layout/title.js +35 -13
- package/src/materialization/bars/aggregate.js +11 -5
- package/src/materialization/bars/histogram.js +4 -1
- package/src/materialization/bars/ranged.js +19 -6
- package/src/materialization/bars/resolve.js +22 -1
- package/src/materialization/compositionSnapshot.js +2 -7
- package/src/materialization/coordinateBounds.js +21 -0
- package/src/materialization/dependencies.js +4 -44
- package/src/materialization/facetGuides/edit.js +30 -0
- package/src/materialization/facetGuides/layout.js +1 -0
- package/src/materialization/facetGuides/owner.js +125 -0
- package/src/materialization/facetGuides/ownerLayout.js +71 -0
- package/src/materialization/facetGuides/placement.js +71 -14
- package/src/materialization/facetGuides/preparation.js +22 -7
- package/src/materialization/facetHeaders.js +1 -347
- package/src/materialization/facets.js +1 -185
- package/src/materialization/graphicHierarchy.js +5 -1
- package/src/materialization/graphicTranslation.js +73 -0
- package/src/materialization/guides/layout.js +1 -57
- package/src/materialization/guides/resources.js +1 -123
- package/src/materialization/layout.js +53 -0
- package/src/materialization/legendBorder.js +28 -0
- package/src/materialization/legendClip.js +76 -0
- package/src/materialization/legendGroups.js +1 -0
- package/src/materialization/legendText.js +1 -0
- package/src/materialization/legends.js +2 -2
- package/src/materialization/marks/capabilities.js +5 -6
- package/src/materialization/rect.js +1 -1
- package/src/materialization/scaleGuideDependencies.js +14 -15
- package/src/materialization/scales/map.js +6 -0
- package/src/materialization/scales/policies/arc.js +8 -7
- package/src/materialization/scales/policies/bar.js +19 -7
- package/src/materialization/scales/policies/series.js +2 -1
- package/src/materialization/scales/resolve.js +7 -3
- package/src/materialization/selection/items/arc.js +1 -1
- package/src/materialization/selection/items/bar.js +7 -6
- package/src/materialization/selection/items/path.js +7 -6
- package/src/materialization/selection/items/rect.js +2 -2
- package/src/materialization/text.js +13 -4
- package/src/materialization/textLines.js +15 -0
- package/src/materialization/typography.js +10 -2
- package/src/persistence/codec.js +37 -6
- package/src/persistence/validation.js +220 -0
- package/src/persistence.js +19 -6
- package/src/renderers/canvas/circle.js +6 -3
- package/src/renderers/canvas/fill.js +7 -1
- package/src/renderers/canvas/index.js +22 -11
- package/src/renderers/canvas/isolated.js +166 -0
- package/src/renderers/canvas/limits.js +3 -0
- package/src/renderers/canvas/line.js +1 -0
- package/src/renderers/canvas/path.js +1 -1
- package/src/renderers/canvas/rect.js +11 -8
- package/src/renderers/canvas/stroke.js +2 -1
- package/src/renderers/canvas/text.js +5 -3
- package/src/renderers/pdf.js +2 -2
- package/src/renderers/png.js +2 -2
- package/src/renderers/svg.js +14 -4
- package/src/selectors/axes.js +1 -0
- package/src/selectors/graphicCapacity.js +38 -0
- package/src/selectors/layers.js +19 -0
- package/src/theme/defaults.js +8 -2
- package/src/version.js +1 -1
- package/types/basic.d.ts +3 -0
- package/types/index.d.ts +12 -0
- package/types/program.d.ts +536 -129
|
@@ -135,7 +135,7 @@ export const createIntervalPlot = /* @__PURE__ */ action(
|
|
|
135
135
|
|
|
136
136
|
const REGRESSION_OPTIONS = Object.freeze([
|
|
137
137
|
"id", "data", "coordinate", "x", "y", "color", "size", "shape", "point",
|
|
138
|
-
"groupBy", "method", "degree", "span", "confidenceMethod", "level", "confidence",
|
|
138
|
+
"groupBy", "method", "degree", "span", "robustIterations", "confidenceMethod", "level", "confidence",
|
|
139
139
|
"interval", "band", "line", "guides"
|
|
140
140
|
]);
|
|
141
141
|
|
|
@@ -163,7 +163,7 @@ export const createRegressionPlot = /* @__PURE__ */ action(
|
|
|
163
163
|
guides: false
|
|
164
164
|
});
|
|
165
165
|
const regression = Object.fromEntries([
|
|
166
|
-
"groupBy", "method", "degree", "span", "confidenceMethod", "level",
|
|
166
|
+
"groupBy", "method", "degree", "span", "robustIterations", "confidenceMethod", "level",
|
|
167
167
|
"confidence", "interval", "band", "line"
|
|
168
168
|
].filter(key => Object.hasOwn(args, key)).map(key => [key, args[key]]));
|
|
169
169
|
next = next.createRegression({ target: id, ...regression });
|
|
@@ -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", "stroke", "opacity", "closed",
|
|
23
|
+
"strokeWidth", "curve", "tension", "stroke", "opacity", "closed",
|
|
24
24
|
...STROKE_STYLE_PROPERTIES
|
|
25
25
|
]);
|
|
26
26
|
|
|
@@ -1,52 +1,8 @@
|
|
|
1
1
|
import { action } from "../../core/action.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
applyFacadeGuides, normalizeAppearance, normalizeCategoricalColor, normalizeCategoricalGuides,
|
|
5
|
-
normalizeArcCategory, normalizeCategoryAggregate, omitUndefinedOptions,
|
|
6
|
-
resolveFacadeData, resolveFacadeId, validateFacadeOptions
|
|
7
|
-
} from "./shared.js";
|
|
8
|
-
|
|
9
|
-
const OPERATION = "createPiePlot";
|
|
10
|
-
const OPTIONS = ["id", "data", "coordinate", "category", "value", "aggregate", "color", "arc", "guides"];
|
|
11
|
-
const ARC_OPTIONS = [
|
|
12
|
-
"innerRadius", "padAngle", "fill", "opacity", "stroke", "strokeWidth",
|
|
13
|
-
...STROKE_STYLE_PROPERTIES
|
|
14
|
-
];
|
|
15
|
-
function guideOptions(value, color) {
|
|
16
|
-
const guides = normalizeCategoricalGuides(value, OPERATION, color);
|
|
17
|
-
if (guides === false) return false;
|
|
18
|
-
for (const key of ["axes", "grid"]) {
|
|
19
|
-
if (guides[key] !== undefined && guides[key] !== false) {
|
|
20
|
-
throw new TypeError(`${OPERATION} guides.${key} only accepts false.`);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
return { ...guides, axes: false, grid: false };
|
|
24
|
-
}
|
|
2
|
+
import { createArcPlot } from "./radial.js";
|
|
25
3
|
|
|
26
4
|
export const createPiePlot = /* @__PURE__ */ action({
|
|
27
|
-
op:
|
|
5
|
+
op: "createPiePlot", description: "Create a categorical count or weighted-sum pie or donut plot."
|
|
28
6
|
}, function (args = {}) {
|
|
29
|
-
|
|
30
|
-
const id = resolveFacadeId(this, args.id, { defaultId: "piePlot", operation: OPERATION });
|
|
31
|
-
const data = resolveFacadeData(this, args.data, OPERATION);
|
|
32
|
-
const category = normalizeArcCategory(args.category, OPERATION);
|
|
33
|
-
const aggregate = normalizeCategoryAggregate(args, OPERATION);
|
|
34
|
-
const arc = omitUndefinedOptions(normalizeAppearance(args.arc, ARC_OPTIONS, `${OPERATION} arc`));
|
|
35
|
-
const color = args.color === false ? undefined
|
|
36
|
-
: normalizeCategoricalColor(args.color === undefined ? category.field : args.color, `${OPERATION} color`);
|
|
37
|
-
if (color !== undefined && arc.fill !== undefined) {
|
|
38
|
-
throw new Error(`${OPERATION} arc.fill cannot be combined with color; use color:false.`);
|
|
39
|
-
}
|
|
40
|
-
const guides = guideOptions(args.guides, color);
|
|
41
|
-
let next = this.createArcMark({ id, data, ...arc }).encodeTheta({
|
|
42
|
-
...category, target: id, aggregate,
|
|
43
|
-
...(args.coordinate === undefined ? {} : { coordinate: args.coordinate }),
|
|
44
|
-
...(aggregate === "sum" ? { weight: args.value } : {})
|
|
45
|
-
});
|
|
46
|
-
if (color !== undefined) next = next.encodeColor({ ...color, target: id });
|
|
47
|
-
next = applyFacadeGuides(next, guides, id, args.guides ?? {});
|
|
48
|
-
return next._withMarkConfig(id, {
|
|
49
|
-
...next.markConfigs[id],
|
|
50
|
-
compositionRole: "pie"
|
|
51
|
-
});
|
|
7
|
+
return createArcPlot(this, args, { operation: "createPiePlot", defaultId: "piePlot" });
|
|
52
8
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { findSemanticScale } from "../../selectors/scales.js";
|
|
1
2
|
import { action } from "../../core/action.js";
|
|
2
3
|
import { STROKE_STYLE_PROPERTIES } from "../../grammar/strokeStyle.js";
|
|
3
4
|
import {
|
|
@@ -6,21 +7,22 @@ import {
|
|
|
6
7
|
resolveFacadeData, resolveFacadeId, validateFacadeOptions
|
|
7
8
|
} from "./shared.js";
|
|
8
9
|
|
|
9
|
-
const OPTIONS = ["id", "data", "coordinate", "category", "value", "aggregate", "
|
|
10
|
+
const OPTIONS = ["id", "data", "coordinate", "category", "value", "aggregate", "color", "arc", "guides"];
|
|
10
11
|
const ARC_OPTIONS = [
|
|
11
12
|
"innerRadius", "padAngle", "fill", "opacity", "stroke", "strokeWidth",
|
|
12
13
|
...STROKE_STYLE_PROPERTIES
|
|
13
14
|
];
|
|
14
15
|
const RADIUS_OPTIONS = ["id", "type", "domain", "range", "zero", "nice", "reverse", "clamp"];
|
|
15
16
|
|
|
16
|
-
function
|
|
17
|
-
|
|
17
|
+
export function createArcPlot(program, args, { operation, defaultId, mapping }) {
|
|
18
|
+
const measured = mapping !== undefined;
|
|
19
|
+
validateFacadeOptions(args, [...OPTIONS, measured ? "radiusScale" : "radius"], operation);
|
|
18
20
|
const id = resolveFacadeId(program, args.id, { defaultId, operation });
|
|
19
21
|
const data = resolveFacadeData(program, args.data, operation);
|
|
20
22
|
const category = normalizeArcCategory(args.category, operation);
|
|
21
23
|
const aggregate = normalizeCategoryAggregate(args, operation);
|
|
22
24
|
const arc = omitUndefinedOptions(normalizeAppearance(args.arc, ARC_OPTIONS, `${operation} arc`));
|
|
23
|
-
if (arc.padAngle !== undefined && arc.padAngle !== 0) throw new Error(`${operation} requires padAngle 0.`);
|
|
25
|
+
if (measured && arc.padAngle !== undefined && arc.padAngle !== 0) throw new Error(`${operation} requires padAngle 0.`);
|
|
24
26
|
const radiusScale = args.radiusScale === undefined ? undefined
|
|
25
27
|
: omitUndefinedOptions(normalizeAppearance(args.radiusScale, RADIUS_OPTIONS, `${operation} radiusScale`));
|
|
26
28
|
const color = args.color === false ? undefined
|
|
@@ -28,23 +30,43 @@ function createMeasuredPlot(program, args, { operation, defaultId, mapping }) {
|
|
|
28
30
|
if (color !== undefined && arc.fill !== undefined) {
|
|
29
31
|
throw new Error(`${operation} arc.fill cannot be combined with color; use color:false.`);
|
|
30
32
|
}
|
|
31
|
-
|
|
33
|
+
let guides = normalizeCategoricalGuides(args.guides, operation, color);
|
|
34
|
+
if (!measured && guides !== false) {
|
|
35
|
+
for (const key of ["axes", "grid"]) {
|
|
36
|
+
if (guides[key] !== undefined && guides[key] !== false) {
|
|
37
|
+
throw new TypeError(`${operation} guides.${key} only accepts false.`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
guides = { ...guides, axes: false, grid: false };
|
|
41
|
+
}
|
|
32
42
|
let next = program.createArcMark({ id, data, ...arc }).encodeTheta({
|
|
33
|
-
...category, target: id, ...(args.coordinate === undefined ? {} : { coordinate: args.coordinate })
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
43
|
+
...category, target: id, ...(args.coordinate === undefined ? {} : { coordinate: args.coordinate }),
|
|
44
|
+
...(!measured ? { aggregate, ...(aggregate === "sum" ? { weight: args.value } : {}) } : {})
|
|
45
|
+
});
|
|
46
|
+
if (measured) {
|
|
47
|
+
next = next.encodeR({ target: id, aggregate, mapping,
|
|
48
|
+
...(aggregate === "sum" ? { field: args.value } : {}),
|
|
49
|
+
...(radiusScale === undefined ? {} : { scale: radiusScale }) });
|
|
50
|
+
} else if (args.radius !== undefined) {
|
|
51
|
+
const radius = typeof args.radius === "string" ? { field: args.radius }
|
|
52
|
+
: normalizeAppearance(args.radius, ["field", "aggregate", "scale"], `${operation} radius`);
|
|
53
|
+
const scale = radius.scale ?? {};
|
|
54
|
+
next = next.encodeR({ target: id, ...omitUndefinedOptions(radius), scale: {
|
|
55
|
+
...(scale.type !== "log" && findSemanticScale(next, scale.id ?? "radius") === undefined ? { zero: true } : {}),
|
|
56
|
+
...scale
|
|
57
|
+
} });
|
|
58
|
+
}
|
|
37
59
|
if (color !== undefined) next = next.encodeColor({ ...color, target: id });
|
|
38
60
|
next = applyFacadeGuides(next, guides, id, args.guides ?? {});
|
|
39
61
|
return next._withMarkConfig(id, {
|
|
40
62
|
...next.markConfigs[id],
|
|
41
|
-
compositionRole: "rose"
|
|
63
|
+
compositionRole: measured ? "rose" : "pie"
|
|
42
64
|
});
|
|
43
65
|
}
|
|
44
66
|
|
|
45
67
|
export const createRosePlot = /* @__PURE__ */ action({ op: "createRosePlot", description: "Create equal-angle sectors with area proportional to category count or sum." }, function (args = {}) {
|
|
46
|
-
return
|
|
68
|
+
return createArcPlot(this, args, { operation: "createRosePlot", defaultId: "rosePlot", mapping: "area" });
|
|
47
69
|
});
|
|
48
70
|
export const createRadialBarPlot = /* @__PURE__ */ action({ op: "createRadialBarPlot", description: "Create equal-angle sectors with radial length proportional to category count or sum." }, function (args = {}) {
|
|
49
|
-
return
|
|
71
|
+
return createArcPlot(this, args, { operation: "createRadialBarPlot", defaultId: "radialBarPlot", mapping: "radius-length" });
|
|
50
72
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { encodeStroke } from "../encodings/stroke.js";
|
|
1
2
|
import { action } from "../../core/action.js";
|
|
2
3
|
import { validateNonNegativeFinite } from "../../core/validation.js";
|
|
3
4
|
import { STROKE_STYLE_PROPERTIES } from "../../grammar/strokeStyle.js";
|
|
@@ -15,7 +16,7 @@ import {
|
|
|
15
16
|
} from "./shared.js";
|
|
16
17
|
|
|
17
18
|
const OPTIONS = Object.freeze([
|
|
18
|
-
"id", "data", "coordinate", "x", "y", "color", "size", "shape",
|
|
19
|
+
"id", "data", "coordinate", "x", "y", "color", "stroke", "size", "shape",
|
|
19
20
|
"point", "guides"
|
|
20
21
|
]);
|
|
21
22
|
const POINT_OPTIONS = Object.freeze([
|
|
@@ -43,6 +44,13 @@ export const createScatterPlot = /* @__PURE__ */ action(
|
|
|
43
44
|
const x = normalizeFieldEncoding(args.x, "createScatterPlot x");
|
|
44
45
|
const y = normalizeFieldEncoding(args.y, "createScatterPlot y");
|
|
45
46
|
const color = normalizeEncoding(args.color, "createScatterPlot color");
|
|
47
|
+
const stroke = normalizeEncoding(args.stroke, "createScatterPlot stroke");
|
|
48
|
+
if (stroke !== undefined) {
|
|
49
|
+
if (typeof stroke.field !== "string" || stroke.field.length === 0 || Object.hasOwn(stroke, "value")) {
|
|
50
|
+
throw new TypeError("createScatterPlot stroke requires a field; constant stroke belongs in point.");
|
|
51
|
+
}
|
|
52
|
+
if (Object.hasOwn(point, "stroke")) throw new Error("createScatterPlot stroke conflicts with point.stroke.");
|
|
53
|
+
}
|
|
46
54
|
const size = normalizeEncoding(args.size, "createScatterPlot size");
|
|
47
55
|
const shape = normalizeEncoding(args.shape, "createScatterPlot shape");
|
|
48
56
|
const guides = normalizeGuides(args.guides, "createScatterPlot");
|
|
@@ -51,12 +59,18 @@ export const createScatterPlot = /* @__PURE__ */ action(
|
|
|
51
59
|
if (size !== undefined) throw new Error("createScatterPlot point radius conflicts with size.");
|
|
52
60
|
}
|
|
53
61
|
|
|
62
|
+
const initialPoint = { ...point };
|
|
63
|
+
if (stroke !== undefined) delete initialPoint.strokeWidth;
|
|
54
64
|
let next = this
|
|
55
|
-
.createPointMark({ id, data, ...
|
|
65
|
+
.createPointMark({ id, data, ...initialPoint })
|
|
56
66
|
.encodeX(positionArgs(x, { target: id, coordinate: args.coordinate }))
|
|
57
67
|
.encodeY(positionArgs(y, { target: id, coordinate: args.coordinate }));
|
|
58
68
|
if (radius !== undefined) next = next.encodePointRadius({ target: id, value: radius });
|
|
59
69
|
if (color !== undefined) next = next.encodeColor(targetArgs(color, id));
|
|
70
|
+
if (stroke !== undefined) {
|
|
71
|
+
next = encodeStroke.call(next, targetArgs(stroke, id));
|
|
72
|
+
if (Object.hasOwn(point, "strokeWidth")) next = next.editPointMark({ target: id, strokeWidth: point.strokeWidth });
|
|
73
|
+
}
|
|
60
74
|
if (size !== undefined) next = next.encodeSize(targetArgs(size, id));
|
|
61
75
|
if (shape !== undefined) next = next.encodeShape(targetArgs(shape, id));
|
|
62
76
|
return applyFacadeGuides(next, guides, id);
|
|
@@ -191,9 +191,9 @@ export function normalizeArcCategory(value, operation) {
|
|
|
191
191
|
}
|
|
192
192
|
|
|
193
193
|
export function normalizeCategoryAggregate(args, operation) {
|
|
194
|
-
const aggregate = args.aggregate === undefined ? "count" : args.aggregate;
|
|
194
|
+
const aggregate = args.aggregate === undefined ? args.value === undefined ? "count" : "sum" : args.aggregate;
|
|
195
195
|
if (!["count", "sum"].includes(aggregate) || (aggregate === "sum") !== (args.value !== undefined)) {
|
|
196
|
-
throw new Error(`${operation} requires count without value or
|
|
196
|
+
throw new Error(`${operation} requires count without value or sum with value.`);
|
|
197
197
|
}
|
|
198
198
|
if (args.value !== undefined) validateNonEmptyString(args.value, `${operation} value`);
|
|
199
199
|
return aggregate;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { action } from "../../core/action.js";
|
|
2
|
+
import { TEXT_MARK_STYLE_OPTIONS } from "../../grammar/text.js";
|
|
3
|
+
import {
|
|
4
|
+
applyFacadeGuides, normalizeAppearance, normalizeEncoding, normalizeFieldEncoding,
|
|
5
|
+
normalizeGuides, positionArgs, resolveFacadeData, resolveFacadeId, targetArgs,
|
|
6
|
+
validateFacadeOptions
|
|
7
|
+
} from "./shared.js";
|
|
8
|
+
|
|
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")]);
|
|
11
|
+
|
|
12
|
+
export const createTextPlot = /* @__PURE__ */ action({
|
|
13
|
+
op: "createTextPlot", description: "Create a Cartesian text plot from existing chart data."
|
|
14
|
+
}, function (args = {}) {
|
|
15
|
+
validateFacadeOptions(args, OPTIONS, "createTextPlot");
|
|
16
|
+
const id = resolveFacadeId(this, args.id, { defaultId: "textPlot", operation: "createTextPlot" });
|
|
17
|
+
const data = resolveFacadeData(this, args.data, "createTextPlot");
|
|
18
|
+
const x = normalizeFieldEncoding(args.x, "createTextPlot x");
|
|
19
|
+
const y = normalizeFieldEncoding(args.y, "createTextPlot y");
|
|
20
|
+
const text = normalizeEncoding(args.text, "createTextPlot text");
|
|
21
|
+
if (text === undefined) throw new Error("createTextPlot requires text.");
|
|
22
|
+
const color = normalizeEncoding(args.color, "createTextPlot color");
|
|
23
|
+
const style = normalizeAppearance(args.style, STYLE_OPTIONS, "createTextPlot style");
|
|
24
|
+
const guides = normalizeGuides(args.guides, "createTextPlot");
|
|
25
|
+
const apply = program => {
|
|
26
|
+
let next = program.createTextMark({ id, data, ...style })
|
|
27
|
+
.encodeX(positionArgs(x, { target: id, coordinate: args.coordinate }))
|
|
28
|
+
.encodeY(positionArgs(y, { target: id, coordinate: args.coordinate }))
|
|
29
|
+
.encodeText(targetArgs(text, id));
|
|
30
|
+
if (color !== undefined) next = next.encodeColor(targetArgs(color, id));
|
|
31
|
+
return applyFacadeGuides(next, guides, id);
|
|
32
|
+
};
|
|
33
|
+
apply(this);
|
|
34
|
+
return apply(this);
|
|
35
|
+
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveGraphicBounds } from "../../layout/canvas.js";
|
|
1
2
|
import { inheritTextMetrics } from "../textMetrics/index.js";
|
|
2
3
|
import { action, closedAction } from "../../core/action.js";
|
|
3
4
|
import { ChartProgram as CoreChartProgram } from "../../core/ChartProgram.js";
|
|
@@ -19,7 +20,7 @@ const CONCAT_OPTIONS = Object.freeze([
|
|
|
19
20
|
"id", "programs", "gap", "align", "padding"
|
|
20
21
|
]);
|
|
21
22
|
const LAYOUT_EDIT_OPTIONS = Object.freeze([
|
|
22
|
-
"columns", "gap", "align", "padding"
|
|
23
|
+
"columns", "gap", "spacing", "align", "padding"
|
|
23
24
|
]);
|
|
24
25
|
const REPLACEMENT_OPTIONS = Object.freeze(["target", "program"]);
|
|
25
26
|
const INSERTION_OPTIONS = Object.freeze(["id", "program", "before", "after"]);
|
|
@@ -179,6 +180,7 @@ const editCompositionLayout = /* @__PURE__ */ closedAction(
|
|
|
179
180
|
"editCompositionLayout columns is available only on a facet composition."
|
|
180
181
|
);
|
|
181
182
|
}
|
|
183
|
+
if (current.type !== "facet" && Object.hasOwn(args, "spacing")) throw new Error("Plot spacing requires a facet composition.");
|
|
182
184
|
const padding = Object.hasOwn(args, "padding")
|
|
183
185
|
? normalizeCompositionPadding(args.padding, current.padding)
|
|
184
186
|
: current.padding;
|
|
@@ -188,6 +190,8 @@ const editCompositionLayout = /* @__PURE__ */ closedAction(
|
|
|
188
190
|
(current.facet.grid?.cells ?? []).map(cell => [cell.id, cell])
|
|
189
191
|
);
|
|
190
192
|
layout = resolveFacetLayout({
|
|
193
|
+
spacing: option(args, "spacing", current.spacing),
|
|
194
|
+
plots: current.children.map(id => ({ id, ...resolveGraphicBounds(this.children[id]) })),
|
|
191
195
|
children: current.children.map((id, index) => ({
|
|
192
196
|
...childDescriptor({ id, program: this.children[id] }),
|
|
193
197
|
value: current.facet.values[index],
|
|
@@ -218,7 +222,7 @@ const editCompositionLayout = /* @__PURE__ */ closedAction(
|
|
|
218
222
|
children: this.children,
|
|
219
223
|
compositionSpec: {
|
|
220
224
|
...current,
|
|
221
|
-
...(current.type === "facet" ? { columns: layout.columns } : {}),
|
|
225
|
+
...(current.type === "facet" ? { columns: layout.columns, ...(layout.spacing !== undefined ? { spacing: layout.spacing } : current.spacing !== undefined ? { spacing: "canvas" } : {}) } : {}),
|
|
222
226
|
gap: layout.gap,
|
|
223
227
|
align: layout.align,
|
|
224
228
|
padding: layout.padding
|
package/src/actions/data/box.js
CHANGED
|
@@ -2,7 +2,7 @@ import { BOX_FIELDS, deriveBoxData, normalizeBoxTransform } from "../../grammar/
|
|
|
2
2
|
import { derivedCreator, derivedMaterializer } from "./shared.js";
|
|
3
3
|
|
|
4
4
|
const OPTIONS = Object.freeze([
|
|
5
|
-
"id", "source", "category", "field", "whisker", "factor", "as"
|
|
5
|
+
"id", "source", "category", "field", "whisker", "factor", "as", "summary"
|
|
6
6
|
]);
|
|
7
7
|
|
|
8
8
|
function materializer(type, op, select) {
|
|
@@ -28,6 +28,7 @@ function creator(type, op, materialize) {
|
|
|
28
28
|
type,
|
|
29
29
|
category: args.category,
|
|
30
30
|
field: args.field,
|
|
31
|
+
...(args.summary === undefined ? {} : { summary: args.summary }),
|
|
31
32
|
...(args.whisker === undefined ? {} : { whisker: args.whisker }),
|
|
32
33
|
...(args.factor === undefined ? {} : { factor: args.factor }),
|
|
33
34
|
as: args.as ?? BOX_FIELDS
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { closedAction } from "../../core/action.js";
|
|
2
|
+
import { validateGraphicItemLimit } from "../../core/validation.js";
|
|
3
|
+
import { resolveGraphicItemCapacity } from "../../selectors/graphicCapacity.js";
|
|
2
4
|
import { validateUserId } from "../../core/identifiers.js";
|
|
3
5
|
|
|
4
6
|
import {
|
|
@@ -89,6 +91,7 @@ export const releaseDerivedData = /* @__PURE__ */ closedAction(
|
|
|
89
91
|
next = next._withoutMaterializationConfig([
|
|
90
92
|
"calculations", "datasets", validatedId
|
|
91
93
|
]);
|
|
94
|
+
next = next._withoutMaterializationConfig(["regressionFits", validatedId]);
|
|
92
95
|
for (const owner of selfOwners) {
|
|
93
96
|
const [, family, ownerId] = owner.path;
|
|
94
97
|
next = next._withoutMaterializationConfig(["data", family, ownerId]);
|
|
@@ -110,10 +113,17 @@ export const rebindLayerData = /* @__PURE__ */ closedAction(
|
|
|
110
113
|
requestedData,
|
|
111
114
|
"Layer dataset"
|
|
112
115
|
).id;
|
|
113
|
-
requireLayer(this, id);
|
|
116
|
+
const layer = requireLayer(this, id);
|
|
114
117
|
if (!hasDataset(this, data)) {
|
|
115
118
|
throw new Error(`Layer dataset "${data}" does not exist.`);
|
|
116
119
|
}
|
|
120
|
+
const dataset = findDataset(this, data);
|
|
121
|
+
if (layer.mark?.type === "point" && Array.isArray(dataset.values)) {
|
|
122
|
+
validateGraphicItemLimit(dataset.values.length, {
|
|
123
|
+
...resolveGraphicItemCapacity(this, { id, label: "Point mark item count" }),
|
|
124
|
+
rawCount: dataset.values.length
|
|
125
|
+
});
|
|
126
|
+
}
|
|
117
127
|
return this.editSemantic({
|
|
118
128
|
property: `layer[${id}].data`,
|
|
119
129
|
value: data
|
package/src/actions/data/edit.js
CHANGED
|
@@ -38,6 +38,7 @@ const CREATOR_BY_TYPE = Object.freeze({
|
|
|
38
38
|
interval: "createIntervalData",
|
|
39
39
|
normalize: "createNormalizedData",
|
|
40
40
|
regression: "createRegressionData",
|
|
41
|
+
regressionStatistics: "createRegressionStatisticsData",
|
|
41
42
|
sort: "createSortedData",
|
|
42
43
|
stack: "createStackData",
|
|
43
44
|
summary: "createSummaryData",
|
|
@@ -57,6 +58,7 @@ const REVISION_ROLE = Object.freeze({
|
|
|
57
58
|
interval: "IntervalData",
|
|
58
59
|
normalize: "NormalizedData",
|
|
59
60
|
regression: "RegressionData",
|
|
61
|
+
regressionStatistics: "RegressionStatisticsData",
|
|
60
62
|
sort: "SortedData",
|
|
61
63
|
stack: "StackData",
|
|
62
64
|
summary: "SummaryData",
|
|
@@ -509,7 +511,7 @@ export const editStackData = /* @__PURE__ */ focusedEditor(
|
|
|
509
511
|
);
|
|
510
512
|
export const editRegressionData = /* @__PURE__ */ focusedEditor(
|
|
511
513
|
"editRegressionData", "regression", [
|
|
512
|
-
"x", "y", "groupBy", "method", "degree", "span", "confidenceMethod",
|
|
514
|
+
"x", "y", "groupBy", "method", "degree", "span", "robustIterations", "confidenceMethod",
|
|
513
515
|
"level", "confidence", "interval", "predict"
|
|
514
516
|
]
|
|
515
517
|
);
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
materializeGradientProfileData
|
|
22
22
|
} from "./gradientProfile.js";
|
|
23
23
|
import { createRegressionData, materializeRegressionData } from "./regression.js";
|
|
24
|
+
import { createRegressionStatisticsData, editRegressionStatisticsData, materializeRegressionStatisticsData } from "./regressionStatistics.js";
|
|
24
25
|
import {
|
|
25
26
|
createCategoricalDensityData,
|
|
26
27
|
createDensityData,
|
|
@@ -69,6 +70,9 @@ export function registerDataActions(ProgramClass) {
|
|
|
69
70
|
materializeEmptyMark,
|
|
70
71
|
removeMarkFilter,
|
|
71
72
|
materializeRegressionData,
|
|
73
|
+
materializeRegressionStatisticsData,
|
|
74
|
+
createRegressionStatisticsData,
|
|
75
|
+
editRegressionStatisticsData,
|
|
72
76
|
materializeDensityData,
|
|
73
77
|
createGradientProfileData,
|
|
74
78
|
materializeGradientProfileData,
|
|
@@ -5,33 +5,42 @@ import {
|
|
|
5
5
|
deriveRegression,
|
|
6
6
|
normalizeRegressionTransform
|
|
7
7
|
} from "../../grammar/regression/index.js";
|
|
8
|
-
import { resolveDatasetReference } from "../../selectors/datasets.js";
|
|
8
|
+
import { resolveDatasetReference, requireDataset, findDataset } from "../../selectors/datasets.js";
|
|
9
9
|
import { derivedMaterializer } from "./shared.js";
|
|
10
10
|
|
|
11
11
|
const OPTIONS = Object.freeze([
|
|
12
|
-
"id", "source", "x", "y", "groupBy", "method", "degree", "span",
|
|
12
|
+
"id", "source", "x", "y", "groupBy", "method", "degree", "span", "robustIterations",
|
|
13
13
|
"confidenceMethod", "level", "confidence", "interval"
|
|
14
14
|
, "predict", "missing"
|
|
15
15
|
]);
|
|
16
16
|
|
|
17
|
+
function calculateRegression(values, transform) {
|
|
18
|
+
return deriveRegression(values, transform);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function retainFitStatistics(program, { id, result }) {
|
|
22
|
+
return result.fitStatistics === undefined ? program : program._withMaterializationConfig(
|
|
23
|
+
["regressionFits", id], result.fitStatistics
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function materializeMissingFitStatistics(program, args) {
|
|
28
|
+
const dataset = findDataset(program, args.id);
|
|
29
|
+
if (dataset?.values === undefined || dataset.transform?.length !== 1 ||
|
|
30
|
+
dataset.transform[0].type !== "regression" || dataset.transform[0].method !== "linear" ||
|
|
31
|
+
program.materializationConfigs.regressionFits?.[dataset.id] !== undefined) return undefined;
|
|
32
|
+
const source = requireDataset(program, dataset.source);
|
|
33
|
+
const result = calculateRegression(source.values, dataset.transform[0]);
|
|
34
|
+
return retainFitStatistics(program, { id: dataset.id, result });
|
|
35
|
+
}
|
|
36
|
+
|
|
17
37
|
export const materializeRegressionData = /* @__PURE__ */ derivedMaterializer(
|
|
18
38
|
"materializeRegressionData",
|
|
19
39
|
"Materialize one regression derived dataset.",
|
|
20
40
|
"regression",
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
groupBy: transform.groupBy,
|
|
25
|
-
method: transform.method,
|
|
26
|
-
degree: transform.degree,
|
|
27
|
-
span: transform.span,
|
|
28
|
-
confidenceMethod: transform.confidenceMethod,
|
|
29
|
-
level: transform.level,
|
|
30
|
-
confidence: transform.confidence,
|
|
31
|
-
interval: transform.interval,
|
|
32
|
-
predict: transform.predict
|
|
33
|
-
, missing: transform.missing
|
|
34
|
-
})
|
|
41
|
+
calculateRegression,
|
|
42
|
+
undefined,
|
|
43
|
+
{ before: materializeMissingFitStatistics, after: retainFitStatistics }
|
|
35
44
|
);
|
|
36
45
|
|
|
37
46
|
export const createRegressionData = /* @__PURE__ */ closedAction(
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { closedAction } from "../../core/action.js";
|
|
2
|
+
import { validateUserId } from "../../core/identifiers.js";
|
|
3
|
+
import { requireDataset, resolveDatasetReference, hasDataset, hasDatasetOwner } from "../../selectors/datasets.js";
|
|
4
|
+
import {
|
|
5
|
+
requireRegressionStatisticsSource,
|
|
6
|
+
validateRegressionFitStatistics,
|
|
7
|
+
regressionStatisticsRows
|
|
8
|
+
} from "../../grammar/regression/statistics.js";
|
|
9
|
+
import { requireDerivedDataset } from "./shared.js";
|
|
10
|
+
import { resolveDerivedDataOwner, reviseDerivedData } from "./edit.js";
|
|
11
|
+
|
|
12
|
+
function ensureFitStatistics(program, source) {
|
|
13
|
+
requireRegressionStatisticsSource(source);
|
|
14
|
+
if (!Array.isArray(source.values)) throw new Error("Regression statistics requires a materialized linear fit source.");
|
|
15
|
+
const next = program.materializationConfigs.regressionFits?.[source.id] === undefined
|
|
16
|
+
? program.materializeRegressionData({ id: source.id }) : program;
|
|
17
|
+
validateRegressionFitStatistics(next.materializationConfigs.regressionFits[source.id], source,
|
|
18
|
+
requireDataset(next, source.source));
|
|
19
|
+
return next;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function statisticsOwner(program, target) {
|
|
23
|
+
if (target !== undefined) return resolveDerivedDataOwner(program, target, "regressionStatistics");
|
|
24
|
+
const records = Object.entries(program.materializationConfigs.data?.regressionStatistics ?? {})
|
|
25
|
+
.map(([owner, config]) => ({ owner, current: config.current }));
|
|
26
|
+
const current = records.filter(record => record.current === program.context.currentData);
|
|
27
|
+
const candidate = current.length === 1 ? current[0] : records.length === 1 ? records[0] : undefined;
|
|
28
|
+
if (candidate === undefined) throw new Error(records.length === 0
|
|
29
|
+
? "No standalone regression statistics dataset is available."
|
|
30
|
+
: "Regression statistics target is ambiguous; provide target.");
|
|
31
|
+
return resolveDerivedDataOwner(program, candidate.owner, "regressionStatistics");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const materializeRegressionStatisticsData = /* @__PURE__ */ closedAction(
|
|
35
|
+
{ op: "materializeRegressionStatisticsData", description: "Materialize statistics from an existing linear fit cache." }, ["id"],
|
|
36
|
+
function (args = {}) {
|
|
37
|
+
const { id, source } = requireDerivedDataset(this, args.id, "regressionStatistics");
|
|
38
|
+
const next = ensureFitStatistics(this, source);
|
|
39
|
+
const values = regressionStatisticsRows(next.materializationConfigs.regressionFits[source.id], source);
|
|
40
|
+
return next.editSemantic({ property: `dataset[${id}].values`, value: values });
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
export const createRegressionStatisticsData = /* @__PURE__ */ closedAction(
|
|
45
|
+
{ op: "createRegressionStatisticsData", description: "Create counts, coefficients and R-squared from a linear regression dataset." }, ["id", "source"],
|
|
46
|
+
function (args = {}) {
|
|
47
|
+
const id = validateUserId(args.id, "Regression statistics dataset id");
|
|
48
|
+
if (hasDataset(this, id) || hasDatasetOwner(this, id)) throw new Error(`Dataset "${id}" already exists.`);
|
|
49
|
+
const source = resolveDatasetReference(this,
|
|
50
|
+
validateUserId(args.source, "Regression statistics source id"), "Regression statistics source");
|
|
51
|
+
const next = ensureFitStatistics(this, source)
|
|
52
|
+
.createDerivedData({ id, source: source.id, transform: [{ type: "regressionStatistics" }] })
|
|
53
|
+
.materializeRegressionStatisticsData({ id });
|
|
54
|
+
return this.actionStack.length === 1 ? next._withMaterializationConfig(
|
|
55
|
+
["data", "regressionStatistics", id], { current: id }
|
|
56
|
+
) : next;
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
export const editRegressionStatisticsData = /* @__PURE__ */ closedAction(
|
|
61
|
+
{ op: "editRegressionStatisticsData", description: "Revise the source of a standalone regression statistics dataset." }, ["target", "source"],
|
|
62
|
+
function (args = {}) {
|
|
63
|
+
const resolved = statisticsOwner(this, args.target);
|
|
64
|
+
if (!Object.hasOwn(args, "source")) return this;
|
|
65
|
+
const source = resolveDatasetReference(this,
|
|
66
|
+
validateUserId(args.source, "Regression statistics source id"), "Regression statistics source");
|
|
67
|
+
if (source.id === resolved.dataset.source) return this;
|
|
68
|
+
const next = ensureFitStatistics(this, source);
|
|
69
|
+
return reviseDerivedData(next, {
|
|
70
|
+
resolved, source: source.id, definition: { type: "regressionStatistics" }, dependents: "recompute"
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
);
|
|
@@ -35,9 +35,11 @@ export function requireDerivedDataset(program, id, type) {
|
|
|
35
35
|
return { id: validatedId, dataset, source, transform: dataset.transform[0] };
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
export function derivedMaterializer(op, description, type, derive, resolve) {
|
|
38
|
+
export function derivedMaterializer(op, description, type, derive, resolve, { before, after } = {}) {
|
|
39
39
|
return action({ op, description }, function (args = {}) {
|
|
40
40
|
validateKeys(args, MATERIALIZE_OPTIONS, op);
|
|
41
|
+
const existing = before?.(this, args);
|
|
42
|
+
if (existing !== undefined) return existing;
|
|
41
43
|
const { id, source, transform } = requireDerivedDataset(
|
|
42
44
|
this,
|
|
43
45
|
args.id,
|
|
@@ -51,6 +53,7 @@ export function derivedMaterializer(op, description, type, derive, resolve) {
|
|
|
51
53
|
const values = Array.isArray(result) ? result : result.values;
|
|
52
54
|
const schema = deriveTransformSchema(source.schema, transform, values, {
|
|
53
55
|
sourceId: source.id,
|
|
56
|
+
sourceTransform: source.transform?.[0],
|
|
54
57
|
ownerId: id
|
|
55
58
|
});
|
|
56
59
|
validateRowsAgainstSchema(values, schema, `Derived dataset "${id}"`);
|
|
@@ -75,7 +78,7 @@ export function derivedMaterializer(op, description, type, derive, resolve) {
|
|
|
75
78
|
report
|
|
76
79
|
);
|
|
77
80
|
}
|
|
78
|
-
return next;
|
|
81
|
+
return after === undefined ? next : after(next, { id, source, transform, result });
|
|
79
82
|
});
|
|
80
83
|
}
|
|
81
84
|
|
|
@@ -87,11 +90,12 @@ export function derivedCreator(
|
|
|
87
90
|
sourceLabel,
|
|
88
91
|
transform,
|
|
89
92
|
materialize,
|
|
90
|
-
requireSource = false
|
|
93
|
+
requireSource = false,
|
|
94
|
+
defaultId
|
|
91
95
|
) {
|
|
92
96
|
return action({ op, description }, function (args = {}) {
|
|
93
97
|
validateKeys(args, options, op);
|
|
94
|
-
const id = validateUserId(args.id, idLabel);
|
|
98
|
+
const id = validateUserId(args.id === undefined ? defaultId : args.id, idLabel);
|
|
95
99
|
const requestedSource = validateUserId(
|
|
96
100
|
requireSource ? args.source : args.source ?? this.context.currentData,
|
|
97
101
|
sourceLabel
|