ggaction 0.0.12 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +127 -0
- package/README.md +20 -11
- package/knowledge/action-card.schema.json +1 -1
- package/knowledge/action-cards.json +1 -1
- package/knowledge/action-cards.schema.json +1 -1
- package/knowledge/extension-authoring.md +2 -1
- package/knowledge/intent-taxonomy.json +1 -1
- package/knowledge/mcp-resources.json +1 -1
- package/knowledge/task-resolver.js +1 -1
- package/package.json +10 -3
- package/src/actions/basic.js +4 -2
- package/src/actions/boxPlots/components.js +14 -4
- package/src/actions/boxPlots/edit.js +31 -5
- package/src/actions/boxPlots/materialize.js +13 -4
- package/src/actions/boxPlots/options.js +48 -16
- package/src/actions/canvas/actions.js +3 -1
- package/src/actions/canvas/fitting.js +211 -0
- package/src/actions/canvas/index.js +2 -0
- package/src/actions/categoryOrder/index.js +18 -6
- package/src/actions/charts/area.js +51 -0
- package/src/actions/charts/bar.js +13 -6
- package/src/actions/charts/beeswarm.js +70 -0
- package/src/actions/charts/density.js +48 -0
- package/src/actions/charts/ecdf.js +186 -0
- package/src/actions/charts/endpoints.js +473 -0
- package/src/actions/charts/heatmap.js +4 -3
- package/src/actions/charts/histogram.js +5 -4
- package/src/actions/charts/horizon.js +73 -0
- package/src/actions/charts/index.js +37 -0
- package/src/actions/charts/interval-regression.js +172 -0
- package/src/actions/charts/line.js +8 -6
- package/src/actions/charts/parallel.js +8 -2
- package/src/actions/charts/pie.js +52 -0
- package/src/actions/charts/polar.js +134 -0
- package/src/actions/charts/radar.js +305 -0
- package/src/actions/charts/radial.js +50 -0
- package/src/actions/charts/raincloud.js +422 -0
- package/src/actions/charts/rug-strip.js +283 -0
- package/src/actions/charts/scatter.js +11 -3
- package/src/actions/charts/shared.js +69 -10
- package/src/actions/composition/actions.js +129 -3
- package/src/actions/coordinates/actions.js +1 -1
- package/src/actions/coordinates/edit.js +76 -0
- package/src/actions/data/bin.js +29 -0
- package/src/actions/data/bin2d.js +57 -185
- package/src/actions/data/complete.js +26 -0
- package/src/actions/data/computed.js +24 -0
- package/src/actions/data/create.js +2 -2
- package/src/actions/data/density.js +12 -20
- package/src/actions/data/derived.js +111 -15
- package/src/actions/data/ecdf.js +38 -0
- package/src/actions/data/edit.js +539 -0
- package/src/actions/data/filter.js +226 -30
- package/src/actions/data/fold.js +24 -0
- package/src/actions/data/impute.js +26 -0
- package/src/actions/data/index.js +38 -0
- package/src/actions/data/interval.js +2 -0
- package/src/actions/data/intervalEdit.js +86 -4
- package/src/actions/data/normalize.js +27 -0
- package/src/actions/data/regression.js +19 -21
- package/src/actions/data/revisionBindings.js +145 -0
- package/src/actions/data/shared.js +20 -4
- package/src/actions/data/stack.js +26 -0
- package/src/actions/data/summary.js +26 -0
- package/src/actions/data/timeUnit.js +4 -1
- package/src/actions/data/window.js +1 -1
- package/src/actions/encodings/appearance.js +32 -13
- package/src/actions/encodings/barWidth.js +8 -0
- package/src/actions/encodings/basic.js +2 -0
- package/src/actions/encodings/channels.js +415 -0
- package/src/actions/encodings/color/continuous.js +19 -59
- package/src/actions/encodings/color/index.js +30 -23
- package/src/actions/encodings/color/layout.js +3 -97
- package/src/actions/encodings/color/policy.js +5 -8
- package/src/actions/encodings/density/resolve.js +37 -5
- package/src/actions/encodings/density.js +124 -34
- package/src/actions/encodings/histogram.js +3 -2
- package/src/actions/encodings/horizon/resolve.js +8 -4
- package/src/actions/encodings/horizon.js +18 -8
- package/src/actions/encodings/index.js +6 -0
- package/src/actions/encodings/offset.js +30 -29
- package/src/actions/encodings/parallel.js +2 -8
- package/src/actions/encodings/position/apply.js +63 -11
- package/src/actions/encodings/position/index.js +52 -6
- package/src/actions/encodings/position/policies/arc.js +14 -0
- package/src/actions/encodings/position/policies/area.js +4 -42
- package/src/actions/encodings/position/policies/bar.js +57 -13
- package/src/actions/encodings/position/resolve.js +88 -26
- package/src/actions/encodings/ranged.js +123 -97
- package/src/actions/encodings/remove.js +44 -34
- package/src/actions/encodings/ruleAppearance.js +24 -32
- package/src/actions/encodings/seriesLayout.js +105 -0
- package/src/actions/encodings/shared.js +107 -37
- package/src/actions/encodings/stroke.js +226 -0
- package/src/actions/encodings/strokeDash.js +9 -6
- package/src/actions/encodings/temporal.js +7 -0
- package/src/actions/encodings/text.js +30 -15
- package/src/actions/errorBands/create.js +41 -8
- package/src/actions/errorBands/edit.js +360 -25
- package/src/actions/errorBars/create.js +56 -17
- package/src/actions/errorBars/edit.js +372 -21
- package/src/actions/facets/actions.js +619 -41
- package/src/actions/facets/derive.js +139 -25
- package/src/actions/gradientPlots/components.js +43 -13
- package/src/actions/gradientPlots/edit.js +14 -4
- package/src/actions/gradientPlots/materialize.js +8 -8
- package/src/actions/gradientPlots/options.js +10 -2
- package/src/actions/guides/applicability.js +28 -19
- package/src/actions/guides/axes/axes.js +4 -3
- package/src/actions/guides/axes/axis.js +18 -18
- package/src/actions/guides/axes/components.js +43 -0
- package/src/actions/guides/axes/edit.js +16 -51
- package/src/actions/guides/axes/labels.js +184 -28
- package/src/actions/guides/axes/lines.js +13 -7
- package/src/actions/guides/axes/parallel/lifecycle.js +117 -0
- package/src/actions/guides/axes/parallel/policy.js +137 -0
- package/src/actions/guides/axes/parallel/resolve.js +50 -25
- package/src/actions/guides/axes/parallel.js +93 -217
- package/src/actions/guides/axes/policy.js +21 -67
- package/src/actions/guides/axes/tickGroups.js +15 -8
- package/src/actions/guides/axes/ticks.js +11 -6
- package/src/actions/guides/axes/titles.js +32 -11
- package/src/actions/guides/basic.js +2 -0
- package/src/actions/guides/facade.js +106 -0
- package/src/actions/guides/facadeAxes.js +200 -0
- package/src/actions/guides/facadeLegend.js +63 -0
- package/src/actions/guides/grids/grid.js +37 -33
- package/src/actions/guides/grids/resolve.js +17 -4
- package/src/actions/guides/guides.js +54 -31
- package/src/actions/guides/legends/blocks.js +426 -0
- package/src/actions/guides/legends/categorical/actions.js +309 -279
- package/src/actions/guides/legends/categorical/components.js +21 -17
- package/src/actions/guides/legends/categorical/index.js +37 -33
- package/src/actions/guides/legends/categorical/layout.js +123 -354
- package/src/actions/guides/legends/categorical/options.js +32 -16
- package/src/actions/guides/legends/categorical/recipes.js +114 -9
- package/src/actions/guides/legends/categorical/resolve.js +30 -15
- package/src/actions/guides/legends/categorical/symbols.js +87 -33
- package/src/actions/guides/legends/continuous/common.js +99 -26
- package/src/actions/guides/legends/continuous/gradient.js +120 -89
- package/src/actions/guides/legends/continuous/index.js +8 -2
- package/src/actions/guides/legends/continuous/interval.js +79 -95
- package/src/actions/guides/legends/continuous/opacity.js +113 -89
- package/src/actions/guides/legends/continuous/stroke.js +525 -0
- package/src/actions/guides/legends/creation.js +40 -0
- package/src/actions/guides/legends/edit.js +321 -90
- package/src/actions/guides/legends/focused.js +2 -2
- package/src/actions/guides/legends/index.js +2 -0
- package/src/actions/guides/legends/lane.js +149 -102
- package/src/actions/guides/legends/lifecycle.js +143 -0
- package/src/actions/guides/legends/remove.js +43 -78
- package/src/actions/guides/legends/sampling.js +140 -0
- package/src/actions/guides/legends/size.js +213 -116
- package/src/actions/guides/legends/strokeWidth.js +121 -73
- package/src/actions/guides/legends/target.js +123 -0
- package/src/actions/guides/legends/transition.js +192 -0
- package/src/actions/guides/polar/axes/facade.js +81 -66
- package/src/actions/guides/polar/axes/labels.js +28 -8
- package/src/actions/guides/polar/axes/lines.js +12 -5
- package/src/actions/guides/polar/axes/shared.js +22 -0
- package/src/actions/guides/polar/axes/ticks.js +6 -5
- package/src/actions/guides/polar/axes/titles.js +6 -5
- package/src/actions/guides/polar/grids.js +8 -8
- package/src/actions/guides/polar/resolve.js +12 -8
- package/src/actions/guides/reuse.js +44 -0
- package/src/actions/guides/tickValues.js +19 -21
- package/src/actions/index.js +15 -2
- package/src/actions/intervals/resolve.js +35 -15
- package/src/actions/marks/arc/actions.js +78 -20
- package/src/actions/marks/area/actions.js +51 -12
- package/src/actions/marks/area/materialize.js +22 -3
- package/src/actions/marks/bar/create.js +11 -2
- package/src/actions/marks/bar/edit.js +20 -3
- package/src/actions/marks/bar/materialize.js +33 -9
- package/src/actions/marks/index.js +14 -0
- package/src/actions/marks/line/actions.js +71 -113
- package/src/actions/marks/line/materialize.js +57 -56
- package/src/actions/marks/point/create.js +8 -2
- package/src/actions/marks/point/edit.js +29 -21
- package/src/actions/marks/point/index.js +1 -0
- package/src/actions/marks/point/jitter.js +3 -0
- package/src/actions/marks/point/materialize.js +154 -16
- package/src/actions/marks/point/packing.js +68 -0
- package/src/actions/marks/rect/actions.js +33 -12
- package/src/actions/marks/references.js +658 -0
- package/src/actions/marks/remove.js +87 -4
- package/src/actions/marks/rule/actions.js +77 -9
- package/src/actions/marks/rule/appearance.js +26 -0
- package/src/actions/marks/shared.js +13 -13
- package/src/actions/marks/text/actions.js +296 -13
- package/src/actions/marks/text/index.js +4 -0
- package/src/actions/marks/text/layout.js +156 -8
- package/src/actions/marks/text/removal.js +173 -0
- package/src/actions/marks/text/selection.js +73 -0
- package/src/actions/marks/tick/actions.js +22 -5
- package/src/actions/primitives/createGraphics.js +3 -1
- package/src/actions/primitives/editGraphics.js +26 -0
- package/src/actions/primitives/semantic.js +3 -2
- package/src/actions/primitives/semanticAction.js +120 -10
- package/src/actions/primitives/semanticValidation/guide.js +10 -0
- package/src/actions/primitives/semanticValidation/index.js +9 -1
- package/src/actions/primitives/semanticValidation/layer.js +23 -1
- package/src/actions/primitives/semanticValidation/scale.js +38 -8
- package/src/actions/regression/components.js +26 -11
- package/src/actions/regression/create.js +11 -3
- package/src/actions/regression/edit.js +40 -13
- package/src/actions/regression/resolve.js +1 -1
- package/src/actions/resources/index.js +7 -0
- package/src/actions/resources/remove.js +172 -0
- package/src/actions/scales/channels.js +212 -0
- package/src/actions/scales/consumers/common.js +21 -54
- package/src/actions/scales/consumers/families.js +28 -14
- package/src/actions/scales/consumers/index.js +42 -4
- package/src/actions/scales/consumers/seriesLayout.js +57 -12
- package/src/actions/scales/create.js +58 -26
- package/src/actions/scales/definitions.js +109 -39
- package/src/actions/scales/edit.js +101 -34
- package/src/actions/scales/editPolicy.js +95 -35
- package/src/actions/scales/index.js +6 -0
- package/src/actions/scales/materialize.js +14 -49
- package/src/actions/scales/offset.js +48 -0
- package/src/actions/scales/parallel.js +71 -0
- package/src/actions/scales/patch.js +1 -1
- package/src/actions/scales/preview.js +140 -0
- package/src/actions/scales/quantitativeColor.js +9 -5
- package/src/actions/selection/actions.js +154 -30
- package/src/actions/selection/index.js +3 -0
- package/src/actions/theme/actions.js +98 -0
- package/src/actions/theme/composition.js +238 -0
- package/src/actions/theme/index.js +16 -0
- package/src/actions/theme/reconcile.js +1130 -0
- package/src/actions/theme/state.js +160 -0
- package/src/actions/titles/actions.js +11 -10
- package/src/actions/titles/resolve.js +1 -40
- package/src/actions/violinPlots/create.js +90 -43
- package/src/actions/violinPlots/edit.js +192 -0
- package/src/actions/violinPlots/index.js +2 -0
- package/src/core/ChartProgram.js +7 -0
- package/src/core/action.js +32 -2
- package/src/core/compositionState.js +141 -8
- package/src/core/programState.js +20 -0
- package/src/core/resourceReferences.js +332 -0
- package/src/core/vocabulary.js +16 -3
- package/src/grammar/aggregate.js +66 -23
- package/src/grammar/arcs.js +58 -1
- package/src/grammar/areaEndpoints.js +46 -0
- package/src/grammar/areaSeries.js +87 -41
- package/src/grammar/bars/aggregate.js +37 -13
- package/src/grammar/bars/geometry.js +44 -0
- package/src/grammar/bars/policy.js +9 -7
- package/src/grammar/bin.js +226 -0
- package/src/grammar/categoryOrder.js +34 -0
- package/src/grammar/complete.js +279 -0
- package/src/grammar/computed.js +351 -0
- package/src/grammar/coordinates.js +37 -0
- package/src/grammar/density.js +239 -37
- package/src/grammar/displayLabels.js +57 -0
- package/src/grammar/ecdf.js +198 -0
- package/src/grammar/facets/dependencies.js +133 -1
- package/src/grammar/facets/guides.js +3 -0
- package/src/grammar/facets/index.js +123 -52
- package/src/grammar/facets/scales.js +15 -18
- package/src/grammar/fold.js +123 -0
- package/src/grammar/horizon.js +6 -4
- package/src/grammar/impute.js +340 -0
- package/src/grammar/interval.js +37 -20
- package/src/grammar/lineSeries.js +20 -63
- package/src/grammar/markFilter.js +22 -4
- package/src/grammar/markLabelSelection.js +57 -0
- package/src/grammar/markLabels.js +110 -0
- package/src/grammar/normalize.js +366 -0
- package/src/grammar/parallelAxisTitles.js +16 -0
- package/src/grammar/pathSeries.js +109 -0
- package/src/grammar/pointPacking.js +183 -0
- package/src/grammar/pointShapes.js +13 -4
- package/src/grammar/polar.js +90 -8
- package/src/grammar/positionDatum.js +12 -0
- package/src/grammar/rects.js +9 -1
- package/src/grammar/regression/derive.js +4 -0
- package/src/grammar/regression/index.js +8 -2
- package/src/grammar/regression/models.js +22 -7
- package/src/grammar/regression/parameters.js +63 -13
- package/src/grammar/rotation.js +29 -0
- package/src/grammar/roundedRect.js +180 -0
- package/src/grammar/rules.js +8 -21
- package/src/grammar/scales/color.js +23 -1
- package/src/grammar/scales/colorConsumers.js +57 -0
- package/src/grammar/scales/continuous.js +2 -2
- package/src/grammar/scales/definition.js +42 -5
- package/src/grammar/scales/discretized.js +11 -5
- package/src/grammar/scales/fields.js +38 -8
- package/src/grammar/scales/index.js +1 -0
- package/src/grammar/scales/mapping.js +2 -0
- package/src/grammar/scales/ordinal.js +12 -3
- package/src/grammar/scales/policies.js +2 -2
- package/src/grammar/scales/radial.js +55 -0
- package/src/grammar/scales/size.js +456 -0
- package/src/grammar/scales/types.js +1 -0
- package/src/grammar/schemas/concreteGraphic.js +14 -2
- package/src/grammar/schemas/graphic.js +15 -0
- package/src/grammar/schemas/graphicBounds.js +179 -30
- package/src/grammar/schemas/semanticPath.js +23 -4
- package/src/grammar/stack.js +170 -0
- package/src/grammar/statisticalReference.js +103 -0
- package/src/grammar/statistics/confidenceInterval.js +101 -0
- package/src/grammar/strokeStyle.js +77 -0
- package/src/grammar/summary.js +245 -0
- package/src/grammar/text.js +22 -16
- package/src/grammar/timeUnit.js +234 -13
- package/src/grammar/transformTopology.js +10 -0
- package/src/grammar/transforms.js +418 -16
- package/src/grammar/valueFormat.js +112 -0
- package/src/grammar/weightedStatistics.js +374 -0
- package/src/grammar/window.js +232 -21
- package/src/layout/aspect.js +80 -0
- package/src/layout/facets.js +100 -12
- package/src/layout/guideCollisions.js +12 -0
- package/src/layout/labels.js +343 -0
- package/src/layout/legend.js +2 -10
- package/src/layout/legendItems.js +102 -0
- package/src/layout/legendLane.js +100 -11
- package/src/materialization/bars/aggregate.js +56 -147
- package/src/materialization/bars/histogram.js +104 -20
- package/src/materialization/bars/ranged.js +19 -3
- package/src/materialization/bars/resolve.js +7 -4
- package/src/materialization/categorySlotOffset.js +40 -0
- package/src/materialization/composition.js +3 -1
- package/src/materialization/compositionSnapshot.js +1 -1
- package/src/materialization/coordinateBounds.js +204 -0
- package/src/materialization/dependencies.js +93 -16
- package/src/materialization/encodings.js +1 -1
- package/src/materialization/facetGuides/legacyCategorical.js +3 -0
- package/src/materialization/facetGuides/placement.js +8 -2
- package/src/materialization/facetGuides/preparation.js +12 -7
- package/src/materialization/facetHeaders.js +346 -0
- package/src/materialization/facets.js +23 -66
- package/src/materialization/guides/layout.js +57 -0
- package/src/materialization/guides/resources.js +28 -2
- package/src/materialization/legends.js +11 -2
- package/src/materialization/marks/capabilities.js +20 -5
- package/src/materialization/marks/grouping.js +52 -0
- package/src/materialization/marks/index.js +68 -27
- package/src/materialization/marks/policies.js +4 -1
- package/src/materialization/rect.js +55 -42
- package/src/materialization/rectConfig.js +5 -1
- package/src/materialization/rowEncoding.js +13 -13
- package/src/materialization/scaleGuideDependencies.js +8 -5
- package/src/materialization/scales/map.js +6 -3
- package/src/materialization/scales/policies/arc.js +42 -0
- package/src/materialization/scales/policies/binnedPosition.js +7 -4
- package/src/materialization/scales/policies/offset.js +50 -8
- package/src/materialization/scales/policies/series.js +5 -1
- package/src/materialization/scales/resolve.js +65 -17
- package/src/materialization/selection/compatibility.js +11 -0
- package/src/materialization/selection/items/arc.js +28 -4
- package/src/materialization/selection/items/bar.js +42 -71
- package/src/materialization/selection/items/common.js +27 -6
- package/src/materialization/selection/items/path.js +3 -13
- package/src/materialization/selection/items/rect.js +35 -8
- package/src/materialization/selection/path.js +1 -1
- package/src/materialization/selection/point.js +3 -1
- package/src/materialization/text.js +324 -14
- package/src/mcp/adapter.js +2 -2
- package/src/renderers/canvas/circle.js +2 -3
- package/src/renderers/canvas/line.js +2 -3
- package/src/renderers/canvas/native.js +4 -4
- package/src/renderers/canvas/path.js +2 -3
- package/src/renderers/canvas/rect.js +2 -3
- package/src/renderers/canvas/stroke.js +11 -0
- package/src/renderers/svg.js +19 -0
- package/src/selectors/datasets.js +44 -0
- package/src/selectors/layers.js +7 -2
- package/src/selectors/scales.js +6 -0
- package/src/theme/defaults.js +140 -0
- package/types/basic.d.ts +17 -2
- package/types/index.d.ts +211 -0
- package/types/program.d.ts +2182 -204
- package/src/materialization/bars/grouped.js +0 -144
|
@@ -1,22 +1,28 @@
|
|
|
1
1
|
import { action } from "../../core/action.js";
|
|
2
2
|
import { validateUserId } from "../../core/identifiers.js";
|
|
3
3
|
import { validateKeys } from "../../core/validation.js";
|
|
4
|
+
import { withPreviewDatasetValues } from
|
|
5
|
+
"../primitives/semanticAction.js";
|
|
4
6
|
import {
|
|
5
7
|
deriveFilteredRows,
|
|
6
8
|
normalizeFilterTransform
|
|
7
9
|
} from "../../grammar/filter.js";
|
|
8
10
|
import {
|
|
9
11
|
deriveMarkFilteredRows,
|
|
12
|
+
markFilterSelectors,
|
|
10
13
|
normalizeMarkFilterTransform
|
|
11
14
|
} from "../../grammar/markFilter.js";
|
|
12
15
|
import { resolveMarkFilterSelection } from "../../materialization/selection/filter.js";
|
|
13
16
|
import { findSelectionPolicy } from
|
|
14
17
|
"../../materialization/selection/policies/index.js";
|
|
15
18
|
import {
|
|
16
|
-
applyLayerDataRematerialization
|
|
19
|
+
applyLayerDataRematerialization,
|
|
20
|
+
applyLayerEmptyDataView
|
|
17
21
|
} from "../../materialization/dependencies.js";
|
|
18
22
|
import {
|
|
19
23
|
hasDataset,
|
|
24
|
+
findDataset,
|
|
25
|
+
resolveDatasetReference,
|
|
20
26
|
requireLayer,
|
|
21
27
|
resolveEligibleLayer
|
|
22
28
|
} from "../../selectors/index.js";
|
|
@@ -29,7 +35,9 @@ const MARK_SELECTOR_KEYS = Object.freeze([
|
|
|
29
35
|
"grain", "field", "channel", "property", "op", "value", "values",
|
|
30
36
|
"min", "max", "inclusive", "count", "groupBy", "ties"
|
|
31
37
|
]);
|
|
32
|
-
const MARK_OPTIONS = Object.freeze(["target", ...MARK_SELECTOR_KEYS]);
|
|
38
|
+
const MARK_OPTIONS = Object.freeze(["target", "mode", ...MARK_SELECTOR_KEYS]);
|
|
39
|
+
const REMOVE_MARK_FILTER_OPTIONS = Object.freeze(["target"]);
|
|
40
|
+
const EMPTY_MARK_OPTIONS = Object.freeze(["id"]);
|
|
33
41
|
|
|
34
42
|
function retainedHistogramBoundaries(layer, items) {
|
|
35
43
|
if (layer.mark?.type !== "bar" || layer.encoding?.x?.bin === undefined) {
|
|
@@ -63,18 +71,29 @@ export const filterData = action(
|
|
|
63
71
|
function (args = {}) {
|
|
64
72
|
validateKeys(args, OPTIONS, "filterData");
|
|
65
73
|
const id = validateUserId(args.id, "Filtered dataset id");
|
|
66
|
-
const
|
|
74
|
+
const requestedSource = validateUserId(
|
|
67
75
|
args.source ?? this.context.currentData,
|
|
68
76
|
"Source dataset id"
|
|
69
77
|
);
|
|
78
|
+
const source = resolveDatasetReference(
|
|
79
|
+
this,
|
|
80
|
+
requestedSource,
|
|
81
|
+
"Filter source dataset"
|
|
82
|
+
).id;
|
|
70
83
|
const transform = normalizeFilterTransform(args);
|
|
71
|
-
|
|
84
|
+
const next = this
|
|
72
85
|
.createDerivedData({
|
|
73
86
|
id,
|
|
74
87
|
source,
|
|
75
88
|
transform: [transform]
|
|
76
89
|
})
|
|
77
90
|
.materializeFilteredData({ id });
|
|
91
|
+
return this.actionStack.length === 1
|
|
92
|
+
? next._withMaterializationConfig(
|
|
93
|
+
["data", "filter", id],
|
|
94
|
+
{ current: id }
|
|
95
|
+
)
|
|
96
|
+
: next;
|
|
78
97
|
}
|
|
79
98
|
);
|
|
80
99
|
|
|
@@ -96,15 +115,168 @@ export const materializeMarkFilteredData = action(
|
|
|
96
115
|
`Mark filter target "${transform.target}" must still use source dataset "${dataset.source}".`
|
|
97
116
|
);
|
|
98
117
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
118
|
+
let preview = this;
|
|
119
|
+
let currentRows = source.values;
|
|
120
|
+
const selectors = markFilterSelectors(transform);
|
|
121
|
+
for (const [index, selector] of selectors.entries()) {
|
|
122
|
+
const resolved = resolveMarkFilterSelection(
|
|
123
|
+
preview,
|
|
124
|
+
transform.target,
|
|
125
|
+
selector
|
|
126
|
+
);
|
|
127
|
+
currentRows = deriveMarkFilteredRows(
|
|
128
|
+
currentRows,
|
|
129
|
+
resolved.items,
|
|
130
|
+
resolved.keys
|
|
131
|
+
);
|
|
132
|
+
if (index < selectors.length - 1) {
|
|
133
|
+
preview = withPreviewDatasetValues(preview, {
|
|
134
|
+
id,
|
|
135
|
+
values: currentRows,
|
|
136
|
+
target: transform.target
|
|
137
|
+
});
|
|
138
|
+
preview = currentRows.length === 0
|
|
139
|
+
? applyLayerEmptyDataView(preview, transform.target)
|
|
140
|
+
: applyLayerDataRematerialization(preview, transform.target);
|
|
141
|
+
currentRows = findDataset(preview, id).values;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (selectors.length > 1) {
|
|
145
|
+
preview = withPreviewDatasetValues(preview, {
|
|
146
|
+
id,
|
|
147
|
+
omitValues: true
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
let next = preview.editSemantic({
|
|
105
151
|
property: `dataset[${id}].values`,
|
|
106
|
-
value:
|
|
152
|
+
value: currentRows
|
|
153
|
+
});
|
|
154
|
+
if (requireLayer(next, transform.target).data !== id) {
|
|
155
|
+
next = next.editSemantic({
|
|
156
|
+
property: `layer[${transform.target}].data`,
|
|
157
|
+
value: id
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
next = next._withMarkConfig(transform.target, {
|
|
161
|
+
...next.markConfigs[transform.target],
|
|
162
|
+
markFilter: {
|
|
163
|
+
...next.markConfigs[transform.target].markFilter,
|
|
164
|
+
empty: currentRows.length === 0
|
|
165
|
+
}
|
|
107
166
|
});
|
|
167
|
+
return currentRows.length === 0
|
|
168
|
+
? next.materializeEmptyMark({ id: transform.target })
|
|
169
|
+
: applyLayerDataRematerialization(next, transform.target);
|
|
170
|
+
}
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
export const materializeEmptyMark = action(
|
|
174
|
+
{
|
|
175
|
+
op: "materializeEmptyMark",
|
|
176
|
+
description: "Clear one active empty-filter mark without changing its domains."
|
|
177
|
+
},
|
|
178
|
+
function (args = {}) {
|
|
179
|
+
validateKeys(args, EMPTY_MARK_OPTIONS, "materializeEmptyMark");
|
|
180
|
+
const id = validateUserId(args.id, "Empty mark id");
|
|
181
|
+
const layer = requireLayer(this, id);
|
|
182
|
+
const owner = this.markConfigs[id]?.markFilter;
|
|
183
|
+
const dataset = findDataset(this, layer.data);
|
|
184
|
+
if (owner?.empty !== true || dataset?.values?.length !== 0) {
|
|
185
|
+
throw new Error(`Mark "${id}" does not own an active empty filter.`);
|
|
186
|
+
}
|
|
187
|
+
return applyLayerEmptyDataView(this, id);
|
|
188
|
+
}
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
function activeMarkFilter(program, layer) {
|
|
192
|
+
const configured = program.markConfigs[layer.id]?.markFilter;
|
|
193
|
+
const dataset = findDataset(program, layer.data);
|
|
194
|
+
const transform = dataset?.transform?.[0];
|
|
195
|
+
if (
|
|
196
|
+
dataset?.source === undefined ||
|
|
197
|
+
transform?.type !== "markFilter" ||
|
|
198
|
+
transform.target !== layer.id
|
|
199
|
+
) {
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
return {
|
|
203
|
+
dataset: dataset.id,
|
|
204
|
+
source: dataset.source,
|
|
205
|
+
selectors: markFilterSelectors(transform),
|
|
206
|
+
...(configured?.originalBin === undefined
|
|
207
|
+
? {}
|
|
208
|
+
: { originalBin: configured.originalBin })
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function withoutMarkFilterConfig(program, id) {
|
|
213
|
+
const config = program.markConfigs[id] ?? {};
|
|
214
|
+
const { markFilter: unused, ...remaining } = config;
|
|
215
|
+
void unused;
|
|
216
|
+
return program._withMarkConfig(id, remaining);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function restoreHistogramBin(program, layer, originalBin) {
|
|
220
|
+
let next = program;
|
|
221
|
+
const current = layer.encoding?.x?.bin ?? {};
|
|
222
|
+
for (const property of ["maxBins", "step", "boundaries"]) {
|
|
223
|
+
if (Object.hasOwn(originalBin, property)) {
|
|
224
|
+
next = next.editSemantic({
|
|
225
|
+
property: `layer[${layer.id}].encoding.x.bin.${property}`,
|
|
226
|
+
value: originalBin[property]
|
|
227
|
+
});
|
|
228
|
+
} else if (Object.hasOwn(current, property)) {
|
|
229
|
+
next = next.editSemantic({
|
|
230
|
+
property: `layer[${layer.id}].encoding.x.bin.${property}`,
|
|
231
|
+
remove: true
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return next;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function removeActiveMarkFilter(program, layer, owner) {
|
|
239
|
+
let next = program.editSemantic({
|
|
240
|
+
property: `layer[${layer.id}].data`,
|
|
241
|
+
value: owner.source
|
|
242
|
+
});
|
|
243
|
+
if (owner.originalBin !== undefined) {
|
|
244
|
+
next = restoreHistogramBin(next, requireLayer(next, layer.id), owner.originalBin);
|
|
245
|
+
}
|
|
246
|
+
next = withoutMarkFilterConfig(next, layer.id)
|
|
247
|
+
.releaseDerivedData({ id: owner.dataset })
|
|
248
|
+
._withContext({ currentData: owner.source });
|
|
249
|
+
return applyLayerDataRematerialization(next, layer.id);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function nextMarkFilterDatasetId(program, layerId) {
|
|
253
|
+
const base = `${layerId}FilteredData`;
|
|
254
|
+
if (!hasDataset(program, base)) return base;
|
|
255
|
+
let revision = 2;
|
|
256
|
+
while (hasDataset(program, `${base}${revision}`)) revision += 1;
|
|
257
|
+
return `${base}${revision}`;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function sameSelector(left, right) {
|
|
261
|
+
return JSON.stringify(left) === JSON.stringify(right);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export const removeMarkFilter = action(
|
|
265
|
+
{
|
|
266
|
+
op: "removeMarkFilter",
|
|
267
|
+
description: "Remove one active final-item filter and restore its source."
|
|
268
|
+
},
|
|
269
|
+
function (args = {}) {
|
|
270
|
+
validateKeys(args, REMOVE_MARK_FILTER_OPTIONS, "removeMarkFilter");
|
|
271
|
+
const target = args.target === undefined
|
|
272
|
+
? undefined
|
|
273
|
+
: validateUserId(args.target, "Mark filter target id");
|
|
274
|
+
const layer = resolveEligibleLayer(this, {
|
|
275
|
+
target,
|
|
276
|
+
label: "mark filter",
|
|
277
|
+
predicate: candidate => activeMarkFilter(this, candidate) !== undefined
|
|
278
|
+
});
|
|
279
|
+
return removeActiveMarkFilter(this, layer, activeMarkFilter(this, layer));
|
|
108
280
|
}
|
|
109
281
|
);
|
|
110
282
|
|
|
@@ -115,6 +287,9 @@ export const filterMarks = action(
|
|
|
115
287
|
},
|
|
116
288
|
function (args = {}) {
|
|
117
289
|
validateKeys(args, MARK_OPTIONS, "filterMarks");
|
|
290
|
+
if (args.mode !== undefined && !["replace", "compose"].includes(args.mode)) {
|
|
291
|
+
throw new Error(`Unknown mark filter mode "${args.mode}".`);
|
|
292
|
+
}
|
|
118
293
|
const target = args.target === undefined
|
|
119
294
|
? undefined
|
|
120
295
|
: validateUserId(args.target, "Filter mark target id");
|
|
@@ -130,46 +305,67 @@ export const filterMarks = action(
|
|
|
130
305
|
`filterMarks does not support composite mark "${layer.id}"; filter its source dataset first.`
|
|
131
306
|
);
|
|
132
307
|
}
|
|
133
|
-
const
|
|
134
|
-
if (hasDataset(this, derivedId)) {
|
|
135
|
-
throw new Error(`Dataset "${derivedId}" already exists.`);
|
|
136
|
-
}
|
|
308
|
+
const owner = activeMarkFilter(this, layer);
|
|
137
309
|
const selector = Object.fromEntries(
|
|
138
310
|
MARK_SELECTOR_KEYS.flatMap(key =>
|
|
139
311
|
Object.hasOwn(args, key) ? [[key, args[key]]] : []
|
|
140
312
|
)
|
|
141
313
|
);
|
|
142
314
|
const resolved = resolveMarkFilterSelection(this, layer.id, selector);
|
|
143
|
-
|
|
144
|
-
|
|
315
|
+
const previousSelector = owner?.selectors.at(-1);
|
|
316
|
+
if (previousSelector !== undefined && sameSelector(previousSelector, resolved.selector)) {
|
|
317
|
+
return this;
|
|
318
|
+
}
|
|
319
|
+
if (owner !== undefined && args.mode === undefined) {
|
|
320
|
+
throw new Error(
|
|
321
|
+
"Repeated filterMarks requires mode \"replace\" or \"compose\"."
|
|
322
|
+
);
|
|
145
323
|
}
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
324
|
+
const selectors = owner === undefined || args.mode === "replace"
|
|
325
|
+
? [resolved.selector]
|
|
326
|
+
: [...owner.selectors, resolved.selector];
|
|
327
|
+
let next = owner === undefined
|
|
328
|
+
? this
|
|
329
|
+
: removeActiveMarkFilter(this, layer, owner);
|
|
330
|
+
const baseLayer = requireLayer(next, layer.id);
|
|
331
|
+
const first = resolveMarkFilterSelection(next, layer.id, selectors[0]);
|
|
332
|
+
const transform = normalizeMarkFilterTransform(layer.id, selectors);
|
|
333
|
+
const boundaries = retainedHistogramBoundaries(baseLayer, first.items);
|
|
334
|
+
const originalBin = baseLayer.mark?.type === "bar" &&
|
|
335
|
+
baseLayer.encoding?.x?.bin !== undefined
|
|
336
|
+
? baseLayer.encoding.x.bin
|
|
337
|
+
: undefined;
|
|
338
|
+
const derivedId = nextMarkFilterDatasetId(next, layer.id);
|
|
339
|
+
next = next
|
|
149
340
|
.createDerivedData({
|
|
150
341
|
id: derivedId,
|
|
151
|
-
source:
|
|
342
|
+
source: baseLayer.data,
|
|
152
343
|
transform: [transform]
|
|
153
|
-
})
|
|
154
|
-
.materializeMarkFilteredData({ id: derivedId });
|
|
344
|
+
});
|
|
155
345
|
if (boundaries !== undefined) {
|
|
156
346
|
for (const property of ["maxBins", "step"]) {
|
|
157
|
-
if (Object.hasOwn(
|
|
347
|
+
if (Object.hasOwn(baseLayer.encoding.x.bin, property)) {
|
|
158
348
|
next = next.editSemantic({
|
|
159
|
-
property: `layer[${
|
|
349
|
+
property: `layer[${baseLayer.id}].encoding.x.bin.${property}`,
|
|
160
350
|
remove: true
|
|
161
351
|
});
|
|
162
352
|
}
|
|
163
353
|
}
|
|
164
354
|
next = next.editSemantic({
|
|
165
|
-
property: `layer[${
|
|
355
|
+
property: `layer[${baseLayer.id}].encoding.x.bin.boundaries`,
|
|
166
356
|
value: boundaries
|
|
167
357
|
});
|
|
168
358
|
}
|
|
169
|
-
next = next.
|
|
170
|
-
|
|
171
|
-
|
|
359
|
+
next = next._withMarkConfig(baseLayer.id, {
|
|
360
|
+
...next.markConfigs[baseLayer.id],
|
|
361
|
+
markFilter: {
|
|
362
|
+
dataset: derivedId,
|
|
363
|
+
source: baseLayer.data,
|
|
364
|
+
selectors,
|
|
365
|
+
empty: false,
|
|
366
|
+
...(originalBin === undefined ? {} : { originalBin })
|
|
367
|
+
}
|
|
172
368
|
});
|
|
173
|
-
return
|
|
369
|
+
return next.materializeMarkFilteredData({ id: derivedId });
|
|
174
370
|
}
|
|
175
371
|
);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import {
|
|
2
|
+
deriveFoldRows,
|
|
3
|
+
normalizeFoldTransform
|
|
4
|
+
} from "../../grammar/fold.js";
|
|
5
|
+
import { derivedCreator, derivedMaterializer } from "./shared.js";
|
|
6
|
+
|
|
7
|
+
const OPTIONS = Object.freeze(["id", "source", "fields", "as"]);
|
|
8
|
+
|
|
9
|
+
export const materializeFoldData = derivedMaterializer(
|
|
10
|
+
"materializeFoldData",
|
|
11
|
+
"Materialize one immutable wide-to-long dataset.",
|
|
12
|
+
"fold",
|
|
13
|
+
deriveFoldRows
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
export const createFoldData = derivedCreator(
|
|
17
|
+
"createFoldData",
|
|
18
|
+
"Create reusable key/value rows from selected wide fields.",
|
|
19
|
+
OPTIONS,
|
|
20
|
+
"Fold dataset id",
|
|
21
|
+
"Fold source dataset id",
|
|
22
|
+
normalizeFoldTransform,
|
|
23
|
+
"materializeFoldData"
|
|
24
|
+
);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {
|
|
2
|
+
deriveImputedRows,
|
|
3
|
+
normalizeImputeTransform
|
|
4
|
+
} from "../../grammar/impute.js";
|
|
5
|
+
import { derivedCreator, derivedMaterializer } from "./shared.js";
|
|
6
|
+
|
|
7
|
+
const OPTIONS = Object.freeze([
|
|
8
|
+
"id", "source", "fields", "groupBy", "sortBy", "method", "value", "edges", "maxGap"
|
|
9
|
+
]);
|
|
10
|
+
|
|
11
|
+
export const materializeImputedData = derivedMaterializer(
|
|
12
|
+
"materializeImputedData",
|
|
13
|
+
"Materialize one immutable missing-value dataset.",
|
|
14
|
+
"impute",
|
|
15
|
+
deriveImputedRows
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
export const createImputedData = derivedCreator(
|
|
19
|
+
"createImputedData",
|
|
20
|
+
"Replace explicit missing cells within independent groups.",
|
|
21
|
+
OPTIONS,
|
|
22
|
+
"Imputed dataset id",
|
|
23
|
+
"Imputed source dataset id",
|
|
24
|
+
normalizeImputeTransform,
|
|
25
|
+
"materializeImputedData"
|
|
26
|
+
);
|
|
@@ -4,12 +4,15 @@ import {
|
|
|
4
4
|
} from "./timeUnit.js";
|
|
5
5
|
import {
|
|
6
6
|
createDerivedData,
|
|
7
|
+
bindMarkData,
|
|
7
8
|
rebindLayerData,
|
|
8
9
|
releaseDerivedData
|
|
9
10
|
} from "./derived.js";
|
|
10
11
|
import {
|
|
11
12
|
filterData,
|
|
12
13
|
filterMarks,
|
|
14
|
+
materializeEmptyMark,
|
|
15
|
+
removeMarkFilter,
|
|
13
16
|
materializeFilteredData,
|
|
14
17
|
materializeMarkFilteredData
|
|
15
18
|
} from "./filter.js";
|
|
@@ -24,6 +27,7 @@ import {
|
|
|
24
27
|
materializeDensityData
|
|
25
28
|
} from "./density.js";
|
|
26
29
|
import { createIntervalData, materializeIntervalData } from "./interval.js";
|
|
30
|
+
import { createECDFData, materializeECDFData } from "./ecdf.js";
|
|
27
31
|
import { createHorizonData, materializeHorizonData } from "./horizon.js";
|
|
28
32
|
import {
|
|
29
33
|
createBin2DData,
|
|
@@ -32,11 +36,25 @@ import {
|
|
|
32
36
|
} from "./bin2d.js";
|
|
33
37
|
import { createData } from "./create.js";
|
|
34
38
|
import { createWindowData, materializeWindowData } from "./window.js";
|
|
39
|
+
import { createSummaryData, materializeSummaryData } from "./summary.js";
|
|
40
|
+
import { createBinData, materializeBinData } from "./bin.js";
|
|
41
|
+
import { createFoldData, materializeFoldData } from "./fold.js";
|
|
42
|
+
import { createComputedData, materializeComputedData } from "./computed.js";
|
|
43
|
+
import {
|
|
44
|
+
createNormalizedData,
|
|
45
|
+
materializeNormalizedData
|
|
46
|
+
} from "./normalize.js";
|
|
47
|
+
import { createCompleteData, materializeCompleteData } from "./complete.js";
|
|
48
|
+
import { createImputedData, materializeImputedData } from "./impute.js";
|
|
49
|
+
import { createStackData, materializeStackData } from "./stack.js";
|
|
50
|
+
import { EDIT_DERIVED_DATA_ACTIONS } from "./edit.js";
|
|
35
51
|
import { createBoxSummaryData, createBoxOutlierData, materializeBoxSummaryData, materializeBoxOutlierData } from "./box.js";
|
|
36
52
|
|
|
37
53
|
export function registerDataActions(ProgramClass) {
|
|
54
|
+
Object.assign(ProgramClass.prototype, EDIT_DERIVED_DATA_ACTIONS);
|
|
38
55
|
ProgramClass.prototype.createData = createData;
|
|
39
56
|
ProgramClass.prototype.createDerivedData = createDerivedData;
|
|
57
|
+
ProgramClass.prototype.bindMarkData = bindMarkData;
|
|
40
58
|
ProgramClass.prototype.releaseDerivedData = releaseDerivedData;
|
|
41
59
|
ProgramClass.prototype.rebindLayerData = rebindLayerData;
|
|
42
60
|
ProgramClass.prototype.createDensityData = createDensityData;
|
|
@@ -46,6 +64,8 @@ export function registerDataActions(ProgramClass) {
|
|
|
46
64
|
ProgramClass.prototype.materializeMarkFilteredData = materializeMarkFilteredData;
|
|
47
65
|
ProgramClass.prototype.filterData = filterData;
|
|
48
66
|
ProgramClass.prototype.filterMarks = filterMarks;
|
|
67
|
+
ProgramClass.prototype.materializeEmptyMark = materializeEmptyMark;
|
|
68
|
+
ProgramClass.prototype.removeMarkFilter = removeMarkFilter;
|
|
49
69
|
ProgramClass.prototype.materializeRegressionData = materializeRegressionData;
|
|
50
70
|
ProgramClass.prototype.materializeDensityData = materializeDensityData;
|
|
51
71
|
ProgramClass.prototype.createGradientProfileData = createGradientProfileData;
|
|
@@ -54,10 +74,28 @@ export function registerDataActions(ProgramClass) {
|
|
|
54
74
|
ProgramClass.prototype.createRegressionData = createRegressionData;
|
|
55
75
|
ProgramClass.prototype.materializeIntervalData = materializeIntervalData;
|
|
56
76
|
ProgramClass.prototype.createIntervalData = createIntervalData;
|
|
77
|
+
ProgramClass.prototype.createECDFData = createECDFData;
|
|
78
|
+
ProgramClass.prototype.materializeECDFData = materializeECDFData;
|
|
57
79
|
ProgramClass.prototype.createHorizonData = createHorizonData;
|
|
58
80
|
ProgramClass.prototype.materializeHorizonData = materializeHorizonData;
|
|
59
81
|
ProgramClass.prototype.createWindowData = createWindowData;
|
|
60
82
|
ProgramClass.prototype.materializeWindowData = materializeWindowData;
|
|
83
|
+
ProgramClass.prototype.createSummaryData = createSummaryData;
|
|
84
|
+
ProgramClass.prototype.materializeSummaryData = materializeSummaryData;
|
|
85
|
+
ProgramClass.prototype.createBinData = createBinData;
|
|
86
|
+
ProgramClass.prototype.materializeBinData = materializeBinData;
|
|
87
|
+
ProgramClass.prototype.createFoldData = createFoldData;
|
|
88
|
+
ProgramClass.prototype.materializeFoldData = materializeFoldData;
|
|
89
|
+
ProgramClass.prototype.createComputedData = createComputedData;
|
|
90
|
+
ProgramClass.prototype.materializeComputedData = materializeComputedData;
|
|
91
|
+
ProgramClass.prototype.createNormalizedData = createNormalizedData;
|
|
92
|
+
ProgramClass.prototype.materializeNormalizedData = materializeNormalizedData;
|
|
93
|
+
ProgramClass.prototype.createCompleteData = createCompleteData;
|
|
94
|
+
ProgramClass.prototype.materializeCompleteData = materializeCompleteData;
|
|
95
|
+
ProgramClass.prototype.createImputedData = createImputedData;
|
|
96
|
+
ProgramClass.prototype.materializeImputedData = materializeImputedData;
|
|
97
|
+
ProgramClass.prototype.createStackData = createStackData;
|
|
98
|
+
ProgramClass.prototype.materializeStackData = materializeStackData;
|
|
61
99
|
ProgramClass.prototype.createTimeUnitData = createTimeUnitData;
|
|
62
100
|
ProgramClass.prototype.materializeTimeUnitData = materializeTimeUnitData;
|
|
63
101
|
ProgramClass.prototype.createBin2DData = createBin2DData;
|
|
@@ -11,6 +11,7 @@ const OPTIONS = Object.freeze([
|
|
|
11
11
|
"groupBy",
|
|
12
12
|
"center",
|
|
13
13
|
"extent",
|
|
14
|
+
"method",
|
|
14
15
|
"level",
|
|
15
16
|
"as"
|
|
16
17
|
]);
|
|
@@ -39,6 +40,7 @@ export const createIntervalData = derivedCreator(
|
|
|
39
40
|
groupBy: args.groupBy,
|
|
40
41
|
center: args.center,
|
|
41
42
|
extent: args.extent,
|
|
43
|
+
method: args.method,
|
|
42
44
|
level: args.level,
|
|
43
45
|
as
|
|
44
46
|
});
|
|
@@ -7,7 +7,7 @@ import { planDerivedDataRevision } from
|
|
|
7
7
|
import { findDataset } from "../../selectors/datasets.js";
|
|
8
8
|
import { resolveEligibleLayer } from "../../selectors/layers.js";
|
|
9
9
|
|
|
10
|
-
const STATISTICS_OPTIONS = Object.freeze(["center", "extent", "level"]);
|
|
10
|
+
const STATISTICS_OPTIONS = Object.freeze(["center", "extent", "method", "level"]);
|
|
11
11
|
|
|
12
12
|
export function ownOptions(value, options) {
|
|
13
13
|
return Object.fromEntries(
|
|
@@ -42,6 +42,7 @@ export function createResolvedIntervalData(program, resolved) {
|
|
|
42
42
|
groupBy: resolved.groupBy,
|
|
43
43
|
center: resolved.interval.center,
|
|
44
44
|
extent: resolved.interval.extent,
|
|
45
|
+
method: resolved.interval.method,
|
|
45
46
|
level: resolved.interval.level,
|
|
46
47
|
as: resolved.fields
|
|
47
48
|
});
|
|
@@ -49,7 +50,9 @@ export function createResolvedIntervalData(program, resolved) {
|
|
|
49
50
|
|
|
50
51
|
export function applyIntervalRevision(program, interval) {
|
|
51
52
|
if (!interval.changed) return program;
|
|
52
|
-
let next =
|
|
53
|
+
let next = interval.dataArgs === undefined
|
|
54
|
+
? program
|
|
55
|
+
: program.createIntervalData(interval.dataArgs);
|
|
53
56
|
for (const rebind of interval.revision.rebinds) {
|
|
54
57
|
next = next.rebindLayerData(rebind);
|
|
55
58
|
}
|
|
@@ -57,11 +60,84 @@ export function applyIntervalRevision(program, interval) {
|
|
|
57
60
|
}
|
|
58
61
|
|
|
59
62
|
export function releaseIntervalRevision(program, interval) {
|
|
60
|
-
return interval.changed
|
|
63
|
+
return interval.changed && interval.revision.release !== undefined
|
|
61
64
|
? program.releaseDerivedData(interval.revision.release)
|
|
62
65
|
: program;
|
|
63
66
|
}
|
|
64
67
|
|
|
68
|
+
export function findIntervalTransform(program, data) {
|
|
69
|
+
const dataset = findDataset(program, data);
|
|
70
|
+
return dataset?.transform?.length === 1 &&
|
|
71
|
+
dataset.transform[0].type === "interval"
|
|
72
|
+
? dataset.transform[0]
|
|
73
|
+
: undefined;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function collectIntervalConsumers(program, owners) {
|
|
77
|
+
const consumers = new Set(owners);
|
|
78
|
+
let changed = true;
|
|
79
|
+
while (changed) {
|
|
80
|
+
changed = false;
|
|
81
|
+
for (const layer of program.semanticSpec.layers ?? []) {
|
|
82
|
+
if (
|
|
83
|
+
layer.source !== undefined &&
|
|
84
|
+
consumers.has(layer.source) &&
|
|
85
|
+
!consumers.has(layer.id)
|
|
86
|
+
) {
|
|
87
|
+
consumers.add(layer.id);
|
|
88
|
+
changed = true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return [...consumers];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function planIntervalRoleData(program, {
|
|
96
|
+
owner,
|
|
97
|
+
currentData,
|
|
98
|
+
candidate,
|
|
99
|
+
consumers
|
|
100
|
+
}) {
|
|
101
|
+
const previousTransform = findIntervalTransform(program, currentData);
|
|
102
|
+
if (candidate.interval.mode === "statistical") {
|
|
103
|
+
const revision = planDerivedDataRevision(program, {
|
|
104
|
+
owner,
|
|
105
|
+
role: "IntervalData",
|
|
106
|
+
...(previousTransform === undefined ? {} : { previous: currentData }),
|
|
107
|
+
consumers
|
|
108
|
+
});
|
|
109
|
+
return {
|
|
110
|
+
changed: true,
|
|
111
|
+
revision,
|
|
112
|
+
dataId: revision.id,
|
|
113
|
+
dataArgs: {
|
|
114
|
+
id: revision.id,
|
|
115
|
+
source: candidate.source,
|
|
116
|
+
field: candidate.interval.field,
|
|
117
|
+
groupBy: candidate.groupBy,
|
|
118
|
+
center: candidate.interval.center,
|
|
119
|
+
extent: candidate.interval.extent,
|
|
120
|
+
method: candidate.interval.method,
|
|
121
|
+
level: candidate.interval.level,
|
|
122
|
+
as: candidate.fields
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
const changed = currentData !== candidate.source;
|
|
127
|
+
return {
|
|
128
|
+
changed,
|
|
129
|
+
dataId: candidate.source,
|
|
130
|
+
revision: {
|
|
131
|
+
rebinds: changed
|
|
132
|
+
? consumers.map(id => ({ id, data: candidate.source }))
|
|
133
|
+
: [],
|
|
134
|
+
...(previousTransform === undefined
|
|
135
|
+
? {}
|
|
136
|
+
: { release: { id: currentData } })
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
65
141
|
export function planIntervalEdit(program, {
|
|
66
142
|
owner,
|
|
67
143
|
data,
|
|
@@ -75,7 +151,7 @@ export function planIntervalEdit(program, {
|
|
|
75
151
|
validateKeys(statistics, STATISTICS_OPTIONS, `${operation} statistics`);
|
|
76
152
|
if (!STATISTICS_OPTIONS.some(key => Object.hasOwn(statistics, key))) {
|
|
77
153
|
throw new Error(
|
|
78
|
-
`${operation} statistics requires center, extent, or level.`
|
|
154
|
+
`${operation} statistics requires center, extent, method, or level.`
|
|
79
155
|
);
|
|
80
156
|
}
|
|
81
157
|
const previous = findDataset(program, data);
|
|
@@ -95,6 +171,11 @@ export function planIntervalEdit(program, {
|
|
|
95
171
|
? statistics.extent
|
|
96
172
|
: transform.extent;
|
|
97
173
|
const raw = { center, extent };
|
|
174
|
+
if (Object.hasOwn(statistics, "method")) {
|
|
175
|
+
raw.method = statistics.method;
|
|
176
|
+
} else if (extent === "ci" && transform.extent === "ci") {
|
|
177
|
+
raw.method = transform.method;
|
|
178
|
+
}
|
|
98
179
|
if (Object.hasOwn(statistics, "level")) {
|
|
99
180
|
raw.level = statistics.level;
|
|
100
181
|
} else if (extent === "ci" && transform.extent === "ci") {
|
|
@@ -104,6 +185,7 @@ export function planIntervalEdit(program, {
|
|
|
104
185
|
const current = {
|
|
105
186
|
center: transform.center,
|
|
106
187
|
extent: transform.extent,
|
|
188
|
+
...(transform.method === undefined ? {} : { method: transform.method }),
|
|
107
189
|
...(transform.level === undefined ? {} : { level: transform.level })
|
|
108
190
|
};
|
|
109
191
|
const changed = JSON.stringify(parameters) !== JSON.stringify(current);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {
|
|
2
|
+
deriveNormalizedRows,
|
|
3
|
+
normalizeNormalizeTransform
|
|
4
|
+
} from "../../grammar/normalize.js";
|
|
5
|
+
import { derivedCreator, derivedMaterializer } from "./shared.js";
|
|
6
|
+
|
|
7
|
+
const OPTIONS = Object.freeze([
|
|
8
|
+
"id", "source", "field", "as", "groupBy", "method",
|
|
9
|
+
"variance", "zeroDenominator", "baseline", "sortBy"
|
|
10
|
+
]);
|
|
11
|
+
|
|
12
|
+
export const materializeNormalizedData = derivedMaterializer(
|
|
13
|
+
"materializeNormalizedData",
|
|
14
|
+
"Materialize one immutable grouped normalization dataset.",
|
|
15
|
+
"normalize",
|
|
16
|
+
deriveNormalizedRows
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
export const createNormalizedData = derivedCreator(
|
|
20
|
+
"createNormalizedData",
|
|
21
|
+
"Create a row-preserving grouped normalization dataset.",
|
|
22
|
+
OPTIONS,
|
|
23
|
+
"Normalized dataset id",
|
|
24
|
+
"Normalized source dataset id",
|
|
25
|
+
normalizeNormalizeTransform,
|
|
26
|
+
"materializeNormalizedData"
|
|
27
|
+
);
|