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
|
@@ -4,10 +4,14 @@ import { readQuantitativeField } from "../../grammar/scales/index.js";
|
|
|
4
4
|
import { BAR_GRAINS, resolveBarGrain } from "../../grammar/bars/policy.js";
|
|
5
5
|
import { resolveFacetScaleDomains } from "../../grammar/facets/scales.js";
|
|
6
6
|
import {
|
|
7
|
+
applyLayerEmptyDataView,
|
|
7
8
|
applyMaterializationPlan,
|
|
8
9
|
planScaleGuideRematerialization
|
|
9
10
|
} from "../../materialization/dependencies.js";
|
|
10
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
getLayerScaleIds,
|
|
13
|
+
getMarkMaterializationStep
|
|
14
|
+
} from "../../materialization/marks/index.js";
|
|
11
15
|
import { buildMaterializationPlan } from "../../materialization/planner.js";
|
|
12
16
|
import { requireDataset } from "../../selectors/datasets.js";
|
|
13
17
|
import { requireLayer } from "../../selectors/layers.js";
|
|
@@ -56,19 +60,31 @@ function applySharedHistogramBoundaries(program, layerId, boundaries) {
|
|
|
56
60
|
});
|
|
57
61
|
}
|
|
58
62
|
|
|
59
|
-
function
|
|
63
|
+
function buildFacetCellCandidate(
|
|
60
64
|
base,
|
|
61
65
|
definition,
|
|
62
66
|
cell,
|
|
63
67
|
histogramBoundaries,
|
|
64
68
|
scales
|
|
65
69
|
) {
|
|
66
|
-
|
|
67
|
-
id: cell.data,
|
|
68
|
-
source: definition.data,
|
|
70
|
+
const filters = cell.filters ?? [{
|
|
69
71
|
field: definition.field,
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
+
value: cell.value
|
|
73
|
+
}];
|
|
74
|
+
let child = base;
|
|
75
|
+
let source = definition.data;
|
|
76
|
+
for (const [index, filter] of filters.entries()) {
|
|
77
|
+
const id = index === filters.length - 1
|
|
78
|
+
? cell.data
|
|
79
|
+
: `${cell.id}-partition-${index + 1}-data`;
|
|
80
|
+
child = child.filterData({
|
|
81
|
+
id,
|
|
82
|
+
source,
|
|
83
|
+
field: filter.field,
|
|
84
|
+
oneOf: [filter.value]
|
|
85
|
+
});
|
|
86
|
+
source = id;
|
|
87
|
+
}
|
|
72
88
|
const datasets = new Map([[definition.data, cell.data]]);
|
|
73
89
|
for (const replay of definition.dependencies.replay) {
|
|
74
90
|
const source = datasets.get(replay.source);
|
|
@@ -90,6 +106,7 @@ function deriveCellProgram(
|
|
|
90
106
|
});
|
|
91
107
|
datasets.set(replay.id, id);
|
|
92
108
|
}
|
|
109
|
+
const reboundData = new Map();
|
|
93
110
|
for (const layer of definition.dependencies.layers) {
|
|
94
111
|
const data = datasets.get(layer.data);
|
|
95
112
|
if (data === undefined) {
|
|
@@ -97,6 +114,14 @@ function deriveCellProgram(
|
|
|
97
114
|
`Facet layer "${layer.id}" has no replayed dataset in cell "${cell.id}".`
|
|
98
115
|
);
|
|
99
116
|
}
|
|
117
|
+
reboundData.set(layer.id, data);
|
|
118
|
+
const statistical = child.markConfigs[layer.id]?.statisticalReference;
|
|
119
|
+
if (statistical !== undefined) {
|
|
120
|
+
child = child._withMarkConfig(layer.id, {
|
|
121
|
+
...child.markConfigs[layer.id],
|
|
122
|
+
statisticalReference: { ...statistical, dataId: data }
|
|
123
|
+
});
|
|
124
|
+
}
|
|
100
125
|
child = child.rebindLayerData({ id: layer.id, data });
|
|
101
126
|
child = applySharedHistogramBoundaries(
|
|
102
127
|
child,
|
|
@@ -116,20 +141,35 @@ function deriveCellProgram(
|
|
|
116
141
|
}
|
|
117
142
|
child = child.rebindGradientPlotProfile({ id, profile, source });
|
|
118
143
|
}
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
144
|
+
const primaryLayers = definition.dependencies.primaryLayers ??
|
|
145
|
+
definition.dependencies.layers.map(layer => layer.id);
|
|
146
|
+
const populated = primaryLayers.some(id => {
|
|
147
|
+
const data = reboundData.get(id);
|
|
148
|
+
return data !== undefined && requireDataset(child, data).values.length > 0;
|
|
149
|
+
});
|
|
150
|
+
if (!populated) {
|
|
151
|
+
for (const layer of definition.dependencies.layers) {
|
|
152
|
+
child = applyLayerEmptyDataView(child, layer.id);
|
|
153
|
+
}
|
|
154
|
+
return { program: child, populated: false };
|
|
155
|
+
}
|
|
156
|
+
const scaleIds = [...new Set(child.semanticSpec.layers.flatMap(getLayerScaleIds))];
|
|
157
|
+
const program = applyMaterializationPlan(child, buildMaterializationPlan({
|
|
125
158
|
scales: scaleIds.map(id => ({
|
|
126
159
|
op: "rematerializeScale",
|
|
127
160
|
args: { id, guides: false, marks: false }
|
|
128
161
|
}))
|
|
129
162
|
}));
|
|
163
|
+
return { program, populated: true };
|
|
130
164
|
}
|
|
131
165
|
|
|
132
|
-
function applyResolvedDomains(
|
|
166
|
+
function applyResolvedDomains(
|
|
167
|
+
program,
|
|
168
|
+
childId,
|
|
169
|
+
resolution,
|
|
170
|
+
baseResolved,
|
|
171
|
+
{ marks: materializeMarks = true } = {}
|
|
172
|
+
) {
|
|
133
173
|
let next = program;
|
|
134
174
|
for (const [id, scaleResolution] of Object.entries(resolution.scales)) {
|
|
135
175
|
const current = next.resolvedScales[id];
|
|
@@ -139,19 +179,22 @@ function applyResolvedDomains(program, childId, resolution, baseResolved) {
|
|
|
139
179
|
const shared = scaleResolution.policy === "shared"
|
|
140
180
|
? baseResolved?.[id]
|
|
141
181
|
: undefined;
|
|
182
|
+
const semanticDomain = findSemanticScale(next, id)?.domain;
|
|
183
|
+
const domain = scaleResolution.childDomains[childId] ??
|
|
184
|
+
scaleResolution.domain ?? semanticDomain;
|
|
142
185
|
next = next._withResolvedScale(id, {
|
|
143
186
|
...current,
|
|
144
187
|
...shared,
|
|
145
|
-
domain
|
|
188
|
+
domain
|
|
146
189
|
});
|
|
147
190
|
}
|
|
148
|
-
const marks = next.semanticSpec.layers.flatMap(layer => {
|
|
191
|
+
const marks = materializeMarks ? next.semanticSpec.layers.flatMap(layer => {
|
|
149
192
|
const step = getMarkMaterializationStep(next, layer);
|
|
150
193
|
if (step === undefined) return [];
|
|
151
|
-
return ["bar", "line", "area"].includes(layer.mark?.type)
|
|
194
|
+
return ["bar", "line", "area", "arc"].includes(layer.mark?.type)
|
|
152
195
|
? [{ ...step, args: { ...step.args, scales: false } }]
|
|
153
196
|
: [step];
|
|
154
|
-
});
|
|
197
|
+
}) : [];
|
|
155
198
|
const guides = Object.keys(resolution.scales).flatMap(id =>
|
|
156
199
|
planScaleGuideRematerialization(next, id)
|
|
157
200
|
);
|
|
@@ -161,6 +204,22 @@ function applyResolvedDomains(program, childId, resolution, baseResolved) {
|
|
|
161
204
|
);
|
|
162
205
|
}
|
|
163
206
|
|
|
207
|
+
function materializeFacetCell(
|
|
208
|
+
child,
|
|
209
|
+
childId,
|
|
210
|
+
resolution,
|
|
211
|
+
baseResolved,
|
|
212
|
+
populated
|
|
213
|
+
) {
|
|
214
|
+
return applyResolvedDomains(
|
|
215
|
+
child,
|
|
216
|
+
childId,
|
|
217
|
+
resolution,
|
|
218
|
+
baseResolved,
|
|
219
|
+
{ marks: populated }
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
164
223
|
export function deriveFacetChildren(
|
|
165
224
|
base,
|
|
166
225
|
definition,
|
|
@@ -178,34 +237,89 @@ export function deriveFacetChildren(
|
|
|
178
237
|
const bins = xPolicy === "shared"
|
|
179
238
|
? sharedHistogramBoundaries(template)
|
|
180
239
|
: new Map();
|
|
181
|
-
const
|
|
240
|
+
const candidates = Object.fromEntries(definition.cells.map(cell => [
|
|
182
241
|
cell.id,
|
|
183
|
-
|
|
242
|
+
buildFacetCellCandidate(template, definition, cell, bins, scales)
|
|
184
243
|
]));
|
|
244
|
+
const independentlyResolved = Object.fromEntries(Object.entries(candidates).map(
|
|
245
|
+
([id, candidate]) => [id, candidate.program]
|
|
246
|
+
));
|
|
247
|
+
const populatedIds = new Set(Object.entries(candidates).flatMap(
|
|
248
|
+
([id, candidate]) => candidate.populated ? [id] : []
|
|
249
|
+
));
|
|
250
|
+
return resolveFacetChildrenScales(
|
|
251
|
+
template,
|
|
252
|
+
definition.cells.map(cell => cell.id),
|
|
253
|
+
independentlyResolved,
|
|
254
|
+
scales,
|
|
255
|
+
closeInheritedAction,
|
|
256
|
+
populatedIds
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export function resolveFacetChildrenScales(
|
|
261
|
+
template,
|
|
262
|
+
cellIds,
|
|
263
|
+
independentlyResolved,
|
|
264
|
+
scales = {},
|
|
265
|
+
closeInheritedAction = false,
|
|
266
|
+
populatedIds = undefined
|
|
267
|
+
) {
|
|
268
|
+
const populated = Object.fromEntries(cellIds.flatMap(id => {
|
|
269
|
+
const child = independentlyResolved[id];
|
|
270
|
+
if (child === undefined) {
|
|
271
|
+
throw new Error(`Facet derivation is missing child "${id}".`);
|
|
272
|
+
}
|
|
273
|
+
const populated = populatedIds === undefined
|
|
274
|
+
? child.semanticSpec.layers.length > 0
|
|
275
|
+
: populatedIds.has(id);
|
|
276
|
+
return populated ? [[id, child]] : [];
|
|
277
|
+
}));
|
|
278
|
+
if (Object.keys(populated).length === 0) {
|
|
279
|
+
throw new Error("Facet derivation requires at least one populated cell.");
|
|
280
|
+
}
|
|
185
281
|
const resolution = resolveFacetScaleDomains(
|
|
186
282
|
template.semanticSpec,
|
|
187
|
-
Object.fromEntries(Object.entries(
|
|
283
|
+
Object.fromEntries(Object.entries(populated).map(([id, child]) => [
|
|
188
284
|
id,
|
|
189
285
|
child.resolvedScales
|
|
190
286
|
])),
|
|
191
287
|
scales,
|
|
192
288
|
template.resolvedScales
|
|
193
289
|
);
|
|
290
|
+
const emptyIds = cellIds.filter(id => !Object.hasOwn(populated, id));
|
|
291
|
+
const scalesById = new Map(template.semanticSpec.scales.map(scale => [scale.id, scale]));
|
|
292
|
+
for (const childId of emptyIds) {
|
|
293
|
+
const unresolved = Object.entries(resolution.scales).find(([id, value]) =>
|
|
294
|
+
value.policy === "independent" && scalesById.get(id)?.domain === "auto"
|
|
295
|
+
);
|
|
296
|
+
if (unresolved !== undefined) {
|
|
297
|
+
throw new Error(
|
|
298
|
+
`Facet child "${childId}" cannot resolve independent scale "${unresolved[0]}" from an empty partition.`
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
194
302
|
const resolvedChildren = Object.fromEntries(
|
|
195
|
-
|
|
196
|
-
const
|
|
303
|
+
cellIds.map(id => {
|
|
304
|
+
const child = independentlyResolved[id];
|
|
305
|
+
if (child.semanticSpec.layers.length === 0) {
|
|
306
|
+
return [id, closeInheritedAction ? child._exitAction() : child];
|
|
307
|
+
}
|
|
308
|
+
const resolved = materializeFacetCell(
|
|
197
309
|
child,
|
|
198
310
|
id,
|
|
199
311
|
resolution,
|
|
200
|
-
template.resolvedScales
|
|
312
|
+
template.resolvedScales,
|
|
313
|
+
Object.hasOwn(populated, id)
|
|
201
314
|
);
|
|
202
315
|
return [id, closeInheritedAction ? resolved._exitAction() : resolved];
|
|
203
316
|
})
|
|
204
317
|
);
|
|
318
|
+
const firstPopulatedId = Object.keys(populated)[0];
|
|
205
319
|
const sharedScales = Object.fromEntries(
|
|
206
320
|
Object.entries(resolution.scales)
|
|
207
321
|
.filter(([, value]) => value.policy === "shared")
|
|
208
|
-
.map(([id]) => [id, resolvedChildren[
|
|
322
|
+
.map(([id]) => [id, resolvedChildren[firstPopulatedId].resolvedScales[id]])
|
|
209
323
|
);
|
|
210
324
|
return freezeOwned({
|
|
211
325
|
children: freezeOwned(resolvedChildren),
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import { assertGuideOptions, guideConflict } from "../guides/reuse.js";
|
|
1
2
|
import { action } from "../../core/action.js";
|
|
2
3
|
import { validateKeys } from "../../core/validation.js";
|
|
3
4
|
import { GRADIENT_PROFILE_FIELDS } from "../../grammar/gradientProfile.js";
|
|
5
|
+
import {
|
|
6
|
+
requestedStrokeDetails,
|
|
7
|
+
STROKE_STYLE_PROPERTIES
|
|
8
|
+
} from "../../grammar/strokeStyle.js";
|
|
4
9
|
import { resolveGraphicBounds } from "../../layout/canvas.js";
|
|
5
10
|
import { findLayer } from "../../selectors/layers.js";
|
|
6
11
|
import { createDensityLegendPaint } from "./paint.js";
|
|
@@ -8,7 +13,7 @@ import { createDensityLegendPaint } from "./paint.js";
|
|
|
8
13
|
const CENTER_OPTIONS = Object.freeze([
|
|
9
14
|
"id", "owner", "data", "category", "categoryType", "coordinate",
|
|
10
15
|
"categoryScale", "measureScale", "orientation", "size", "stroke",
|
|
11
|
-
"strokeWidth"
|
|
16
|
+
"strokeWidth", ...STROKE_STYLE_PROPERTIES
|
|
12
17
|
]);
|
|
13
18
|
const LEGEND_OPTIONS = Object.freeze(["owner", "title", "position"]);
|
|
14
19
|
|
|
@@ -22,7 +27,11 @@ export const createGradientPlotCenter = action(
|
|
|
22
27
|
const categoryAction = args.orientation === "vertical" ? "encodeX" : "encodeY";
|
|
23
28
|
const measureAction = args.orientation === "vertical" ? "encodeY" : "encodeX";
|
|
24
29
|
const spanOrientation = args.orientation === "vertical" ? "horizontal" : "vertical";
|
|
25
|
-
let next = this.createRuleMark({
|
|
30
|
+
let next = this.createRuleMark({
|
|
31
|
+
id: args.id,
|
|
32
|
+
data: args.data,
|
|
33
|
+
...requestedStrokeDetails(args, "createGradientPlotCenter")
|
|
34
|
+
});
|
|
26
35
|
next = next[categoryAction]({
|
|
27
36
|
target: args.id,
|
|
28
37
|
field: args.category,
|
|
@@ -120,23 +129,44 @@ export const rematerializeGradientPlotLegend = action(
|
|
|
120
129
|
}
|
|
121
130
|
);
|
|
122
131
|
|
|
132
|
+
function resolveDensityLegend(program, args) {
|
|
133
|
+
validateKeys(args, LEGEND_OPTIONS, "createGradientPlotLegend");
|
|
134
|
+
requireLegendOwner(program, args.owner);
|
|
135
|
+
if (args.position !== undefined && args.position !== "right") {
|
|
136
|
+
throw new Error('Gradient plot density legend currently requires position "right".');
|
|
137
|
+
}
|
|
138
|
+
if (args.title !== undefined && (typeof args.title !== "string" || args.title.length === 0)) {
|
|
139
|
+
throw new TypeError("Gradient plot density legend title must be a non-empty string.");
|
|
140
|
+
}
|
|
141
|
+
const ids = legendIds(args.owner);
|
|
142
|
+
const densityScale = `${args.owner}Density`;
|
|
143
|
+
const title = args.title ?? "Relative density";
|
|
144
|
+
return { ids, densityScale, title };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function fulfillGradientPlotLegend(program, args) {
|
|
148
|
+
const { ids, densityScale } = resolveDensityLegend(program, args);
|
|
149
|
+
const occupied = program.semanticSpec.guides.legend?.color;
|
|
150
|
+
if (occupied !== undefined && occupied.scale !== densityScale) {
|
|
151
|
+
guideConflict("Gradient plot density legend uses a different scale or family");
|
|
152
|
+
}
|
|
153
|
+
const existing = Object.values(ids).filter(id => program.graphicSpec.objects[id] !== undefined);
|
|
154
|
+
if (existing.length === 0) return program.createGradientPlotLegend(args);
|
|
155
|
+
if (existing.length !== Object.keys(ids).length || occupied?.scale !== densityScale) {
|
|
156
|
+
guideConflict("Gradient plot density legend has incomplete ownership");
|
|
157
|
+
}
|
|
158
|
+
const { owner, ...explicit } = args;
|
|
159
|
+
assertGuideOptions(explicit, program.markConfigs[owner].gradientPlot.guides.legend, "Gradient plot density legend");
|
|
160
|
+
return program;
|
|
161
|
+
}
|
|
162
|
+
|
|
123
163
|
export const createGradientPlotLegend = action(
|
|
124
164
|
{
|
|
125
165
|
op: "createGradientPlotLegend",
|
|
126
166
|
description: "Create the neutral density legend owned by one gradient plot."
|
|
127
167
|
},
|
|
128
168
|
function (args = {}) {
|
|
129
|
-
|
|
130
|
-
requireLegendOwner(this, args.owner);
|
|
131
|
-
if (args.position !== undefined && args.position !== "right") {
|
|
132
|
-
throw new Error('Gradient plot density legend currently requires position "right".');
|
|
133
|
-
}
|
|
134
|
-
if (args.title !== undefined && (typeof args.title !== "string" || args.title.length === 0)) {
|
|
135
|
-
throw new TypeError("Gradient plot density legend title must be a non-empty string.");
|
|
136
|
-
}
|
|
137
|
-
const ids = legendIds(args.owner);
|
|
138
|
-
const densityScale = `${args.owner}Density`;
|
|
139
|
-
const title = args.title ?? "Relative density";
|
|
169
|
+
const { ids, densityScale, title } = resolveDensityLegend(this, args);
|
|
140
170
|
let next = this;
|
|
141
171
|
for (const [property, value] of [
|
|
142
172
|
[`scale[${densityScale}].type`, "sequential"],
|
|
@@ -7,6 +7,7 @@ import { findDataset } from "../../selectors/datasets.js";
|
|
|
7
7
|
import { findLayer } from "../../selectors/layers.js";
|
|
8
8
|
import { removeOwnedMark } from "../marks/remove.js";
|
|
9
9
|
import { GRADIENT_PROFILE_FIELDS } from "../../grammar/gradientProfile.js";
|
|
10
|
+
import { requestedStrokeDetails } from "../../grammar/strokeStyle.js";
|
|
10
11
|
import { removeGradientPlotLegend } from "./components.js";
|
|
11
12
|
import {
|
|
12
13
|
resolveDistributionRoles,
|
|
@@ -40,6 +41,13 @@ function removeCenter(program, id) {
|
|
|
40
41
|
return removeOwnedMark(program, id, true);
|
|
41
42
|
}
|
|
42
43
|
|
|
44
|
+
function editCenterStrokeDetails(program, id, center) {
|
|
45
|
+
const details = requestedStrokeDetails(center, "Gradient plot center");
|
|
46
|
+
return Object.keys(details).length === 0
|
|
47
|
+
? program
|
|
48
|
+
: program.editRuleMark({ target: id, ...details });
|
|
49
|
+
}
|
|
50
|
+
|
|
43
51
|
function roleCandidate(program, owner, current, args) {
|
|
44
52
|
return {
|
|
45
53
|
source: Object.hasOwn(args, "data")
|
|
@@ -219,10 +227,11 @@ export const editGradientPlot = action(
|
|
|
219
227
|
orientation: candidate.orientation,
|
|
220
228
|
size: spanSize,
|
|
221
229
|
stroke: center.stroke,
|
|
222
|
-
strokeWidth: center.strokeWidth
|
|
230
|
+
strokeWidth: center.strokeWidth,
|
|
231
|
+
...requestedStrokeDetails(center, "Gradient plot center")
|
|
223
232
|
});
|
|
224
233
|
} else if (retainedCenter) {
|
|
225
|
-
next = next
|
|
234
|
+
next = editCenterStrokeDetails(next, current.centerId, center)
|
|
226
235
|
.encodeStroke({ target: current.centerId, value: center.stroke })
|
|
227
236
|
.encodeStrokeWidth({
|
|
228
237
|
target: current.centerId,
|
|
@@ -291,10 +300,11 @@ export const editGradientPlot = action(
|
|
|
291
300
|
orientation: current.orientation,
|
|
292
301
|
size: 1,
|
|
293
302
|
stroke: center.stroke,
|
|
294
|
-
strokeWidth: center.strokeWidth
|
|
303
|
+
strokeWidth: center.strokeWidth,
|
|
304
|
+
...requestedStrokeDetails(center, "Gradient plot center")
|
|
295
305
|
});
|
|
296
306
|
} else if (center !== false) {
|
|
297
|
-
next = next
|
|
307
|
+
next = editCenterStrokeDetails(next, current.centerId, center)
|
|
298
308
|
.encodeStroke({ target: current.centerId, value: center.stroke })
|
|
299
309
|
.encodeStrokeWidth({ target: current.centerId, value: center.strokeWidth });
|
|
300
310
|
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { applyFacadeGuides } from "../charts/shared.js";
|
|
2
|
+
import { fulfillGradientPlotLegend } from "./components.js";
|
|
1
3
|
import { action } from "../../core/action.js";
|
|
2
4
|
import { validateUserId } from "../../core/identifiers.js";
|
|
3
5
|
import { isPlainObject } from "../../core/immutable.js";
|
|
4
6
|
import { GRADIENT_PROFILE_FIELDS } from "../../grammar/gradientProfile.js";
|
|
7
|
+
import { requestedStrokeDetails } from "../../grammar/strokeStyle.js";
|
|
5
8
|
import {
|
|
6
9
|
mapContinuousScaleValues,
|
|
7
10
|
mapOrdinalPositionValues
|
|
@@ -246,26 +249,23 @@ export const materializeGradientPlot = action(
|
|
|
246
249
|
orientation,
|
|
247
250
|
size: Math.max(1, categoryScale.bandwidth * config.width.band - 16),
|
|
248
251
|
stroke: config.center.stroke,
|
|
249
|
-
strokeWidth: config.center.strokeWidth
|
|
252
|
+
strokeWidth: config.center.strokeWidth,
|
|
253
|
+
...requestedStrokeDetails(config.center, "Gradient plot center")
|
|
250
254
|
});
|
|
251
255
|
}
|
|
252
256
|
const guides = config.guides;
|
|
253
257
|
if (guides !== false) {
|
|
254
258
|
const wantsStandard = guides.axes !== false || guides.grid !== false;
|
|
255
259
|
if (wantsStandard) {
|
|
256
|
-
next = next
|
|
260
|
+
next = applyFacadeGuides(next, {
|
|
257
261
|
axes: gradientAxesOptions(next.markConfigs[owner].gradientPlot),
|
|
258
262
|
grid: guides.grid,
|
|
259
263
|
legend: false
|
|
260
|
-
});
|
|
264
|
+
}, owner, guides);
|
|
261
265
|
}
|
|
262
266
|
if (guides.legend !== false) {
|
|
263
267
|
const legend = isPlainObject(guides.legend) ? guides.legend : {};
|
|
264
|
-
next = next
|
|
265
|
-
owner,
|
|
266
|
-
title: legend.title ?? "Relative density",
|
|
267
|
-
position: legend.position ?? "right"
|
|
268
|
-
});
|
|
268
|
+
next = fulfillGradientPlotLegend(next, { owner, ...legend });
|
|
269
269
|
}
|
|
270
270
|
}
|
|
271
271
|
return next._withContext({ currentMark: owner, currentData: layer.data });
|
|
@@ -5,6 +5,10 @@ import {
|
|
|
5
5
|
validateUnitInterval
|
|
6
6
|
} from "../../core/validation.js";
|
|
7
7
|
import { normalizePalette } from "../../grammar/palettes.js";
|
|
8
|
+
import {
|
|
9
|
+
requestedStrokeDetails,
|
|
10
|
+
STROKE_STYLE_PROPERTIES
|
|
11
|
+
} from "../../grammar/strokeStyle.js";
|
|
8
12
|
|
|
9
13
|
export const GRADIENT_PLOT_OPTIONS = Object.freeze([
|
|
10
14
|
"id", "target", "data", "x", "y", "coordinate", "density", "width",
|
|
@@ -90,7 +94,7 @@ export function resolveGradientCenter(
|
|
|
90
94
|
if (value === false) return false;
|
|
91
95
|
const options = plain(
|
|
92
96
|
value,
|
|
93
|
-
["type", "stroke", "strokeWidth"],
|
|
97
|
+
["type", "stroke", "strokeWidth", ...STROKE_STYLE_PROPERTIES],
|
|
94
98
|
"center",
|
|
95
99
|
operation
|
|
96
100
|
);
|
|
@@ -108,7 +112,11 @@ export function resolveGradientCenter(
|
|
|
108
112
|
: validateNonNegativeFinite(
|
|
109
113
|
options.strokeWidth,
|
|
110
114
|
`${operation} center.strokeWidth`
|
|
111
|
-
)
|
|
115
|
+
),
|
|
116
|
+
...requestedStrokeDetails(
|
|
117
|
+
{ ...(previous ?? {}), ...options },
|
|
118
|
+
`${operation} center`
|
|
119
|
+
)
|
|
112
120
|
});
|
|
113
121
|
}
|
|
114
122
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isSourceOwnedText } from "../../grammar/text.js";
|
|
1
2
|
import {
|
|
2
3
|
BAR_ORIENTATIONS,
|
|
3
4
|
resolveBarOrientation
|
|
@@ -8,6 +9,7 @@ import {
|
|
|
8
9
|
} from "../../core/vocabulary.js";
|
|
9
10
|
import { findSemanticScale } from "../../selectors/scales.js";
|
|
10
11
|
import { findDataset } from "../../selectors/datasets.js";
|
|
12
|
+
import { isOpacityLegendLayer } from "../../materialization/legends.js";
|
|
11
13
|
import { findUpstreamTransform } from
|
|
12
14
|
"../../materialization/dataProvenance.js";
|
|
13
15
|
|
|
@@ -19,8 +21,8 @@ function isHorizonLayer(program, layer) {
|
|
|
19
21
|
) !== undefined;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
|
-
function hasEncoding(program, channel, { scaled = false, grid = false } = {}) {
|
|
23
|
-
return
|
|
24
|
+
function hasEncoding(program, layers, channel, { scaled = false, grid = false } = {}) {
|
|
25
|
+
return layers.some(layer => {
|
|
24
26
|
if (isHorizonLayer(program, layer) && channel !== "x") return false;
|
|
25
27
|
const encoding = layer.encoding?.[channel];
|
|
26
28
|
if (!scaled && !grid) return encoding !== undefined;
|
|
@@ -31,25 +33,26 @@ function hasEncoding(program, channel, { scaled = false, grid = false } = {}) {
|
|
|
31
33
|
});
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
function positionalApplicability(program, channels) {
|
|
36
|
+
function positionalApplicability(program, layers, channels) {
|
|
35
37
|
return Object.freeze(Object.fromEntries(
|
|
36
38
|
channels.map(channel => [
|
|
37
39
|
channel,
|
|
38
40
|
Object.freeze({
|
|
39
|
-
axis: hasEncoding(program, channel),
|
|
40
|
-
grid: hasEncoding(program, channel, { grid: true })
|
|
41
|
+
axis: hasEncoding(program, layers, channel),
|
|
42
|
+
grid: hasEncoding(program, layers, channel, { grid: true })
|
|
41
43
|
})
|
|
42
44
|
])
|
|
43
45
|
));
|
|
44
46
|
}
|
|
45
47
|
|
|
46
|
-
export function hasInferableLegend(program) {
|
|
47
|
-
return
|
|
48
|
+
export function hasInferableLegend(program, layers = program.semanticSpec.layers) {
|
|
49
|
+
return layers.some(layer =>
|
|
48
50
|
!isHorizonLayer(program, layer) && (
|
|
49
|
-
(layer
|
|
50
|
-
layer.encoding?.opacity?.scale !== undefined) ||
|
|
51
|
+
isOpacityLegendLayer(layer) ||
|
|
51
52
|
(layer.mark?.type === "point" &&
|
|
52
53
|
layer.encoding?.size?.scale !== undefined) ||
|
|
54
|
+
(layer.mark?.type === "point" &&
|
|
55
|
+
layer.encoding?.stroke?.scale !== undefined) ||
|
|
53
56
|
(layer.mark?.type === "point" &&
|
|
54
57
|
layer.encoding?.color?.scale !== undefined &&
|
|
55
58
|
(layer.encoding?.shape?.scale !== undefined ||
|
|
@@ -57,22 +60,27 @@ export function hasInferableLegend(program) {
|
|
|
57
60
|
findSemanticScale(program, layer.encoding.color.scale)?.type
|
|
58
61
|
))) ||
|
|
59
62
|
(layer.mark?.type === "line" &&
|
|
60
|
-
["color", "strokeDash"].some(
|
|
63
|
+
["color", "stroke", "strokeDash"].some(
|
|
61
64
|
channel => layer.encoding?.[channel]?.scale !== undefined
|
|
62
65
|
)) ||
|
|
63
66
|
(["bar", "area", "arc", "rect"].includes(layer.mark?.type) &&
|
|
64
|
-
|
|
67
|
+
["color", "stroke"].some(
|
|
68
|
+
channel => layer.encoding?.[channel]?.scale !== undefined
|
|
69
|
+
)) ||
|
|
70
|
+
(["rule", "tick"].includes(layer.mark?.type) &&
|
|
71
|
+
layer.encoding?.stroke?.scale !== undefined)
|
|
65
72
|
)
|
|
66
73
|
);
|
|
67
74
|
}
|
|
68
75
|
|
|
69
|
-
export function resolveGuideApplicability(program) {
|
|
76
|
+
export function resolveGuideApplicability(program, layers = program.semanticSpec.layers) {
|
|
70
77
|
const cartesian = positionalApplicability(
|
|
71
78
|
program,
|
|
79
|
+
layers,
|
|
72
80
|
CARTESIAN_POSITION_CHANNELS
|
|
73
81
|
);
|
|
74
|
-
const polar = positionalApplicability(program, POLAR_POSITION_CHANNELS);
|
|
75
|
-
const parallel =
|
|
82
|
+
const polar = positionalApplicability(program, layers, POLAR_POSITION_CHANNELS);
|
|
83
|
+
const parallel = layers.some(layer =>
|
|
76
84
|
layer.encoding?.parallel?.dimensions?.length >= 2
|
|
77
85
|
);
|
|
78
86
|
return Object.freeze({
|
|
@@ -101,12 +109,13 @@ export function resolveGuideApplicability(program) {
|
|
|
101
109
|
radial: polar.radius.grid
|
|
102
110
|
})
|
|
103
111
|
}),
|
|
104
|
-
legend: hasInferableLegend(program)
|
|
112
|
+
legend: hasInferableLegend(program, layers)
|
|
105
113
|
});
|
|
106
114
|
}
|
|
107
115
|
|
|
108
|
-
export function resolveAutomaticGridOptions(program) {
|
|
109
|
-
|
|
116
|
+
export function resolveAutomaticGridOptions(program, layers = program.semanticSpec.layers) {
|
|
117
|
+
layers = layers.filter(layer => !isSourceOwnedText(layer));
|
|
118
|
+
const applicability = resolveGuideApplicability(program, layers);
|
|
110
119
|
const directions = applicability.grid.directions;
|
|
111
120
|
if (applicability.grid.polar && !applicability.grid.cartesian) {
|
|
112
121
|
return Object.freeze({
|
|
@@ -118,10 +127,10 @@ export function resolveAutomaticGridOptions(program) {
|
|
|
118
127
|
return Object.freeze({ horizontal: false, vertical: {} });
|
|
119
128
|
}
|
|
120
129
|
|
|
121
|
-
const barOrientations =
|
|
130
|
+
const barOrientations = layers
|
|
122
131
|
.map(resolveBarOrientation)
|
|
123
132
|
.filter(Boolean);
|
|
124
|
-
const positionedLayers =
|
|
133
|
+
const positionedLayers = layers.filter(
|
|
125
134
|
layer => layer.encoding?.x !== undefined && layer.encoding?.y !== undefined
|
|
126
135
|
);
|
|
127
136
|
const horizontalQuantitative = positionedLayers.length > 0 &&
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isSourceOwnedText } from "../../../grammar/text.js";
|
|
1
2
|
import { action } from "../../../core/action.js";
|
|
2
3
|
import { isPlainObject } from "../../../core/immutable.js";
|
|
3
4
|
import { validateUserId } from "../../../core/identifiers.js";
|
|
@@ -19,7 +20,7 @@ function validateAxisOption(value, channel) {
|
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
function
|
|
23
|
+
export function validateAxesArgs(args) {
|
|
23
24
|
validateOptionObject(args, TOP_OPTIONS, "createAxes");
|
|
24
25
|
validateAxisOption(args.x, "x");
|
|
25
26
|
validateAxisOption(args.y, "y");
|
|
@@ -189,9 +190,9 @@ const createAxes = action(
|
|
|
189
190
|
description: "Read a semantic coordinate and create its Cartesian axes."
|
|
190
191
|
},
|
|
191
192
|
function (args = {}) {
|
|
192
|
-
const coordinateDescriptor =
|
|
193
|
+
const coordinateDescriptor = validateAxesArgs(args);
|
|
193
194
|
const { cartesianLayers, polarLayers, parallelLayers } = inspectChannels(
|
|
194
|
-
this.semanticSpec.layers
|
|
195
|
+
this.semanticSpec.layers.filter(layer => !isSourceOwnedText(layer))
|
|
195
196
|
);
|
|
196
197
|
const requestedCoordinateType = coordinateDescriptor.id === undefined
|
|
197
198
|
? undefined
|