ggaction 0.0.3 → 0.0.5
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 +58 -3
- package/README.md +117 -83
- package/package.json +27 -11
- package/src/actions/boxPlots/create.js +13 -7
- package/src/actions/boxPlots/edit.js +31 -35
- package/src/actions/boxPlots/materialize.js +3 -0
- package/src/actions/boxPlots/options.js +8 -1
- package/src/actions/boxPlots/resolve.js +10 -2
- package/src/actions/charts/bar.js +50 -0
- package/src/actions/charts/heatmap.js +205 -0
- package/src/actions/charts/histogram.js +58 -0
- package/src/actions/charts/index.js +15 -0
- package/src/actions/charts/line.js +69 -0
- package/src/actions/charts/parallel.js +76 -0
- package/src/actions/charts/scatter.js +56 -0
- package/src/actions/charts/shared.js +121 -0
- package/src/actions/coordinates/parallel.js +50 -0
- package/src/actions/data/bin2d.js +137 -0
- package/src/actions/data/density.js +54 -13
- package/src/actions/data/derived.js +22 -0
- package/src/actions/data/filter.js +5 -0
- package/src/actions/data/gradientProfile.js +65 -0
- package/src/actions/data/horizon.js +71 -0
- package/src/actions/data/index.js +29 -2
- package/src/actions/data/regression.js +1 -1
- package/src/actions/data/window.js +50 -0
- package/src/actions/encodings/appearance.js +1 -1
- package/src/actions/encodings/color/continuous.js +137 -0
- package/src/actions/encodings/color/index.js +167 -0
- package/src/actions/encodings/color/layout.js +99 -0
- package/src/actions/encodings/color/policy.js +88 -0
- package/src/actions/encodings/density/resolve.js +109 -0
- package/src/actions/encodings/density.js +193 -88
- package/src/actions/encodings/horizon/resolve.js +283 -0
- package/src/actions/encodings/horizon.js +364 -0
- package/src/actions/encodings/index.js +8 -2
- package/src/actions/encodings/offset.js +1 -1
- package/src/actions/encodings/parallel.js +115 -0
- package/src/actions/encodings/pathOrder.js +131 -0
- package/src/actions/encodings/position/apply.js +73 -4
- package/src/actions/encodings/{position.js → position/index.js} +21 -8
- package/src/actions/encodings/position/policies/arc.js +27 -4
- package/src/actions/encodings/position/policies/area.js +33 -2
- package/src/actions/encodings/position/policies/index.js +7 -2
- package/src/actions/encodings/position/policies/line.js +18 -2
- package/src/actions/encodings/position/resolve.js +25 -3
- package/src/actions/encodings/ranged.js +5 -3
- package/src/actions/encodings/ruleAppearance.js +88 -10
- package/src/actions/encodings/strokeDash.js +1 -1
- package/src/actions/encodings/text.js +1 -1
- package/src/actions/errorBands/options.js +1 -1
- package/src/actions/errorBars/options.js +1 -1
- package/src/actions/facets/actions.js +2 -3
- package/src/actions/facets/derive.js +35 -5
- package/src/actions/facets/guides.js +1 -1
- package/src/actions/facets/replay.js +7 -36
- package/src/actions/gradientPlots/components.js +177 -0
- package/src/actions/gradientPlots/create.js +96 -0
- package/src/actions/gradientPlots/edit.js +153 -0
- package/src/actions/gradientPlots/index.js +24 -0
- package/src/actions/gradientPlots/materialize.js +287 -0
- package/src/actions/gradientPlots/options.js +120 -0
- package/src/actions/gradientPlots/paint.js +107 -0
- package/src/actions/gradientPlots/rebind.js +51 -0
- package/src/actions/gradientPlots/resolve.js +81 -0
- package/src/actions/guides/applicability.js +44 -17
- package/src/actions/guides/axes/axes.js +37 -3
- package/src/actions/guides/axes/index.js +2 -0
- package/src/actions/guides/axes/labels.js +12 -7
- package/src/actions/guides/axes/parallel/resolve.js +86 -0
- package/src/actions/guides/axes/parallel.js +228 -0
- package/src/actions/guides/axes/ticks.js +1 -1
- package/src/actions/guides/axes/titles.js +12 -9
- package/src/actions/guides/grids/resolve.js +1 -1
- package/src/actions/guides/guides.js +60 -5
- package/src/actions/guides/legends/categorical/actions.js +48 -11
- package/src/actions/guides/legends/categorical/layout.js +4 -2
- package/src/actions/guides/legends/continuous/interval.js +1 -1
- package/src/actions/guides/legends/continuous/opacity.js +1 -1
- package/src/actions/guides/legends/edit.js +7 -20
- package/src/actions/guides/legends/index.js +2 -0
- package/src/actions/guides/legends/remove.js +6 -31
- package/src/actions/guides/legends/size.js +1 -1
- package/src/actions/guides/legends/strokeWidth.js +170 -0
- package/src/actions/guides/legends/target.js +25 -0
- package/src/actions/guides/polar/{axes.js → axes/index.js} +5 -5
- package/src/actions/guides/polar/index.js +1 -1
- package/src/actions/guides/polar/resolve.js +1 -1
- package/src/actions/guides/tickValues.js +1 -1
- package/src/actions/index.js +6 -0
- package/src/actions/intervals/resolve.js +1 -1
- package/src/actions/marks/arc/actions.js +2 -2
- package/src/actions/marks/area/actions.js +61 -137
- package/src/actions/marks/area/materialize.js +163 -0
- package/src/actions/marks/bar/edit.js +1 -1
- package/src/actions/marks/index.js +5 -1
- package/src/actions/marks/line/actions.js +100 -81
- package/src/actions/marks/line/materialize.js +146 -0
- package/src/actions/marks/point/create.js +76 -0
- package/src/actions/marks/point/edit.js +85 -0
- package/src/actions/marks/point/index.js +11 -1
- package/src/actions/marks/point/jitter.js +72 -0
- package/src/actions/marks/point/{actions.js → materialize.js} +175 -170
- package/src/actions/marks/rect/actions.js +4 -1
- package/src/actions/marks/remove.js +13 -2
- package/src/actions/marks/rule/actions.js +26 -4
- package/src/actions/marks/shared.js +1 -1
- package/src/actions/marks/text/actions.js +20 -5
- package/src/actions/marks/text/index.js +7 -1
- package/src/actions/marks/text/layout.js +321 -0
- package/src/actions/primitives/semanticValidation/dataset.js +22 -0
- package/src/actions/primitives/semanticValidation/guide.js +43 -0
- package/src/actions/primitives/semanticValidation/index.js +23 -0
- package/src/actions/primitives/semanticValidation/layer.js +74 -0
- package/src/actions/primitives/semanticValidation/scale.js +74 -0
- package/src/actions/primitives/semanticValidation/shared.js +5 -0
- package/src/actions/primitives/semanticValue.js +1 -204
- package/src/actions/regression/components.js +1 -1
- package/src/actions/regression/create.js +1 -1
- package/src/actions/regression/edit.js +20 -22
- package/src/actions/scales/consumers/common.js +109 -0
- package/src/actions/scales/consumers/families.js +58 -0
- package/src/actions/scales/consumers/index.js +41 -0
- package/src/actions/scales/{consumers.js → consumers/seriesLayout.js} +10 -132
- package/src/actions/scales/create.js +1 -1
- package/src/actions/scales/definitions.js +32 -2
- package/src/actions/scales/edit.js +8 -206
- package/src/actions/scales/editPolicy.js +214 -0
- package/src/actions/scales/materialize.js +3 -3
- package/src/actions/scales/patch.js +26 -0
- package/src/actions/selection/actions.js +28 -3
- package/src/actions/violinPlots/create.js +198 -0
- package/src/actions/violinPlots/index.js +5 -0
- package/src/core/ChartProgram.js +22 -236
- package/src/core/compositionState.js +169 -0
- package/src/core/materializationState.js +65 -0
- package/src/core/programState.js +28 -0
- package/src/core/textMetrics.js +47 -0
- package/src/core/vocabulary.js +7 -2
- package/src/grammar/arcs.js +50 -13
- package/src/grammar/areaSeries.js +42 -6
- package/src/grammar/bars/aggregate.js +1 -1
- package/src/grammar/bin2d.js +333 -0
- package/src/grammar/categoricalDensity.js +192 -0
- package/src/grammar/coordinates.js +1 -1
- package/src/grammar/curveCommands.js +3 -1
- package/src/grammar/density.js +253 -27
- package/src/grammar/facets/dependencies.js +3 -11
- package/src/grammar/{facets.js → facets/index.js} +8 -6
- package/src/grammar/gradientProfile.js +213 -0
- package/src/grammar/horizon.js +455 -0
- package/src/grammar/interval.js +2 -96
- package/src/grammar/jitter.js +197 -0
- package/src/grammar/lineSeries.js +70 -1
- package/src/grammar/paint.js +88 -0
- package/src/grammar/palettes.js +5 -7
- package/src/grammar/parallelCoordinates.js +213 -0
- package/src/grammar/pathOrder.js +35 -0
- package/src/grammar/pointShapes.js +24 -0
- package/src/grammar/polarLineCommands.js +1 -1
- package/src/grammar/regression/derive.js +97 -0
- package/src/grammar/regression/index.js +22 -0
- package/src/grammar/regression/models.js +282 -0
- package/src/grammar/regression/parameters.js +106 -0
- package/src/grammar/rules.js +2 -1
- package/src/grammar/scales/appearance.js +21 -0
- package/src/grammar/scales/color.js +4 -2
- package/src/grammar/schemas/concreteGraphic.js +11 -1
- package/src/grammar/schemas/graphicBounds.js +19 -37
- package/src/grammar/schemas/semanticPath.js +17 -2
- package/src/grammar/statistics/studentT.js +98 -0
- package/src/grammar/transforms.js +101 -12
- package/src/grammar/window.js +339 -0
- package/src/layout/labels.js +270 -0
- package/src/layout/text.js +4 -1
- package/src/layout/title.js +10 -20
- package/src/materialization/bars/aggregate.js +1 -1
- package/src/materialization/bars/grouped.js +1 -1
- package/src/materialization/bars/histogram.js +1 -1
- package/src/materialization/bars/ranged.js +1 -1
- package/src/materialization/dataProvenance.js +56 -2
- package/src/materialization/density.js +1 -1
- package/src/materialization/dependencies.js +15 -101
- package/src/materialization/encodings.js +2 -2
- package/src/materialization/facetGuides/index.js +2 -0
- package/src/materialization/facetGuides/legacyCategorical.js +125 -0
- package/src/materialization/facetGuides/placement.js +126 -0
- package/src/materialization/facetGuides/preparation.js +188 -0
- package/src/materialization/facets.js +1 -1
- package/src/materialization/guides/resources.js +74 -24
- package/src/materialization/horizon.js +29 -0
- package/src/materialization/layout.js +15 -0
- package/src/materialization/marks/capabilities.js +161 -0
- package/src/materialization/marks/index.js +108 -0
- package/src/materialization/marks/pathOrder.js +71 -0
- package/src/materialization/marks/policies.js +91 -0
- package/src/materialization/rect.js +1 -1
- package/src/materialization/rowEncoding.js +1 -1
- package/src/materialization/scaleGuideDependencies.js +102 -0
- package/src/materialization/scales/map.js +1 -1
- package/src/materialization/scales/policies/series.js +1 -1
- package/src/materialization/scales/resolve.js +3 -1
- package/src/materialization/selection/items/bar.js +1 -1
- package/src/materialization/selection/items/path.js +27 -1
- package/src/materialization/selection/items/point.js +1 -5
- package/src/materialization/selection/items/rect.js +21 -0
- package/src/materialization/selection/styles.js +21 -10
- package/src/materialization/text.js +12 -4
- package/src/renderers/canvas/fill.js +33 -0
- package/src/renderers/canvas/index.js +7 -0
- package/src/renderers/canvas/path.js +7 -4
- package/src/renderers/canvas/rect.js +9 -3
- package/src/renderers/canvas/text.js +14 -1
- package/src/selectors/datasets.js +4 -0
- package/src/theme/defaults.js +4 -0
- package/types/extension.d.ts +10 -1
- package/types/index.d.ts +76 -0
- package/types/program.d.ts +632 -10
- package/src/actions/encodings/color.js +0 -424
- package/src/grammar/regression.js +0 -578
- package/src/grammar/scales.js +0 -1
- package/src/materialization/facetGuides.js +0 -426
- package/src/materialization/marks.js +0 -316
|
@@ -9,6 +9,44 @@ function replaceAlternateBinding(program, target, channel, previous, usesField)
|
|
|
9
9
|
: program;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
function reconcileInheritedRulePosition(program, {
|
|
13
|
+
target,
|
|
14
|
+
channel,
|
|
15
|
+
layer,
|
|
16
|
+
hasField
|
|
17
|
+
}) {
|
|
18
|
+
const config = program.markConfigs[target] ?? {};
|
|
19
|
+
const inherited = config.inheritedPosition;
|
|
20
|
+
if (layer.mark.type !== "rule" || inherited === undefined) return program;
|
|
21
|
+
|
|
22
|
+
let channels = inherited.channels.filter(candidate => candidate !== channel);
|
|
23
|
+
let next = program;
|
|
24
|
+
if (
|
|
25
|
+
!hasField &&
|
|
26
|
+
["x", "y"].includes(channel) &&
|
|
27
|
+
layer.encoding?.x2 === undefined &&
|
|
28
|
+
layer.encoding?.y2 === undefined
|
|
29
|
+
) {
|
|
30
|
+
const opposite = channel === "x" ? "y" : "x";
|
|
31
|
+
if (channels.includes(opposite) && layer.encoding?.[opposite] !== undefined) {
|
|
32
|
+
next = next.editSemantic({
|
|
33
|
+
property: `layer[${target}].encoding.${opposite}`,
|
|
34
|
+
remove: true
|
|
35
|
+
});
|
|
36
|
+
channels = channels.filter(candidate => candidate !== opposite);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const { inheritedPosition, ...rest } = config;
|
|
41
|
+
void inheritedPosition;
|
|
42
|
+
return next._withMarkConfig(target, channels.length === 0
|
|
43
|
+
? rest
|
|
44
|
+
: {
|
|
45
|
+
...rest,
|
|
46
|
+
inheritedPosition: { ...inherited, channels }
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
12
50
|
function applyBin(program, target, channel, previous, bin) {
|
|
13
51
|
if (bin === undefined) return program;
|
|
14
52
|
const [mode] = Object.keys(bin);
|
|
@@ -26,9 +64,26 @@ function applyBin(program, target, channel, previous, bin) {
|
|
|
26
64
|
});
|
|
27
65
|
}
|
|
28
66
|
|
|
67
|
+
function applyArcThetaWeight(program, target, channel, previous, aggregate, weight) {
|
|
68
|
+
if (channel !== "theta") return program;
|
|
69
|
+
if (aggregate !== "sum") {
|
|
70
|
+
return previous?.weight === undefined
|
|
71
|
+
? program
|
|
72
|
+
: program.editSemantic({
|
|
73
|
+
property: `layer[${target}].encoding.theta.weight`,
|
|
74
|
+
remove: true
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
return program.editSemantic({
|
|
78
|
+
property: `layer[${target}].encoding.theta.weight`,
|
|
79
|
+
value: weight
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
29
83
|
export function applyPositionSemantics(program, {
|
|
30
84
|
target,
|
|
31
85
|
channel,
|
|
86
|
+
layer,
|
|
32
87
|
previous,
|
|
33
88
|
field,
|
|
34
89
|
datum,
|
|
@@ -36,10 +91,17 @@ export function applyPositionSemantics(program, {
|
|
|
36
91
|
fieldType,
|
|
37
92
|
bin,
|
|
38
93
|
aggregate,
|
|
39
|
-
stack
|
|
94
|
+
stack,
|
|
95
|
+
weight
|
|
40
96
|
}) {
|
|
41
|
-
let next =
|
|
42
|
-
|
|
97
|
+
let next = reconcileInheritedRulePosition(program, {
|
|
98
|
+
target,
|
|
99
|
+
channel,
|
|
100
|
+
layer,
|
|
101
|
+
hasField
|
|
102
|
+
});
|
|
103
|
+
next = replaceAlternateBinding(
|
|
104
|
+
next,
|
|
43
105
|
target,
|
|
44
106
|
channel,
|
|
45
107
|
previous,
|
|
@@ -62,5 +124,12 @@ export function applyPositionSemantics(program, {
|
|
|
62
124
|
value
|
|
63
125
|
});
|
|
64
126
|
}
|
|
65
|
-
return
|
|
127
|
+
return applyArcThetaWeight(
|
|
128
|
+
next,
|
|
129
|
+
target,
|
|
130
|
+
channel,
|
|
131
|
+
previous,
|
|
132
|
+
aggregate,
|
|
133
|
+
weight
|
|
134
|
+
);
|
|
66
135
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { action } from "
|
|
1
|
+
import { action } from "../../../core/action.js";
|
|
2
2
|
import {
|
|
3
3
|
getPositionEncodingMaterializationSteps
|
|
4
|
-
} from "
|
|
5
|
-
import { resolvePositionEncoding } from "./
|
|
6
|
-
import { findLayer } from "
|
|
7
|
-
import { applyPositionSemantics } from "./
|
|
4
|
+
} from "../../../materialization/marks/index.js";
|
|
5
|
+
import { resolvePositionEncoding } from "./resolve.js";
|
|
6
|
+
import { findLayer } from "../../../selectors/layers.js";
|
|
7
|
+
import { applyPositionSemantics } from "./apply.js";
|
|
8
8
|
import {
|
|
9
9
|
applyEncodingScale,
|
|
10
10
|
rebindPositionGuides
|
|
11
|
-
} from "
|
|
11
|
+
} from "../shared.js";
|
|
12
12
|
|
|
13
13
|
function encodePosition(program, channel, args, operation) {
|
|
14
14
|
const {
|
|
@@ -24,7 +24,8 @@ function encodePosition(program, channel, args, operation) {
|
|
|
24
24
|
coordinate,
|
|
25
25
|
bin,
|
|
26
26
|
aggregate,
|
|
27
|
-
stack
|
|
27
|
+
stack,
|
|
28
|
+
weight
|
|
28
29
|
} = resolvePositionEncoding(program, channel, args, operation);
|
|
29
30
|
|
|
30
31
|
let next = program
|
|
@@ -36,6 +37,7 @@ function encodePosition(program, channel, args, operation) {
|
|
|
36
37
|
next = applyPositionSemantics(next, {
|
|
37
38
|
target,
|
|
38
39
|
channel,
|
|
40
|
+
layer,
|
|
39
41
|
previous,
|
|
40
42
|
field,
|
|
41
43
|
datum,
|
|
@@ -43,7 +45,8 @@ function encodePosition(program, channel, args, operation) {
|
|
|
43
45
|
fieldType,
|
|
44
46
|
bin,
|
|
45
47
|
aggregate,
|
|
46
|
-
stack
|
|
48
|
+
stack,
|
|
49
|
+
weight
|
|
47
50
|
});
|
|
48
51
|
|
|
49
52
|
next = next.editSemantic({
|
|
@@ -71,6 +74,16 @@ function encodePosition(program, channel, args, operation) {
|
|
|
71
74
|
}
|
|
72
75
|
}
|
|
73
76
|
|
|
77
|
+
if (layer.mark.type === "rect") {
|
|
78
|
+
const updated = findLayer(next, target);
|
|
79
|
+
const pendingGradient = next.markConfigs[target]?.gradientPlot;
|
|
80
|
+
if (pendingGradient !== undefined && !pendingGradient.materialized) {
|
|
81
|
+
return updated.encoding?.x !== undefined && updated.encoding?.y !== undefined
|
|
82
|
+
? next.materializeGradientPlot({ id: target })
|
|
83
|
+
: next;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
74
87
|
const updated = findLayer(next, target);
|
|
75
88
|
for (const step of getPositionEncodingMaterializationSteps(
|
|
76
89
|
next,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { validateAggregate } from "../../../../grammar/aggregate.js";
|
|
2
|
+
import { validateNonEmptyString } from "../../../../core/validation.js";
|
|
2
3
|
import { emptyPositionPolicy } from "./common.js";
|
|
3
4
|
|
|
4
5
|
export function resolveArcPositionPolicy({ channel, args, fieldType }) {
|
|
@@ -12,15 +13,37 @@ export function resolveArcPositionPolicy({ channel, args, fieldType }) {
|
|
|
12
13
|
if (args.aggregate !== undefined) {
|
|
13
14
|
throw new Error("Arc radius encoding does not support aggregate.");
|
|
14
15
|
}
|
|
16
|
+
if (args.weight !== undefined) {
|
|
17
|
+
throw new Error("Arc radius encoding does not support weight.");
|
|
18
|
+
}
|
|
15
19
|
return emptyPositionPolicy();
|
|
16
20
|
}
|
|
17
21
|
if (!["ordinal", "nominal"].includes(fieldType)) {
|
|
18
22
|
throw new Error("Arc theta encoding requires an ordinal or nominal field.");
|
|
19
23
|
}
|
|
20
|
-
if (args.aggregate === undefined)
|
|
24
|
+
if (args.aggregate === undefined) {
|
|
25
|
+
if (args.weight !== undefined) {
|
|
26
|
+
throw new Error('Arc theta weight requires aggregate: "sum".');
|
|
27
|
+
}
|
|
28
|
+
return emptyPositionPolicy();
|
|
29
|
+
}
|
|
21
30
|
const aggregate = validateAggregate(args.aggregate);
|
|
22
|
-
if (
|
|
23
|
-
throw new Error('Arc theta aggregate
|
|
31
|
+
if (!["count", "sum"].includes(aggregate)) {
|
|
32
|
+
throw new Error('Arc theta aggregate supports only "count" or "sum".');
|
|
33
|
+
}
|
|
34
|
+
if (aggregate === "count") {
|
|
35
|
+
if (args.weight !== undefined) {
|
|
36
|
+
throw new Error('Arc theta weight requires aggregate: "sum".');
|
|
37
|
+
}
|
|
38
|
+
return { bin: undefined, aggregate, stack: undefined, weight: undefined };
|
|
39
|
+
}
|
|
40
|
+
if (args.weight === undefined) {
|
|
41
|
+
throw new Error('Arc theta aggregate "sum" requires weight.');
|
|
24
42
|
}
|
|
25
|
-
return {
|
|
43
|
+
return {
|
|
44
|
+
bin: undefined,
|
|
45
|
+
aggregate,
|
|
46
|
+
stack: undefined,
|
|
47
|
+
weight: validateNonEmptyString(args.weight, "Arc theta weight")
|
|
48
|
+
};
|
|
26
49
|
}
|
|
@@ -1,6 +1,37 @@
|
|
|
1
1
|
import { validateStack, emptyPositionPolicy } from "./common.js";
|
|
2
2
|
|
|
3
|
-
export function
|
|
3
|
+
export function isCategoricalDensityPosition({
|
|
4
|
+
layer,
|
|
5
|
+
dataset,
|
|
6
|
+
channel,
|
|
7
|
+
fieldType,
|
|
8
|
+
field
|
|
9
|
+
}) {
|
|
10
|
+
const density = dataset.transform?.find(transform => transform.type === "density");
|
|
11
|
+
return layer.mark?.type === "area" &&
|
|
12
|
+
["nominal", "ordinal"].includes(fieldType) &&
|
|
13
|
+
density?.placement?.type === "category" &&
|
|
14
|
+
density.placement.channel === channel &&
|
|
15
|
+
density.placement.categoryField === field;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function resolveAreaPositionPolicy({ dataset, channel, args, fieldType, field }) {
|
|
19
|
+
const density = dataset.transform?.find(transform => transform.type === "density");
|
|
20
|
+
if (["nominal", "ordinal"].includes(fieldType)) {
|
|
21
|
+
if (
|
|
22
|
+
density?.placement?.type !== "category" ||
|
|
23
|
+
density.placement.channel !== channel ||
|
|
24
|
+
density.placement.categoryField !== field
|
|
25
|
+
) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
"Categorical area position requires a matching category density placement."
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
if (args.aggregate !== undefined || args.bin !== undefined || args.stack !== undefined) {
|
|
31
|
+
throw new Error("Categorical density position does not support aggregate, bin, or stack.");
|
|
32
|
+
}
|
|
33
|
+
return emptyPositionPolicy();
|
|
34
|
+
}
|
|
4
35
|
if (!["quantitative", "temporal"].includes(fieldType)) {
|
|
5
36
|
throw new Error(
|
|
6
37
|
"Area position encoding requires quantitative or temporal fields."
|
|
@@ -12,7 +43,7 @@ export function resolveAreaPositionPolicy({ dataset, channel, args, fieldType })
|
|
|
12
43
|
if (args.stack === undefined) return emptyPositionPolicy();
|
|
13
44
|
if (
|
|
14
45
|
channel !== "y" ||
|
|
15
|
-
|
|
46
|
+
density === undefined
|
|
16
47
|
) {
|
|
17
48
|
throw new Error("Area stack currently requires a density y encoding.");
|
|
18
49
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { validatePositionFieldCompatibility } from
|
|
2
2
|
"../../../../grammar/positionCompatibility.js";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
isCategoricalDensityPosition,
|
|
5
|
+
resolveAreaPositionPolicy
|
|
6
|
+
} from "./area.js";
|
|
4
7
|
import { resolveArcPositionPolicy } from "./arc.js";
|
|
5
8
|
import { resolveBarPositionPolicy } from "./bar.js";
|
|
6
9
|
import { resolveLinePositionPolicy } from "./line.js";
|
|
@@ -20,7 +23,9 @@ const POSITION_POLICIES = Object.freeze({
|
|
|
20
23
|
|
|
21
24
|
export function resolveMarkPositionPolicy(context) {
|
|
22
25
|
const { layer, channel, fieldType } = context;
|
|
23
|
-
|
|
26
|
+
if (!isCategoricalDensityPosition(context)) {
|
|
27
|
+
validatePositionFieldCompatibility(layer.mark.type, channel, fieldType);
|
|
28
|
+
}
|
|
24
29
|
const policy = POSITION_POLICIES[layer.mark.type];
|
|
25
30
|
if (policy === undefined) {
|
|
26
31
|
throw new Error(`Unsupported position policy for mark "${layer.mark.type}".`);
|
|
@@ -44,9 +44,14 @@ export function resolveLinePositionPolicy({
|
|
|
44
44
|
layer.encoding?.y?.aggregate === undefined &&
|
|
45
45
|
["quantitative", "temporal"].includes(layer.encoding?.y?.fieldType) &&
|
|
46
46
|
fieldType === "quantitative";
|
|
47
|
+
const pendingQuantitativePair =
|
|
48
|
+
layer.encoding?.y === undefined && fieldType === "quantitative";
|
|
47
49
|
if (
|
|
48
50
|
fieldType !== "temporal" &&
|
|
49
|
-
!(
|
|
51
|
+
!(
|
|
52
|
+
(regression || interval || directPair || pendingQuantitativePair) &&
|
|
53
|
+
fieldType === "quantitative"
|
|
54
|
+
)
|
|
50
55
|
) {
|
|
51
56
|
throw new Error(
|
|
52
57
|
"Line x encoding requires a temporal field or a compatible derived quantitative field."
|
|
@@ -60,10 +65,14 @@ export function resolveLinePositionPolicy({
|
|
|
60
65
|
}
|
|
61
66
|
|
|
62
67
|
rejectSharedOptions(args, "y");
|
|
68
|
+
const quantitativePair =
|
|
69
|
+
fieldType === "quantitative" &&
|
|
70
|
+
layer.encoding?.x?.fieldType === "quantitative";
|
|
63
71
|
const prospectiveDirect =
|
|
64
72
|
args.aggregate === undefined &&
|
|
65
73
|
(fieldType === "temporal" ||
|
|
66
|
-
(fieldType === "quantitative" &&
|
|
74
|
+
(fieldType === "quantitative" &&
|
|
75
|
+
(layer.encoding?.x === undefined || quantitativePair)));
|
|
67
76
|
if (interval || prospectiveDirect) {
|
|
68
77
|
if (!["quantitative", "temporal"].includes(fieldType)) {
|
|
69
78
|
throw new Error(
|
|
@@ -85,6 +94,13 @@ export function resolveLinePositionPolicy({
|
|
|
85
94
|
return emptyPositionPolicy();
|
|
86
95
|
}
|
|
87
96
|
|
|
97
|
+
if (
|
|
98
|
+
layer.encoding?.x !== undefined &&
|
|
99
|
+
layer.encoding.x.fieldType !== "temporal"
|
|
100
|
+
) {
|
|
101
|
+
throw new Error("Aggregate line y encoding requires a temporal x encoding.");
|
|
102
|
+
}
|
|
103
|
+
|
|
88
104
|
const aggregate = validateAggregate(args.aggregate);
|
|
89
105
|
validateAggregateFieldType(aggregate, fieldType);
|
|
90
106
|
return { bin: undefined, aggregate, stack: undefined };
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
readTemporalField,
|
|
8
8
|
validateFieldType,
|
|
9
9
|
validatePositionChannel
|
|
10
|
-
} from "../../../grammar/scales.js";
|
|
10
|
+
} from "../../../grammar/scales/index.js";
|
|
11
11
|
import { resolvePositionScaleDefinition } from "../../scales/definitions.js";
|
|
12
12
|
import { findCoordinate } from "../../../selectors/coordinates.js";
|
|
13
13
|
import {
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
validateAggregateFieldValues,
|
|
22
22
|
} from "../../../grammar/aggregate.js";
|
|
23
23
|
import { normalizeRuleDatum } from "../../../grammar/rules.js";
|
|
24
|
+
import { readArcThetaWeights } from "../../../grammar/arcs.js";
|
|
24
25
|
import { resolveMarkPositionPolicy } from "./policies/index.js";
|
|
25
26
|
import {
|
|
26
27
|
getPositionChannelDefinition,
|
|
@@ -29,7 +30,7 @@ import {
|
|
|
29
30
|
|
|
30
31
|
const POSITION_ENCODING_OPTIONS = Object.freeze([
|
|
31
32
|
"field", "datum", "target", "fieldType", "scale", "coordinate",
|
|
32
|
-
"aggregate", "bin", "stack"
|
|
33
|
+
"aggregate", "bin", "stack", "weight"
|
|
33
34
|
]);
|
|
34
35
|
|
|
35
36
|
function validateCoordinateFamily(layer, channel, operation) {
|
|
@@ -82,6 +83,12 @@ export function resolvePositionEncoding(program, channel, args, operation) {
|
|
|
82
83
|
args.target,
|
|
83
84
|
getPositionChannelDefinition(channel).markTypes
|
|
84
85
|
);
|
|
86
|
+
if (
|
|
87
|
+
Object.hasOwn(args, "weight") &&
|
|
88
|
+
!(layer.mark.type === "arc" && channel === "theta")
|
|
89
|
+
) {
|
|
90
|
+
throw new Error(`${operation} weight is supported only for arc theta encoding.`);
|
|
91
|
+
}
|
|
85
92
|
validateCoordinateFamily(layer, channel, operation);
|
|
86
93
|
const hasField = Object.hasOwn(args, "field");
|
|
87
94
|
const hasDatum = Object.hasOwn(args, "datum");
|
|
@@ -97,7 +104,8 @@ export function resolvePositionEncoding(program, channel, args, operation) {
|
|
|
97
104
|
}
|
|
98
105
|
const previous = layer.encoding?.[channel];
|
|
99
106
|
const requestedFieldType = args.fieldType ?? previous?.fieldType ?? (
|
|
100
|
-
layer.mark.type === "arc" && channel === "theta" &&
|
|
107
|
+
layer.mark.type === "arc" && channel === "theta" &&
|
|
108
|
+
["count", "sum"].includes(args.aggregate)
|
|
101
109
|
? "nominal"
|
|
102
110
|
: "quantitative"
|
|
103
111
|
);
|
|
@@ -117,6 +125,14 @@ export function resolvePositionEncoding(program, channel, args, operation) {
|
|
|
117
125
|
effectiveArgs[property] = previous[property];
|
|
118
126
|
}
|
|
119
127
|
}
|
|
128
|
+
if (
|
|
129
|
+
!Object.hasOwn(effectiveArgs, "weight") &&
|
|
130
|
+
effectiveArgs.aggregate === "sum" &&
|
|
131
|
+
previous !== undefined &&
|
|
132
|
+
Object.hasOwn(previous, "weight")
|
|
133
|
+
) {
|
|
134
|
+
effectiveArgs.weight = previous.weight;
|
|
135
|
+
}
|
|
120
136
|
const policy = resolveMarkPositionPolicy({
|
|
121
137
|
program,
|
|
122
138
|
layer,
|
|
@@ -179,6 +195,12 @@ export function resolvePositionEncoding(program, channel, args, operation) {
|
|
|
179
195
|
} else if (aggregateOutput) {
|
|
180
196
|
validateAggregateFieldType(policy.aggregate, fieldType);
|
|
181
197
|
validateAggregateFieldValues(dataset.values, field, fieldType);
|
|
198
|
+
} else if (
|
|
199
|
+
layer.mark.type === "arc" &&
|
|
200
|
+
channel === "theta" &&
|
|
201
|
+
policy.aggregate === "sum"
|
|
202
|
+
) {
|
|
203
|
+
readArcThetaWeights(dataset.values, policy.weight, layer.id);
|
|
182
204
|
} else if (program.markConfigs[target]?.boxPlot !== undefined) {
|
|
183
205
|
for (const [index, row] of dataset.values.entries()) {
|
|
184
206
|
const value = row[field];
|
|
@@ -7,12 +7,12 @@ import {
|
|
|
7
7
|
readScaleField,
|
|
8
8
|
readTemporalField,
|
|
9
9
|
validateSemanticFieldType
|
|
10
|
-
} from "../../grammar/scales.js";
|
|
10
|
+
} from "../../grammar/scales/index.js";
|
|
11
11
|
import { normalizeRuleDatum } from "../../grammar/rules.js";
|
|
12
12
|
import {
|
|
13
13
|
canMaterializeArea,
|
|
14
14
|
canMaterializeLine
|
|
15
|
-
} from "../../materialization/marks.js";
|
|
15
|
+
} from "../../materialization/marks/index.js";
|
|
16
16
|
import { findLayer } from "../../selectors/layers.js";
|
|
17
17
|
import {
|
|
18
18
|
resolveTarget,
|
|
@@ -157,7 +157,9 @@ function encodeSecondaryPosition(program, channel, args, operation, types) {
|
|
|
157
157
|
? next.rematerializeBarMark({ id: target })
|
|
158
158
|
: layer.mark.type === "rect"
|
|
159
159
|
? next.rematerializeRectMark({ id: target })
|
|
160
|
-
: next
|
|
160
|
+
: canMaterializeArea(next, findLayer(next, target))
|
|
161
|
+
? next.rematerializeAreaMark({ id: target })
|
|
162
|
+
: next;
|
|
161
163
|
}
|
|
162
164
|
|
|
163
165
|
const encodeX2 = action(
|
|
@@ -3,9 +3,22 @@ import {
|
|
|
3
3
|
validateRuleStroke,
|
|
4
4
|
validateRuleStrokeWidth
|
|
5
5
|
} from "../../grammar/ruleAppearance.js";
|
|
6
|
-
import {
|
|
6
|
+
import { readQuantitativeField } from "../../grammar/scales/index.js";
|
|
7
|
+
import { resolveStrokeWidthScaleDefinition } from "../scales/definitions.js";
|
|
8
|
+
import {
|
|
9
|
+
applyEncodingScale,
|
|
10
|
+
resolveReassignmentScaleOptions,
|
|
11
|
+
resolveTarget,
|
|
12
|
+
validateOptions
|
|
13
|
+
} from "./shared.js";
|
|
14
|
+
import { applyMaterializationPlan } from "../../materialization/dependencies.js";
|
|
15
|
+
import { planEncodingRematerialization } from "../../materialization/encodings.js";
|
|
16
|
+
import { findLayer } from "../../selectors/layers.js";
|
|
7
17
|
|
|
8
|
-
const
|
|
18
|
+
const STROKE_OPTIONS = Object.freeze(["target", "value"]);
|
|
19
|
+
const WIDTH_OPTIONS = Object.freeze([
|
|
20
|
+
"target", "value", "field", "fieldType", "scale"
|
|
21
|
+
]);
|
|
9
22
|
|
|
10
23
|
const encodeStroke = action(
|
|
11
24
|
{
|
|
@@ -13,7 +26,7 @@ const encodeStroke = action(
|
|
|
13
26
|
description: "Set a constant graphical stroke on a rule mark."
|
|
14
27
|
},
|
|
15
28
|
function (args = {}) {
|
|
16
|
-
validateOptions(args,
|
|
29
|
+
validateOptions(args, STROKE_OPTIONS, "encodeStroke");
|
|
17
30
|
const { id } = resolveTarget(this, args.target, ["rule"], "rule mark");
|
|
18
31
|
return this
|
|
19
32
|
._withMarkConfig(id, {
|
|
@@ -30,14 +43,79 @@ const encodeStrokeWidth = action(
|
|
|
30
43
|
description: "Set a constant graphical stroke width on a rule mark."
|
|
31
44
|
},
|
|
32
45
|
function (args = {}) {
|
|
33
|
-
validateOptions(args,
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
46
|
+
validateOptions(args, WIDTH_OPTIONS, "encodeStrokeWidth");
|
|
47
|
+
const hasValue = Object.hasOwn(args, "value");
|
|
48
|
+
const hasField = Object.hasOwn(args, "field");
|
|
49
|
+
if (hasValue === hasField) {
|
|
50
|
+
throw new Error("encodeStrokeWidth requires exactly one of value or field.");
|
|
51
|
+
}
|
|
52
|
+
if (hasValue) {
|
|
53
|
+
const { id } = resolveTarget(this, args.target, ["rule"], "rule mark");
|
|
54
|
+
let next = this.guideConfigs.legend?.strokeWidth?.target === id
|
|
55
|
+
? this.removeLegend({ target: id })
|
|
56
|
+
: this;
|
|
57
|
+
if (findLayer(next, id)?.encoding?.strokeWidth !== undefined) {
|
|
58
|
+
next = next.editSemantic({
|
|
59
|
+
property: `layer[${id}].encoding.strokeWidth`,
|
|
60
|
+
remove: true
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return next
|
|
64
|
+
._withMarkConfig(id, {
|
|
65
|
+
...next.markConfigs[id],
|
|
66
|
+
strokeWidth: validateRuleStrokeWidth(args.value)
|
|
67
|
+
})
|
|
68
|
+
.rematerializeRuleMark({ id });
|
|
69
|
+
}
|
|
70
|
+
const { id, dataset, layer } = resolveTarget(
|
|
71
|
+
this,
|
|
72
|
+
args.target,
|
|
73
|
+
["rule", "line"],
|
|
74
|
+
"rule or line mark"
|
|
75
|
+
);
|
|
76
|
+
const fieldType = args.fieldType ?? "quantitative";
|
|
77
|
+
if (fieldType !== "quantitative") {
|
|
78
|
+
throw new Error("encodeStrokeWidth requires a quantitative field.");
|
|
79
|
+
}
|
|
80
|
+
const values = readQuantitativeField(dataset.values, args.field);
|
|
81
|
+
if (values.some(value => value < 0)) {
|
|
82
|
+
throw new RangeError(
|
|
83
|
+
`encodeStrokeWidth field "${args.field}" cannot contain negative values.`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
const previous = layer.encoding?.strokeWidth;
|
|
87
|
+
const requestedScale = resolveReassignmentScaleOptions(
|
|
88
|
+
previous,
|
|
89
|
+
args.scale ?? {}
|
|
90
|
+
);
|
|
91
|
+
const scale = resolveStrokeWidthScaleDefinition(this, requestedScale);
|
|
92
|
+
const { strokeWidth, ...config } = this.markConfigs[id] ?? {};
|
|
93
|
+
void strokeWidth;
|
|
94
|
+
let next = this
|
|
95
|
+
._withMarkConfig(id, config)
|
|
96
|
+
.editSemantic({
|
|
97
|
+
property: `layer[${id}].encoding.strokeWidth.field`,
|
|
98
|
+
value: args.field
|
|
39
99
|
})
|
|
40
|
-
.
|
|
100
|
+
.editSemantic({
|
|
101
|
+
property: `layer[${id}].encoding.strokeWidth.fieldType`,
|
|
102
|
+
value: fieldType
|
|
103
|
+
})
|
|
104
|
+
.editSemantic({
|
|
105
|
+
property: `layer[${id}].encoding.strokeWidth.scale`,
|
|
106
|
+
value: scale.id
|
|
107
|
+
});
|
|
108
|
+
next = applyEncodingScale(next, scale, requestedScale, {
|
|
109
|
+
reassignment: previous?.scale === scale.id
|
|
110
|
+
});
|
|
111
|
+
return applyMaterializationPlan(
|
|
112
|
+
next,
|
|
113
|
+
planEncodingRematerialization(next, {
|
|
114
|
+
target: id,
|
|
115
|
+
channel: "strokeWidth",
|
|
116
|
+
scale: scale.id
|
|
117
|
+
})
|
|
118
|
+
);
|
|
41
119
|
}
|
|
42
120
|
);
|
|
43
121
|
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
normalizeStrokeDashPattern,
|
|
4
4
|
readNominalField,
|
|
5
5
|
validateNominalFieldType
|
|
6
|
-
} from "../../grammar/scales.js";
|
|
6
|
+
} from "../../grammar/scales/index.js";
|
|
7
7
|
import { resolveStrokeDashScaleDefinition } from "../scales/definitions.js";
|
|
8
8
|
import { applyMaterializationPlan } from "../../materialization/dependencies.js";
|
|
9
9
|
import { planEncodingRematerialization } from "../../materialization/encodings.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { action } from "../../core/action.js";
|
|
2
2
|
import { formatTextValue, validateTextFormat } from "../../grammar/text.js";
|
|
3
|
-
import { canMaterializeText } from "../../materialization/marks.js";
|
|
3
|
+
import { canMaterializeText } from "../../materialization/marks/index.js";
|
|
4
4
|
import { findLayer } from "../../selectors/layers.js";
|
|
5
5
|
import { resolveTarget, validateOptions } from "./shared.js";
|
|
6
6
|
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
validateUnitInterval
|
|
7
7
|
} from "../../core/validation.js";
|
|
8
8
|
import { validateCurveInterpolation } from "../../grammar/curveCommands.js";
|
|
9
|
-
import { normalizeStrokeDashPattern } from "../../grammar/scales.js";
|
|
9
|
+
import { normalizeStrokeDashPattern } from "../../grammar/scales/index.js";
|
|
10
10
|
|
|
11
11
|
export const ERROR_BAND_BOUNDARY_OPTIONS = Object.freeze([
|
|
12
12
|
"stroke", "strokeWidth", "strokeDash", "opacity", "curve"
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
validateOptionObject,
|
|
7
7
|
validatePositiveFinite
|
|
8
8
|
} from "../../core/validation.js";
|
|
9
|
-
import { resolveFacetDefinition } from "../../grammar/facets.js";
|
|
9
|
+
import { resolveFacetDefinition } from "../../grammar/facets/index.js";
|
|
10
10
|
import { normalizeFacetScalePolicies } from
|
|
11
11
|
"../../grammar/facets/scales.js";
|
|
12
12
|
import { resolveFacetLayout } from "../../layout/facets.js";
|
|
@@ -14,7 +14,7 @@ import { compositionChildDescriptor } from
|
|
|
14
14
|
"../../materialization/composition.js";
|
|
15
15
|
import { DEFAULT_COLORS, DEFAULT_FONT_FAMILY } from "../../theme/defaults.js";
|
|
16
16
|
import { deriveFacetChildren } from "./derive.js";
|
|
17
|
-
import {
|
|
17
|
+
import { replayDerivedData } from "./replay.js";
|
|
18
18
|
import { composeFacetGuides } from "./guides.js";
|
|
19
19
|
|
|
20
20
|
const FACET_OPTIONS = Object.freeze([
|
|
@@ -155,7 +155,6 @@ export const editFacetHeaders = action(
|
|
|
155
155
|
|
|
156
156
|
export function registerFacetActions(ProgramClass) {
|
|
157
157
|
ProgramClass.prototype.replayDerivedData = replayDerivedData;
|
|
158
|
-
ProgramClass.prototype.rebindLayerData = rebindLayerData;
|
|
159
158
|
ProgramClass.prototype.composeFacetGuides = composeFacetGuides;
|
|
160
159
|
ProgramClass.prototype.facet = facet;
|
|
161
160
|
ProgramClass.prototype.editFacetHeaders = editFacetHeaders;
|