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
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { validateUserId } from "../../core/identifiers.js";
|
|
2
|
+
import { findCoordinate } from "../../selectors/coordinates.js";
|
|
3
|
+
|
|
4
|
+
export function resolveParallelCoordinate(program, {
|
|
5
|
+
requested,
|
|
6
|
+
layer,
|
|
7
|
+
operation,
|
|
8
|
+
useCurrent = false
|
|
9
|
+
}) {
|
|
10
|
+
const explicit = requested === undefined
|
|
11
|
+
? undefined
|
|
12
|
+
: validateUserId(requested, "Parallel coordinate id");
|
|
13
|
+
if (layer?.coordinate !== undefined) {
|
|
14
|
+
if (explicit !== undefined && explicit !== layer.coordinate) {
|
|
15
|
+
throw new Error(
|
|
16
|
+
`Layer "${layer.id}" already uses coordinate "${layer.coordinate}".`
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
const coordinate = findCoordinate(program, layer.coordinate);
|
|
20
|
+
if (coordinate?.type !== "parallel") {
|
|
21
|
+
throw new Error(`Coordinate "${layer.coordinate}" is not Parallel.`);
|
|
22
|
+
}
|
|
23
|
+
return { id: layer.coordinate, create: false };
|
|
24
|
+
}
|
|
25
|
+
if (explicit !== undefined) {
|
|
26
|
+
const coordinate = findCoordinate(program, explicit);
|
|
27
|
+
if (coordinate !== undefined && coordinate.type !== "parallel") {
|
|
28
|
+
throw new Error(`Coordinate "${explicit}" is not Parallel.`);
|
|
29
|
+
}
|
|
30
|
+
return { id: explicit, create: coordinate === undefined };
|
|
31
|
+
}
|
|
32
|
+
const current = useCurrent ? program.context.currentCoordinate : undefined;
|
|
33
|
+
if (current !== undefined && findCoordinate(program, current)?.type === "parallel") {
|
|
34
|
+
return { id: current, create: false };
|
|
35
|
+
}
|
|
36
|
+
const compatible = program.semanticSpec.coordinates.filter(
|
|
37
|
+
coordinate => coordinate.type === "parallel"
|
|
38
|
+
);
|
|
39
|
+
if (compatible.length > 1) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`${operation} requires coordinate when multiple Parallel coordinates are available.`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
if (compatible.length === 1) return { id: compatible[0].id, create: false };
|
|
45
|
+
const conflict = findCoordinate(program, "parallel");
|
|
46
|
+
if (conflict !== undefined) {
|
|
47
|
+
throw new Error('Coordinate "parallel" already exists with a different type.');
|
|
48
|
+
}
|
|
49
|
+
return { id: "parallel", create: true };
|
|
50
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { action } from "../../core/action.js";
|
|
2
|
+
import { validateUserId } from "../../core/identifiers.js";
|
|
3
|
+
import { validateKeys } from "../../core/validation.js";
|
|
4
|
+
import {
|
|
5
|
+
deriveBin2DRows,
|
|
6
|
+
normalizeBin2DTransform
|
|
7
|
+
} from "../../grammar/bin2d.js";
|
|
8
|
+
import { applyLayerDataRematerialization } from
|
|
9
|
+
"../../materialization/dependencies.js";
|
|
10
|
+
import { planDerivedDataRevision } from
|
|
11
|
+
"../../materialization/dataProvenance.js";
|
|
12
|
+
import {
|
|
13
|
+
findDataset,
|
|
14
|
+
findDatasetConsumer
|
|
15
|
+
} from "../../selectors/datasets.js";
|
|
16
|
+
import { MATERIALIZE_OPTIONS, requireDerivedDataset } from "./shared.js";
|
|
17
|
+
|
|
18
|
+
const OPTIONS = Object.freeze([
|
|
19
|
+
"id", "source", "x", "y", "bins", "extent", "includeEmpty", "members", "as"
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
function ownerConfig(program, id) {
|
|
23
|
+
return program.materializationConfigs.data?.bin2d?.[id];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function requireCurrentBin2D(program, id, config) {
|
|
27
|
+
const current = findDataset(program, config.current);
|
|
28
|
+
if (
|
|
29
|
+
current?.source === undefined ||
|
|
30
|
+
current.transform?.length !== 1 ||
|
|
31
|
+
current.transform[0].type !== "bin2d"
|
|
32
|
+
) {
|
|
33
|
+
throw new Error(`2D bin owner "${id}" has no current derived dataset.`);
|
|
34
|
+
}
|
|
35
|
+
return current;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function directLayerConsumers(program, data) {
|
|
39
|
+
return program.semanticSpec.layers
|
|
40
|
+
.filter(layer => layer.data === data)
|
|
41
|
+
.map(layer => layer.id);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function rejectDerivedConsumers(program, data) {
|
|
45
|
+
const dependent = findDatasetConsumer(program, data);
|
|
46
|
+
if (dependent !== undefined) {
|
|
47
|
+
throw new Error(
|
|
48
|
+
`Cannot replace 2D bin dataset "${data}" while derived dataset ` +
|
|
49
|
+
`"${dependent.id}" depends on it.`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function preflight(program, sourceId, transform) {
|
|
55
|
+
const source = findDataset(program, sourceId);
|
|
56
|
+
if (source?.values === undefined) {
|
|
57
|
+
throw new Error(`Source dataset "${sourceId}" has no values.`);
|
|
58
|
+
}
|
|
59
|
+
deriveBin2DRows(source.values, transform);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const materializeBin2DData = action(
|
|
63
|
+
{
|
|
64
|
+
op: "materializeBin2DData",
|
|
65
|
+
description: "Materialize one immutable rectangular 2D-bin dataset."
|
|
66
|
+
},
|
|
67
|
+
function (args = {}) {
|
|
68
|
+
validateKeys(args, MATERIALIZE_OPTIONS, "materializeBin2DData");
|
|
69
|
+
const { id, source, transform } = requireDerivedDataset(
|
|
70
|
+
this,
|
|
71
|
+
args.id,
|
|
72
|
+
"bin2d"
|
|
73
|
+
);
|
|
74
|
+
const result = deriveBin2DRows(source.values, transform);
|
|
75
|
+
return this
|
|
76
|
+
.editSemantic({
|
|
77
|
+
property: `dataset[${id}].transform`,
|
|
78
|
+
value: [{ ...transform, resolved: result.resolved }]
|
|
79
|
+
})
|
|
80
|
+
.editSemantic({
|
|
81
|
+
property: `dataset[${id}].values`,
|
|
82
|
+
value: result.values
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
export const createBin2DData = action(
|
|
88
|
+
{
|
|
89
|
+
op: "createBin2DData",
|
|
90
|
+
description: "Create or revise immutable rectangular 2D-bin values."
|
|
91
|
+
},
|
|
92
|
+
function (args = {}) {
|
|
93
|
+
validateKeys(args, OPTIONS, "createBin2DData");
|
|
94
|
+
const owner = validateUserId(args.id, "2D bin dataset id");
|
|
95
|
+
const config = ownerConfig(this, owner);
|
|
96
|
+
const previous = config === undefined
|
|
97
|
+
? undefined
|
|
98
|
+
: requireCurrentBin2D(this, owner, config);
|
|
99
|
+
const source = validateUserId(
|
|
100
|
+
args.source ?? previous?.source ?? this.context.currentData,
|
|
101
|
+
"Source dataset id"
|
|
102
|
+
);
|
|
103
|
+
const transform = normalizeBin2DTransform({ ...args, id: owner });
|
|
104
|
+
preflight(this, source, transform);
|
|
105
|
+
|
|
106
|
+
if (previous === undefined) {
|
|
107
|
+
return this
|
|
108
|
+
.createDerivedData({ id: owner, source, transform: [transform] })
|
|
109
|
+
.materializeBin2DData({ id: owner })
|
|
110
|
+
._withMaterializationConfig(
|
|
111
|
+
["data", "bin2d", owner],
|
|
112
|
+
{ current: owner }
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
rejectDerivedConsumers(this, previous.id);
|
|
117
|
+
const consumers = directLayerConsumers(this, previous.id);
|
|
118
|
+
const revision = planDerivedDataRevision(this, {
|
|
119
|
+
owner,
|
|
120
|
+
role: "Bin2DData",
|
|
121
|
+
previous: previous.id,
|
|
122
|
+
consumers
|
|
123
|
+
});
|
|
124
|
+
let next = this
|
|
125
|
+
.createDerivedData({ id: revision.id, source, transform: [transform] })
|
|
126
|
+
.materializeBin2DData({ id: revision.id });
|
|
127
|
+
for (const rebind of revision.rebinds) {
|
|
128
|
+
next = next.rebindLayerData(rebind);
|
|
129
|
+
next = applyLayerDataRematerialization(next, rebind.id);
|
|
130
|
+
}
|
|
131
|
+
next = next.releaseDerivedData(revision.release);
|
|
132
|
+
return next._withMaterializationConfig(
|
|
133
|
+
["data", "bin2d", owner],
|
|
134
|
+
{ current: revision.id }
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
);
|
|
@@ -8,6 +8,23 @@ const OPTIONS = Object.freeze([
|
|
|
8
8
|
"id", "source", "field", "groupBy", "bandwidth", "extent", "steps",
|
|
9
9
|
"kernel", "normalization", "as"
|
|
10
10
|
]);
|
|
11
|
+
const CATEGORICAL_OPTIONS = Object.freeze([...OPTIONS, "placement"]);
|
|
12
|
+
|
|
13
|
+
function densityTransform(args, placement) {
|
|
14
|
+
return {
|
|
15
|
+
type: "density",
|
|
16
|
+
field: args.field,
|
|
17
|
+
...(args.groupBy === undefined ? {} : { groupBy: args.groupBy }),
|
|
18
|
+
bandwidth: args.bandwidth ?? "auto",
|
|
19
|
+
extent: args.extent ?? "auto",
|
|
20
|
+
steps: args.steps ?? 100,
|
|
21
|
+
kernel: args.kernel ?? "gaussian",
|
|
22
|
+
normalization: args.normalization ?? "unit",
|
|
23
|
+
as: args.as ?? [`${args.field}_value`, `${args.field}_density`],
|
|
24
|
+
resolve: "shared",
|
|
25
|
+
...(placement === undefined ? {} : { placement })
|
|
26
|
+
};
|
|
27
|
+
}
|
|
11
28
|
|
|
12
29
|
export const materializeDensityData = action(
|
|
13
30
|
{ op: "materializeDensityData", description: "Materialize one grouped kernel-density dataset." },
|
|
@@ -26,7 +43,10 @@ export const materializeDensityData = action(
|
|
|
26
43
|
...transform,
|
|
27
44
|
resolved: {
|
|
28
45
|
bandwidth: result.bandwidth,
|
|
29
|
-
extent: result.extent
|
|
46
|
+
extent: result.extent,
|
|
47
|
+
...(result.splitDomain === undefined
|
|
48
|
+
? {}
|
|
49
|
+
: { splitDomain: result.splitDomain })
|
|
30
50
|
}
|
|
31
51
|
}]
|
|
32
52
|
})
|
|
@@ -49,20 +69,41 @@ export const createDensityData = action(
|
|
|
49
69
|
if (typeof args.field !== "string" || args.field.length === 0) {
|
|
50
70
|
throw new TypeError("createDensityData requires a non-empty field string.");
|
|
51
71
|
}
|
|
52
|
-
const transform =
|
|
53
|
-
type: "density",
|
|
54
|
-
field: args.field,
|
|
55
|
-
...(args.groupBy === undefined ? {} : { groupBy: args.groupBy }),
|
|
56
|
-
bandwidth: args.bandwidth ?? "auto",
|
|
57
|
-
extent: args.extent ?? "auto",
|
|
58
|
-
steps: args.steps ?? 100,
|
|
59
|
-
kernel: args.kernel ?? "gaussian",
|
|
60
|
-
normalization: args.normalization ?? "unit",
|
|
61
|
-
as: args.as ?? [`${args.field}_value`, `${args.field}_density`],
|
|
62
|
-
resolve: "shared"
|
|
63
|
-
};
|
|
72
|
+
const transform = densityTransform(args);
|
|
64
73
|
return this
|
|
65
74
|
.createDerivedData({ id, source, transform: [transform] })
|
|
66
75
|
.materializeDensityData({ id });
|
|
67
76
|
}
|
|
68
77
|
);
|
|
78
|
+
|
|
79
|
+
export const createCategoricalDensityData = action(
|
|
80
|
+
{
|
|
81
|
+
op: "createCategoricalDensityData",
|
|
82
|
+
description: "Create category-placed kernel-density values."
|
|
83
|
+
},
|
|
84
|
+
function (args = {}) {
|
|
85
|
+
validateKeys(args, CATEGORICAL_OPTIONS, "createCategoricalDensityData");
|
|
86
|
+
const id = validateUserId(args.id, "Density dataset id");
|
|
87
|
+
const source = validateUserId(
|
|
88
|
+
args.source ?? this.context.currentData,
|
|
89
|
+
"Source dataset id"
|
|
90
|
+
);
|
|
91
|
+
if (typeof args.field !== "string" || args.field.length === 0) {
|
|
92
|
+
throw new TypeError(
|
|
93
|
+
"createCategoricalDensityData requires a non-empty field string."
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
if (args.placement?.type !== "category") {
|
|
97
|
+
throw new Error(
|
|
98
|
+
"createCategoricalDensityData requires normalized category placement."
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return this
|
|
102
|
+
.createDerivedData({
|
|
103
|
+
id,
|
|
104
|
+
source,
|
|
105
|
+
transform: [densityTransform(args, args.placement)]
|
|
106
|
+
})
|
|
107
|
+
.materializeDensityData({ id });
|
|
108
|
+
}
|
|
109
|
+
);
|
|
@@ -3,9 +3,11 @@ import { validateUserId } from "../../core/identifiers.js";
|
|
|
3
3
|
import { validateKeys } from "../../core/validation.js";
|
|
4
4
|
import { hasDataset } from "../../selectors/index.js";
|
|
5
5
|
import { findDataset } from "../../selectors/datasets.js";
|
|
6
|
+
import { requireLayer } from "../../selectors/layers.js";
|
|
6
7
|
|
|
7
8
|
const OPTIONS = Object.freeze(["id", "source", "transform"]);
|
|
8
9
|
const RELEASE_OPTIONS = Object.freeze(["id"]);
|
|
10
|
+
const REBIND_OPTIONS = Object.freeze(["id", "data"]);
|
|
9
11
|
|
|
10
12
|
export const createDerivedData = action(
|
|
11
13
|
{ op: "createDerivedData", description: "Create an immutable derived dataset definition." },
|
|
@@ -50,3 +52,23 @@ export const releaseDerivedData = action(
|
|
|
50
52
|
});
|
|
51
53
|
}
|
|
52
54
|
);
|
|
55
|
+
|
|
56
|
+
export const rebindLayerData = action(
|
|
57
|
+
{
|
|
58
|
+
op: "rebindLayerData",
|
|
59
|
+
description: "Rebind one semantic layer to an existing dataset."
|
|
60
|
+
},
|
|
61
|
+
function (args = {}) {
|
|
62
|
+
validateKeys(args, REBIND_OPTIONS, "rebindLayerData");
|
|
63
|
+
const id = validateUserId(args.id, "Layer id");
|
|
64
|
+
const data = validateUserId(args.data, "Layer dataset id");
|
|
65
|
+
requireLayer(this, id);
|
|
66
|
+
if (!hasDataset(this, data)) {
|
|
67
|
+
throw new Error(`Layer dataset "${data}" does not exist.`);
|
|
68
|
+
}
|
|
69
|
+
return this.editSemantic({
|
|
70
|
+
property: `layer[${id}].data`,
|
|
71
|
+
value: data
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
);
|
|
@@ -125,6 +125,11 @@ export const filterMarks = action(
|
|
|
125
125
|
candidate.data !== undefined &&
|
|
126
126
|
findSelectionPolicy(candidate.mark?.type) !== undefined
|
|
127
127
|
});
|
|
128
|
+
if (this.markConfigs[layer.id]?.itemFilterable === false) {
|
|
129
|
+
throw new Error(
|
|
130
|
+
`filterMarks does not support composite mark "${layer.id}"; filter its source dataset first.`
|
|
131
|
+
);
|
|
132
|
+
}
|
|
128
133
|
const derivedId = `${layer.id}FilteredData`;
|
|
129
134
|
if (hasDataset(this, derivedId)) {
|
|
130
135
|
throw new Error(`Dataset "${derivedId}" already exists.`);
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { action } from "../../core/action.js";
|
|
2
|
+
import { validateUserId } from "../../core/identifiers.js";
|
|
3
|
+
import { validateKeys } from "../../core/validation.js";
|
|
4
|
+
import {
|
|
5
|
+
deriveGradientProfiles,
|
|
6
|
+
normalizeGradientProfileTransform
|
|
7
|
+
} from "../../grammar/gradientProfile.js";
|
|
8
|
+
import { MATERIALIZE_OPTIONS, requireDerivedDataset } from "./shared.js";
|
|
9
|
+
|
|
10
|
+
const OPTIONS = Object.freeze([
|
|
11
|
+
"id", "source", "category", "field", "bandwidth", "extent", "steps",
|
|
12
|
+
"kernel", "normalization", "center", "as"
|
|
13
|
+
]);
|
|
14
|
+
|
|
15
|
+
export const materializeGradientProfileData = action(
|
|
16
|
+
{
|
|
17
|
+
op: "materializeGradientProfileData",
|
|
18
|
+
description: "Materialize one categorical density-profile dataset."
|
|
19
|
+
},
|
|
20
|
+
function (args = {}) {
|
|
21
|
+
validateKeys(
|
|
22
|
+
args,
|
|
23
|
+
MATERIALIZE_OPTIONS,
|
|
24
|
+
"materializeGradientProfileData"
|
|
25
|
+
);
|
|
26
|
+
const { id, source, transform } = requireDerivedDataset(
|
|
27
|
+
this,
|
|
28
|
+
args.id,
|
|
29
|
+
"gradientProfile"
|
|
30
|
+
);
|
|
31
|
+
const result = deriveGradientProfiles(source.values, transform);
|
|
32
|
+
return this
|
|
33
|
+
.editSemantic({
|
|
34
|
+
property: `dataset[${id}].transform`,
|
|
35
|
+
value: [{
|
|
36
|
+
...transform,
|
|
37
|
+
resolved: {
|
|
38
|
+
bandwidth: result.bandwidth,
|
|
39
|
+
extent: result.extent,
|
|
40
|
+
intensityDomain: result.intensityDomain
|
|
41
|
+
}
|
|
42
|
+
}]
|
|
43
|
+
})
|
|
44
|
+
.editSemantic({ property: `dataset[${id}].values`, value: result.values });
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
export const createGradientProfileData = action(
|
|
49
|
+
{
|
|
50
|
+
op: "createGradientProfileData",
|
|
51
|
+
description: "Create one immutable categorical density-profile dataset."
|
|
52
|
+
},
|
|
53
|
+
function (args = {}) {
|
|
54
|
+
validateKeys(args, OPTIONS, "createGradientProfileData");
|
|
55
|
+
const id = validateUserId(args.id, "Gradient profile dataset id");
|
|
56
|
+
const source = validateUserId(
|
|
57
|
+
args.source ?? this.context.currentData,
|
|
58
|
+
"Gradient profile source dataset id"
|
|
59
|
+
);
|
|
60
|
+
const transform = normalizeGradientProfileTransform(args);
|
|
61
|
+
return this
|
|
62
|
+
.createDerivedData({ id, source, transform: [transform] })
|
|
63
|
+
.materializeGradientProfileData({ id });
|
|
64
|
+
}
|
|
65
|
+
);
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { action } from "../../core/action.js";
|
|
2
|
+
import { validateUserId } from "../../core/identifiers.js";
|
|
3
|
+
import { validateKeys } from "../../core/validation.js";
|
|
4
|
+
import {
|
|
5
|
+
deriveHorizon,
|
|
6
|
+
validateHorizonTransform
|
|
7
|
+
} from "../../grammar/horizon.js";
|
|
8
|
+
import { MATERIALIZE_OPTIONS, requireDerivedDataset } from "./shared.js";
|
|
9
|
+
|
|
10
|
+
const OPTIONS = Object.freeze([
|
|
11
|
+
"id", "source", "x", "y", "groupBy", "bands", "baseline", "extent",
|
|
12
|
+
"resolve", "missing", "overflow", "palette", "as"
|
|
13
|
+
]);
|
|
14
|
+
|
|
15
|
+
function requestedTransform(args) {
|
|
16
|
+
return validateHorizonTransform({
|
|
17
|
+
type: "horizon",
|
|
18
|
+
x: args.x,
|
|
19
|
+
y: args.y,
|
|
20
|
+
...(args.groupBy === undefined ? {} : { groupBy: args.groupBy }),
|
|
21
|
+
bands: args.bands ?? 3,
|
|
22
|
+
baseline: args.baseline ?? 0,
|
|
23
|
+
extent: args.extent ?? "auto",
|
|
24
|
+
resolve: args.resolve ?? "shared",
|
|
25
|
+
missing: args.missing ?? "break",
|
|
26
|
+
overflow: args.overflow ?? "clip",
|
|
27
|
+
palette: args.palette ?? {},
|
|
28
|
+
as: args.as
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const materializeHorizonData = action(
|
|
33
|
+
{
|
|
34
|
+
op: "materializeHorizonData",
|
|
35
|
+
description: "Materialize one immutable Horizon band dataset."
|
|
36
|
+
},
|
|
37
|
+
function (args = {}) {
|
|
38
|
+
validateKeys(args, MATERIALIZE_OPTIONS, "materializeHorizonData");
|
|
39
|
+
const { id, source, transform } = requireDerivedDataset(
|
|
40
|
+
this,
|
|
41
|
+
args.id,
|
|
42
|
+
"horizon"
|
|
43
|
+
);
|
|
44
|
+
const result = deriveHorizon(source.values, transform);
|
|
45
|
+
return this
|
|
46
|
+
.editSemantic({
|
|
47
|
+
property: `dataset[${id}].transform`,
|
|
48
|
+
value: [{ ...result.transform, resolved: result.resolved }]
|
|
49
|
+
})
|
|
50
|
+
.editSemantic({
|
|
51
|
+
property: `dataset[${id}].values`,
|
|
52
|
+
value: result.values
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
export const createHorizonData = action(
|
|
58
|
+
{
|
|
59
|
+
op: "createHorizonData",
|
|
60
|
+
description: "Create one immutable Horizon band dataset."
|
|
61
|
+
},
|
|
62
|
+
function (args = {}) {
|
|
63
|
+
validateKeys(args, OPTIONS, "createHorizonData");
|
|
64
|
+
const id = validateUserId(args.id, "Horizon dataset id");
|
|
65
|
+
const source = validateUserId(args.source, "Horizon source dataset id");
|
|
66
|
+
const transform = requestedTransform(args);
|
|
67
|
+
return this
|
|
68
|
+
.createDerivedData({ id, source, transform: [transform] })
|
|
69
|
+
.materializeHorizonData({ id });
|
|
70
|
+
}
|
|
71
|
+
);
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { createData } from "./create.js";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
createDerivedData,
|
|
4
|
+
rebindLayerData,
|
|
5
|
+
releaseDerivedData
|
|
6
|
+
} from "./derived.js";
|
|
3
7
|
import {
|
|
4
8
|
filterData,
|
|
5
9
|
filterMarks,
|
|
@@ -7,24 +11,47 @@ import {
|
|
|
7
11
|
materializeMarkFilteredData
|
|
8
12
|
} from "./filter.js";
|
|
9
13
|
import { createRegressionData, materializeRegressionData } from "./regression.js";
|
|
10
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
createCategoricalDensityData,
|
|
16
|
+
createDensityData,
|
|
17
|
+
materializeDensityData
|
|
18
|
+
} from "./density.js";
|
|
19
|
+
import {
|
|
20
|
+
createGradientProfileData,
|
|
21
|
+
materializeGradientProfileData
|
|
22
|
+
} from "./gradientProfile.js";
|
|
11
23
|
import { createIntervalData, materializeIntervalData } from "./interval.js";
|
|
24
|
+
import { createHorizonData, materializeHorizonData } from "./horizon.js";
|
|
25
|
+
import { createWindowData, materializeWindowData } from "./window.js";
|
|
26
|
+
import { createBin2DData, materializeBin2DData } from "./bin2d.js";
|
|
12
27
|
import { createBoxSummaryData, createBoxOutlierData, materializeBoxSummaryData, materializeBoxOutlierData } from "./box.js";
|
|
13
28
|
|
|
14
29
|
export function registerDataActions(ProgramClass) {
|
|
15
30
|
ProgramClass.prototype.createData = createData;
|
|
16
31
|
ProgramClass.prototype.createDerivedData = createDerivedData;
|
|
17
32
|
ProgramClass.prototype.releaseDerivedData = releaseDerivedData;
|
|
33
|
+
ProgramClass.prototype.rebindLayerData = rebindLayerData;
|
|
18
34
|
ProgramClass.prototype.createDensityData = createDensityData;
|
|
35
|
+
ProgramClass.prototype.createCategoricalDensityData =
|
|
36
|
+
createCategoricalDensityData;
|
|
19
37
|
ProgramClass.prototype.materializeFilteredData = materializeFilteredData;
|
|
20
38
|
ProgramClass.prototype.materializeMarkFilteredData = materializeMarkFilteredData;
|
|
21
39
|
ProgramClass.prototype.filterData = filterData;
|
|
22
40
|
ProgramClass.prototype.filterMarks = filterMarks;
|
|
23
41
|
ProgramClass.prototype.materializeRegressionData = materializeRegressionData;
|
|
24
42
|
ProgramClass.prototype.materializeDensityData = materializeDensityData;
|
|
43
|
+
ProgramClass.prototype.createGradientProfileData = createGradientProfileData;
|
|
44
|
+
ProgramClass.prototype.materializeGradientProfileData =
|
|
45
|
+
materializeGradientProfileData;
|
|
25
46
|
ProgramClass.prototype.createRegressionData = createRegressionData;
|
|
26
47
|
ProgramClass.prototype.materializeIntervalData = materializeIntervalData;
|
|
27
48
|
ProgramClass.prototype.createIntervalData = createIntervalData;
|
|
49
|
+
ProgramClass.prototype.createHorizonData = createHorizonData;
|
|
50
|
+
ProgramClass.prototype.materializeHorizonData = materializeHorizonData;
|
|
51
|
+
ProgramClass.prototype.createWindowData = createWindowData;
|
|
52
|
+
ProgramClass.prototype.materializeWindowData = materializeWindowData;
|
|
53
|
+
ProgramClass.prototype.createBin2DData = createBin2DData;
|
|
54
|
+
ProgramClass.prototype.materializeBin2DData = materializeBin2DData;
|
|
28
55
|
ProgramClass.prototype.createBoxSummaryData = createBoxSummaryData;
|
|
29
56
|
ProgramClass.prototype.createBoxOutlierData = createBoxOutlierData;
|
|
30
57
|
ProgramClass.prototype.materializeBoxSummaryData = materializeBoxSummaryData;
|
|
@@ -4,7 +4,7 @@ import { validateKeys } from "../../core/validation.js";
|
|
|
4
4
|
import {
|
|
5
5
|
deriveRegression,
|
|
6
6
|
normalizeRegressionParameters
|
|
7
|
-
} from "../../grammar/regression.js";
|
|
7
|
+
} from "../../grammar/regression/index.js";
|
|
8
8
|
import { MATERIALIZE_OPTIONS, requireDerivedDataset } from "./shared.js";
|
|
9
9
|
|
|
10
10
|
const OPTIONS = Object.freeze([
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { action } from "../../core/action.js";
|
|
2
|
+
import { validateUserId } from "../../core/identifiers.js";
|
|
3
|
+
import { validateKeys } from "../../core/validation.js";
|
|
4
|
+
import {
|
|
5
|
+
deriveWindowRows,
|
|
6
|
+
normalizeWindowTransform
|
|
7
|
+
} from "../../grammar/window.js";
|
|
8
|
+
import { MATERIALIZE_OPTIONS, requireDerivedDataset } from "./shared.js";
|
|
9
|
+
|
|
10
|
+
const OPTIONS = Object.freeze([
|
|
11
|
+
"id", "source", "partitionBy", "sortBy", "operations"
|
|
12
|
+
]);
|
|
13
|
+
|
|
14
|
+
export const materializeWindowData = action(
|
|
15
|
+
{
|
|
16
|
+
op: "materializeWindowData",
|
|
17
|
+
description: "Materialize one immutable window-derived dataset."
|
|
18
|
+
},
|
|
19
|
+
function (args = {}) {
|
|
20
|
+
validateKeys(args, MATERIALIZE_OPTIONS, "materializeWindowData");
|
|
21
|
+
const { id, source, transform } = requireDerivedDataset(
|
|
22
|
+
this,
|
|
23
|
+
args.id,
|
|
24
|
+
"window"
|
|
25
|
+
);
|
|
26
|
+
return this.editSemantic({
|
|
27
|
+
property: `dataset[${id}].values`,
|
|
28
|
+
value: deriveWindowRows(source.values, transform)
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
export const createWindowData = action(
|
|
34
|
+
{
|
|
35
|
+
op: "createWindowData",
|
|
36
|
+
description: "Create immutable partitioned window values."
|
|
37
|
+
},
|
|
38
|
+
function (args = {}) {
|
|
39
|
+
validateKeys(args, OPTIONS, "createWindowData");
|
|
40
|
+
const id = validateUserId(args.id, "Window dataset id");
|
|
41
|
+
const source = validateUserId(
|
|
42
|
+
args.source ?? this.context.currentData,
|
|
43
|
+
"Source dataset id"
|
|
44
|
+
);
|
|
45
|
+
const transform = normalizeWindowTransform(args);
|
|
46
|
+
return this
|
|
47
|
+
.createDerivedData({ id, source, transform: [transform] })
|
|
48
|
+
.materializeWindowData({ id });
|
|
49
|
+
}
|
|
50
|
+
);
|