ggaction 0.0.13 → 0.0.16

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 (359) hide show
  1. package/CHANGELOG.md +146 -0
  2. package/README.md +41 -12
  3. package/knowledge/action-cards.json +1 -1
  4. package/knowledge/intent-taxonomy.json +1 -1
  5. package/knowledge/mcp-resources.json +1 -1
  6. package/knowledge/task-packet.schema.json +1 -1
  7. package/knowledge/task-resolver.js +1 -1
  8. package/package.json +39 -7
  9. package/src/BasicChartProgram.js +3 -1
  10. package/src/ChartProgram.js +2 -0
  11. package/src/accessibility.js +157 -0
  12. package/src/actions/basic.js +2 -2
  13. package/src/actions/boxPlots/components.js +20 -12
  14. package/src/actions/boxPlots/create.js +4 -5
  15. package/src/actions/boxPlots/edit.js +34 -9
  16. package/src/actions/boxPlots/materialize.js +12 -4
  17. package/src/actions/boxPlots/options.js +48 -16
  18. package/src/actions/canvas/actions.js +3 -3
  19. package/src/actions/canvas/fitting.js +1 -1
  20. package/src/actions/categoryOrder/index.js +21 -12
  21. package/src/actions/charts/area.js +6 -2
  22. package/src/actions/charts/bar.js +3 -2
  23. package/src/actions/charts/beeswarm.js +1 -1
  24. package/src/actions/charts/density.js +7 -3
  25. package/src/actions/charts/ecdf.js +6 -3
  26. package/src/actions/charts/endpoints.js +29 -7
  27. package/src/actions/charts/heatmap.js +3 -2
  28. package/src/actions/charts/histogram.js +5 -4
  29. package/src/actions/charts/horizon.js +4 -2
  30. package/src/actions/charts/interval-regression.js +7 -4
  31. package/src/actions/charts/line.js +4 -2
  32. package/src/actions/charts/parallel.js +9 -3
  33. package/src/actions/charts/pie.js +11 -3
  34. package/src/actions/charts/polar.js +17 -6
  35. package/src/actions/charts/radar.js +9 -3
  36. package/src/actions/charts/radial.js +12 -4
  37. package/src/actions/charts/raincloud.js +2 -2
  38. package/src/actions/charts/rug-strip.js +8 -4
  39. package/src/actions/charts/scatter.js +4 -2
  40. package/src/actions/composition/actions.js +29 -24
  41. package/src/actions/coordinates/actions.js +2 -2
  42. package/src/actions/coordinates/edit.js +76 -0
  43. package/src/actions/data/basicBin2d.js +4 -5
  44. package/src/actions/data/bin.js +3 -3
  45. package/src/actions/data/bin2d.js +63 -193
  46. package/src/actions/data/bin2dMaterialize.js +4 -5
  47. package/src/actions/data/box.js +4 -4
  48. package/src/actions/data/complete.js +26 -0
  49. package/src/actions/data/computed.js +4 -4
  50. package/src/actions/data/create.js +7 -14
  51. package/src/actions/data/density.js +15 -23
  52. package/src/actions/data/derived.js +57 -31
  53. package/src/actions/data/ecdf.js +2 -2
  54. package/src/actions/data/edit.js +551 -0
  55. package/src/actions/data/filter.js +28 -22
  56. package/src/actions/data/fold.js +2 -2
  57. package/src/actions/data/gradientProfile.js +2 -2
  58. package/src/actions/data/horizon.js +2 -2
  59. package/src/actions/data/impute.js +26 -0
  60. package/src/actions/data/index.js +62 -47
  61. package/src/actions/data/interval.js +2 -2
  62. package/src/actions/data/intervalEdit.js +26 -18
  63. package/src/actions/data/normalize.js +27 -0
  64. package/src/actions/data/regression.js +21 -27
  65. package/src/actions/data/revise.js +48 -0
  66. package/src/actions/data/revisionBindings.js +125 -0
  67. package/src/actions/data/shared.js +20 -4
  68. package/src/actions/data/stack.js +2 -2
  69. package/src/actions/data/summary.js +3 -3
  70. package/src/actions/data/timeUnit.js +6 -3
  71. package/src/actions/data/window.js +3 -3
  72. package/src/actions/encodings/angle.js +1 -1
  73. package/src/actions/encodings/appearance.js +4 -4
  74. package/src/actions/encodings/barWidth.js +1 -1
  75. package/src/actions/encodings/channels.js +415 -0
  76. package/src/actions/encodings/color/index.js +3 -2
  77. package/src/actions/encodings/density.js +7 -4
  78. package/src/actions/encodings/histogram.js +4 -3
  79. package/src/actions/encodings/horizon.js +6 -8
  80. package/src/actions/encodings/index.js +4 -0
  81. package/src/actions/encodings/offset.js +22 -15
  82. package/src/actions/encodings/parallel.js +4 -5
  83. package/src/actions/encodings/pathOrder.js +6 -11
  84. package/src/actions/encodings/position/apply.js +53 -7
  85. package/src/actions/encodings/position/index.js +14 -6
  86. package/src/actions/encodings/position/policies/bar.js +9 -0
  87. package/src/actions/encodings/position/resolve.js +24 -7
  88. package/src/actions/encodings/ranged.js +5 -5
  89. package/src/actions/encodings/remove.js +13 -9
  90. package/src/actions/encodings/ruleAppearance.js +2 -24
  91. package/src/actions/encodings/seriesLayout.js +2 -1
  92. package/src/actions/encodings/shared.js +82 -14
  93. package/src/actions/encodings/stroke.js +226 -0
  94. package/src/actions/encodings/strokeDash.js +2 -2
  95. package/src/actions/encodings/text.js +1 -1
  96. package/src/actions/errorBands/create.js +34 -20
  97. package/src/actions/errorBands/edit.js +34 -137
  98. package/src/actions/errorBars/create.js +43 -20
  99. package/src/actions/errorBars/edit.js +29 -125
  100. package/src/actions/facets/actions.js +267 -73
  101. package/src/actions/facets/derive.js +99 -28
  102. package/src/actions/facets/guides.js +4 -5
  103. package/src/actions/facets/replay.js +4 -5
  104. package/src/actions/gradientPlots/components.js +15 -8
  105. package/src/actions/gradientPlots/create.js +4 -5
  106. package/src/actions/gradientPlots/edit.js +18 -9
  107. package/src/actions/gradientPlots/materialize.js +5 -3
  108. package/src/actions/gradientPlots/options.js +10 -2
  109. package/src/actions/gradientPlots/rebind.js +4 -5
  110. package/src/actions/guides/applicability.js +8 -2
  111. package/src/actions/guides/axes/axes.js +23 -4
  112. package/src/actions/guides/axes/axis.js +2 -2
  113. package/src/actions/guides/axes/edit.js +2 -2
  114. package/src/actions/guides/axes/labels.js +67 -21
  115. package/src/actions/guides/axes/lines.js +15 -9
  116. package/src/actions/guides/axes/parallel/lifecycle.js +13 -13
  117. package/src/actions/guides/axes/parallel/resolve.js +6 -2
  118. package/src/actions/guides/axes/parallel.js +5 -5
  119. package/src/actions/guides/axes/remove.js +4 -4
  120. package/src/actions/guides/axes/tickGroups.js +6 -5
  121. package/src/actions/guides/axes/ticks.js +19 -6
  122. package/src/actions/guides/axes/titles.js +21 -13
  123. package/src/actions/guides/grids/grid.js +18 -29
  124. package/src/actions/guides/grids/resolve.js +7 -2
  125. package/src/actions/guides/guides.js +20 -4
  126. package/src/actions/guides/legends/blocks.js +426 -0
  127. package/src/actions/guides/legends/categorical/actions.js +138 -52
  128. package/src/actions/guides/legends/categorical/components.js +55 -45
  129. package/src/actions/guides/legends/categorical/index.js +37 -33
  130. package/src/actions/guides/legends/categorical/layout.js +98 -16
  131. package/src/actions/guides/legends/categorical/options.js +2 -2
  132. package/src/actions/guides/legends/categorical/recipes.js +111 -20
  133. package/src/actions/guides/legends/categorical/resolve.js +12 -8
  134. package/src/actions/guides/legends/categorical/symbols.js +104 -52
  135. package/src/actions/guides/legends/continuous/common.js +76 -20
  136. package/src/actions/guides/legends/continuous/gradient.js +95 -158
  137. package/src/actions/guides/legends/continuous/index.js +2 -0
  138. package/src/actions/guides/legends/continuous/interval.js +21 -16
  139. package/src/actions/guides/legends/continuous/opacity.js +37 -83
  140. package/src/actions/guides/legends/continuous/stroke.js +225 -0
  141. package/src/actions/guides/legends/creation.js +14 -1
  142. package/src/actions/guides/legends/edit.js +159 -60
  143. package/src/actions/guides/legends/focused.js +5 -5
  144. package/src/actions/guides/legends/index.js +2 -0
  145. package/src/actions/guides/legends/lane.js +59 -24
  146. package/src/actions/guides/legends/lifecycle.js +19 -8
  147. package/src/actions/guides/legends/remove.js +17 -8
  148. package/src/actions/guides/legends/sampling.js +140 -0
  149. package/src/actions/guides/legends/size.js +100 -108
  150. package/src/actions/guides/legends/strokeWidth.js +38 -92
  151. package/src/actions/guides/legends/target.js +112 -1
  152. package/src/actions/guides/legends/transition.js +165 -16
  153. package/src/actions/guides/polar/axes/facade.js +8 -8
  154. package/src/actions/guides/polar/axes/labels.js +29 -10
  155. package/src/actions/guides/polar/axes/lines.js +19 -19
  156. package/src/actions/guides/polar/axes/shared.js +16 -0
  157. package/src/actions/guides/polar/axes/ticks.js +10 -16
  158. package/src/actions/guides/polar/axes/titles.js +6 -6
  159. package/src/actions/guides/polar/grids.js +12 -14
  160. package/src/actions/guides/polar/resolve.js +12 -8
  161. package/src/actions/index.js +16 -3
  162. package/src/actions/intervals/revision.js +126 -0
  163. package/src/actions/marks/arc/actions.js +80 -22
  164. package/src/actions/marks/area/actions.js +38 -13
  165. package/src/actions/marks/area/materialize.js +17 -1
  166. package/src/actions/marks/bar/create.js +12 -3
  167. package/src/actions/marks/bar/edit.js +21 -4
  168. package/src/actions/marks/bar/materialize.js +34 -40
  169. package/src/actions/marks/index.js +10 -1
  170. package/src/actions/marks/line/actions.js +40 -17
  171. package/src/actions/marks/line/materialize.js +29 -10
  172. package/src/actions/marks/point/create.js +9 -3
  173. package/src/actions/marks/point/edit.js +19 -7
  174. package/src/actions/marks/point/jitter.js +6 -8
  175. package/src/actions/marks/point/materialize.js +48 -22
  176. package/src/actions/marks/point/packing.js +6 -8
  177. package/src/actions/marks/rect/actions.js +36 -15
  178. package/src/actions/marks/references.js +602 -33
  179. package/src/actions/marks/remove.js +67 -41
  180. package/src/actions/marks/rule/actions.js +51 -14
  181. package/src/actions/marks/shared.js +1 -1
  182. package/src/actions/marks/text/actions.js +79 -14
  183. package/src/actions/marks/text/index.js +4 -0
  184. package/src/actions/marks/text/layout.js +157 -17
  185. package/src/actions/marks/text/removal.js +173 -0
  186. package/src/actions/marks/text/selection.js +72 -0
  187. package/src/actions/marks/tick/actions.js +25 -8
  188. package/src/actions/primitives/createGraphics.js +5 -4
  189. package/src/actions/primitives/editGraphics.js +31 -4
  190. package/src/actions/primitives/graphicProperties.js +6 -0
  191. package/src/actions/primitives/semantic.js +11 -3
  192. package/src/actions/primitives/semanticAction.js +90 -14
  193. package/src/actions/primitives/semanticValidation/dataset.js +2 -4
  194. package/src/actions/primitives/semanticValidation/guide.js +1 -1
  195. package/src/actions/primitives/semanticValidation/index.js +9 -1
  196. package/src/actions/primitives/semanticValidation/layer.js +5 -0
  197. package/src/actions/primitives/semanticValidation/scale.js +28 -7
  198. package/src/actions/regression/components.js +36 -25
  199. package/src/actions/regression/create.js +13 -6
  200. package/src/actions/regression/edit.js +24 -11
  201. package/src/actions/resources/index.js +7 -0
  202. package/src/actions/resources/remove.js +173 -0
  203. package/src/actions/scales/channels.js +212 -0
  204. package/src/actions/scales/consumers/common.js +1 -1
  205. package/src/actions/scales/consumers/families.js +3 -2
  206. package/src/actions/scales/consumers/index.js +19 -2
  207. package/src/actions/scales/consumers/seriesLayout.js +28 -14
  208. package/src/actions/scales/create.js +55 -23
  209. package/src/actions/scales/definitions.js +94 -40
  210. package/src/actions/scales/edit.js +67 -12
  211. package/src/actions/scales/editPolicy.js +81 -11
  212. package/src/actions/scales/index.js +6 -0
  213. package/src/actions/scales/materialize.js +5 -4
  214. package/src/actions/scales/offset.js +48 -0
  215. package/src/actions/scales/parallel.js +71 -0
  216. package/src/actions/scales/preview.js +111 -10
  217. package/src/actions/scales/quantitativeColor.js +4 -5
  218. package/src/actions/selection/actions.js +179 -66
  219. package/src/actions/selection/index.js +3 -0
  220. package/src/actions/textMetrics/index.js +56 -0
  221. package/src/actions/theme/actions.js +70 -15
  222. package/src/actions/theme/composition.js +238 -0
  223. package/src/actions/theme/index.js +9 -2
  224. package/src/actions/theme/reconcile.js +313 -121
  225. package/src/actions/theme/state.js +160 -0
  226. package/src/actions/titles/actions.js +8 -8
  227. package/src/actions/titles/resolve.js +3 -3
  228. package/src/actions/violinPlots/create.js +6 -3
  229. package/src/actions/violinPlots/edit.js +2 -1
  230. package/src/core/action.js +117 -35
  231. package/src/core/compositionState.js +6 -1
  232. package/src/core/diagnostics.js +16 -0
  233. package/src/core/extensionRegistry.js +27 -0
  234. package/src/core/font.js +18 -0
  235. package/src/core/identifiers.js +5 -4
  236. package/src/core/immutable.js +10 -3
  237. package/src/core/optionRequirements.js +8 -0
  238. package/src/core/programState.js +21 -1
  239. package/src/core/resourceReferences.js +341 -0
  240. package/src/core/textMetricProfile.js +28 -0
  241. package/src/core/textMetrics.js +24 -3
  242. package/src/core/validation.js +22 -10
  243. package/src/core/vocabulary.js +16 -3
  244. package/src/diagnostics.js +1 -0
  245. package/src/grammar/bars/aggregate.js +4 -1
  246. package/src/grammar/bars/geometry.js +44 -0
  247. package/src/grammar/bin.js +54 -9
  248. package/src/grammar/complete.js +279 -0
  249. package/src/grammar/computed.js +265 -64
  250. package/src/grammar/coordinates.js +37 -0
  251. package/src/grammar/density.js +239 -37
  252. package/src/grammar/displayLabels.js +57 -0
  253. package/src/grammar/facets/dependencies.js +133 -1
  254. package/src/grammar/facets/guides.js +3 -0
  255. package/src/grammar/facets/index.js +7 -47
  256. package/src/grammar/facets/scales.js +15 -18
  257. package/src/grammar/impute.js +341 -0
  258. package/src/grammar/markLabelSelection.js +57 -0
  259. package/src/grammar/markLabels.js +18 -1
  260. package/src/grammar/normalize.js +366 -0
  261. package/src/grammar/pathSeries.js +26 -8
  262. package/src/grammar/pointShapes.js +13 -4
  263. package/src/grammar/polar.js +90 -8
  264. package/src/grammar/regression/index.js +1 -0
  265. package/src/grammar/regression/parameters.js +23 -0
  266. package/src/grammar/roundedRect.js +180 -0
  267. package/src/grammar/rules.js +1 -0
  268. package/src/grammar/scales/colorConsumers.js +20 -1
  269. package/src/grammar/scales/continuous.js +2 -2
  270. package/src/grammar/scales/definition.js +27 -4
  271. package/src/grammar/scales/index.js +1 -0
  272. package/src/grammar/scales/ordinal.js +12 -3
  273. package/src/grammar/scales/policies.js +2 -2
  274. package/src/grammar/scales/size.js +456 -0
  275. package/src/grammar/scales/types.js +8 -0
  276. package/src/grammar/schemas/concreteGraphic.js +14 -2
  277. package/src/grammar/schemas/graphic.js +15 -0
  278. package/src/grammar/schemas/graphicBounds.js +190 -41
  279. package/src/grammar/schemas/semanticPath.js +7 -2
  280. package/src/grammar/statisticalReference.js +103 -0
  281. package/src/grammar/strokeStyle.js +77 -0
  282. package/src/grammar/summary.js +78 -16
  283. package/src/grammar/timeUnit.js +216 -5
  284. package/src/grammar/transformTopology.js +4 -0
  285. package/src/grammar/transforms.js +394 -28
  286. package/src/grammar/weightedStatistics.js +374 -0
  287. package/src/grammar/window.js +221 -16
  288. package/src/layout/aspect.js +80 -0
  289. package/src/layout/facets.js +59 -5
  290. package/src/layout/labels.js +351 -7
  291. package/src/layout/legend.js +4 -4
  292. package/src/layout/legendItems.js +6 -6
  293. package/src/layout/text.js +10 -9
  294. package/src/layout/title.js +9 -9
  295. package/src/materialization/bars/aggregate.js +25 -2
  296. package/src/materialization/bars/histogram.js +84 -24
  297. package/src/materialization/bars/ranged.js +19 -3
  298. package/src/materialization/bars/resolve.js +7 -4
  299. package/src/materialization/composition.js +3 -1
  300. package/src/materialization/coordinateBounds.js +204 -0
  301. package/src/materialization/dependencies.js +36 -0
  302. package/src/materialization/facetGuides/legacyCategorical.js +3 -0
  303. package/src/materialization/facetGuides/placement.js +9 -3
  304. package/src/materialization/facetGuides/preparation.js +13 -8
  305. package/src/materialization/facetHeaders.js +347 -0
  306. package/src/materialization/facets.js +15 -65
  307. package/src/materialization/guides/layout.js +3 -3
  308. package/src/materialization/guides/resources.js +26 -0
  309. package/src/materialization/legends.js +1 -1
  310. package/src/materialization/marks/index.js +11 -5
  311. package/src/materialization/marks/policies.js +2 -1
  312. package/src/materialization/rect.js +25 -12
  313. package/src/materialization/rectConfig.js +5 -1
  314. package/src/materialization/scaleGuideDependencies.js +10 -0
  315. package/src/materialization/scales/map.js +5 -3
  316. package/src/materialization/scales/policies/binnedPosition.js +2 -2
  317. package/src/materialization/scales/policies/offset.js +50 -8
  318. package/src/materialization/scales/policies/series.js +4 -1
  319. package/src/materialization/scales/resolve.js +22 -6
  320. package/src/materialization/selection/items/arc.js +28 -4
  321. package/src/materialization/selection/items/bar.js +30 -3
  322. package/src/materialization/selection/items/common.js +20 -5
  323. package/src/materialization/selection/items/rect.js +28 -4
  324. package/src/materialization/selection/path.js +1 -1
  325. package/src/materialization/selection/point.js +3 -1
  326. package/src/materialization/text.js +265 -14
  327. package/src/materialization/typography.js +31 -0
  328. package/src/mcp/cli.js +5 -3
  329. package/src/persistence/codec.js +65 -0
  330. package/src/persistence/validation.js +185 -0
  331. package/src/persistence.js +74 -0
  332. package/src/renderers/canvas/circle.js +2 -3
  333. package/src/renderers/canvas/index.js +5 -4
  334. package/src/renderers/canvas/line.js +2 -3
  335. package/src/renderers/canvas/native.js +4 -4
  336. package/src/renderers/canvas/path.js +2 -3
  337. package/src/renderers/canvas/rect.js +2 -3
  338. package/src/renderers/canvas/stroke.js +11 -0
  339. package/src/renderers/nativeBackend.js +10 -0
  340. package/src/renderers/options.js +13 -0
  341. package/src/renderers/pdf.js +25 -54
  342. package/src/renderers/png.js +22 -17
  343. package/src/renderers/svg.js +29 -14
  344. package/src/renderers/text.js +1 -11
  345. package/src/selectors/coordinates.js +3 -1
  346. package/src/selectors/datasets.js +38 -5
  347. package/src/selectors/layers.js +10 -4
  348. package/src/selectors/markOwners.js +46 -0
  349. package/src/selectors/scales.js +6 -4
  350. package/src/theme/defaults.js +103 -1
  351. package/src/version.js +2 -0
  352. package/types/accessibility.d.ts +37 -0
  353. package/types/basic.d.ts +10 -2
  354. package/types/diagnostics.d.ts +15 -0
  355. package/types/index.d.ts +90 -0
  356. package/types/pdf.d.ts +9 -0
  357. package/types/persistence.d.ts +7 -0
  358. package/types/png.d.ts +9 -0
  359. package/types/program.d.ts +944 -118
@@ -0,0 +1,366 @@
1
+ import { cloneAndFreeze, isPlainObject } from "../core/immutable.js";
2
+ import {
3
+ inverseLerp,
4
+ numericExtent,
5
+ requireFiniteResult,
6
+ stableFiniteDeviation,
7
+ stableFiniteSum
8
+ } from "./numeric.js";
9
+
10
+ const TRANSFORM_KEYS = Object.freeze([
11
+ "type", "field", "as", "groupBy", "method", "variance",
12
+ "zeroDenominator", "baseline", "sortBy"
13
+ ]);
14
+ const METHODS = Object.freeze([
15
+ "share", "zscore", "minmax", "index", "change", "percentChange"
16
+ ]);
17
+ const ZERO_POLICIES = Object.freeze(["error", "null", "zero"]);
18
+ const SORT_KEYS = Object.freeze(["field", "order"]);
19
+ const ORDERS = Object.freeze(["ascending", "descending"]);
20
+ const BASELINE_KEYS = Object.freeze(["position", "value"]);
21
+ const BASELINE_METHODS = new Set(["index", "change", "percentChange"]);
22
+
23
+ function rejectUnknownKeys(value, supported, label) {
24
+ const unknown = Object.keys(value).find(key => !supported.includes(key));
25
+ if (unknown !== undefined) throw new Error(`Unknown ${label} property "${unknown}".`);
26
+ }
27
+
28
+ function requireField(value, label) {
29
+ if (typeof value !== "string" || value.length === 0) {
30
+ throw new TypeError(`${label} must be a non-empty string.`);
31
+ }
32
+ return value;
33
+ }
34
+
35
+ function normalizeGroupBy(value) {
36
+ if (value === undefined) return [];
37
+ return Array.isArray(value) ? [...value] : [value];
38
+ }
39
+
40
+ function validateGroupBy(groupBy) {
41
+ if (!Array.isArray(groupBy) || groupBy.some(field =>
42
+ typeof field !== "string" || field.length === 0
43
+ )) {
44
+ throw new TypeError("Normalize groupBy must contain field names.");
45
+ }
46
+ if (new Set(groupBy).size !== groupBy.length) {
47
+ throw new Error("Normalize groupBy fields must be unique.");
48
+ }
49
+ }
50
+
51
+ function normalizeSortBy(value) {
52
+ if (value === undefined) return [];
53
+ if (!Array.isArray(value)) return value;
54
+ return value.map(sort => isPlainObject(sort)
55
+ ? { ...sort, order: sort.order ?? "ascending" }
56
+ : sort
57
+ );
58
+ }
59
+
60
+ function validateSortBy(sortBy) {
61
+ if (!Array.isArray(sortBy)) throw new TypeError("Normalize sortBy must be an array.");
62
+ const fields = [];
63
+ sortBy.forEach((sort, index) => {
64
+ if (!isPlainObject(sort)) {
65
+ throw new TypeError(`Normalize sortBy[${index}] must be a plain object.`);
66
+ }
67
+ rejectUnknownKeys(sort, SORT_KEYS, `normalize sortBy[${index}]`);
68
+ fields.push(requireField(sort.field, `Normalize sortBy[${index}].field`));
69
+ if (!ORDERS.includes(sort.order)) {
70
+ throw new Error(`Unsupported normalize sort order "${sort.order}".`);
71
+ }
72
+ });
73
+ if (new Set(fields).size !== fields.length) {
74
+ throw new Error("Normalize sortBy fields must be unique.");
75
+ }
76
+ }
77
+
78
+ function normalizeBaseline(value) {
79
+ if (!isPlainObject(value)) return value;
80
+ return { ...value };
81
+ }
82
+
83
+ function validateBaseline(baseline, sortBy) {
84
+ if (!isPlainObject(baseline)) {
85
+ throw new TypeError("Normalize baseline must be a plain object.");
86
+ }
87
+ rejectUnknownKeys(baseline, BASELINE_KEYS, "normalize baseline");
88
+ const modes = BASELINE_KEYS.filter(key => Object.hasOwn(baseline, key));
89
+ if (modes.length !== 1) {
90
+ throw new Error("Normalize baseline requires exactly one of position or value.");
91
+ }
92
+ if (modes[0] === "value") {
93
+ if (!Number.isFinite(baseline.value)) {
94
+ throw new TypeError("Normalize baseline value must be finite.");
95
+ }
96
+ } else {
97
+ if (!["first", "last"].includes(baseline.position)) {
98
+ throw new Error("Normalize baseline position must be first or last.");
99
+ }
100
+ if (sortBy.length === 0) {
101
+ throw new Error("Normalize baseline position requires non-empty sortBy.");
102
+ }
103
+ }
104
+ }
105
+
106
+ export function validateNormalizeTransform(transform) {
107
+ if (!isPlainObject(transform)) {
108
+ throw new TypeError("Normalize transform must be a plain object.");
109
+ }
110
+ rejectUnknownKeys(transform, TRANSFORM_KEYS, "normalize transform");
111
+ if (transform.type !== "normalize") {
112
+ throw new Error(`Unsupported normalize transform "${transform.type}".`);
113
+ }
114
+ requireField(transform.field, "Normalize field");
115
+ requireField(transform.as, "Normalize output field");
116
+ validateGroupBy(transform.groupBy);
117
+ if (!METHODS.includes(transform.method)) {
118
+ throw new Error(`Unsupported normalize method "${transform.method}".`);
119
+ }
120
+
121
+ const hasVariance = Object.hasOwn(transform, "variance");
122
+ const hasZero = Object.hasOwn(transform, "zeroDenominator");
123
+ const hasBaseline = Object.hasOwn(transform, "baseline");
124
+ const hasSort = Object.hasOwn(transform, "sortBy");
125
+ if (transform.method === "zscore") {
126
+ if (!["population", "sample"].includes(transform.variance)) {
127
+ throw new Error("Normalize zscore variance must be population or sample.");
128
+ }
129
+ } else if (hasVariance) {
130
+ throw new Error(`Normalize variance is not available for ${transform.method}.`);
131
+ }
132
+ if (hasZero && !ZERO_POLICIES.includes(transform.zeroDenominator)) {
133
+ throw new Error(`Unsupported normalize zeroDenominator "${transform.zeroDenominator}".`);
134
+ }
135
+ if (transform.method === "change" && hasZero) {
136
+ throw new Error("Normalize zeroDenominator is not available for change.");
137
+ }
138
+ if (BASELINE_METHODS.has(transform.method)) {
139
+ validateSortBy(transform.sortBy);
140
+ validateBaseline(transform.baseline, transform.sortBy);
141
+ } else {
142
+ if (hasBaseline) {
143
+ throw new Error(`Normalize baseline is not available for ${transform.method}.`);
144
+ }
145
+ if (hasSort) {
146
+ throw new Error(`Normalize sortBy is not available for ${transform.method}.`);
147
+ }
148
+ }
149
+ return transform;
150
+ }
151
+
152
+ export function normalizeNormalizeTransform(args = {}) {
153
+ const {
154
+ field,
155
+ as,
156
+ groupBy,
157
+ method,
158
+ variance,
159
+ zeroDenominator,
160
+ baseline,
161
+ sortBy
162
+ } = args;
163
+ const transform = {
164
+ type: "normalize",
165
+ field,
166
+ as,
167
+ groupBy: normalizeGroupBy(groupBy),
168
+ method
169
+ };
170
+ if (method === "zscore") transform.variance = variance ?? "population";
171
+ else if (Object.hasOwn(args, "variance")) transform.variance = variance;
172
+ if (method !== "change") transform.zeroDenominator = zeroDenominator ?? "error";
173
+ else if (Object.hasOwn(args, "zeroDenominator")) {
174
+ transform.zeroDenominator = zeroDenominator;
175
+ }
176
+ if (BASELINE_METHODS.has(method)) {
177
+ transform.baseline = normalizeBaseline(baseline ?? { position: "first" });
178
+ transform.sortBy = normalizeSortBy(sortBy);
179
+ } else {
180
+ if (Object.hasOwn(args, "baseline")) transform.baseline = normalizeBaseline(baseline);
181
+ if (Object.hasOwn(args, "sortBy")) transform.sortBy = normalizeSortBy(sortBy);
182
+ }
183
+ validateNormalizeTransform(transform);
184
+ return cloneAndFreeze(transform);
185
+ }
186
+
187
+ function scalarKey(value, label) {
188
+ if (value === null) return "null";
189
+ if (typeof value === "string") return `string:${value.length}:${value}`;
190
+ if (typeof value === "boolean") return `boolean:${value}`;
191
+ if (typeof value === "number" && Number.isFinite(value)) {
192
+ return `number:${Object.is(value, -0) ? 0 : value}`;
193
+ }
194
+ throw new TypeError(
195
+ `${label} must contain null, strings, booleans, or finite numbers.`
196
+ );
197
+ }
198
+
199
+ function compareScalar(left, right, label) {
200
+ const leftMissing = left === null || left === undefined;
201
+ const rightMissing = right === null || right === undefined;
202
+ if (leftMissing || rightMissing) {
203
+ if (leftMissing && rightMissing) return 0;
204
+ return leftMissing ? 1 : -1;
205
+ }
206
+ if (typeof left !== typeof right ||
207
+ !["number", "string", "boolean"].includes(typeof left) ||
208
+ typeof left === "number" && (!Number.isFinite(left) || !Number.isFinite(right))) {
209
+ throw new TypeError(`${label} must contain one comparable primitive type.`);
210
+ }
211
+ if (left === right) return 0;
212
+ return left < right ? -1 : 1;
213
+ }
214
+
215
+ function compareEntries(left, right, sortBy) {
216
+ for (const sort of sortBy) {
217
+ const comparison = compareScalar(
218
+ left.row[sort.field],
219
+ right.row[sort.field],
220
+ `Normalize sort field "${sort.field}"`
221
+ );
222
+ if (comparison !== 0) return sort.order === "ascending" ? comparison : -comparison;
223
+ }
224
+ return left.index - right.index;
225
+ }
226
+
227
+ function validateRows(rows, transform) {
228
+ if (!Array.isArray(rows) || !rows.every(isPlainObject)) {
229
+ throw new TypeError("Normalize source rows must be plain objects.");
230
+ }
231
+ if (rows.length === 0) return;
232
+ const fields = [
233
+ transform.field,
234
+ ...transform.groupBy,
235
+ ...(transform.sortBy ?? []).map(sort => sort.field)
236
+ ];
237
+ rows.forEach((row, index) => {
238
+ if (Object.hasOwn(row, transform.as)) {
239
+ throw new Error(`Normalize output field "${transform.as}" already exists.`);
240
+ }
241
+ for (const field of fields) {
242
+ if (!Object.hasOwn(row, field)) {
243
+ throw new Error(`Normalize source does not contain field "${field}" at row ${index}.`);
244
+ }
245
+ }
246
+ if (!Number.isFinite(row[transform.field])) {
247
+ throw new TypeError(
248
+ `Normalize field "${transform.field}" must contain finite numbers at row ${index}.`
249
+ );
250
+ }
251
+ for (const field of transform.groupBy) {
252
+ scalarKey(row[field], `Normalize group field "${field}"`);
253
+ }
254
+ for (const sort of transform.sortBy ?? []) {
255
+ compareScalar(
256
+ row[sort.field],
257
+ row[sort.field],
258
+ `Normalize sort field "${sort.field}"`
259
+ );
260
+ }
261
+ });
262
+ }
263
+
264
+ function groupRows(rows, transform) {
265
+ const groups = new Map();
266
+ rows.forEach((row, index) => {
267
+ const key = transform.groupBy.length === 0
268
+ ? "all"
269
+ : transform.groupBy.map(field =>
270
+ scalarKey(row[field], `Normalize group field "${field}"`)
271
+ ).join("\0");
272
+ if (!groups.has(key)) groups.set(key, []);
273
+ groups.get(key).push({ row, index });
274
+ });
275
+ return [...groups.values()];
276
+ }
277
+
278
+ function zeroResult(policy, method) {
279
+ if (policy === "null") return null;
280
+ if (policy === "zero") return 0;
281
+ throw new RangeError(`Normalize ${method} denominator is zero.`);
282
+ }
283
+
284
+ function finiteOutput(value, method) {
285
+ return requireFiniteResult(value, `Normalize ${method} output`);
286
+ }
287
+
288
+ function zscore(value, mean, deviation, method) {
289
+ const difference = value - mean;
290
+ return finiteOutput(
291
+ Number.isFinite(difference) ? difference / deviation : value / deviation - mean / deviation,
292
+ method
293
+ );
294
+ }
295
+
296
+ function applyGroup(group, transform, outputs) {
297
+ const values = group.map(entry => entry.row[transform.field]);
298
+ if (transform.method === "share" && values.some(value => value < 0)) {
299
+ throw new RangeError("Normalize share does not accept negative values.");
300
+ }
301
+ if (transform.method === "share") {
302
+ const total = stableFiniteSum(values, "Normalize share sum");
303
+ group.forEach((entry, index) => {
304
+ outputs[entry.index] = total === 0
305
+ ? zeroResult(transform.zeroDenominator, transform.method)
306
+ : finiteOutput(values[index] / total, transform.method);
307
+ });
308
+ return;
309
+ }
310
+ if (transform.method === "minmax") {
311
+ const [minimum, maximum] = numericExtent(values);
312
+ group.forEach((entry, index) => {
313
+ outputs[entry.index] = minimum === maximum
314
+ ? zeroResult(transform.zeroDenominator, transform.method)
315
+ : finiteOutput(inverseLerp(values[index], minimum, maximum), transform.method);
316
+ });
317
+ return;
318
+ }
319
+ if (transform.method === "zscore") {
320
+ if (transform.variance === "sample" && values.length < 2) {
321
+ throw new RangeError("Normalize sample zscore requires at least two values.");
322
+ }
323
+ const { mean, deviation } = stableFiniteDeviation(values, {
324
+ sample: transform.variance === "sample",
325
+ label: "Normalize zscore deviation"
326
+ });
327
+ group.forEach((entry, index) => {
328
+ outputs[entry.index] = deviation === 0
329
+ ? zeroResult(transform.zeroDenominator, transform.method)
330
+ : zscore(values[index], mean, deviation, transform.method);
331
+ });
332
+ return;
333
+ }
334
+
335
+ const sorted = [...group].sort((left, right) =>
336
+ compareEntries(left, right, transform.sortBy)
337
+ );
338
+ const baseline = Object.hasOwn(transform.baseline, "value")
339
+ ? transform.baseline.value
340
+ : sorted[transform.baseline.position === "first" ? 0 : sorted.length - 1]
341
+ .row[transform.field];
342
+ group.forEach(entry => {
343
+ const value = entry.row[transform.field];
344
+ if (transform.method === "change") {
345
+ outputs[entry.index] = finiteOutput(value - baseline, transform.method);
346
+ } else if (baseline === 0) {
347
+ outputs[entry.index] = zeroResult(transform.zeroDenominator, transform.method);
348
+ } else if (transform.method === "index") {
349
+ outputs[entry.index] = finiteOutput(value / baseline * 100, transform.method);
350
+ } else {
351
+ outputs[entry.index] = finiteOutput(value / baseline - 1, transform.method);
352
+ }
353
+ });
354
+ }
355
+
356
+ export function deriveNormalizedRows(rows, transform) {
357
+ validateNormalizeTransform(transform);
358
+ validateRows(rows, transform);
359
+ if (rows.length === 0) return cloneAndFreeze([]);
360
+ const outputs = new Array(rows.length);
361
+ for (const group of groupRows(rows, transform)) applyGroup(group, transform, outputs);
362
+ return cloneAndFreeze(rows.map((row, index) => ({
363
+ ...row,
364
+ [transform.as]: outputs[index]
365
+ })));
366
+ }
@@ -1,5 +1,9 @@
1
1
  import { validateNonEmptyString } from "../core/validation.js";
2
- import { readNominalField, readQuantitativeField } from "./scales/fields.js";
2
+ import {
3
+ readNominalField,
4
+ readQuantitativeField,
5
+ readScaleField
6
+ } from "./scales/fields.js";
3
7
 
4
8
  export function normalizeGroupFields(value) {
5
9
  const fields = Array.isArray(value) ? [...value] : [value];
@@ -36,9 +40,13 @@ export function readPathSeriesFields(rows, layer) {
36
40
  return fields;
37
41
  }
38
42
 
39
- function seriesValueIndex(rows, fields, field, channel) {
43
+ function seriesValueIndex(rows, fields, field, channel, encoding = {}) {
40
44
  const quantitative = channel === "strokeWidth" || channel === "opacity";
41
- const values = quantitative
45
+ const values = channel === "stroke"
46
+ ? readScaleField(rows, field, encoding.fieldType ?? "nominal", {
47
+ temporalUnit: encoding.temporalUnit
48
+ })
49
+ : quantitative
42
50
  ? readQuantitativeField(rows, field)
43
51
  : readNominalField(rows, field);
44
52
  const result = new Map();
@@ -56,9 +64,15 @@ function seriesValueIndex(rows, fields, field, channel) {
56
64
  return result;
57
65
  }
58
66
 
59
- export function derivePathSeriesFieldValues(rows, series, field, channel) {
67
+ export function derivePathSeriesFieldValues(
68
+ rows,
69
+ series,
70
+ field,
71
+ channel,
72
+ encoding
73
+ ) {
60
74
  const fields = Object.keys(series[0]?.key ?? {});
61
- const values = seriesValueIndex(rows, fields, field, channel);
75
+ const values = seriesValueIndex(rows, fields, field, channel, encoding);
62
76
  return series.map(item => values.get(JSON.stringify(Object.values(item.key))));
63
77
  }
64
78
 
@@ -67,16 +81,20 @@ export function validatePathSeriesAppearance(rows, layer) {
67
81
  layer.encoding?.parallel !== undefined) return;
68
82
  const grouping = readPathSeriesFields(rows, layer);
69
83
  const channels = layer.mark.type === "line"
70
- ? ["color", "strokeDash", "strokeWidth", "opacity"] : ["color"];
84
+ ? ["color", "stroke", "strokeDash", "strokeWidth", "opacity"]
85
+ : ["color", "stroke"];
71
86
  for (const channel of channels) {
72
87
  const encoding = layer.encoding?.[channel];
73
88
  if (encoding?.field === undefined) continue;
74
- const allowed = channel === "color" ? ["nominal", "ordinal"]
89
+ const allowed = ["color", "stroke"].includes(channel)
90
+ ? channel === "color"
91
+ ? ["nominal", "ordinal"]
92
+ : ["nominal", "ordinal", "quantitative", "temporal"]
75
93
  : channel === "strokeDash" ? ["nominal"] : ["quantitative"];
76
94
  if (!allowed.includes(encoding.fieldType)) {
77
95
  throw new Error(`Path ${channel} encoding has an unsupported field type.`);
78
96
  }
79
- seriesValueIndex(rows, grouping, encoding.field, channel);
97
+ seriesValueIndex(rows, grouping, encoding.field, channel, encoding);
80
98
  }
81
99
  return grouping;
82
100
  }
@@ -1,5 +1,6 @@
1
1
  import { cloneAndFreeze } from "../core/immutable.js";
2
2
  import { buildLinearPathCommands } from "./pathCommands.js";
3
+ import { requestedStrokeDetails } from "./strokeStyle.js";
3
4
 
4
5
  export const POINT_SHAPES = cloneAndFreeze([
5
6
  "circle",
@@ -109,12 +110,13 @@ function normalizePolygon(points, x, y, area) {
109
110
  }));
110
111
  }
111
112
 
112
- function appearance(fill, stroke, strokeWidth, opacity) {
113
+ function appearance(fill, stroke, strokeWidth, opacity, strokeDetails) {
113
114
  return {
114
115
  fill,
115
116
  ...(stroke === undefined ? {} : { stroke }),
116
117
  ...(strokeWidth === undefined ? {} : { strokeWidth }),
117
- ...(opacity === undefined ? {} : { opacity })
118
+ ...(opacity === undefined ? {} : { opacity }),
119
+ ...requestedStrokeDetails(strokeDetails, "Point shape")
118
120
  };
119
121
  }
120
122
 
@@ -127,7 +129,10 @@ export function createPointShapeGraphic({
127
129
  stroke,
128
130
  strokeWidth,
129
131
  opacity,
130
- angle
132
+ angle,
133
+ lineCap,
134
+ lineJoin,
135
+ miterLimit
131
136
  }) {
132
137
  const validated = validatePointShape(shape);
133
138
  if (![x, y, area].every(Number.isFinite) || area < 0) {
@@ -136,7 +141,11 @@ export function createPointShapeGraphic({
136
141
  if (typeof fill !== "string" || fill.length === 0) {
137
142
  throw new TypeError("Point shape fill must be a non-empty string.");
138
143
  }
139
- const shared = appearance(fill, stroke, strokeWidth, opacity);
144
+ const shared = appearance(fill, stroke, strokeWidth, opacity, {
145
+ ...(lineCap === undefined ? {} : { lineCap }),
146
+ ...(lineJoin === undefined ? {} : { lineJoin }),
147
+ ...(miterLimit === undefined ? {} : { miterLimit })
148
+ });
140
149
  if (angle !== undefined && !Number.isFinite(angle)) {
141
150
  throw new TypeError("Point shape angle must be finite degrees.");
142
151
  }
@@ -1,6 +1,12 @@
1
1
  import { cloneAndFreeze, isPlainObject } from "../core/immutable.js";
2
+ import { validateOptionObject } from "../core/validation.js";
2
3
  import { validatePair } from "./scales/validation.js";
3
4
 
5
+ const POLAR_FRAME_OPTIONS = Object.freeze(["center", "radius"]);
6
+ const POLAR_CENTER_OPTIONS = Object.freeze(["x", "y"]);
7
+ const POLAR_RADIUS_OPTIONS = Object.freeze(["unit", "value"]);
8
+ const POLAR_RADIUS_UNITS = new Set(["fraction", "px"]);
9
+
4
10
  function validateBounds(bounds) {
5
11
  if (
6
12
  !isPlainObject(bounds) ||
@@ -15,12 +21,88 @@ function validateBounds(bounds) {
15
21
  return bounds;
16
22
  }
17
23
 
18
- export function resolvePolarFrame(bounds) {
24
+ function finiteUnitInterval(value, label) {
25
+ if (!Number.isFinite(value) || value < 0 || value > 1) {
26
+ throw new RangeError(`${label} must be a finite number from 0 through 1.`);
27
+ }
28
+ return value;
29
+ }
30
+
31
+ export function normalizePolarFrameOptions(value) {
32
+ if (value === "auto") return value;
33
+ if (!isPlainObject(value)) {
34
+ throw new TypeError('Polar frame must be "auto" or a plain object.');
35
+ }
36
+ validateOptionObject(value, POLAR_FRAME_OPTIONS, "polar frame");
37
+ const center = value.center ?? {};
38
+ if (!isPlainObject(center)) {
39
+ throw new TypeError("Polar frame center must be a plain object.");
40
+ }
41
+ validateOptionObject(center, POLAR_CENTER_OPTIONS, "polar frame center");
42
+ const radius = value.radius ?? { unit: "fraction", value: 1 };
43
+ if (!isPlainObject(radius)) {
44
+ throw new TypeError("Polar frame radius must be a plain object.");
45
+ }
46
+ validateOptionObject(radius, POLAR_RADIUS_OPTIONS, "polar frame radius", {
47
+ allowEmpty: false,
48
+ emptyError: TypeError
49
+ });
50
+ if (!POLAR_RADIUS_UNITS.has(radius.unit)) {
51
+ throw new Error(`Unknown Polar frame radius unit "${radius.unit}".`);
52
+ }
53
+ if (!Number.isFinite(radius.value) || radius.value <= 0) {
54
+ throw new RangeError("Polar frame radius must be a positive finite number.");
55
+ }
56
+ if (radius.unit === "fraction" && radius.value > 1) {
57
+ throw new RangeError("Polar frame radius fraction must not exceed 1.");
58
+ }
59
+ return cloneAndFreeze({
60
+ center: {
61
+ x: finiteUnitInterval(center.x ?? 0.5, "Polar frame center x"),
62
+ y: finiteUnitInterval(center.y ?? 0.5, "Polar frame center y")
63
+ },
64
+ radius: {
65
+ unit: radius.unit,
66
+ value: radius.value
67
+ }
68
+ });
69
+ }
70
+
71
+ export function resolvePolarFrame(bounds, requestedFrame = "auto") {
19
72
  validateBounds(bounds);
73
+ if (requestedFrame === undefined || requestedFrame === "auto") {
74
+ return cloneAndFreeze({
75
+ centerX: bounds.x + bounds.width / 2,
76
+ centerY: bounds.y + bounds.height / 2,
77
+ availableRadius: Math.min(bounds.width, bounds.height) / 2
78
+ });
79
+ }
80
+ const requested = normalizePolarFrameOptions(requestedFrame);
81
+ const centerX = bounds.x + bounds.width * requested.center.x;
82
+ const centerY = bounds.y + bounds.height * requested.center.y;
83
+ const maximumRadius = Math.min(
84
+ centerX - bounds.x,
85
+ bounds.x + bounds.width - centerX,
86
+ centerY - bounds.y,
87
+ bounds.y + bounds.height - centerY
88
+ );
89
+ if (!Number.isFinite(maximumRadius) || maximumRadius <= 0) {
90
+ throw new RangeError(
91
+ "Polar frame center must leave a positive radius inside its bounds."
92
+ );
93
+ }
94
+ const availableRadius = requested.radius.unit === "fraction"
95
+ ? maximumRadius * requested.radius.value
96
+ : requested.radius.value;
97
+ if (availableRadius > maximumRadius) {
98
+ throw new RangeError(
99
+ `Polar frame radius ${availableRadius} exceeds the maximum radius ${maximumRadius}.`
100
+ );
101
+ }
20
102
  return cloneAndFreeze({
21
- centerX: bounds.x + bounds.width / 2,
22
- centerY: bounds.y + bounds.height / 2,
23
- availableRadius: Math.min(bounds.width, bounds.height) / 2
103
+ centerX,
104
+ centerY,
105
+ availableRadius
24
106
  });
25
107
  }
26
108
 
@@ -50,7 +132,7 @@ export function validateRadialRange(range, availableRadius) {
50
132
  return validated;
51
133
  }
52
134
 
53
- export function resolvePolarScaleRange(range, channel, bounds) {
135
+ export function resolvePolarScaleRange(range, channel, bounds, frame) {
54
136
  if (channel === "theta") {
55
137
  return range === "auto"
56
138
  ? cloneAndFreeze([0, 360])
@@ -59,10 +141,10 @@ export function resolvePolarScaleRange(range, channel, bounds) {
59
141
  if (channel !== "radius") {
60
142
  throw new Error(`Unknown Polar position channel "${channel}".`);
61
143
  }
62
- const frame = resolvePolarFrame(bounds);
144
+ const resolvedFrame = frame ?? resolvePolarFrame(bounds);
63
145
  return range === "auto"
64
- ? cloneAndFreeze([0, frame.availableRadius])
65
- : validateRadialRange(range, frame.availableRadius);
146
+ ? cloneAndFreeze([0, resolvedFrame.availableRadius])
147
+ : validateRadialRange(range, resolvedFrame.availableRadius);
66
148
  }
67
149
 
68
150
  export function polarDirection(theta) {
@@ -9,6 +9,7 @@ export {
9
9
  } from "./derive.js";
10
10
  export {
11
11
  normalizeRegressionParameters,
12
+ normalizeRegressionTransform,
12
13
  validateRegressionTransform
13
14
  } from "./parameters.js";
14
15
 
@@ -139,3 +139,26 @@ export function validateRegressionTransform(transform) {
139
139
  }
140
140
  return transform;
141
141
  }
142
+
143
+ export function normalizeRegressionTransform(args = {}) {
144
+ const parameters = normalizeRegressionParameters(args);
145
+ const transform = {
146
+ type: "regression",
147
+ method: parameters.method,
148
+ x: args.x,
149
+ y: args.y,
150
+ ...(args.groupBy === undefined ? {} : { groupBy: args.groupBy }),
151
+ ...(parameters.method === "polynomial"
152
+ ? { degree: parameters.degree }
153
+ : {}),
154
+ ...(parameters.method === "loess"
155
+ ? { span: parameters.span }
156
+ : {
157
+ confidenceMethod: parameters.confidenceMethod,
158
+ level: parameters.level,
159
+ interval: parameters.interval
160
+ })
161
+ };
162
+ validateRegressionTransform(transform);
163
+ return cloneAndFreeze(transform);
164
+ }