ggaction 0.0.12 → 0.0.13
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 +49 -0
- package/README.md +2 -2
- 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 +4 -2
- package/src/actions/basic.js +2 -0
- package/src/actions/boxPlots/materialize.js +2 -1
- 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 +3 -2
- package/src/actions/charts/area.js +47 -0
- package/src/actions/charts/bar.js +11 -5
- package/src/actions/charts/beeswarm.js +70 -0
- package/src/actions/charts/density.js +44 -0
- package/src/actions/charts/ecdf.js +183 -0
- package/src/actions/charts/endpoints.js +451 -0
- package/src/actions/charts/heatmap.js +2 -2
- package/src/actions/charts/histogram.js +1 -1
- package/src/actions/charts/horizon.js +71 -0
- package/src/actions/charts/index.js +37 -0
- package/src/actions/charts/interval-regression.js +169 -0
- package/src/actions/charts/line.js +5 -5
- package/src/actions/charts/parallel.js +1 -1
- package/src/actions/charts/pie.js +44 -0
- package/src/actions/charts/polar.js +123 -0
- package/src/actions/charts/radar.js +299 -0
- package/src/actions/charts/radial.js +42 -0
- package/src/actions/charts/raincloud.js +422 -0
- package/src/actions/charts/rug-strip.js +279 -0
- package/src/actions/charts/scatter.js +9 -3
- package/src/actions/charts/shared.js +69 -10
- package/src/actions/composition/actions.js +118 -1
- package/src/actions/data/bin.js +29 -0
- package/src/actions/data/computed.js +24 -0
- package/src/actions/data/derived.js +66 -0
- package/src/actions/data/ecdf.js +38 -0
- package/src/actions/data/filter.js +212 -28
- package/src/actions/data/fold.js +24 -0
- package/src/actions/data/index.js +24 -0
- package/src/actions/data/interval.js +2 -0
- package/src/actions/data/intervalEdit.js +86 -4
- package/src/actions/data/regression.js +5 -2
- package/src/actions/data/stack.js +26 -0
- package/src/actions/data/summary.js +26 -0
- package/src/actions/data/timeUnit.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/color/continuous.js +19 -59
- package/src/actions/encodings/color/index.js +28 -22
- 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 +120 -33
- package/src/actions/encodings/horizon/resolve.js +8 -4
- package/src/actions/encodings/horizon.js +18 -8
- package/src/actions/encodings/index.js +2 -0
- package/src/actions/encodings/offset.js +10 -16
- package/src/actions/encodings/parallel.js +2 -8
- package/src/actions/encodings/position/apply.js +10 -4
- package/src/actions/encodings/position/index.js +43 -5
- 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 +48 -13
- package/src/actions/encodings/position/resolve.js +67 -22
- package/src/actions/encodings/ranged.js +123 -97
- package/src/actions/encodings/remove.js +37 -32
- package/src/actions/encodings/ruleAppearance.js +23 -9
- package/src/actions/encodings/seriesLayout.js +104 -0
- package/src/actions/encodings/shared.js +25 -23
- 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 +18 -5
- package/src/actions/errorBands/edit.js +341 -21
- package/src/actions/errorBars/create.js +21 -10
- package/src/actions/errorBars/edit.js +355 -19
- package/src/actions/facets/actions.js +410 -12
- package/src/actions/facets/derive.js +57 -8
- package/src/actions/gradientPlots/components.js +33 -11
- package/src/actions/gradientPlots/materialize.js +5 -7
- package/src/actions/guides/applicability.js +20 -17
- 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 +129 -19
- package/src/actions/guides/axes/lines.js +7 -5
- 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 +44 -23
- 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 +14 -8
- package/src/actions/guides/axes/ticks.js +5 -4
- package/src/actions/guides/axes/titles.js +21 -8
- 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 +10 -2
- package/src/actions/guides/guides.js +35 -28
- package/src/actions/guides/legends/categorical/actions.js +193 -249
- package/src/actions/guides/legends/categorical/components.js +4 -5
- package/src/actions/guides/legends/categorical/layout.js +36 -349
- package/src/actions/guides/legends/categorical/options.js +30 -14
- package/src/actions/guides/legends/categorical/recipes.js +14 -0
- package/src/actions/guides/legends/categorical/resolve.js +21 -10
- package/src/actions/guides/legends/categorical/symbols.js +2 -3
- package/src/actions/guides/legends/continuous/common.js +69 -14
- package/src/actions/guides/legends/continuous/gradient.js +111 -83
- package/src/actions/guides/legends/continuous/index.js +6 -2
- package/src/actions/guides/legends/continuous/interval.js +71 -92
- package/src/actions/guides/legends/continuous/opacity.js +105 -84
- package/src/actions/guides/legends/creation.js +27 -0
- package/src/actions/guides/legends/edit.js +198 -66
- package/src/actions/guides/legends/focused.js +2 -2
- package/src/actions/guides/legends/lane.js +98 -86
- package/src/actions/guides/legends/lifecycle.js +132 -0
- package/src/actions/guides/legends/remove.js +31 -76
- package/src/actions/guides/legends/size.js +149 -105
- package/src/actions/guides/legends/strokeWidth.js +106 -64
- package/src/actions/guides/legends/target.js +12 -0
- package/src/actions/guides/legends/transition.js +43 -0
- package/src/actions/guides/polar/axes/facade.js +77 -62
- package/src/actions/guides/polar/axes/labels.js +5 -4
- package/src/actions/guides/polar/axes/lines.js +2 -1
- package/src/actions/guides/polar/axes/shared.js +6 -0
- package/src/actions/guides/polar/axes/ticks.js +5 -4
- package/src/actions/guides/polar/axes/titles.js +5 -4
- package/src/actions/guides/polar/grids.js +7 -7
- package/src/actions/guides/reuse.js +44 -0
- package/src/actions/guides/tickValues.js +19 -21
- package/src/actions/index.js +2 -0
- package/src/actions/intervals/resolve.js +35 -15
- package/src/actions/marks/arc/actions.js +1 -1
- package/src/actions/marks/area/actions.js +18 -4
- package/src/actions/marks/area/materialize.js +5 -2
- package/src/actions/marks/bar/materialize.js +11 -7
- package/src/actions/marks/index.js +5 -0
- package/src/actions/marks/line/actions.js +43 -108
- package/src/actions/marks/line/materialize.js +34 -52
- package/src/actions/marks/point/edit.js +11 -15
- 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 +106 -2
- package/src/actions/marks/point/packing.js +68 -0
- package/src/actions/marks/references.js +87 -0
- package/src/actions/marks/remove.js +17 -4
- package/src/actions/marks/rule/actions.js +34 -3
- package/src/actions/marks/rule/appearance.js +26 -0
- package/src/actions/marks/shared.js +12 -12
- package/src/actions/marks/text/actions.js +224 -6
- package/src/actions/marks/text/layout.js +2 -2
- package/src/actions/primitives/createGraphics.js +3 -1
- package/src/actions/primitives/semantic.js +1 -1
- package/src/actions/primitives/semanticAction.js +39 -2
- package/src/actions/primitives/semanticValidation/guide.js +10 -0
- package/src/actions/primitives/semanticValidation/layer.js +18 -1
- package/src/actions/primitives/semanticValidation/scale.js +10 -1
- package/src/actions/regression/create.js +1 -1
- package/src/actions/regression/edit.js +19 -6
- package/src/actions/regression/resolve.js +1 -1
- package/src/actions/scales/consumers/common.js +20 -53
- package/src/actions/scales/consumers/families.js +27 -14
- package/src/actions/scales/consumers/index.js +23 -2
- package/src/actions/scales/consumers/seriesLayout.js +33 -2
- package/src/actions/scales/create.js +4 -4
- package/src/actions/scales/definitions.js +19 -3
- package/src/actions/scales/edit.js +46 -34
- package/src/actions/scales/editPolicy.js +21 -31
- package/src/actions/scales/materialize.js +10 -46
- package/src/actions/scales/patch.js +1 -1
- package/src/actions/scales/preview.js +39 -0
- package/src/actions/scales/quantitativeColor.js +9 -5
- package/src/actions/theme/actions.js +43 -0
- package/src/actions/theme/index.js +9 -0
- package/src/actions/theme/reconcile.js +882 -0
- package/src/actions/titles/actions.js +11 -10
- package/src/actions/titles/resolve.js +1 -40
- package/src/actions/violinPlots/create.js +86 -42
- package/src/actions/violinPlots/edit.js +191 -0
- package/src/actions/violinPlots/index.js +2 -0
- package/src/core/ChartProgram.js +7 -0
- package/src/core/action.js +22 -2
- package/src/core/compositionState.js +136 -8
- 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 +33 -12
- package/src/grammar/bars/policy.js +9 -7
- package/src/grammar/bin.js +181 -0
- package/src/grammar/categoryOrder.js +34 -0
- package/src/grammar/computed.js +150 -0
- package/src/grammar/ecdf.js +198 -0
- package/src/grammar/facets/index.js +117 -6
- package/src/grammar/fold.js +123 -0
- package/src/grammar/horizon.js +6 -4
- package/src/grammar/interval.js +37 -20
- package/src/grammar/lineSeries.js +20 -63
- package/src/grammar/markFilter.js +22 -4
- package/src/grammar/markLabels.js +93 -0
- package/src/grammar/parallelAxisTitles.js +16 -0
- package/src/grammar/pathSeries.js +91 -0
- package/src/grammar/pointPacking.js +183 -0
- 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 +7 -2
- package/src/grammar/regression/models.js +22 -7
- package/src/grammar/regression/parameters.js +40 -13
- package/src/grammar/rotation.js +29 -0
- package/src/grammar/rules.js +7 -21
- package/src/grammar/scales/color.js +23 -1
- package/src/grammar/scales/colorConsumers.js +38 -0
- package/src/grammar/scales/definition.js +15 -1
- package/src/grammar/scales/discretized.js +11 -5
- package/src/grammar/scales/fields.js +38 -8
- package/src/grammar/scales/mapping.js +2 -0
- package/src/grammar/scales/radial.js +55 -0
- package/src/grammar/scales/types.js +1 -0
- package/src/grammar/schemas/semanticPath.js +17 -3
- package/src/grammar/stack.js +170 -0
- package/src/grammar/statistics/confidenceInterval.js +101 -0
- package/src/grammar/summary.js +183 -0
- package/src/grammar/text.js +22 -16
- package/src/grammar/timeUnit.js +21 -11
- package/src/grammar/transformTopology.js +6 -0
- package/src/grammar/transforms.js +36 -0
- package/src/grammar/valueFormat.js +112 -0
- package/src/grammar/window.js +13 -7
- package/src/layout/facets.js +41 -7
- package/src/layout/guideCollisions.js +12 -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 +38 -152
- package/src/materialization/bars/histogram.js +24 -0
- package/src/materialization/categorySlotOffset.js +40 -0
- package/src/materialization/compositionSnapshot.js +1 -1
- package/src/materialization/dependencies.js +57 -16
- package/src/materialization/encodings.js +1 -1
- package/src/materialization/facets.js +8 -1
- package/src/materialization/guides/layout.js +57 -0
- package/src/materialization/guides/resources.js +2 -2
- package/src/materialization/legends.js +10 -1
- package/src/materialization/marks/capabilities.js +20 -5
- package/src/materialization/marks/grouping.js +52 -0
- package/src/materialization/marks/index.js +58 -23
- package/src/materialization/marks/policies.js +2 -0
- package/src/materialization/rect.js +33 -33
- package/src/materialization/rowEncoding.js +13 -13
- package/src/materialization/scaleGuideDependencies.js +8 -5
- package/src/materialization/scales/map.js +1 -0
- package/src/materialization/scales/policies/arc.js +42 -0
- package/src/materialization/scales/policies/binnedPosition.js +7 -4
- package/src/materialization/scales/policies/series.js +2 -1
- package/src/materialization/scales/resolve.js +46 -14
- package/src/materialization/selection/compatibility.js +11 -0
- package/src/materialization/selection/items/bar.js +12 -68
- package/src/materialization/selection/items/common.js +8 -2
- package/src/materialization/selection/items/path.js +3 -13
- package/src/materialization/selection/items/rect.js +7 -4
- package/src/materialization/text.js +64 -5
- package/src/mcp/adapter.js +2 -2
- package/src/selectors/datasets.js +13 -0
- package/src/selectors/layers.js +3 -2
- package/src/selectors/scales.js +6 -0
- package/src/theme/defaults.js +39 -0
- package/types/basic.d.ts +11 -2
- package/types/index.d.ts +126 -0
- package/types/program.d.ts +1320 -135
- package/src/materialization/bars/grouped.js +0 -144
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { deriveSeriesBarCells } from "../../../grammar/bars/aggregate.js";
|
|
2
|
+
import { readSeriesIdentity } from "../../../grammar/pathSeries.js";
|
|
2
3
|
import {
|
|
3
4
|
BAR_GRAINS,
|
|
4
5
|
resolveBarChannels,
|
|
@@ -7,7 +8,6 @@ import {
|
|
|
7
8
|
resolveBarGrain
|
|
8
9
|
} from "../../../grammar/bars/policy.js";
|
|
9
10
|
import { numericExtent } from "../../../grammar/numeric.js";
|
|
10
|
-
import { layoutSeriesPartition } from "../../../grammar/seriesLayout.js";
|
|
11
11
|
import {
|
|
12
12
|
readNominalField,
|
|
13
13
|
readTemporalField
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
|
|
25
25
|
function categoryValues(rows, encoding) {
|
|
26
26
|
return encoding.fieldType === "temporal"
|
|
27
|
-
? readTemporalField(rows, encoding.field)
|
|
27
|
+
? readTemporalField(rows, encoding.field, encoding.temporalUnit)
|
|
28
28
|
: readNominalField(rows, encoding.field);
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -36,20 +36,17 @@ function aggregateMembers(rows, layer, cell, channels) {
|
|
|
36
36
|
const colors = !["nominal", "ordinal"].includes(color?.fieldType)
|
|
37
37
|
? undefined
|
|
38
38
|
: readNominalField(rows, color.field);
|
|
39
|
+
const identity = layer.encoding?.group === undefined ? undefined : readSeriesIdentity(rows, layer);
|
|
39
40
|
return rows.filter((_, index) =>
|
|
40
41
|
categories[index] === categoryValue &&
|
|
41
|
-
(colors === undefined || colors[index] === cell.color)
|
|
42
|
+
(identity === undefined ? colors === undefined || colors[index] === cell.color : identity.values[index] === cell.series)
|
|
42
43
|
);
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
function aggregateCellDefinitions(program, layer, dataset) {
|
|
46
47
|
const channels = resolveBarChannels(layer);
|
|
47
|
-
const derived = deriveBarAggregates(dataset.values, layer).values;
|
|
48
48
|
const categoryEncoding = layer.encoding[channels.category];
|
|
49
49
|
const categoryScale = program.resolvedScales[categoryEncoding.scale];
|
|
50
|
-
const measureScale = program.resolvedScales[
|
|
51
|
-
layer.encoding[channels.measure].scale
|
|
52
|
-
];
|
|
53
50
|
const colorEncoding = layer.encoding?.color;
|
|
54
51
|
const colorScale = program.resolvedScales[colorEncoding?.scale];
|
|
55
52
|
const offsetChannel = resolveBarOffsetChannel(layer);
|
|
@@ -67,70 +64,17 @@ function aggregateCellDefinitions(program, layer, dataset) {
|
|
|
67
64
|
...(cell.color === undefined ? {} : { color: cell.color }),
|
|
68
65
|
...(layer.encoding?.[offsetChannel] === undefined
|
|
69
66
|
? {}
|
|
70
|
-
: { [offsetChannel]: cell.color })
|
|
67
|
+
: { [offsetChannel]: cell.series ?? cell.color })
|
|
71
68
|
},
|
|
72
69
|
members
|
|
73
70
|
};
|
|
74
71
|
}
|
|
75
72
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const categories = ["ordinal", "band", "point"].includes(categoryScale.type)
|
|
82
|
-
? categoryScale.domain
|
|
83
|
-
: [...new Set(derived.map(cell => cell[channels.category]))]
|
|
84
|
-
.sort((left, right) => left - right);
|
|
85
|
-
return categories.flatMap(category => {
|
|
86
|
-
const cell = cells.get(category);
|
|
87
|
-
return cell === undefined
|
|
88
|
-
? []
|
|
89
|
-
: [definition(cell, measureScale.domain[0], cell[channels.measure])];
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (layout === "group" && offsetScale !== undefined) {
|
|
94
|
-
const categoryIndex = new Map(
|
|
95
|
-
categoryScale.domain.map((value, index) => [value, index])
|
|
96
|
-
);
|
|
97
|
-
const offsetIndex = new Map(
|
|
98
|
-
offsetScale.domain.map((value, index) => [value, index])
|
|
99
|
-
);
|
|
100
|
-
const cells = [...derived].sort((left, right) =>
|
|
101
|
-
categoryIndex.get(left[channels.category]) -
|
|
102
|
-
categoryIndex.get(right[channels.category]) ||
|
|
103
|
-
offsetIndex.get(left.color) - offsetIndex.get(right.color)
|
|
104
|
-
);
|
|
105
|
-
return cells.map(cell => definition(
|
|
106
|
-
cell,
|
|
107
|
-
measureScale.domain[0],
|
|
108
|
-
cell[channels.measure]
|
|
109
|
-
));
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const categories = ["ordinal", "band", "point"].includes(categoryScale.type)
|
|
113
|
-
? categoryScale.domain
|
|
114
|
-
: [...new Set(derived.map(cell => cell[channels.category]))]
|
|
115
|
-
.sort((left, right) => left - right);
|
|
116
|
-
const series = colorScale?.domain ?? [undefined];
|
|
117
|
-
const lookup = new Map(derived.map(cell => [
|
|
118
|
-
JSON.stringify([cell[channels.category], cell.color]),
|
|
119
|
-
cell
|
|
120
|
-
]));
|
|
121
|
-
const baseline = layout === "overlay" ? measureScale.domain[0] : 0;
|
|
122
|
-
return categories.flatMap(category => {
|
|
123
|
-
const cells = series.map(color =>
|
|
124
|
-
lookup.get(JSON.stringify([category, color]))
|
|
125
|
-
);
|
|
126
|
-
const values = cells.map(cell => cell?.[channels.measure] ?? 0);
|
|
127
|
-
return layoutSeriesPartition(values, layout, { baseline }).flatMap(segment => {
|
|
128
|
-
const cell = cells[segment.index];
|
|
129
|
-
return cell === undefined
|
|
130
|
-
? []
|
|
131
|
-
: [definition(cell, segment.start, segment.end)];
|
|
132
|
-
});
|
|
133
|
-
});
|
|
73
|
+
const categories = categoryScale.type === "time" ? undefined : categoryScale.domain;
|
|
74
|
+
const series = layout === "group" ? offsetScale?.domain
|
|
75
|
+
: layer.encoding.group === undefined && colorEncoding?.fieldType !== "quantitative" ? colorScale?.domain : undefined;
|
|
76
|
+
return deriveSeriesBarCells(dataset.values, layer, categories, series)
|
|
77
|
+
.map(({ cell, start, end }) => definition(cell, start, end));
|
|
134
78
|
}
|
|
135
79
|
|
|
136
80
|
function histogramDefinitions(program, layer, dataset) {
|
|
@@ -145,7 +89,7 @@ function histogramDefinitions(program, layer, dataset) {
|
|
|
145
89
|
});
|
|
146
90
|
const colorScale = program.resolvedScales[colorEncoding?.scale];
|
|
147
91
|
return segments.map(segment => {
|
|
148
|
-
const colorValue = colorScale?.domain[segment.category];
|
|
92
|
+
const colorValue = segment.colorValue ?? colorScale?.domain[segment.category];
|
|
149
93
|
return {
|
|
150
94
|
fields: uniqueFields(segment.members),
|
|
151
95
|
channels: {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { normalizeTemporalValue } from "../../../grammar/scales/fields.js";
|
|
1
2
|
import { cloneAndFreeze, isPlainObject } from "../../../core/immutable.js";
|
|
2
3
|
import {
|
|
3
4
|
MARK_GRAPHIC_PROPERTIES,
|
|
@@ -16,8 +17,13 @@ function graphicId(layer, index) {
|
|
|
16
17
|
|
|
17
18
|
function encodingValue(row, encoding) {
|
|
18
19
|
if (encoding === undefined) return undefined;
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
const value = Object.hasOwn(encoding, "field") ? row?.[encoding.field] : encoding.datum;
|
|
21
|
+
if (encoding.fieldType !== "temporal") return value;
|
|
22
|
+
try {
|
|
23
|
+
return normalizeTemporalValue(value, encoding.field, 0, encoding.temporalUnit);
|
|
24
|
+
} catch {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
21
27
|
}
|
|
22
28
|
|
|
23
29
|
export function channelMapFromRow(row, layer) {
|
|
@@ -25,20 +25,10 @@ function rowsForSeries(rows, key) {
|
|
|
25
25
|
|
|
26
26
|
function seriesDefinitions(layer, rows, series) {
|
|
27
27
|
return series.map(item => {
|
|
28
|
-
const members = rowsForSeries(rows, item.key)
|
|
28
|
+
const members = item.sourceIndices === undefined ? rowsForSeries(rows, item.key)
|
|
29
|
+
: item.sourceIndices.map(index => rows[index]);
|
|
29
30
|
const fields = { ...uniqueFields(members), ...item.key };
|
|
30
|
-
const channels =
|
|
31
|
-
Object.entries(layer.encoding ?? {}).flatMap(([channel, encoding]) => {
|
|
32
|
-
if (encoding.field === undefined) {
|
|
33
|
-
return Object.hasOwn(encoding, "datum")
|
|
34
|
-
? [[channel, encoding.datum]]
|
|
35
|
-
: [];
|
|
36
|
-
}
|
|
37
|
-
return Object.hasOwn(fields, encoding.field)
|
|
38
|
-
? [[channel, fields[encoding.field]]]
|
|
39
|
-
: [];
|
|
40
|
-
})
|
|
41
|
-
);
|
|
31
|
+
const channels = channelMapFromRow(fields, layer);
|
|
42
32
|
return { fields, channels, members };
|
|
43
33
|
});
|
|
44
34
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { rectUsesFields } from "../../../grammar/rects.js";
|
|
1
2
|
import { resolveRectRows } from "../../rect.js";
|
|
2
3
|
import {
|
|
3
4
|
channelMapFromRow,
|
|
4
5
|
concreteProperties,
|
|
5
6
|
finalizeItems,
|
|
6
7
|
itemKey,
|
|
7
|
-
ownFields
|
|
8
|
+
ownFields,
|
|
9
|
+
uniqueFields
|
|
8
10
|
} from "./common.js";
|
|
9
11
|
|
|
10
12
|
function resolveGradientPlotItems(program, layer, dataset) {
|
|
@@ -33,12 +35,13 @@ export function resolveRectItems(program, layer, dataset) {
|
|
|
33
35
|
return resolveGradientPlotItems(program, layer, dataset);
|
|
34
36
|
}
|
|
35
37
|
const rows = resolveRectRows(program, layer, dataset);
|
|
38
|
+
const hasField = rectUsesFields(layer);
|
|
36
39
|
const definitions = rows.map((item, graphicIndex) => ({
|
|
37
40
|
key: itemKey(layer, "rect", item.sourceIndex),
|
|
38
|
-
fields: ownFields(item.row),
|
|
39
|
-
channels: item.
|
|
41
|
+
fields: hasField ? ownFields(item.row) : uniqueFields(dataset.values),
|
|
42
|
+
channels: channelMapFromRow(item.row, layer),
|
|
40
43
|
properties: concreteProperties(graphic.items[graphicIndex]?.properties),
|
|
41
|
-
members: [item.row]
|
|
44
|
+
members: hasField ? [item.row] : dataset.values
|
|
42
45
|
}));
|
|
43
46
|
return finalizeItems(program, layer, "rect", definitions, "rect");
|
|
44
47
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { resolveBarChannels } from "../grammar/bars/policy.js";
|
|
2
|
+
import { resolveMarkLabelValues } from "../grammar/markLabels.js";
|
|
2
3
|
import { formatTextValue } from "../grammar/text.js";
|
|
4
|
+
import { normalizePositionDatum } from "../grammar/positionDatum.js";
|
|
5
|
+
import { mapOrdinalPositionValues } from "../grammar/scales/index.js";
|
|
3
6
|
import { findDataset } from "../selectors/datasets.js";
|
|
4
7
|
import { findLayer } from "../selectors/layers.js";
|
|
5
8
|
import { resolveMarkItems } from "./selection/policies/index.js";
|
|
@@ -7,6 +10,14 @@ import { mapScaleConsumerValues } from "./scales/map.js";
|
|
|
7
10
|
import { resolveRowEncodingValues } from "./rowEncoding.js";
|
|
8
11
|
|
|
9
12
|
function sourceValue(item, source, field) {
|
|
13
|
+
const measure = source.mark.type === "bar" ? resolveBarChannels(source).measure
|
|
14
|
+
: source.mark.type === "arc" ? "radius" : undefined;
|
|
15
|
+
const encoding = source.encoding?.[measure];
|
|
16
|
+
if (encoding?.field === field && encoding.aggregate != null && item.channels[measure] !== undefined) {
|
|
17
|
+
return source.mark.type === "bar"
|
|
18
|
+
? item.channels[`${measure}2`] ?? item.channels[measure]
|
|
19
|
+
: item.channels[measure];
|
|
20
|
+
}
|
|
10
21
|
if (Object.hasOwn(item.fields, field)) return item.fields[field];
|
|
11
22
|
for (const [channel, encoding] of Object.entries(source.encoding ?? {})) {
|
|
12
23
|
if (encoding?.field !== field || item.channels[channel] === undefined) continue;
|
|
@@ -18,6 +29,10 @@ function sourceValue(item, source, field) {
|
|
|
18
29
|
if (item.members.length === 1 && Object.hasOwn(item.members[0], field)) {
|
|
19
30
|
return item.members[0][field];
|
|
20
31
|
}
|
|
32
|
+
if (source.mark.type === "line" && item.members.length > 0) {
|
|
33
|
+
const endpoint = item.members.at(-1);
|
|
34
|
+
if (Object.hasOwn(endpoint, field)) return endpoint[field];
|
|
35
|
+
}
|
|
21
36
|
return undefined;
|
|
22
37
|
}
|
|
23
38
|
|
|
@@ -54,6 +69,17 @@ function sourceAnchor(program, source, item) {
|
|
|
54
69
|
y: item.properties.y2
|
|
55
70
|
};
|
|
56
71
|
}
|
|
72
|
+
if (source.mark.type === "line") {
|
|
73
|
+
const graphicId = item.graphicIds?.[0];
|
|
74
|
+
const graphic = program.graphicSpec.objects[source.id]?.items?.find(
|
|
75
|
+
candidate => candidate.id === graphicId
|
|
76
|
+
);
|
|
77
|
+
const commands = graphic?.properties?.commands;
|
|
78
|
+
const endpoint = Array.isArray(commands)
|
|
79
|
+
? [...commands].reverse().find(command => Number.isFinite(command.x) && Number.isFinite(command.y))
|
|
80
|
+
: undefined;
|
|
81
|
+
return { x: endpoint?.x, y: endpoint?.y };
|
|
82
|
+
}
|
|
57
83
|
return { x: item.properties.x, y: item.properties.y };
|
|
58
84
|
}
|
|
59
85
|
|
|
@@ -122,12 +148,14 @@ function resolveSourceTextItems(program, layer, config) {
|
|
|
122
148
|
throw new Error(`Text mark "${layer.id}" requires source layer "${layer.source}".`);
|
|
123
149
|
}
|
|
124
150
|
const items = resolveMarkItems(program, source.id);
|
|
125
|
-
|
|
151
|
+
const values = layer.encoding.text.content === undefined ? undefined
|
|
152
|
+
: resolveMarkLabelValues(source, items, layer.encoding.text);
|
|
153
|
+
return items.flatMap((item, index) => {
|
|
126
154
|
const anchor = sourceAnchor(program, source, item);
|
|
127
155
|
const concrete = concreteItem(
|
|
128
156
|
sourceTextConfig(config, source, item),
|
|
129
157
|
anchor,
|
|
130
|
-
contentValue(layer.encoding.text, item, source),
|
|
158
|
+
values === undefined ? contentValue(layer.encoding.text, item, source) : values[index],
|
|
131
159
|
layer.encoding.text.format
|
|
132
160
|
);
|
|
133
161
|
return concrete === undefined ? [] : [{ graphic: concrete, anchor }];
|
|
@@ -139,10 +167,41 @@ function resolveRowTextItems(program, layer, config) {
|
|
|
139
167
|
if (dataset === undefined) {
|
|
140
168
|
throw new Error(`Text mark "${layer.id}" requires an existing dataset.`);
|
|
141
169
|
}
|
|
142
|
-
const
|
|
143
|
-
const
|
|
170
|
+
const encodings = [layer.encoding?.x, layer.encoding?.y, layer.encoding?.text];
|
|
171
|
+
const length = encodings.some(encoding => encoding !== undefined && Object.hasOwn(encoding, "field"))
|
|
172
|
+
? dataset.values.length
|
|
173
|
+
: 1;
|
|
174
|
+
const positionValues = channel => {
|
|
175
|
+
const encoding = layer.encoding?.[channel];
|
|
176
|
+
if (encoding === undefined) return undefined;
|
|
177
|
+
if (Object.hasOwn(encoding, "field")) {
|
|
178
|
+
return resolveRowEncodingValues(program, layer, dataset, channel);
|
|
179
|
+
}
|
|
180
|
+
const scale = program.resolvedScales[encoding.scale];
|
|
181
|
+
if (scale === undefined) {
|
|
182
|
+
throw new Error(
|
|
183
|
+
`text mark "${layer.id}" requires resolved ${channel} scale "${encoding.scale}".`
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
const datum = normalizePositionDatum(
|
|
187
|
+
encoding.datum,
|
|
188
|
+
encoding.fieldType,
|
|
189
|
+
channel,
|
|
190
|
+
encoding.temporalUnit,
|
|
191
|
+
"Text"
|
|
192
|
+
);
|
|
193
|
+
const mapped = ["nominal", "ordinal"].includes(encoding.fieldType)
|
|
194
|
+
? mapOrdinalPositionValues([datum], scale)
|
|
195
|
+
: mapScaleConsumerValues([datum], scale, channel);
|
|
196
|
+
return Array.from({ length }, () => mapped[0]);
|
|
197
|
+
};
|
|
198
|
+
const x = positionValues("x");
|
|
199
|
+
const y = positionValues("y");
|
|
144
200
|
if (x === undefined || y === undefined) return [];
|
|
145
|
-
|
|
201
|
+
const rows = length === 1 && dataset.values.length === 0
|
|
202
|
+
? [undefined]
|
|
203
|
+
: dataset.values.slice(0, length);
|
|
204
|
+
return rows.flatMap((row, index) => {
|
|
146
205
|
const concrete = concreteItem(
|
|
147
206
|
config,
|
|
148
207
|
{ x: x[index], y: y[index] },
|
package/src/mcp/adapter.js
CHANGED
|
@@ -203,8 +203,8 @@ export function readKnowledgeResource(uri, { allowedDocs = [] } = {}) {
|
|
|
203
203
|
throw new KnowledgeResourceError(`Unknown knowledge resource URI: ${uri}`);
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
-
if (cardsArtifact.schemaVersion !==
|
|
207
|
-
throw new Error("MCP action cards and resources must use schemaVersion 2.");
|
|
206
|
+
if (cardsArtifact.schemaVersion !== 3 || resourcesArtifact.schemaVersion !== 2) {
|
|
207
|
+
throw new Error("MCP action cards must use schemaVersion 3 and resources must use schemaVersion 2.");
|
|
208
208
|
}
|
|
209
209
|
if (resourcesArtifact.packageVersion !== cardsArtifact.packageVersion) {
|
|
210
210
|
throw new Error("MCP action cards and resources must use one packageVersion.");
|
|
@@ -15,3 +15,16 @@ export function requireDataset(program, id, label = `Dataset "${id}"`) {
|
|
|
15
15
|
if (dataset === undefined) throw new Error(`${label} does not exist.`);
|
|
16
16
|
return dataset;
|
|
17
17
|
}
|
|
18
|
+
|
|
19
|
+
export function requireMaterializedDataset(program, id) {
|
|
20
|
+
const dataset = findDataset(program, id);
|
|
21
|
+
if (dataset === undefined) throw new Error(`Unknown dataset "${id}".`);
|
|
22
|
+
if (!Array.isArray(dataset.values)) {
|
|
23
|
+
throw new Error(
|
|
24
|
+
`Dataset "${id}" requires materialized values. ` +
|
|
25
|
+
"createDerivedData stores a definition only; use the corresponding " +
|
|
26
|
+
"value-producing data action before creating a chart or mark."
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
return dataset;
|
|
30
|
+
}
|
package/src/selectors/layers.js
CHANGED
|
@@ -16,17 +16,18 @@ export function resolveEligibleLayer(program, {
|
|
|
16
16
|
target,
|
|
17
17
|
predicate,
|
|
18
18
|
label,
|
|
19
|
+
targetOption = "target",
|
|
19
20
|
current = program.context.currentMark
|
|
20
21
|
}) {
|
|
21
22
|
const candidates = program.semanticSpec.layers.filter(predicate);
|
|
22
23
|
if (target !== undefined) {
|
|
23
24
|
const selected = candidates.find(layer => layer.id === target);
|
|
24
|
-
if (selected === undefined) throw new Error(`Unknown ${label}
|
|
25
|
+
if (selected === undefined) throw new Error(`Unknown ${label} ${targetOption} "${target}".`);
|
|
25
26
|
return selected;
|
|
26
27
|
}
|
|
27
28
|
const selected = candidates.find(layer => layer.id === current);
|
|
28
29
|
if (selected !== undefined) return selected;
|
|
29
30
|
if (candidates.length === 1) return candidates[0];
|
|
30
31
|
if (candidates.length === 0) throw new Error(`${label} requires an eligible layer.`);
|
|
31
|
-
throw new Error(`${label}
|
|
32
|
+
throw new Error(`${label} ${targetOption} is ambiguous; provide ${targetOption}.`);
|
|
32
33
|
}
|
package/src/selectors/scales.js
CHANGED
|
@@ -19,3 +19,9 @@ export function requireResolvedScale(program, id, type) {
|
|
|
19
19
|
}
|
|
20
20
|
return scale;
|
|
21
21
|
}
|
|
22
|
+
|
|
23
|
+
export function hasSemanticScaleReferences(spec, id) {
|
|
24
|
+
const referenced = value => value !== null && typeof value === "object" && Object.entries(value).some(([key, child]) =>
|
|
25
|
+
(key === "scale" && child === id) || (key === "scales" && Array.isArray(child) && child.includes(id)) || referenced(child));
|
|
26
|
+
return referenced(spec.layers) || referenced(spec.guides);
|
|
27
|
+
}
|
package/src/theme/defaults.js
CHANGED
|
@@ -13,5 +13,44 @@ export const DEFAULT_COLORS = Object.freeze({
|
|
|
13
13
|
border: "#cbd5e1",
|
|
14
14
|
sizeSymbol: "#94a3b8",
|
|
15
15
|
regressionBand: "#111111",
|
|
16
|
+
boxLine: "#111111",
|
|
17
|
+
boxMedian: "#1f2937",
|
|
18
|
+
referenceLine: "#64748b",
|
|
19
|
+
referenceBand: "#94a3b8",
|
|
20
|
+
gradientCenter: "#0f172a",
|
|
16
21
|
highlight: "#dc2626"
|
|
17
22
|
});
|
|
23
|
+
|
|
24
|
+
export const THEME_NAMES = Object.freeze(["light", "dark"]);
|
|
25
|
+
|
|
26
|
+
export const THEME_TOKENS = Object.freeze({
|
|
27
|
+
light: Object.freeze({
|
|
28
|
+
background: "white",
|
|
29
|
+
...DEFAULT_COLORS,
|
|
30
|
+
fontFamily: DEFAULT_FONT_FAMILY
|
|
31
|
+
}),
|
|
32
|
+
dark: Object.freeze({
|
|
33
|
+
background: "#0f172a",
|
|
34
|
+
mark: "#60a5fa",
|
|
35
|
+
text: "#e2e8f0",
|
|
36
|
+
strongText: "#f8fafc",
|
|
37
|
+
mutedText: "#94a3b8",
|
|
38
|
+
axis: "#cbd5e1",
|
|
39
|
+
axisTitle: "#f1f5f9",
|
|
40
|
+
grid: "#334155",
|
|
41
|
+
border: "#475569",
|
|
42
|
+
sizeSymbol: "#94a3b8",
|
|
43
|
+
regressionBand: "#f8fafc",
|
|
44
|
+
boxLine: "#f8fafc",
|
|
45
|
+
boxMedian: "#f8fafc",
|
|
46
|
+
referenceLine: "#94a3b8",
|
|
47
|
+
referenceBand: "#94a3b8",
|
|
48
|
+
gradientCenter: "#f8fafc",
|
|
49
|
+
highlight: DEFAULT_COLORS.highlight,
|
|
50
|
+
fontFamily: DEFAULT_FONT_FAMILY
|
|
51
|
+
})
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
export function themeTokens(name = "light") {
|
|
55
|
+
return THEME_TOKENS[name];
|
|
56
|
+
}
|
package/types/basic.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ChartProgram } from "./program.js";
|
|
1
|
+
import type { ChartProgram, BasicSeriesLayoutOptions } from "./program.js";
|
|
2
2
|
|
|
3
3
|
export type {
|
|
4
4
|
AxisLabelOptions,
|
|
@@ -6,7 +6,9 @@ export type {
|
|
|
6
6
|
AxisTickOptions,
|
|
7
7
|
AxisTicksAndLabelsOptions,
|
|
8
8
|
AxisTitleOptions,
|
|
9
|
+
ApplyThemeOptions,
|
|
9
10
|
BarWidthOptions,
|
|
11
|
+
BasicSeriesLayoutOptions,
|
|
10
12
|
Bin2DDataOptions,
|
|
11
13
|
CanvasOptions,
|
|
12
14
|
ColorEncodingOptions,
|
|
@@ -21,6 +23,7 @@ export type {
|
|
|
21
23
|
CreateScatterPlotOptions,
|
|
22
24
|
CreateScaleOptions,
|
|
23
25
|
GraphicSpec,
|
|
26
|
+
GroupEncodingOptions,
|
|
24
27
|
GridDirectionOptions,
|
|
25
28
|
HistogramEncodingOptions,
|
|
26
29
|
LegendOptions,
|
|
@@ -30,6 +33,8 @@ export type {
|
|
|
30
33
|
SecondaryPositionEncodingOptions,
|
|
31
34
|
SemanticSpec,
|
|
32
35
|
StrokeDashEncodingOptions,
|
|
36
|
+
TemporalInputUnit,
|
|
37
|
+
ThemeName,
|
|
33
38
|
TraceNode,
|
|
34
39
|
XAxisPosition,
|
|
35
40
|
XOffsetEncodingOptions,
|
|
@@ -47,6 +52,8 @@ type BasicStateKey =
|
|
|
47
52
|
|
|
48
53
|
type BasicMethodKey =
|
|
49
54
|
| "createCanvas"
|
|
55
|
+
| "applyTheme"
|
|
56
|
+
| "removeTheme"
|
|
50
57
|
| "createData"
|
|
51
58
|
| "createPointMark"
|
|
52
59
|
| "createLineMark"
|
|
@@ -57,6 +64,7 @@ type BasicMethodKey =
|
|
|
57
64
|
| "encodeX2"
|
|
58
65
|
| "encodeY2"
|
|
59
66
|
| "encodeGroup"
|
|
67
|
+
| "encodePointRadius"
|
|
60
68
|
| "encodeColor"
|
|
61
69
|
| "encodeStrokeDash"
|
|
62
70
|
| "encodeSize"
|
|
@@ -97,7 +105,8 @@ type RebindMethod<T> = T extends (...args: infer Args) => ChartProgram
|
|
|
97
105
|
|
|
98
106
|
export type BasicChartProgram =
|
|
99
107
|
Pick<ChartProgram, BasicStateKey> &
|
|
100
|
-
{ readonly [Key in BasicMethodKey]: RebindMethod<ChartProgram[Key]> }
|
|
108
|
+
{ readonly [Key in BasicMethodKey]: RebindMethod<ChartProgram[Key]> } &
|
|
109
|
+
{ readonly layoutSeries: (options: BasicSeriesLayoutOptions) => BasicChartProgram };
|
|
101
110
|
|
|
102
111
|
export function chart(): BasicChartProgram;
|
|
103
112
|
export function render(
|