ggaction 0.0.17 → 0.0.18
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 +46 -0
- package/README.md +2 -2
- package/knowledge/action-card.schema.json +1 -1
- package/knowledge/action-cards.json +1 -1
- package/knowledge/intent-taxonomy.json +1 -1
- package/knowledge/mcp-resources.json +1 -1
- package/knowledge/task-resolver.js +1 -1
- package/package.json +3 -3
- package/src/BasicChartProgram.js +1 -1
- package/src/accessibility.js +3 -2
- package/src/actions/boxPlots/create.js +14 -4
- package/src/actions/boxPlots/edit.js +39 -33
- package/src/actions/boxPlots/materialize.js +7 -3
- package/src/actions/boxPlots/options.js +37 -11
- package/src/actions/canvas/actions.js +70 -95
- package/src/actions/canvas/fitting.js +16 -1
- package/src/actions/canvas/index.js +3 -0
- package/src/actions/canvas/plotBorder.js +28 -0
- package/src/actions/charts/area.js +2 -2
- package/src/actions/charts/bar.js +34 -7
- package/src/actions/charts/ecdf.js +4 -18
- package/src/actions/charts/endpoints.js +4 -18
- package/src/actions/charts/heatmap.js +4 -4
- package/src/actions/charts/index.js +2 -0
- package/src/actions/charts/interval-regression.js +2 -2
- package/src/actions/charts/line.js +1 -1
- package/src/actions/charts/pie.js +3 -47
- package/src/actions/charts/radial.js +34 -12
- package/src/actions/charts/scatter.js +16 -2
- package/src/actions/charts/shared.js +2 -2
- package/src/actions/charts/text.js +35 -0
- package/src/actions/composition/actions.js +6 -2
- package/src/actions/data/box.js +2 -1
- package/src/actions/data/edit.js +1 -1
- package/src/actions/data/regression.js +2 -1
- package/src/actions/data/shared.js +3 -2
- package/src/actions/data/stack.js +3 -1
- package/src/actions/encodings/appearance.js +37 -29
- package/src/actions/encodings/barWidth.js +36 -11
- package/src/actions/encodings/channels.js +0 -1
- package/src/actions/encodings/color/continuous.js +1 -1
- package/src/actions/encodings/color/index.js +1 -1
- package/src/actions/encodings/color/policy.js +10 -3
- package/src/actions/encodings/density/resolve.js +1 -6
- package/src/actions/encodings/position/policies/arc.js +12 -10
- package/src/actions/encodings/position/policies/area.js +3 -3
- package/src/actions/encodings/position/policies/bar.js +15 -6
- package/src/actions/encodings/position/policies/line.js +17 -6
- package/src/actions/encodings/position/resolve.js +3 -2
- package/src/actions/encodings/ranged.js +17 -0
- package/src/actions/encodings/remove.js +3 -2
- package/src/actions/encodings/seriesLayout.js +1 -0
- package/src/actions/encodings/text.js +6 -3
- package/src/actions/errorBands/create.js +2 -2
- package/src/actions/errorBands/edit.js +2 -1
- package/src/actions/facets/actions.js +158 -240
- package/src/actions/gradientPlots/resolve.js +2 -17
- package/src/actions/guides/applicability.js +1 -1
- package/src/actions/guides/axes/axis.js +16 -4
- package/src/actions/guides/axes/edit.js +4 -4
- package/src/actions/guides/axes/labels.js +120 -46
- package/src/actions/guides/axes/lines.js +6 -5
- package/src/actions/guides/axes/parallel/lifecycle.js +1 -1
- package/src/actions/guides/axes/parallel/policy.js +8 -7
- package/src/actions/guides/axes/remove.js +3 -2
- package/src/actions/guides/axes/tickGroups.js +5 -2
- package/src/actions/guides/axes/ticks.js +6 -3
- package/src/actions/guides/axes/titles.js +71 -26
- package/src/actions/guides/basic.js +2 -0
- package/src/actions/guides/facadeLegend.js +10 -2
- package/src/actions/guides/grids/grid.js +7 -1
- package/src/actions/guides/grids/resolve.js +59 -12
- package/src/actions/guides/legends/blocks.js +3 -1
- package/src/actions/guides/legends/categorical/actions.js +70 -17
- package/src/actions/guides/legends/categorical/components.js +12 -8
- package/src/actions/guides/legends/categorical/index.js +6 -0
- package/src/actions/guides/legends/categorical/layout.js +37 -8
- package/src/actions/guides/legends/categorical/options.js +31 -20
- package/src/actions/guides/legends/categorical/resolve.js +2 -2
- package/src/actions/guides/legends/categorical/symbols.js +18 -12
- package/src/actions/guides/legends/categorical/validation.js +1 -6
- package/src/actions/guides/legends/continuous/colorSymbols.js +1 -0
- package/src/actions/guides/legends/continuous/common.js +1 -447
- package/src/actions/guides/legends/continuous/gradient.js +47 -34
- package/src/actions/guides/legends/continuous/interval.js +4 -4
- package/src/actions/guides/legends/continuous/opacity.js +19 -12
- package/src/actions/guides/legends/edit.js +1 -604
- package/src/actions/guides/legends/focused.js +2 -2
- package/src/actions/guides/legends/group.js +1 -0
- package/src/actions/guides/legends/lane.js +1 -516
- package/src/actions/guides/legends/remove.js +3 -0
- package/src/actions/guides/legends/sampling.js +1 -1
- package/src/actions/guides/legends/size.js +51 -43
- package/src/actions/guides/legends/strokeWidth.js +11 -29
- package/src/actions/guides/legends/target.js +3 -3
- package/src/actions/guides/legends/transition.js +21 -7
- package/src/actions/guides/polar/axes/labels.js +4 -2
- package/src/actions/guides/polar/axes/titles.js +7 -5
- package/src/actions/guides/polar/resolve.js +6 -14
- package/src/actions/index.js +16 -16
- package/src/actions/marks/arc/actions.js +3 -10
- package/src/actions/marks/area/actions.js +8 -5
- package/src/actions/marks/area/materialize.js +8 -9
- package/src/actions/marks/bar/create.js +10 -4
- package/src/actions/marks/bar/edit.js +8 -4
- package/src/actions/marks/bar/materialize.js +9 -6
- package/src/actions/marks/line/actions.js +11 -4
- package/src/actions/marks/line/materialize.js +9 -5
- package/src/actions/marks/point/edit.js +1 -1
- package/src/actions/marks/rect/actions.js +3 -3
- package/src/actions/marks/remove.js +2 -0
- package/src/actions/marks/rule/actions.js +7 -4
- package/src/actions/marks/text/actions.js +17 -5
- package/src/actions/marks/text/layout.js +3 -0
- package/src/actions/primitives/semanticValidation/layer.js +4 -0
- package/src/actions/regression/create.js +1 -1
- package/src/actions/regression/edit.js +3 -3
- package/src/actions/regression/resolve.js +2 -6
- package/src/actions/scales/channels.js +9 -4
- package/src/actions/scales/consumers/families.js +16 -5
- package/src/actions/scales/create.js +8 -3
- package/src/actions/scales/definitions.js +1 -425
- package/src/actions/scales/edit.js +2 -2
- package/src/actions/scales/editPolicy.js +9 -3
- package/src/actions/scales/materialize.js +1 -1
- package/src/actions/scales/preview.js +21 -1
- package/src/actions/scales/quantitativeColor.js +3 -3
- package/src/actions/selection/actions.js +1 -13
- package/src/actions/theme/reconcile.js +81 -27
- package/src/actions/theme/state.js +12 -0
- package/src/actions/titles/actions.js +5 -18
- package/src/actions/titles/resolve.js +41 -19
- package/src/actions/violinPlots/edit.js +3 -20
- package/src/core/compositionState.js +4 -1
- package/src/core/font.js +9 -2
- package/src/core/optionRequirements.js +1 -0
- package/src/core/resourceReferences.js +3 -0
- package/src/core/textMetricProfile.js +3 -2
- package/src/core/textMetrics.js +41 -4
- package/src/core/validation.js +26 -0
- package/src/core/vocabulary.js +4 -0
- package/src/grammar/aggregate.js +4 -18
- package/src/grammar/arcs.js +1 -386
- package/src/grammar/areaPaint.js +10 -0
- package/src/grammar/areaSeries.js +18 -10
- package/src/grammar/bars/geometry.js +30 -3
- package/src/grammar/bars/policy.js +12 -1
- package/src/grammar/bin.js +2 -12
- package/src/grammar/bin2d.js +1 -6
- package/src/grammar/boxPlot.js +56 -9
- package/src/grammar/categoryOrder.js +1 -6
- package/src/grammar/complete.js +15 -19
- package/src/grammar/computed.js +92 -25
- package/src/grammar/curveCommands.js +29 -16
- package/src/grammar/datasetSchema.js +3 -7
- package/src/grammar/displayLabels.js +28 -0
- package/src/grammar/ecdf.js +2 -9
- package/src/grammar/facets/dependencies.js +6 -2
- package/src/grammar/facets/guides.js +5 -0
- package/src/grammar/facets/index.js +2 -5
- package/src/grammar/fold.js +2 -12
- package/src/grammar/gradientProfile.js +1 -6
- package/src/grammar/impute.js +21 -48
- package/src/grammar/interval.js +2 -9
- package/src/grammar/legendGradient.js +18 -0
- package/src/grammar/legendGroups.js +1 -0
- package/src/grammar/legendTitleStyle.js +22 -0
- package/src/grammar/lineSeries.js +32 -17
- package/src/grammar/markLabels.js +5 -2
- package/src/grammar/normalize.js +4 -54
- package/src/grammar/numeric.js +1 -290
- package/src/grammar/parallelCoordinates.js +1 -6
- package/src/grammar/parseTime.js +41 -0
- package/src/grammar/pathCommands.js +11 -4
- package/src/grammar/polar.js +1 -184
- package/src/grammar/positionCompatibility.js +3 -3
- package/src/grammar/regression/derive.js +7 -1
- package/src/grammar/regression/models.js +83 -55
- package/src/grammar/regression/parameters.js +14 -3
- package/src/grammar/roundedRect.js +42 -54
- package/src/grammar/scales/appearance.js +1 -206
- package/src/grammar/scales/color.js +1 -382
- package/src/grammar/scales/colorConsumers.js +5 -2
- package/src/grammar/scales/definition.js +1 -197
- package/src/grammar/scales/discretized.js +1 -195
- package/src/grammar/scales/size.js +1 -456
- package/src/grammar/scales/temporal.js +2 -13
- package/src/grammar/scales/transformed.js +1 -383
- package/src/grammar/scales/types.js +1 -1
- package/src/grammar/scales/validation.js +1 -66
- package/src/grammar/schemas/concreteGraphic.js +11 -0
- package/src/grammar/schemas/graphic.js +3 -0
- package/src/grammar/schemas/semanticPath.js +2 -1
- package/src/grammar/stack.js +2 -10
- package/src/grammar/statisticalReference.js +1 -6
- package/src/grammar/summary.js +3 -26
- package/src/grammar/text.js +19 -0
- package/src/grammar/timeUnit.js +16 -7
- package/src/grammar/transformKeys.js +47 -0
- package/src/grammar/transforms.js +4 -1
- package/src/grammar/valueFormat.js +17 -5
- package/src/grammar/weightedStatistics.js +1 -6
- package/src/grammar/window.js +4 -58
- package/src/inspectionDescriptors.js +1 -1
- package/src/layout/canvas.js +1 -110
- package/src/layout/facets.js +1 -244
- package/src/layout/labels.js +1 -0
- package/src/layout/legend.js +13 -0
- package/src/layout/legendGroup.js +1 -0
- package/src/layout/legendItems.js +59 -15
- package/src/layout/legendLane.js +1 -441
- package/src/layout/legendText.js +1 -0
- package/src/layout/title.js +35 -13
- package/src/materialization/bars/aggregate.js +11 -5
- package/src/materialization/bars/histogram.js +4 -1
- package/src/materialization/bars/ranged.js +19 -6
- package/src/materialization/bars/resolve.js +22 -1
- package/src/materialization/coordinateBounds.js +8 -0
- package/src/materialization/dependencies.js +4 -44
- package/src/materialization/facetGuides/layout.js +1 -0
- package/src/materialization/facetGuides/placement.js +19 -8
- package/src/materialization/facetGuides/preparation.js +15 -7
- package/src/materialization/facetHeaders.js +1 -347
- package/src/materialization/facets.js +1 -185
- package/src/materialization/graphicHierarchy.js +1 -1
- package/src/materialization/guides/layout.js +1 -57
- package/src/materialization/guides/resources.js +1 -123
- package/src/materialization/layout.js +53 -0
- package/src/materialization/legendGroups.js +1 -0
- package/src/materialization/legendText.js +1 -0
- package/src/materialization/legends.js +1 -1
- package/src/materialization/marks/capabilities.js +5 -6
- package/src/materialization/rect.js +1 -1
- package/src/materialization/scaleGuideDependencies.js +1 -1
- package/src/materialization/scales/map.js +3 -0
- package/src/materialization/scales/policies/arc.js +8 -7
- package/src/materialization/scales/policies/bar.js +19 -7
- package/src/materialization/scales/policies/series.js +2 -1
- package/src/materialization/scales/resolve.js +5 -3
- package/src/materialization/selection/items/arc.js +1 -1
- package/src/materialization/selection/items/bar.js +7 -6
- package/src/materialization/selection/items/path.js +7 -6
- package/src/materialization/selection/items/rect.js +2 -2
- package/src/materialization/text.js +13 -4
- package/src/materialization/textLines.js +15 -0
- package/src/persistence/codec.js +37 -6
- package/src/persistence/validation.js +47 -0
- package/src/persistence.js +18 -5
- package/src/renderers/canvas/circle.js +6 -3
- package/src/renderers/canvas/fill.js +7 -1
- package/src/renderers/canvas/index.js +2 -1
- package/src/renderers/canvas/line.js +1 -0
- package/src/renderers/canvas/path.js +1 -1
- package/src/renderers/canvas/rect.js +11 -8
- package/src/renderers/canvas/stroke.js +2 -1
- package/src/renderers/canvas/text.js +5 -3
- package/src/renderers/svg.js +4 -1
- package/src/selectors/layers.js +19 -0
- package/src/theme/defaults.js +8 -2
- package/src/version.js +1 -1
- package/types/basic.d.ts +1 -0
- package/types/index.d.ts +7 -0
- package/types/program.d.ts +347 -85
|
@@ -1,52 +1,8 @@
|
|
|
1
1
|
import { action } from "../../core/action.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
applyFacadeGuides, normalizeAppearance, normalizeCategoricalColor, normalizeCategoricalGuides,
|
|
5
|
-
normalizeArcCategory, normalizeCategoryAggregate, omitUndefinedOptions,
|
|
6
|
-
resolveFacadeData, resolveFacadeId, validateFacadeOptions
|
|
7
|
-
} from "./shared.js";
|
|
8
|
-
|
|
9
|
-
const OPERATION = "createPiePlot";
|
|
10
|
-
const OPTIONS = ["id", "data", "coordinate", "category", "value", "aggregate", "color", "arc", "guides"];
|
|
11
|
-
const ARC_OPTIONS = [
|
|
12
|
-
"innerRadius", "padAngle", "fill", "opacity", "stroke", "strokeWidth",
|
|
13
|
-
...STROKE_STYLE_PROPERTIES
|
|
14
|
-
];
|
|
15
|
-
function guideOptions(value, color) {
|
|
16
|
-
const guides = normalizeCategoricalGuides(value, OPERATION, color);
|
|
17
|
-
if (guides === false) return false;
|
|
18
|
-
for (const key of ["axes", "grid"]) {
|
|
19
|
-
if (guides[key] !== undefined && guides[key] !== false) {
|
|
20
|
-
throw new TypeError(`${OPERATION} guides.${key} only accepts false.`);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
return { ...guides, axes: false, grid: false };
|
|
24
|
-
}
|
|
2
|
+
import { createArcPlot } from "./radial.js";
|
|
25
3
|
|
|
26
4
|
export const createPiePlot = /* @__PURE__ */ action({
|
|
27
|
-
op:
|
|
5
|
+
op: "createPiePlot", description: "Create a categorical count or weighted-sum pie or donut plot."
|
|
28
6
|
}, function (args = {}) {
|
|
29
|
-
|
|
30
|
-
const id = resolveFacadeId(this, args.id, { defaultId: "piePlot", operation: OPERATION });
|
|
31
|
-
const data = resolveFacadeData(this, args.data, OPERATION);
|
|
32
|
-
const category = normalizeArcCategory(args.category, OPERATION);
|
|
33
|
-
const aggregate = normalizeCategoryAggregate(args, OPERATION);
|
|
34
|
-
const arc = omitUndefinedOptions(normalizeAppearance(args.arc, ARC_OPTIONS, `${OPERATION} arc`));
|
|
35
|
-
const color = args.color === false ? undefined
|
|
36
|
-
: normalizeCategoricalColor(args.color === undefined ? category.field : args.color, `${OPERATION} color`);
|
|
37
|
-
if (color !== undefined && arc.fill !== undefined) {
|
|
38
|
-
throw new Error(`${OPERATION} arc.fill cannot be combined with color; use color:false.`);
|
|
39
|
-
}
|
|
40
|
-
const guides = guideOptions(args.guides, color);
|
|
41
|
-
let next = this.createArcMark({ id, data, ...arc }).encodeTheta({
|
|
42
|
-
...category, target: id, aggregate,
|
|
43
|
-
...(args.coordinate === undefined ? {} : { coordinate: args.coordinate }),
|
|
44
|
-
...(aggregate === "sum" ? { weight: args.value } : {})
|
|
45
|
-
});
|
|
46
|
-
if (color !== undefined) next = next.encodeColor({ ...color, target: id });
|
|
47
|
-
next = applyFacadeGuides(next, guides, id, args.guides ?? {});
|
|
48
|
-
return next._withMarkConfig(id, {
|
|
49
|
-
...next.markConfigs[id],
|
|
50
|
-
compositionRole: "pie"
|
|
51
|
-
});
|
|
7
|
+
return createArcPlot(this, args, { operation: "createPiePlot", defaultId: "piePlot" });
|
|
52
8
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { findSemanticScale } from "../../selectors/scales.js";
|
|
1
2
|
import { action } from "../../core/action.js";
|
|
2
3
|
import { STROKE_STYLE_PROPERTIES } from "../../grammar/strokeStyle.js";
|
|
3
4
|
import {
|
|
@@ -6,21 +7,22 @@ import {
|
|
|
6
7
|
resolveFacadeData, resolveFacadeId, validateFacadeOptions
|
|
7
8
|
} from "./shared.js";
|
|
8
9
|
|
|
9
|
-
const OPTIONS = ["id", "data", "coordinate", "category", "value", "aggregate", "
|
|
10
|
+
const OPTIONS = ["id", "data", "coordinate", "category", "value", "aggregate", "color", "arc", "guides"];
|
|
10
11
|
const ARC_OPTIONS = [
|
|
11
12
|
"innerRadius", "padAngle", "fill", "opacity", "stroke", "strokeWidth",
|
|
12
13
|
...STROKE_STYLE_PROPERTIES
|
|
13
14
|
];
|
|
14
15
|
const RADIUS_OPTIONS = ["id", "type", "domain", "range", "zero", "nice", "reverse", "clamp"];
|
|
15
16
|
|
|
16
|
-
function
|
|
17
|
-
|
|
17
|
+
export function createArcPlot(program, args, { operation, defaultId, mapping }) {
|
|
18
|
+
const measured = mapping !== undefined;
|
|
19
|
+
validateFacadeOptions(args, [...OPTIONS, measured ? "radiusScale" : "radius"], operation);
|
|
18
20
|
const id = resolveFacadeId(program, args.id, { defaultId, operation });
|
|
19
21
|
const data = resolveFacadeData(program, args.data, operation);
|
|
20
22
|
const category = normalizeArcCategory(args.category, operation);
|
|
21
23
|
const aggregate = normalizeCategoryAggregate(args, operation);
|
|
22
24
|
const arc = omitUndefinedOptions(normalizeAppearance(args.arc, ARC_OPTIONS, `${operation} arc`));
|
|
23
|
-
if (arc.padAngle !== undefined && arc.padAngle !== 0) throw new Error(`${operation} requires padAngle 0.`);
|
|
25
|
+
if (measured && arc.padAngle !== undefined && arc.padAngle !== 0) throw new Error(`${operation} requires padAngle 0.`);
|
|
24
26
|
const radiusScale = args.radiusScale === undefined ? undefined
|
|
25
27
|
: omitUndefinedOptions(normalizeAppearance(args.radiusScale, RADIUS_OPTIONS, `${operation} radiusScale`));
|
|
26
28
|
const color = args.color === false ? undefined
|
|
@@ -28,23 +30,43 @@ function createMeasuredPlot(program, args, { operation, defaultId, mapping }) {
|
|
|
28
30
|
if (color !== undefined && arc.fill !== undefined) {
|
|
29
31
|
throw new Error(`${operation} arc.fill cannot be combined with color; use color:false.`);
|
|
30
32
|
}
|
|
31
|
-
|
|
33
|
+
let guides = normalizeCategoricalGuides(args.guides, operation, color);
|
|
34
|
+
if (!measured && guides !== false) {
|
|
35
|
+
for (const key of ["axes", "grid"]) {
|
|
36
|
+
if (guides[key] !== undefined && guides[key] !== false) {
|
|
37
|
+
throw new TypeError(`${operation} guides.${key} only accepts false.`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
guides = { ...guides, axes: false, grid: false };
|
|
41
|
+
}
|
|
32
42
|
let next = program.createArcMark({ id, data, ...arc }).encodeTheta({
|
|
33
|
-
...category, target: id, ...(args.coordinate === undefined ? {} : { coordinate: args.coordinate })
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
43
|
+
...category, target: id, ...(args.coordinate === undefined ? {} : { coordinate: args.coordinate }),
|
|
44
|
+
...(!measured ? { aggregate, ...(aggregate === "sum" ? { weight: args.value } : {}) } : {})
|
|
45
|
+
});
|
|
46
|
+
if (measured) {
|
|
47
|
+
next = next.encodeR({ target: id, aggregate, mapping,
|
|
48
|
+
...(aggregate === "sum" ? { field: args.value } : {}),
|
|
49
|
+
...(radiusScale === undefined ? {} : { scale: radiusScale }) });
|
|
50
|
+
} else if (args.radius !== undefined) {
|
|
51
|
+
const radius = typeof args.radius === "string" ? { field: args.radius }
|
|
52
|
+
: normalizeAppearance(args.radius, ["field", "aggregate", "scale"], `${operation} radius`);
|
|
53
|
+
const scale = radius.scale ?? {};
|
|
54
|
+
next = next.encodeR({ target: id, ...omitUndefinedOptions(radius), scale: {
|
|
55
|
+
...(scale.type !== "log" && findSemanticScale(next, scale.id ?? "radius") === undefined ? { zero: true } : {}),
|
|
56
|
+
...scale
|
|
57
|
+
} });
|
|
58
|
+
}
|
|
37
59
|
if (color !== undefined) next = next.encodeColor({ ...color, target: id });
|
|
38
60
|
next = applyFacadeGuides(next, guides, id, args.guides ?? {});
|
|
39
61
|
return next._withMarkConfig(id, {
|
|
40
62
|
...next.markConfigs[id],
|
|
41
|
-
compositionRole: "rose"
|
|
63
|
+
compositionRole: measured ? "rose" : "pie"
|
|
42
64
|
});
|
|
43
65
|
}
|
|
44
66
|
|
|
45
67
|
export const createRosePlot = /* @__PURE__ */ action({ op: "createRosePlot", description: "Create equal-angle sectors with area proportional to category count or sum." }, function (args = {}) {
|
|
46
|
-
return
|
|
68
|
+
return createArcPlot(this, args, { operation: "createRosePlot", defaultId: "rosePlot", mapping: "area" });
|
|
47
69
|
});
|
|
48
70
|
export const createRadialBarPlot = /* @__PURE__ */ action({ op: "createRadialBarPlot", description: "Create equal-angle sectors with radial length proportional to category count or sum." }, function (args = {}) {
|
|
49
|
-
return
|
|
71
|
+
return createArcPlot(this, args, { operation: "createRadialBarPlot", defaultId: "radialBarPlot", mapping: "radius-length" });
|
|
50
72
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { encodeStroke } from "../encodings/stroke.js";
|
|
1
2
|
import { action } from "../../core/action.js";
|
|
2
3
|
import { validateNonNegativeFinite } from "../../core/validation.js";
|
|
3
4
|
import { STROKE_STYLE_PROPERTIES } from "../../grammar/strokeStyle.js";
|
|
@@ -15,7 +16,7 @@ import {
|
|
|
15
16
|
} from "./shared.js";
|
|
16
17
|
|
|
17
18
|
const OPTIONS = Object.freeze([
|
|
18
|
-
"id", "data", "coordinate", "x", "y", "color", "size", "shape",
|
|
19
|
+
"id", "data", "coordinate", "x", "y", "color", "stroke", "size", "shape",
|
|
19
20
|
"point", "guides"
|
|
20
21
|
]);
|
|
21
22
|
const POINT_OPTIONS = Object.freeze([
|
|
@@ -43,6 +44,13 @@ export const createScatterPlot = /* @__PURE__ */ action(
|
|
|
43
44
|
const x = normalizeFieldEncoding(args.x, "createScatterPlot x");
|
|
44
45
|
const y = normalizeFieldEncoding(args.y, "createScatterPlot y");
|
|
45
46
|
const color = normalizeEncoding(args.color, "createScatterPlot color");
|
|
47
|
+
const stroke = normalizeEncoding(args.stroke, "createScatterPlot stroke");
|
|
48
|
+
if (stroke !== undefined) {
|
|
49
|
+
if (typeof stroke.field !== "string" || stroke.field.length === 0 || Object.hasOwn(stroke, "value")) {
|
|
50
|
+
throw new TypeError("createScatterPlot stroke requires a field; constant stroke belongs in point.");
|
|
51
|
+
}
|
|
52
|
+
if (Object.hasOwn(point, "stroke")) throw new Error("createScatterPlot stroke conflicts with point.stroke.");
|
|
53
|
+
}
|
|
46
54
|
const size = normalizeEncoding(args.size, "createScatterPlot size");
|
|
47
55
|
const shape = normalizeEncoding(args.shape, "createScatterPlot shape");
|
|
48
56
|
const guides = normalizeGuides(args.guides, "createScatterPlot");
|
|
@@ -51,12 +59,18 @@ export const createScatterPlot = /* @__PURE__ */ action(
|
|
|
51
59
|
if (size !== undefined) throw new Error("createScatterPlot point radius conflicts with size.");
|
|
52
60
|
}
|
|
53
61
|
|
|
62
|
+
const initialPoint = { ...point };
|
|
63
|
+
if (stroke !== undefined) delete initialPoint.strokeWidth;
|
|
54
64
|
let next = this
|
|
55
|
-
.createPointMark({ id, data, ...
|
|
65
|
+
.createPointMark({ id, data, ...initialPoint })
|
|
56
66
|
.encodeX(positionArgs(x, { target: id, coordinate: args.coordinate }))
|
|
57
67
|
.encodeY(positionArgs(y, { target: id, coordinate: args.coordinate }));
|
|
58
68
|
if (radius !== undefined) next = next.encodePointRadius({ target: id, value: radius });
|
|
59
69
|
if (color !== undefined) next = next.encodeColor(targetArgs(color, id));
|
|
70
|
+
if (stroke !== undefined) {
|
|
71
|
+
next = encodeStroke.call(next, targetArgs(stroke, id));
|
|
72
|
+
if (Object.hasOwn(point, "strokeWidth")) next = next.editPointMark({ target: id, strokeWidth: point.strokeWidth });
|
|
73
|
+
}
|
|
60
74
|
if (size !== undefined) next = next.encodeSize(targetArgs(size, id));
|
|
61
75
|
if (shape !== undefined) next = next.encodeShape(targetArgs(shape, id));
|
|
62
76
|
return applyFacadeGuides(next, guides, id);
|
|
@@ -191,9 +191,9 @@ export function normalizeArcCategory(value, operation) {
|
|
|
191
191
|
}
|
|
192
192
|
|
|
193
193
|
export function normalizeCategoryAggregate(args, operation) {
|
|
194
|
-
const aggregate = args.aggregate === undefined ? "count" : args.aggregate;
|
|
194
|
+
const aggregate = args.aggregate === undefined ? args.value === undefined ? "count" : "sum" : args.aggregate;
|
|
195
195
|
if (!["count", "sum"].includes(aggregate) || (aggregate === "sum") !== (args.value !== undefined)) {
|
|
196
|
-
throw new Error(`${operation} requires count without value or
|
|
196
|
+
throw new Error(`${operation} requires count without value or sum with value.`);
|
|
197
197
|
}
|
|
198
198
|
if (args.value !== undefined) validateNonEmptyString(args.value, `${operation} value`);
|
|
199
199
|
return aggregate;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { action } from "../../core/action.js";
|
|
2
|
+
import { TEXT_MARK_STYLE_OPTIONS } from "../../grammar/text.js";
|
|
3
|
+
import {
|
|
4
|
+
applyFacadeGuides, normalizeAppearance, normalizeEncoding, normalizeFieldEncoding,
|
|
5
|
+
normalizeGuides, positionArgs, resolveFacadeData, resolveFacadeId, targetArgs,
|
|
6
|
+
validateFacadeOptions
|
|
7
|
+
} from "./shared.js";
|
|
8
|
+
|
|
9
|
+
const OPTIONS = Object.freeze(["id", "data", "coordinate", "x", "y", "text", "color", "style", "guides"]);
|
|
10
|
+
const STYLE_OPTIONS = Object.freeze(["missing", ...TEXT_MARK_STYLE_OPTIONS.filter(key => key !== "inheritColor")]);
|
|
11
|
+
|
|
12
|
+
export const createTextPlot = /* @__PURE__ */ action({
|
|
13
|
+
op: "createTextPlot", description: "Create a Cartesian text plot from existing chart data."
|
|
14
|
+
}, function (args = {}) {
|
|
15
|
+
validateFacadeOptions(args, OPTIONS, "createTextPlot");
|
|
16
|
+
const id = resolveFacadeId(this, args.id, { defaultId: "textPlot", operation: "createTextPlot" });
|
|
17
|
+
const data = resolveFacadeData(this, args.data, "createTextPlot");
|
|
18
|
+
const x = normalizeFieldEncoding(args.x, "createTextPlot x");
|
|
19
|
+
const y = normalizeFieldEncoding(args.y, "createTextPlot y");
|
|
20
|
+
const text = normalizeEncoding(args.text, "createTextPlot text");
|
|
21
|
+
if (text === undefined) throw new Error("createTextPlot requires text.");
|
|
22
|
+
const color = normalizeEncoding(args.color, "createTextPlot color");
|
|
23
|
+
const style = normalizeAppearance(args.style, STYLE_OPTIONS, "createTextPlot style");
|
|
24
|
+
const guides = normalizeGuides(args.guides, "createTextPlot");
|
|
25
|
+
const apply = program => {
|
|
26
|
+
let next = program.createTextMark({ id, data, ...style })
|
|
27
|
+
.encodeX(positionArgs(x, { target: id, coordinate: args.coordinate }))
|
|
28
|
+
.encodeY(positionArgs(y, { target: id, coordinate: args.coordinate }))
|
|
29
|
+
.encodeText(targetArgs(text, id));
|
|
30
|
+
if (color !== undefined) next = next.encodeColor(targetArgs(color, id));
|
|
31
|
+
return applyFacadeGuides(next, guides, id);
|
|
32
|
+
};
|
|
33
|
+
apply(this);
|
|
34
|
+
return apply(this);
|
|
35
|
+
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveGraphicBounds } from "../../layout/canvas.js";
|
|
1
2
|
import { inheritTextMetrics } from "../textMetrics/index.js";
|
|
2
3
|
import { action, closedAction } from "../../core/action.js";
|
|
3
4
|
import { ChartProgram as CoreChartProgram } from "../../core/ChartProgram.js";
|
|
@@ -19,7 +20,7 @@ const CONCAT_OPTIONS = Object.freeze([
|
|
|
19
20
|
"id", "programs", "gap", "align", "padding"
|
|
20
21
|
]);
|
|
21
22
|
const LAYOUT_EDIT_OPTIONS = Object.freeze([
|
|
22
|
-
"columns", "gap", "align", "padding"
|
|
23
|
+
"columns", "gap", "spacing", "align", "padding"
|
|
23
24
|
]);
|
|
24
25
|
const REPLACEMENT_OPTIONS = Object.freeze(["target", "program"]);
|
|
25
26
|
const INSERTION_OPTIONS = Object.freeze(["id", "program", "before", "after"]);
|
|
@@ -179,6 +180,7 @@ const editCompositionLayout = /* @__PURE__ */ closedAction(
|
|
|
179
180
|
"editCompositionLayout columns is available only on a facet composition."
|
|
180
181
|
);
|
|
181
182
|
}
|
|
183
|
+
if (current.type !== "facet" && Object.hasOwn(args, "spacing")) throw new Error("Plot spacing requires a facet composition.");
|
|
182
184
|
const padding = Object.hasOwn(args, "padding")
|
|
183
185
|
? normalizeCompositionPadding(args.padding, current.padding)
|
|
184
186
|
: current.padding;
|
|
@@ -188,6 +190,8 @@ const editCompositionLayout = /* @__PURE__ */ closedAction(
|
|
|
188
190
|
(current.facet.grid?.cells ?? []).map(cell => [cell.id, cell])
|
|
189
191
|
);
|
|
190
192
|
layout = resolveFacetLayout({
|
|
193
|
+
spacing: option(args, "spacing", current.spacing),
|
|
194
|
+
plots: current.children.map(id => ({ id, ...resolveGraphicBounds(this.children[id]) })),
|
|
191
195
|
children: current.children.map((id, index) => ({
|
|
192
196
|
...childDescriptor({ id, program: this.children[id] }),
|
|
193
197
|
value: current.facet.values[index],
|
|
@@ -218,7 +222,7 @@ const editCompositionLayout = /* @__PURE__ */ closedAction(
|
|
|
218
222
|
children: this.children,
|
|
219
223
|
compositionSpec: {
|
|
220
224
|
...current,
|
|
221
|
-
...(current.type === "facet" ? { columns: layout.columns } : {}),
|
|
225
|
+
...(current.type === "facet" ? { columns: layout.columns, ...(layout.spacing !== undefined ? { spacing: layout.spacing } : current.spacing !== undefined ? { spacing: "canvas" } : {}) } : {}),
|
|
222
226
|
gap: layout.gap,
|
|
223
227
|
align: layout.align,
|
|
224
228
|
padding: layout.padding
|
package/src/actions/data/box.js
CHANGED
|
@@ -2,7 +2,7 @@ import { BOX_FIELDS, deriveBoxData, normalizeBoxTransform } from "../../grammar/
|
|
|
2
2
|
import { derivedCreator, derivedMaterializer } from "./shared.js";
|
|
3
3
|
|
|
4
4
|
const OPTIONS = Object.freeze([
|
|
5
|
-
"id", "source", "category", "field", "whisker", "factor", "as"
|
|
5
|
+
"id", "source", "category", "field", "whisker", "factor", "as", "summary"
|
|
6
6
|
]);
|
|
7
7
|
|
|
8
8
|
function materializer(type, op, select) {
|
|
@@ -28,6 +28,7 @@ function creator(type, op, materialize) {
|
|
|
28
28
|
type,
|
|
29
29
|
category: args.category,
|
|
30
30
|
field: args.field,
|
|
31
|
+
...(args.summary === undefined ? {} : { summary: args.summary }),
|
|
31
32
|
...(args.whisker === undefined ? {} : { whisker: args.whisker }),
|
|
32
33
|
...(args.factor === undefined ? {} : { factor: args.factor }),
|
|
33
34
|
as: args.as ?? BOX_FIELDS
|
package/src/actions/data/edit.js
CHANGED
|
@@ -509,7 +509,7 @@ export const editStackData = /* @__PURE__ */ focusedEditor(
|
|
|
509
509
|
);
|
|
510
510
|
export const editRegressionData = /* @__PURE__ */ focusedEditor(
|
|
511
511
|
"editRegressionData", "regression", [
|
|
512
|
-
"x", "y", "groupBy", "method", "degree", "span", "confidenceMethod",
|
|
512
|
+
"x", "y", "groupBy", "method", "degree", "span", "robustIterations", "confidenceMethod",
|
|
513
513
|
"level", "confidence", "interval", "predict"
|
|
514
514
|
]
|
|
515
515
|
);
|
|
@@ -9,7 +9,7 @@ import { resolveDatasetReference } from "../../selectors/datasets.js";
|
|
|
9
9
|
import { derivedMaterializer } from "./shared.js";
|
|
10
10
|
|
|
11
11
|
const OPTIONS = Object.freeze([
|
|
12
|
-
"id", "source", "x", "y", "groupBy", "method", "degree", "span",
|
|
12
|
+
"id", "source", "x", "y", "groupBy", "method", "degree", "span", "robustIterations",
|
|
13
13
|
"confidenceMethod", "level", "confidence", "interval"
|
|
14
14
|
, "predict", "missing"
|
|
15
15
|
]);
|
|
@@ -25,6 +25,7 @@ export const materializeRegressionData = /* @__PURE__ */ derivedMaterializer(
|
|
|
25
25
|
method: transform.method,
|
|
26
26
|
degree: transform.degree,
|
|
27
27
|
span: transform.span,
|
|
28
|
+
robustIterations: transform.robustIterations,
|
|
28
29
|
confidenceMethod: transform.confidenceMethod,
|
|
29
30
|
level: transform.level,
|
|
30
31
|
confidence: transform.confidence,
|
|
@@ -87,11 +87,12 @@ export function derivedCreator(
|
|
|
87
87
|
sourceLabel,
|
|
88
88
|
transform,
|
|
89
89
|
materialize,
|
|
90
|
-
requireSource = false
|
|
90
|
+
requireSource = false,
|
|
91
|
+
defaultId
|
|
91
92
|
) {
|
|
92
93
|
return action({ op, description }, function (args = {}) {
|
|
93
94
|
validateKeys(args, options, op);
|
|
94
|
-
const id = validateUserId(args.id, idLabel);
|
|
95
|
+
const id = validateUserId(args.id === undefined ? defaultId : args.id, idLabel);
|
|
95
96
|
const requestedSource = validateUserId(
|
|
96
97
|
requireSource ? args.source : args.source ?? this.context.currentData,
|
|
97
98
|
sourceLabel
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
+
import { canMaterializeBar } from "../../materialization/marks/index.js";
|
|
1
2
|
import { action } from "../../core/action.js";
|
|
2
3
|
import { validatePathSeriesAppearance } from "../../grammar/pathSeries.js";
|
|
3
4
|
import { assertEncodingSelectionCompatibility } from "../../materialization/selection/compatibility.js";
|
|
4
5
|
import {
|
|
5
|
-
readNominalField,
|
|
6
|
-
readQuantitativeField,
|
|
7
6
|
readScaleField,
|
|
8
7
|
validateOpacityValue
|
|
9
8
|
} from "../../grammar/scales/index.js";
|
|
@@ -42,11 +41,11 @@ function encodeAppearanceField(program, channel, args, operation) {
|
|
|
42
41
|
["point"],
|
|
43
42
|
"point mark"
|
|
44
43
|
);
|
|
45
|
-
const
|
|
44
|
+
const fieldTypes = channel === "shape" ? ["nominal"] : ["quantitative", "nominal", "ordinal"];
|
|
46
45
|
const dataset = applyRequestedItemMissingPolicy(layer, sourceDataset, args.field);
|
|
47
|
-
const fieldType = args.fieldType ??
|
|
48
|
-
if (fieldType
|
|
49
|
-
throw new Error(`${operation} requires a ${
|
|
46
|
+
const fieldType = args.fieldType ?? fieldTypes[0];
|
|
47
|
+
if (!fieldTypes.includes(fieldType)) {
|
|
48
|
+
throw new Error(`${operation} requires a ${fieldTypes.join(" or ")} field.`);
|
|
50
49
|
}
|
|
51
50
|
if (channel === "size" && program.markConfigs[target]?.radius !== undefined) {
|
|
52
51
|
throw new Error("encodeSize cannot be combined with a constant radius.");
|
|
@@ -59,17 +58,12 @@ function encodeAppearanceField(program, channel, args, operation) {
|
|
|
59
58
|
const scale = resolveAppearanceScaleDefinition(
|
|
60
59
|
program,
|
|
61
60
|
channel,
|
|
62
|
-
requestedScale
|
|
61
|
+
requestedScale,
|
|
62
|
+
fieldType
|
|
63
63
|
);
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
});
|
|
68
|
-
} else if (channel === "shape") {
|
|
69
|
-
readNominalField(dataset.values, args.field);
|
|
70
|
-
} else {
|
|
71
|
-
readQuantitativeField(dataset.values, args.field);
|
|
72
|
-
}
|
|
64
|
+
readScaleField(dataset.values, args.field, fieldType, {
|
|
65
|
+
allowUnknown: Object.hasOwn(scale, "unknown")
|
|
66
|
+
});
|
|
73
67
|
|
|
74
68
|
let next = setEncodingProperties(program, target, channel, {
|
|
75
69
|
field: args.field,
|
|
@@ -152,7 +146,7 @@ const removePointRadius = /* @__PURE__ */ action(
|
|
|
152
146
|
const encodeSize = /* @__PURE__ */ action(
|
|
153
147
|
{
|
|
154
148
|
op: "encodeSize",
|
|
155
|
-
description: "Encode a
|
|
149
|
+
description: "Encode a field as equal-area point size."
|
|
156
150
|
},
|
|
157
151
|
function (args = {}) {
|
|
158
152
|
return encodeAppearanceField(this, "size", args, "encodeSize");
|
|
@@ -184,6 +178,17 @@ const clearOpacityEncoding = /* @__PURE__ */ action(
|
|
|
184
178
|
}
|
|
185
179
|
);
|
|
186
180
|
|
|
181
|
+
function withoutConstantOpacity(program, target) {
|
|
182
|
+
const { opacity, ...config } = program.markConfigs[target] ?? {};
|
|
183
|
+
void opacity;
|
|
184
|
+
if (config.barAppearance?.opacity !== undefined) {
|
|
185
|
+
const { opacity: barOpacity, ...appearance } = config.barAppearance;
|
|
186
|
+
void barOpacity;
|
|
187
|
+
config.barAppearance = appearance;
|
|
188
|
+
}
|
|
189
|
+
return program._withMarkConfig(target, config);
|
|
190
|
+
}
|
|
191
|
+
|
|
187
192
|
const encodeOpacity = /* @__PURE__ */ action(
|
|
188
193
|
{
|
|
189
194
|
op: "encodeOpacity",
|
|
@@ -202,14 +207,13 @@ const encodeOpacity = /* @__PURE__ */ action(
|
|
|
202
207
|
const { id: target, dataset: sourceDataset, layer } = resolveTarget(
|
|
203
208
|
this,
|
|
204
209
|
args.target,
|
|
205
|
-
["point", "rule", "line"],
|
|
206
|
-
"point, rule or
|
|
210
|
+
["point", "rule", "line", "bar"],
|
|
211
|
+
"point, rule, line or bar mark"
|
|
207
212
|
);
|
|
208
213
|
if (hasValue) {
|
|
209
214
|
validateOpacityValue(args.value, "encodeOpacity");
|
|
210
215
|
assertEncodingSelectionCompatibility(this, target, ["opacity"]);
|
|
211
|
-
const
|
|
212
|
-
void opacity;
|
|
216
|
+
const config = withoutConstantOpacity(this, target).markConfigs[target];
|
|
213
217
|
const withoutLegend = this.guideConfigs.legend?.opacity?.target === target
|
|
214
218
|
? this.removeOpacityLegend()
|
|
215
219
|
: this;
|
|
@@ -220,6 +224,11 @@ const encodeOpacity = /* @__PURE__ */ action(
|
|
|
220
224
|
if (layer.mark.type === "line") {
|
|
221
225
|
return rematerializeEncoding(next, target, "opacity", undefined, layer);
|
|
222
226
|
}
|
|
227
|
+
if (layer.mark.type === "bar") {
|
|
228
|
+
return canMaterializeBar(next, findLayer(next, target))
|
|
229
|
+
? applyDetachedScaleRematerialization(next.rematerializeBarMark({ id: target }), [layer])
|
|
230
|
+
: next;
|
|
231
|
+
}
|
|
223
232
|
const materialized = layer.mark.type === "rule"
|
|
224
233
|
? next.rematerializeRuleMark({ id: target })
|
|
225
234
|
: next.rematerializePointMark({ id: target });
|
|
@@ -244,17 +253,13 @@ const encodeOpacity = /* @__PURE__ */ action(
|
|
|
244
253
|
...layer, encoding: { ...layer.encoding, opacity: { field: args.field, fieldType } }
|
|
245
254
|
});
|
|
246
255
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
});
|
|
251
|
-
} else {
|
|
252
|
-
readQuantitativeField(dataset.values, args.field);
|
|
253
|
-
}
|
|
256
|
+
readScaleField(dataset.values, args.field, fieldType, {
|
|
257
|
+
allowUnknown: Object.hasOwn(scale, "unknown")
|
|
258
|
+
});
|
|
254
259
|
const { opacity, ...config } = this.markConfigs[target] ?? {};
|
|
255
260
|
void opacity;
|
|
256
261
|
let next = setEncodingProperties(
|
|
257
|
-
this
|
|
262
|
+
withoutConstantOpacity(this, target),
|
|
258
263
|
target,
|
|
259
264
|
"opacity",
|
|
260
265
|
{ field: args.field, fieldType, scale: scale.id }
|
|
@@ -262,6 +267,9 @@ const encodeOpacity = /* @__PURE__ */ action(
|
|
|
262
267
|
next = applyEncodingScale(next, scale, requestedScale, {
|
|
263
268
|
reassignment: previous?.scale === scale.id
|
|
264
269
|
});
|
|
270
|
+
if (layer.mark.type === "bar" && !canMaterializeBar(next, findLayer(next, target))) {
|
|
271
|
+
return next.rematerializeScale({ id: scale.id });
|
|
272
|
+
}
|
|
265
273
|
return rematerializeEncoding(next, target, "opacity", scale.id, layer);
|
|
266
274
|
}
|
|
267
275
|
);
|
|
@@ -4,11 +4,33 @@ import {
|
|
|
4
4
|
BAR_GRAINS,
|
|
5
5
|
resolveBarColorLayout,
|
|
6
6
|
resolveBarOffsetChannel,
|
|
7
|
+
resolveBarChannels,
|
|
7
8
|
resolveBarGrain
|
|
8
9
|
} from "../../grammar/bars/policy.js";
|
|
9
10
|
import { normalizeBarWidth } from "../../grammar/bars/geometry.js";
|
|
11
|
+
import { applyMaterializationPlan } from "../../materialization/dependencies.js";
|
|
12
|
+
import {
|
|
13
|
+
getScaleConsumerMarkSteps,
|
|
14
|
+
getSourceDependentMarkSteps
|
|
15
|
+
} from "../../materialization/marks/index.js";
|
|
16
|
+
|
|
17
|
+
function rematerializeWidth(program, target, layer, width) {
|
|
18
|
+
const next = program._withMarkConfig(target, {
|
|
19
|
+
...program.markConfigs[target], barWidth: width
|
|
20
|
+
}).rematerializeBarMark({ id: target });
|
|
21
|
+
const category = resolveBarChannels(layer)?.category;
|
|
22
|
+
const encoding = layer.encoding?.[category];
|
|
23
|
+
if (encoding?.fieldType !== "temporal") return next;
|
|
24
|
+
const marks = getScaleConsumerMarkSteps(next, [encoding.scale])
|
|
25
|
+
.filter(step => step.args.id !== target);
|
|
26
|
+
return applyMaterializationPlan(next, [
|
|
27
|
+
...marks,
|
|
28
|
+
...[target, ...marks.map(step => step.args.id)]
|
|
29
|
+
.flatMap(id => getSourceDependentMarkSteps(next, id))
|
|
30
|
+
]);
|
|
31
|
+
}
|
|
10
32
|
|
|
11
|
-
const OPTIONS = Object.freeze(["band", "pixels", "target"]);
|
|
33
|
+
const OPTIONS = Object.freeze(["band", "pixels", "interval", "target"]);
|
|
12
34
|
|
|
13
35
|
const encodeBarWidth = /* @__PURE__ */ action(
|
|
14
36
|
{
|
|
@@ -26,22 +48,30 @@ const encodeBarWidth = /* @__PURE__ */ action(
|
|
|
26
48
|
const layout = resolveBarColorLayout(layer);
|
|
27
49
|
const width = normalizeBarWidth(
|
|
28
50
|
args,
|
|
29
|
-
this.markConfigs[target]?.barWidth
|
|
51
|
+
this.markConfigs[target]?.barWidth ?? (layer.mark.orientation === undefined ? undefined : { pixels: 5 })
|
|
30
52
|
);
|
|
31
53
|
const grouped = layout === "group";
|
|
32
54
|
const offsetChannel = resolveBarOffsetChannel(layer);
|
|
33
55
|
const grain = resolveBarGrain(layer);
|
|
56
|
+
if (layer.mark.orientation !== undefined && width.band !== undefined) {
|
|
57
|
+
throw new Error("Numeric-center bars require pixel width.");
|
|
58
|
+
}
|
|
34
59
|
if (grain === undefined && this.markConfigs[target]?.boxPlot === undefined && (
|
|
35
60
|
layer.encoding?.x === undefined || layer.encoding?.y === undefined
|
|
36
61
|
)) {
|
|
37
62
|
return this._withMarkConfig(target, { ...this.markConfigs[target], barWidth: width });
|
|
38
63
|
}
|
|
64
|
+
if (width.interval !== undefined && grain !== undefined) {
|
|
65
|
+
const category = resolveBarChannels(layer)?.category;
|
|
66
|
+
if (grain !== BAR_GRAINS.aggregate || grouped || layer.encoding?.[category]?.fieldType !== "temporal") {
|
|
67
|
+
throw new Error("Bar interval width requires ungrouped aggregate temporal categories.");
|
|
68
|
+
}
|
|
69
|
+
}
|
|
39
70
|
if (grain === BAR_GRAINS.histogram) {
|
|
40
71
|
throw new Error("encodeBarWidth requires an aggregate or ranged category slot, not histogram bins.");
|
|
41
72
|
}
|
|
42
|
-
if (
|
|
43
|
-
return this
|
|
44
|
-
.rematerializeBarMark({ id: target });
|
|
73
|
+
if ([BAR_GRAINS.ranged, BAR_GRAINS.centered].includes(grain)) {
|
|
74
|
+
return rematerializeWidth(this, target, layer, width);
|
|
45
75
|
}
|
|
46
76
|
if (
|
|
47
77
|
grain !== BAR_GRAINS.aggregate ||
|
|
@@ -56,12 +86,7 @@ const encodeBarWidth = /* @__PURE__ */ action(
|
|
|
56
86
|
);
|
|
57
87
|
}
|
|
58
88
|
|
|
59
|
-
return this
|
|
60
|
-
._withMarkConfig(target, {
|
|
61
|
-
...this.markConfigs[target],
|
|
62
|
-
barWidth: width
|
|
63
|
-
})
|
|
64
|
-
.rematerializeBarMark({ id: target });
|
|
89
|
+
return rematerializeWidth(this, target, layer, width);
|
|
65
90
|
}
|
|
66
91
|
);
|
|
67
92
|
|
|
@@ -39,7 +39,7 @@ export function encodeContinuousColor(program, args) {
|
|
|
39
39
|
const { id: target, dataset: sourceDataset, layer } = resolveTarget(
|
|
40
40
|
program,
|
|
41
41
|
args.target,
|
|
42
|
-
["point", "bar", "rect"],
|
|
42
|
+
["point", "bar", "rect", "text"],
|
|
43
43
|
"continuous color mark"
|
|
44
44
|
);
|
|
45
45
|
const dataset = applyRequestedItemMissingPolicy(layer, sourceDataset, args.field);
|
|
@@ -63,7 +63,7 @@ const encodeColor = /* @__PURE__ */ action(
|
|
|
63
63
|
const { id: target, dataset: sourceDataset, layer } = resolveTarget(
|
|
64
64
|
this,
|
|
65
65
|
args.target,
|
|
66
|
-
["point", "line", "bar", "area", "arc", "rect"],
|
|
66
|
+
["point", "line", "bar", "area", "arc", "rect", "text"],
|
|
67
67
|
"color mark"
|
|
68
68
|
);
|
|
69
69
|
const dataset = applyRequestedItemMissingPolicy(layer, sourceDataset, args.field);
|
|
@@ -20,6 +20,9 @@ export function resolveColorScaleOptions(args) {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export function assertNoConstantColor(program, layer) {
|
|
23
|
+
if (layer.mark.type === "text" && layer.source !== undefined) {
|
|
24
|
+
throw new Error("Source-owned text uses inheritColor or constant fill; field color requires row-backed text.");
|
|
25
|
+
}
|
|
23
26
|
const config = program.markConfigs[layer.id];
|
|
24
27
|
const hasConstant = {
|
|
25
28
|
point: config?.fill !== undefined,
|
|
@@ -27,7 +30,8 @@ export function assertNoConstantColor(program, layer) {
|
|
|
27
30
|
area: config?.errorBand?.fill !== undefined,
|
|
28
31
|
bar: config?.barAppearance?.fill !== undefined,
|
|
29
32
|
arc: config?.fill !== undefined,
|
|
30
|
-
rect: config?.fillExplicit === true
|
|
33
|
+
rect: config?.fillExplicit === true,
|
|
34
|
+
text: config?.fillExplicit === true
|
|
31
35
|
}[layer.mark.type] ?? false;
|
|
32
36
|
if (hasConstant) {
|
|
33
37
|
throw new Error(
|
|
@@ -58,15 +62,18 @@ export function resolveColorLayout(layer, requested, barGrain) {
|
|
|
58
62
|
layer.mark.type === "bar"
|
|
59
63
|
? barGrain === BAR_GRAINS.histogram
|
|
60
64
|
? "stack"
|
|
61
|
-
:
|
|
65
|
+
: [BAR_GRAINS.ranged, BAR_GRAINS.centered].includes(barGrain) ? "overlay" : "group"
|
|
62
66
|
: layer.mark.type === "area"
|
|
63
67
|
? "overlay"
|
|
64
68
|
: undefined
|
|
65
69
|
);
|
|
66
70
|
|
|
67
|
-
if (["point", "line", "rect"].includes(layer.mark.type) && layout !== undefined) {
|
|
71
|
+
if (["point", "line", "rect", "text"].includes(layer.mark.type) && layout !== undefined) {
|
|
68
72
|
throw new Error(`Color layout is not supported for ${layer.mark.type} marks.`);
|
|
69
73
|
}
|
|
74
|
+
if (barGrain === BAR_GRAINS.centered && layout !== "overlay") {
|
|
75
|
+
throw new Error("Numeric-center bars support only overlay layout.");
|
|
76
|
+
}
|
|
70
77
|
if (layer.mark.type === "area" && layout === "group") {
|
|
71
78
|
throw new Error('Area color layout does not support "group".');
|
|
72
79
|
}
|