ggaction 0.0.1

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.
Files changed (222) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/LICENSE +21 -0
  3. package/README.md +108 -0
  4. package/package.json +84 -0
  5. package/src/AGENTS.md +119 -0
  6. package/src/ChartProgram.js +10 -0
  7. package/src/actions/boxPlots/components.js +88 -0
  8. package/src/actions/boxPlots/create.js +84 -0
  9. package/src/actions/boxPlots/index.js +10 -0
  10. package/src/actions/boxPlots/materialize.js +183 -0
  11. package/src/actions/boxPlots/options.js +147 -0
  12. package/src/actions/boxPlots/resolve.js +38 -0
  13. package/src/actions/canvas/actions.js +144 -0
  14. package/src/actions/canvas/index.js +6 -0
  15. package/src/actions/coordinates/actions.js +85 -0
  16. package/src/actions/coordinates/index.js +5 -0
  17. package/src/actions/data/box.js +40 -0
  18. package/src/actions/data/create.js +33 -0
  19. package/src/actions/data/density.js +62 -0
  20. package/src/actions/data/derived.js +52 -0
  21. package/src/actions/data/filter.js +168 -0
  22. package/src/actions/data/index.js +32 -0
  23. package/src/actions/data/interval.js +69 -0
  24. package/src/actions/data/regression.js +71 -0
  25. package/src/actions/data/shared.js +25 -0
  26. package/src/actions/encodings/appearance.js +243 -0
  27. package/src/actions/encodings/barWidth.js +60 -0
  28. package/src/actions/encodings/color.js +329 -0
  29. package/src/actions/encodings/density.js +225 -0
  30. package/src/actions/encodings/histogram.js +50 -0
  31. package/src/actions/encodings/index.js +23 -0
  32. package/src/actions/encodings/offset.js +104 -0
  33. package/src/actions/encodings/position/policies/area.js +24 -0
  34. package/src/actions/encodings/position/policies/bar.js +110 -0
  35. package/src/actions/encodings/position/policies/common.js +17 -0
  36. package/src/actions/encodings/position/policies/index.js +25 -0
  37. package/src/actions/encodings/position/policies/line.js +74 -0
  38. package/src/actions/encodings/position/policies/point.js +19 -0
  39. package/src/actions/encodings/position/policies/rule.js +17 -0
  40. package/src/actions/encodings/position/resolve.js +170 -0
  41. package/src/actions/encodings/position.js +176 -0
  42. package/src/actions/encodings/ranged.js +276 -0
  43. package/src/actions/encodings/ruleAppearance.js +47 -0
  44. package/src/actions/encodings/shared.js +164 -0
  45. package/src/actions/encodings/strokeDash.js +145 -0
  46. package/src/actions/errorBands/components.js +81 -0
  47. package/src/actions/errorBands/create.js +159 -0
  48. package/src/actions/errorBands/index.js +7 -0
  49. package/src/actions/errorBands/resolve.js +28 -0
  50. package/src/actions/errorBars/components.js +62 -0
  51. package/src/actions/errorBars/create.js +144 -0
  52. package/src/actions/errorBars/index.js +7 -0
  53. package/src/actions/errorBars/resolve.js +25 -0
  54. package/src/actions/guides/axes/axes.js +204 -0
  55. package/src/actions/guides/axes/axis.js +131 -0
  56. package/src/actions/guides/axes/index.js +17 -0
  57. package/src/actions/guides/axes/labels.js +231 -0
  58. package/src/actions/guides/axes/lines.js +149 -0
  59. package/src/actions/guides/axes/policy.js +155 -0
  60. package/src/actions/guides/axes/tickGroups.js +149 -0
  61. package/src/actions/guides/axes/ticks.js +179 -0
  62. package/src/actions/guides/axes/titles.js +264 -0
  63. package/src/actions/guides/grids/grid.js +228 -0
  64. package/src/actions/guides/grids/index.js +1 -0
  65. package/src/actions/guides/grids/resolve.js +258 -0
  66. package/src/actions/guides/guides.js +138 -0
  67. package/src/actions/guides/index.js +11 -0
  68. package/src/actions/guides/legends/categorical/actions.js +329 -0
  69. package/src/actions/guides/legends/categorical/components.js +140 -0
  70. package/src/actions/guides/legends/categorical/index.js +49 -0
  71. package/src/actions/guides/legends/categorical/layout.js +445 -0
  72. package/src/actions/guides/legends/categorical/options.js +188 -0
  73. package/src/actions/guides/legends/categorical/recipes.js +120 -0
  74. package/src/actions/guides/legends/categorical/resolve.js +131 -0
  75. package/src/actions/guides/legends/categorical/symbols.js +280 -0
  76. package/src/actions/guides/legends/categorical/validation.js +27 -0
  77. package/src/actions/guides/legends/continuous/common.js +273 -0
  78. package/src/actions/guides/legends/continuous/gradient.js +363 -0
  79. package/src/actions/guides/legends/continuous/index.js +25 -0
  80. package/src/actions/guides/legends/continuous/interval.js +234 -0
  81. package/src/actions/guides/legends/continuous/opacity.js +382 -0
  82. package/src/actions/guides/legends/edit.js +314 -0
  83. package/src/actions/guides/legends/index.js +9 -0
  84. package/src/actions/guides/legends/size.js +220 -0
  85. package/src/actions/guides/tickValues.js +84 -0
  86. package/src/actions/index.js +31 -0
  87. package/src/actions/intervals/resolve.js +352 -0
  88. package/src/actions/marks/area.js +369 -0
  89. package/src/actions/marks/bar/create.js +46 -0
  90. package/src/actions/marks/bar/edit.js +90 -0
  91. package/src/actions/marks/bar/index.js +9 -0
  92. package/src/actions/marks/bar/materialize.js +130 -0
  93. package/src/actions/marks/index.js +13 -0
  94. package/src/actions/marks/line.js +248 -0
  95. package/src/actions/marks/point.js +420 -0
  96. package/src/actions/marks/rule.js +287 -0
  97. package/src/actions/marks/shared.js +112 -0
  98. package/src/actions/primitives/createGraphics.js +163 -0
  99. package/src/actions/primitives/editGraphics.js +208 -0
  100. package/src/actions/primitives/index.js +9 -0
  101. package/src/actions/primitives/semantic.js +168 -0
  102. package/src/actions/primitives/semanticValue.js +182 -0
  103. package/src/actions/regression/components.js +216 -0
  104. package/src/actions/regression/create.js +102 -0
  105. package/src/actions/regression/index.js +23 -0
  106. package/src/actions/regression/resolve.js +57 -0
  107. package/src/actions/scales/consumers.js +283 -0
  108. package/src/actions/scales/create.js +148 -0
  109. package/src/actions/scales/definitions.js +319 -0
  110. package/src/actions/scales/edit.js +290 -0
  111. package/src/actions/scales/index.js +11 -0
  112. package/src/actions/scales/materialize.js +466 -0
  113. package/src/actions/scales/quantitativeColor.js +45 -0
  114. package/src/actions/selection/actions.js +384 -0
  115. package/src/actions/selection/index.js +23 -0
  116. package/src/actions/titles/actions.js +235 -0
  117. package/src/actions/titles/index.js +19 -0
  118. package/src/actions/titles/resolve.js +321 -0
  119. package/src/core/ChartProgram.js +316 -0
  120. package/src/core/action.js +120 -0
  121. package/src/core/identifiers.js +28 -0
  122. package/src/core/immutable.js +94 -0
  123. package/src/core/specs.js +29 -0
  124. package/src/core/textMetrics.js +23 -0
  125. package/src/core/validation.js +54 -0
  126. package/src/core/vocabulary.js +58 -0
  127. package/src/extension.js +2 -0
  128. package/src/grammar/aggregate.js +259 -0
  129. package/src/grammar/areaSeries.js +217 -0
  130. package/src/grammar/bars/aggregate.js +98 -0
  131. package/src/grammar/bars/geometry.js +54 -0
  132. package/src/grammar/bars/policy.js +90 -0
  133. package/src/grammar/boxPlot.js +140 -0
  134. package/src/grammar/coordinates.js +25 -0
  135. package/src/grammar/curveCommands.js +356 -0
  136. package/src/grammar/density.js +296 -0
  137. package/src/grammar/filter.js +169 -0
  138. package/src/grammar/histogram.js +332 -0
  139. package/src/grammar/interval.js +343 -0
  140. package/src/grammar/lineSeries.js +197 -0
  141. package/src/grammar/markFilter.js +46 -0
  142. package/src/grammar/markSelection.js +326 -0
  143. package/src/grammar/palettes.js +208 -0
  144. package/src/grammar/pathCommands.js +86 -0
  145. package/src/grammar/pointShapes.js +164 -0
  146. package/src/grammar/positionCompatibility.js +32 -0
  147. package/src/grammar/regression.js +578 -0
  148. package/src/grammar/ruleAppearance.js +12 -0
  149. package/src/grammar/rules.js +90 -0
  150. package/src/grammar/scales/appearance.js +185 -0
  151. package/src/grammar/scales/color.js +349 -0
  152. package/src/grammar/scales/continuous.js +111 -0
  153. package/src/grammar/scales/definition.js +153 -0
  154. package/src/grammar/scales/discretized.js +159 -0
  155. package/src/grammar/scales/fields.js +133 -0
  156. package/src/grammar/scales/index.js +12 -0
  157. package/src/grammar/scales/mapping.js +27 -0
  158. package/src/grammar/scales/ordinal.js +221 -0
  159. package/src/grammar/scales/policies.js +50 -0
  160. package/src/grammar/scales/temporal.js +53 -0
  161. package/src/grammar/scales/transformed.js +236 -0
  162. package/src/grammar/scales/types.js +102 -0
  163. package/src/grammar/scales/validation.js +66 -0
  164. package/src/grammar/scales.js +1 -0
  165. package/src/grammar/schemas/concreteGraphic.js +73 -0
  166. package/src/grammar/schemas/graphic.js +131 -0
  167. package/src/grammar/schemas/graphicBounds.js +146 -0
  168. package/src/grammar/schemas/graphicTree.js +133 -0
  169. package/src/grammar/schemas/mark.js +4 -0
  170. package/src/grammar/schemas/semanticPath.js +174 -0
  171. package/src/grammar/seriesLayout.js +76 -0
  172. package/src/grammar/ticks.js +149 -0
  173. package/src/grammar/transforms.js +37 -0
  174. package/src/index.js +2 -0
  175. package/src/layout/canvas.js +114 -0
  176. package/src/layout/grid.js +17 -0
  177. package/src/layout/legend.js +51 -0
  178. package/src/layout/text.js +62 -0
  179. package/src/layout/title.js +107 -0
  180. package/src/materialization/bars/aggregate.js +184 -0
  181. package/src/materialization/bars/grouped.js +117 -0
  182. package/src/materialization/bars/histogram.js +163 -0
  183. package/src/materialization/bars/ranged.js +53 -0
  184. package/src/materialization/bars/resolve.js +56 -0
  185. package/src/materialization/dataProvenance.js +15 -0
  186. package/src/materialization/density.js +29 -0
  187. package/src/materialization/dependencies.js +134 -0
  188. package/src/materialization/encodings.js +50 -0
  189. package/src/materialization/graphicHierarchy.js +104 -0
  190. package/src/materialization/legends.js +20 -0
  191. package/src/materialization/marks.js +110 -0
  192. package/src/materialization/planner.js +38 -0
  193. package/src/materialization/selection/filter.js +40 -0
  194. package/src/materialization/selection/items.js +503 -0
  195. package/src/materialization/selection/path.js +37 -0
  196. package/src/materialization/selection/point.js +118 -0
  197. package/src/materialization/selection/policies/area.js +10 -0
  198. package/src/materialization/selection/policies/bar.js +10 -0
  199. package/src/materialization/selection/policies/index.js +40 -0
  200. package/src/materialization/selection/policies/line.js +10 -0
  201. package/src/materialization/selection/policies/point.js +10 -0
  202. package/src/materialization/selection/policies/rule.js +10 -0
  203. package/src/materialization/selection/state.js +67 -0
  204. package/src/materialization/selection/styles.js +183 -0
  205. package/src/renderers/canvas/circle.js +62 -0
  206. package/src/renderers/canvas/index.js +132 -0
  207. package/src/renderers/canvas/line.js +54 -0
  208. package/src/renderers/canvas/path.js +98 -0
  209. package/src/renderers/canvas/rect.js +57 -0
  210. package/src/renderers/canvas/text.js +96 -0
  211. package/src/renderers/canvas/validation.js +23 -0
  212. package/src/renderers/png.js +29 -0
  213. package/src/selectors/coordinates.js +13 -0
  214. package/src/selectors/datasets.js +13 -0
  215. package/src/selectors/index.js +4 -0
  216. package/src/selectors/layers.js +32 -0
  217. package/src/selectors/scales.js +21 -0
  218. package/src/theme/defaults.js +13 -0
  219. package/types/extension.d.ts +14 -0
  220. package/types/index.d.ts +81 -0
  221. package/types/png.d.ts +14 -0
  222. package/types/program.d.ts +1096 -0
@@ -0,0 +1,62 @@
1
+ import { action } from "../../core/action.js";
2
+ import { validateUserId } from "../../core/identifiers.js";
3
+ import { validateKeys } from "../../core/validation.js";
4
+ import { deriveKernelDensity } from "../../grammar/density.js";
5
+ import { MATERIALIZE_OPTIONS, requireDerivedDataset } from "./shared.js";
6
+
7
+ const OPTIONS = Object.freeze([
8
+ "id", "source", "field", "groupBy", "bandwidth", "extent", "steps",
9
+ "kernel", "normalization", "as"
10
+ ]);
11
+
12
+ export const materializeDensityData = action(
13
+ { op: "materializeDensityData", description: "Materialize one grouped kernel-density dataset." },
14
+ function (args = {}) {
15
+ validateKeys(args, MATERIALIZE_OPTIONS, "materializeDensityData");
16
+ const { id, source, transform } = requireDerivedDataset(
17
+ this,
18
+ args.id,
19
+ "density"
20
+ );
21
+ const result = deriveKernelDensity(source.values, transform);
22
+ return this
23
+ .editSemantic({
24
+ property: `dataset[${id}].transform`,
25
+ value: [{ ...transform, bandwidth: result.bandwidth }]
26
+ })
27
+ .editSemantic({
28
+ property: `dataset[${id}].values`,
29
+ value: result.values
30
+ });
31
+ }
32
+ );
33
+
34
+ export const createDensityData = action(
35
+ { op: "createDensityData", description: "Create grouped kernel-density values." },
36
+ function (args = {}) {
37
+ validateKeys(args, OPTIONS, "createDensityData");
38
+ const id = validateUserId(args.id, "Density dataset id");
39
+ const source = validateUserId(
40
+ args.source ?? this.context.currentData,
41
+ "Source dataset id"
42
+ );
43
+ if (typeof args.field !== "string" || args.field.length === 0) {
44
+ throw new TypeError("createDensityData requires a non-empty field string.");
45
+ }
46
+ const transform = {
47
+ type: "density",
48
+ field: args.field,
49
+ ...(args.groupBy === undefined ? {} : { groupBy: args.groupBy }),
50
+ bandwidth: args.bandwidth ?? "auto",
51
+ extent: args.extent ?? "auto",
52
+ steps: args.steps ?? 100,
53
+ kernel: args.kernel ?? "gaussian",
54
+ normalization: args.normalization ?? "unit",
55
+ as: args.as ?? [`${args.field}_value`, `${args.field}_density`],
56
+ resolve: "shared"
57
+ };
58
+ return this
59
+ .createDerivedData({ id, source, transform: [transform] })
60
+ .materializeDensityData({ id });
61
+ }
62
+ );
@@ -0,0 +1,52 @@
1
+ import { action } from "../../core/action.js";
2
+ import { validateUserId } from "../../core/identifiers.js";
3
+ import { validateKeys } from "../../core/validation.js";
4
+ import { hasDataset } from "../../selectors/index.js";
5
+ import { findDataset } from "../../selectors/datasets.js";
6
+
7
+ const OPTIONS = Object.freeze(["id", "source", "transform"]);
8
+ const RELEASE_OPTIONS = Object.freeze(["id"]);
9
+
10
+ export const createDerivedData = action(
11
+ { op: "createDerivedData", description: "Create an immutable derived dataset definition." },
12
+ function (args = {}) {
13
+ validateKeys(args, OPTIONS, "createDerivedData");
14
+ const id = validateUserId(args.id, "Derived dataset id");
15
+ const source = validateUserId(args.source, "Source dataset id");
16
+ if (hasDataset(this, id)) {
17
+ throw new Error(`Dataset "${id}" already exists.`);
18
+ }
19
+ if (!hasDataset(this, source)) {
20
+ throw new Error(`Unknown source dataset "${source}".`);
21
+ }
22
+ return this
23
+ .editSemantic({ property: `dataset[${id}].source`, value: source })
24
+ .editSemantic({ property: `dataset[${id}].transform`, value: args.transform });
25
+ }
26
+ );
27
+
28
+ export const releaseDerivedData = action(
29
+ {
30
+ op: "releaseDerivedData",
31
+ description: "Release one unreferenced derived dataset."
32
+ },
33
+ function (args = {}) {
34
+ validateKeys(args, RELEASE_OPTIONS, "releaseDerivedData");
35
+ const validatedId = validateUserId(args.id, "Derived dataset id");
36
+ const dataset = findDataset(this, validatedId);
37
+ if (dataset === undefined || dataset.source === undefined) {
38
+ throw new Error(`Unknown derived dataset "${validatedId}".`);
39
+ }
40
+ const referenced = this.semanticSpec.layers.some(
41
+ layer => layer.data === validatedId
42
+ ) || this.semanticSpec.datasets.some(
43
+ candidate => candidate.source === validatedId
44
+ );
45
+ return referenced
46
+ ? this
47
+ : this.editSemantic({
48
+ property: `dataset[${validatedId}]`,
49
+ remove: true
50
+ });
51
+ }
52
+ );
@@ -0,0 +1,168 @@
1
+ import { action } from "../../core/action.js";
2
+ import { validateUserId } from "../../core/identifiers.js";
3
+ import { validateKeys } from "../../core/validation.js";
4
+ import {
5
+ deriveFilteredRows,
6
+ normalizeFilterTransform
7
+ } from "../../grammar/filter.js";
8
+ import {
9
+ deriveMarkFilteredRows,
10
+ normalizeMarkFilterTransform
11
+ } from "../../grammar/markFilter.js";
12
+ import { resolveMarkFilterSelection } from "../../materialization/selection/filter.js";
13
+ import {
14
+ applyLayerDataRematerialization
15
+ } from "../../materialization/dependencies.js";
16
+ import {
17
+ hasDataset,
18
+ requireLayer,
19
+ resolveEligibleLayer
20
+ } from "../../selectors/index.js";
21
+ import { MATERIALIZE_OPTIONS, requireDerivedDataset } from "./shared.js";
22
+
23
+ const OPTIONS = Object.freeze([
24
+ "id", "source", "field", "oneOf", "predicate", "range"
25
+ ]);
26
+ const MARK_SELECTOR_KEYS = Object.freeze([
27
+ "grain", "field", "channel", "property", "op", "value", "values",
28
+ "min", "max", "inclusive", "count", "groupBy", "ties"
29
+ ]);
30
+ const MARK_OPTIONS = Object.freeze(["target", ...MARK_SELECTOR_KEYS]);
31
+
32
+ function retainedHistogramBoundaries(layer, items) {
33
+ if (layer.mark?.type !== "bar" || layer.encoding?.x?.bin === undefined) {
34
+ return undefined;
35
+ }
36
+ const boundaries = [...new Set(items.flatMap(item => [
37
+ item.channels.x,
38
+ item.channels.x2
39
+ ]).filter(Number.isFinite))].sort((left, right) => left - right);
40
+ return boundaries.length < 2 ? undefined : boundaries;
41
+ }
42
+
43
+ export const materializeFilteredData = action(
44
+ { op: "materializeFilteredData", description: "Materialize one filtered derived dataset." },
45
+ function (args = {}) {
46
+ validateKeys(args, MATERIALIZE_OPTIONS, "materializeFilteredData");
47
+ const { id, source, transform } = requireDerivedDataset(
48
+ this,
49
+ args.id,
50
+ "filter"
51
+ );
52
+ return this.editSemantic({
53
+ property: `dataset[${id}].values`,
54
+ value: deriveFilteredRows(source.values, transform)
55
+ });
56
+ }
57
+ );
58
+
59
+ export const filterData = action(
60
+ { op: "filterData", description: "Create a named dataset from one field filter." },
61
+ function (args = {}) {
62
+ validateKeys(args, OPTIONS, "filterData");
63
+ const id = validateUserId(args.id, "Filtered dataset id");
64
+ const source = validateUserId(
65
+ args.source ?? this.context.currentData,
66
+ "Source dataset id"
67
+ );
68
+ const transform = normalizeFilterTransform(args);
69
+ return this
70
+ .createDerivedData({
71
+ id,
72
+ source,
73
+ transform: [transform]
74
+ })
75
+ .materializeFilteredData({ id });
76
+ }
77
+ );
78
+
79
+ export const materializeMarkFilteredData = action(
80
+ {
81
+ op: "materializeMarkFilteredData",
82
+ description: "Materialize member rows retained by one final-item mark selection."
83
+ },
84
+ function (args = {}) {
85
+ validateKeys(args, MATERIALIZE_OPTIONS, "materializeMarkFilteredData");
86
+ const { id, dataset, source, transform } = requireDerivedDataset(
87
+ this,
88
+ args.id,
89
+ "markFilter"
90
+ );
91
+ const layer = requireLayer(this, transform.target);
92
+ if (layer?.data !== dataset.source) {
93
+ throw new Error(
94
+ `Mark filter target "${transform.target}" must still use source dataset "${dataset.source}".`
95
+ );
96
+ }
97
+ const resolved = resolveMarkFilterSelection(
98
+ this,
99
+ transform.target,
100
+ transform.selector
101
+ );
102
+ return this.editSemantic({
103
+ property: `dataset[${id}].values`,
104
+ value: deriveMarkFilteredRows(source.values, resolved.items, resolved.keys)
105
+ });
106
+ }
107
+ );
108
+
109
+ export const filterMarks = action(
110
+ {
111
+ op: "filterMarks",
112
+ description: "Retain selected final mark items through immutable derived data."
113
+ },
114
+ function (args = {}) {
115
+ validateKeys(args, MARK_OPTIONS, "filterMarks");
116
+ const target = args.target === undefined
117
+ ? undefined
118
+ : validateUserId(args.target, "Filter mark target id");
119
+ const layer = resolveEligibleLayer(this, {
120
+ target,
121
+ label: "filter mark",
122
+ predicate: candidate =>
123
+ candidate.data !== undefined &&
124
+ ["point", "bar", "line", "area", "rule"].includes(candidate.mark?.type)
125
+ });
126
+ const derivedId = `${layer.id}FilteredData`;
127
+ if (hasDataset(this, derivedId)) {
128
+ throw new Error(`Dataset "${derivedId}" already exists.`);
129
+ }
130
+ const selector = Object.fromEntries(
131
+ MARK_SELECTOR_KEYS.flatMap(key =>
132
+ Object.hasOwn(args, key) ? [[key, args[key]]] : []
133
+ )
134
+ );
135
+ const resolved = resolveMarkFilterSelection(this, layer.id, selector);
136
+ if (resolved.keys.length === 0) {
137
+ throw new Error("filterMarks requires at least one matching mark item.");
138
+ }
139
+ const transform = normalizeMarkFilterTransform(layer.id, resolved.selector);
140
+ const boundaries = retainedHistogramBoundaries(layer, resolved.items);
141
+ let next = this
142
+ .createDerivedData({
143
+ id: derivedId,
144
+ source: layer.data,
145
+ transform: [transform]
146
+ })
147
+ .materializeMarkFilteredData({ id: derivedId });
148
+ if (boundaries !== undefined) {
149
+ for (const property of ["maxBins", "step"]) {
150
+ if (Object.hasOwn(layer.encoding.x.bin, property)) {
151
+ next = next.editSemantic({
152
+ property: `layer[${layer.id}].encoding.x.bin.${property}`,
153
+ remove: true
154
+ });
155
+ }
156
+ }
157
+ next = next.editSemantic({
158
+ property: `layer[${layer.id}].encoding.x.bin.boundaries`,
159
+ value: boundaries
160
+ });
161
+ }
162
+ next = next.editSemantic({
163
+ property: `layer[${layer.id}].data`,
164
+ value: derivedId
165
+ });
166
+ return applyLayerDataRematerialization(next, layer.id);
167
+ }
168
+ );
@@ -0,0 +1,32 @@
1
+ import { createData } from "./create.js";
2
+ import { createDerivedData, releaseDerivedData } from "./derived.js";
3
+ import {
4
+ filterData,
5
+ filterMarks,
6
+ materializeFilteredData,
7
+ materializeMarkFilteredData
8
+ } from "./filter.js";
9
+ import { createRegressionData, materializeRegressionData } from "./regression.js";
10
+ import { createDensityData, materializeDensityData } from "./density.js";
11
+ import { createIntervalData, materializeIntervalData } from "./interval.js";
12
+ import { createBoxSummaryData, createBoxOutlierData, materializeBoxSummaryData, materializeBoxOutlierData } from "./box.js";
13
+
14
+ export function registerDataActions(ProgramClass) {
15
+ ProgramClass.prototype.createData = createData;
16
+ ProgramClass.prototype.createDerivedData = createDerivedData;
17
+ ProgramClass.prototype.releaseDerivedData = releaseDerivedData;
18
+ ProgramClass.prototype.createDensityData = createDensityData;
19
+ ProgramClass.prototype.materializeFilteredData = materializeFilteredData;
20
+ ProgramClass.prototype.materializeMarkFilteredData = materializeMarkFilteredData;
21
+ ProgramClass.prototype.filterData = filterData;
22
+ ProgramClass.prototype.filterMarks = filterMarks;
23
+ ProgramClass.prototype.materializeRegressionData = materializeRegressionData;
24
+ ProgramClass.prototype.materializeDensityData = materializeDensityData;
25
+ ProgramClass.prototype.createRegressionData = createRegressionData;
26
+ ProgramClass.prototype.materializeIntervalData = materializeIntervalData;
27
+ ProgramClass.prototype.createIntervalData = createIntervalData;
28
+ ProgramClass.prototype.createBoxSummaryData = createBoxSummaryData;
29
+ ProgramClass.prototype.createBoxOutlierData = createBoxOutlierData;
30
+ ProgramClass.prototype.materializeBoxSummaryData = materializeBoxSummaryData;
31
+ ProgramClass.prototype.materializeBoxOutlierData = materializeBoxOutlierData;
32
+ }
@@ -0,0 +1,69 @@
1
+ import { action } from "../../core/action.js";
2
+ import { validateUserId } from "../../core/identifiers.js";
3
+ import { validateKeys } from "../../core/validation.js";
4
+ import {
5
+ deriveInterval,
6
+ normalizeIntervalTransform
7
+ } from "../../grammar/interval.js";
8
+ import { MATERIALIZE_OPTIONS, requireDerivedDataset } from "./shared.js";
9
+
10
+ const OPTIONS = Object.freeze([
11
+ "id",
12
+ "source",
13
+ "field",
14
+ "groupBy",
15
+ "center",
16
+ "extent",
17
+ "level",
18
+ "as"
19
+ ]);
20
+
21
+ export const materializeIntervalData = action(
22
+ {
23
+ op: "materializeIntervalData",
24
+ description: "Materialize one grouped interval-summary dataset."
25
+ },
26
+ function (args = {}) {
27
+ validateKeys(args, MATERIALIZE_OPTIONS, "materializeIntervalData");
28
+ const { id, source, transform } = requireDerivedDataset(
29
+ this,
30
+ args.id,
31
+ "interval"
32
+ );
33
+ return this.editSemantic({
34
+ property: `dataset[${id}].values`,
35
+ value: deriveInterval(source.values, transform)
36
+ });
37
+ }
38
+ );
39
+
40
+ export const createIntervalData = action(
41
+ {
42
+ op: "createIntervalData",
43
+ description: "Create immutable grouped interval-summary values."
44
+ },
45
+ function (args = {}) {
46
+ validateKeys(args, OPTIONS, "createIntervalData");
47
+ const id = validateUserId(args.id, "Interval dataset id");
48
+ const source = validateUserId(
49
+ args.source ?? this.context.currentData,
50
+ "Source dataset id"
51
+ );
52
+ const as = args.as ?? {
53
+ center: `__${id}_center`,
54
+ lower: `__${id}_lower`,
55
+ upper: `__${id}_upper`
56
+ };
57
+ const transform = normalizeIntervalTransform({
58
+ field: args.field,
59
+ groupBy: args.groupBy,
60
+ center: args.center,
61
+ extent: args.extent,
62
+ level: args.level,
63
+ as
64
+ });
65
+ return this
66
+ .createDerivedData({ id, source, transform: [transform] })
67
+ .materializeIntervalData({ id });
68
+ }
69
+ );
@@ -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
+ deriveRegression,
6
+ normalizeRegressionParameters
7
+ } from "../../grammar/regression.js";
8
+ import { MATERIALIZE_OPTIONS, requireDerivedDataset } from "./shared.js";
9
+
10
+ const OPTIONS = Object.freeze([
11
+ "id", "source", "x", "y", "groupBy", "method", "degree", "span",
12
+ "confidence", "interval"
13
+ ]);
14
+
15
+ export const materializeRegressionData = action(
16
+ { op: "materializeRegressionData", description: "Materialize one regression derived dataset." },
17
+ function (args = {}) {
18
+ validateKeys(args, MATERIALIZE_OPTIONS, "materializeRegressionData");
19
+ const { id, source, transform } = requireDerivedDataset(
20
+ this,
21
+ args.id,
22
+ "regression"
23
+ );
24
+ const result = deriveRegression(source.values, {
25
+ x: transform.x,
26
+ y: transform.y,
27
+ groupBy: transform.groupBy,
28
+ method: transform.method,
29
+ degree: transform.degree,
30
+ span: transform.span,
31
+ confidence: transform.confidence,
32
+ interval: transform.interval
33
+ });
34
+ return this.editSemantic({
35
+ property: `dataset[${id}].values`,
36
+ value: result.values
37
+ });
38
+ }
39
+ );
40
+
41
+ export const createRegressionData = action(
42
+ { op: "createRegressionData", description: "Create grouped regression values and optional interval bounds." },
43
+ function (args = {}) {
44
+ validateKeys(args, OPTIONS, "createRegressionData");
45
+ const parameters = normalizeRegressionParameters(args);
46
+ const id = validateUserId(args.id, "Regression dataset id");
47
+ const source = validateUserId(
48
+ args.source ?? this.context.currentData,
49
+ "Source dataset id"
50
+ );
51
+ const transform = {
52
+ type: "regression",
53
+ method: parameters.method,
54
+ x: args.x,
55
+ y: args.y,
56
+ ...(args.groupBy === undefined ? {} : { groupBy: args.groupBy }),
57
+ ...(parameters.method === "polynomial"
58
+ ? { degree: parameters.degree }
59
+ : {}),
60
+ ...(parameters.method === "loess"
61
+ ? { span: parameters.span }
62
+ : {
63
+ confidence: parameters.confidence,
64
+ interval: parameters.interval
65
+ })
66
+ };
67
+ return this
68
+ .createDerivedData({ id, source, transform: [transform] })
69
+ .materializeRegressionData({ id });
70
+ }
71
+ );
@@ -0,0 +1,25 @@
1
+ import { validateUserId } from "../../core/identifiers.js";
2
+ import { findDataset } from "../../selectors/datasets.js";
3
+
4
+ export const MATERIALIZE_OPTIONS = Object.freeze(["id"]);
5
+
6
+ export function requireDerivedDataset(program, id, type) {
7
+ const validatedId = validateUserId(id, "Derived dataset id");
8
+ const dataset = findDataset(program, validatedId);
9
+ if (dataset === undefined || dataset.source === undefined) {
10
+ throw new Error(`Unknown derived dataset "${validatedId}".`);
11
+ }
12
+ if (dataset.values !== undefined) {
13
+ throw new Error(`Derived dataset "${validatedId}" is already materialized.`);
14
+ }
15
+ const source = findDataset(program, dataset.source);
16
+ if (source?.values === undefined) {
17
+ throw new Error(`Source dataset "${dataset.source}" has no values.`);
18
+ }
19
+ if (dataset.transform?.length !== 1 || dataset.transform[0].type !== type) {
20
+ throw new Error(
21
+ `Derived dataset "${validatedId}" requires one ${type} transform.`
22
+ );
23
+ }
24
+ return { id: validatedId, dataset, source, transform: dataset.transform[0] };
25
+ }