ggaction 0.0.17 → 0.0.19

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 (315) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/README.md +6 -2
  3. package/knowledge/action-card.schema.json +1 -1
  4. package/knowledge/action-cards.json +1 -1
  5. package/knowledge/intent-taxonomy.json +1 -1
  6. package/knowledge/mcp-resources.json +1 -1
  7. package/knowledge/task-resolver.js +1 -1
  8. package/package.json +3 -3
  9. package/src/BasicChartProgram.js +1 -1
  10. package/src/accessibility.js +3 -2
  11. package/src/actions/boxPlots/create.js +14 -4
  12. package/src/actions/boxPlots/edit.js +39 -33
  13. package/src/actions/boxPlots/materialize.js +7 -3
  14. package/src/actions/boxPlots/options.js +37 -11
  15. package/src/actions/canvas/actions.js +70 -95
  16. package/src/actions/canvas/fitting.js +20 -1
  17. package/src/actions/canvas/index.js +3 -0
  18. package/src/actions/canvas/plotBorder.js +28 -0
  19. package/src/actions/charts/area.js +2 -2
  20. package/src/actions/charts/bar.js +34 -7
  21. package/src/actions/charts/ecdf.js +4 -18
  22. package/src/actions/charts/endpoints.js +4 -18
  23. package/src/actions/charts/heatmap.js +8 -7
  24. package/src/actions/charts/index.js +2 -0
  25. package/src/actions/charts/interval-regression.js +2 -2
  26. package/src/actions/charts/line.js +1 -1
  27. package/src/actions/charts/pie.js +3 -47
  28. package/src/actions/charts/radial.js +34 -12
  29. package/src/actions/charts/scatter.js +16 -2
  30. package/src/actions/charts/shared.js +2 -2
  31. package/src/actions/charts/text.js +35 -0
  32. package/src/actions/composition/actions.js +6 -2
  33. package/src/actions/data/box.js +2 -1
  34. package/src/actions/data/derived.js +11 -1
  35. package/src/actions/data/edit.js +3 -1
  36. package/src/actions/data/index.js +4 -0
  37. package/src/actions/data/regression.js +25 -16
  38. package/src/actions/data/regressionStatistics.js +73 -0
  39. package/src/actions/data/shared.js +8 -4
  40. package/src/actions/data/stack.js +3 -1
  41. package/src/actions/distributions/revision.js +24 -18
  42. package/src/actions/encodings/appearance.js +37 -29
  43. package/src/actions/encodings/barWidth.js +36 -11
  44. package/src/actions/encodings/channels.js +0 -1
  45. package/src/actions/encodings/color/continuous.js +1 -1
  46. package/src/actions/encodings/color/index.js +1 -1
  47. package/src/actions/encodings/color/policy.js +10 -3
  48. package/src/actions/encodings/density/resolve.js +1 -6
  49. package/src/actions/encodings/position/policies/arc.js +12 -10
  50. package/src/actions/encodings/position/policies/area.js +3 -3
  51. package/src/actions/encodings/position/policies/bar.js +15 -6
  52. package/src/actions/encodings/position/policies/line.js +17 -6
  53. package/src/actions/encodings/position/resolve.js +3 -2
  54. package/src/actions/encodings/ranged.js +17 -0
  55. package/src/actions/encodings/remove.js +14 -8
  56. package/src/actions/encodings/seriesLayout.js +1 -0
  57. package/src/actions/encodings/shared.js +26 -24
  58. package/src/actions/encodings/text.js +6 -3
  59. package/src/actions/errorBands/create.js +2 -2
  60. package/src/actions/errorBands/edit.js +2 -1
  61. package/src/actions/facets/actions.js +176 -247
  62. package/src/actions/facets/guides.js +2 -1
  63. package/src/actions/gradientPlots/resolve.js +2 -17
  64. package/src/actions/guides/applicability.js +1 -1
  65. package/src/actions/guides/axes/axes.js +30 -11
  66. package/src/actions/guides/axes/axis.js +72 -10
  67. package/src/actions/guides/axes/components.js +13 -13
  68. package/src/actions/guides/axes/edit.js +36 -24
  69. package/src/actions/guides/axes/labels.js +155 -71
  70. package/src/actions/guides/axes/lines.js +27 -24
  71. package/src/actions/guides/axes/parallel/lifecycle.js +1 -1
  72. package/src/actions/guides/axes/parallel/policy.js +8 -7
  73. package/src/actions/guides/axes/remove.js +13 -8
  74. package/src/actions/guides/axes/tickGroups.js +11 -7
  75. package/src/actions/guides/axes/ticks.js +36 -24
  76. package/src/actions/guides/axes/titles.js +107 -69
  77. package/src/actions/guides/basic.js +2 -0
  78. package/src/actions/guides/facadeAxes.js +33 -24
  79. package/src/actions/guides/facadeLegend.js +12 -4
  80. package/src/actions/guides/grids/grid.js +8 -2
  81. package/src/actions/guides/grids/resolve.js +102 -58
  82. package/src/actions/guides/legends/blocks.js +46 -20
  83. package/src/actions/guides/legends/categorical/actions.js +95 -19
  84. package/src/actions/guides/legends/categorical/components.js +15 -18
  85. package/src/actions/guides/legends/categorical/index.js +8 -0
  86. package/src/actions/guides/legends/categorical/layout.js +45 -20
  87. package/src/actions/guides/legends/categorical/options.js +39 -22
  88. package/src/actions/guides/legends/categorical/recipes.js +7 -3
  89. package/src/actions/guides/legends/categorical/resolve.js +11 -4
  90. package/src/actions/guides/legends/categorical/symbols.js +38 -18
  91. package/src/actions/guides/legends/categorical/validation.js +1 -6
  92. package/src/actions/guides/legends/colorSize.js +110 -0
  93. package/src/actions/guides/legends/combine.js +37 -0
  94. package/src/actions/guides/legends/continuous/colorSymbols.js +1 -0
  95. package/src/actions/guides/legends/continuous/common.js +1 -447
  96. package/src/actions/guides/legends/continuous/gradient.js +73 -46
  97. package/src/actions/guides/legends/continuous/interval.js +4 -4
  98. package/src/actions/guides/legends/continuous/opacity.js +33 -21
  99. package/src/actions/guides/legends/creation.js +2 -0
  100. package/src/actions/guides/legends/edit.js +1 -604
  101. package/src/actions/guides/legends/focused.js +8 -7
  102. package/src/actions/guides/legends/group.js +1 -0
  103. package/src/actions/guides/legends/lane.js +1 -516
  104. package/src/actions/guides/legends/lifecycle.js +2 -1
  105. package/src/actions/guides/legends/remove.js +9 -3
  106. package/src/actions/guides/legends/sampling.js +1 -1
  107. package/src/actions/guides/legends/size.js +65 -47
  108. package/src/actions/guides/legends/strokeWidth.js +13 -29
  109. package/src/actions/guides/legends/target.js +2 -79
  110. package/src/actions/guides/legends/transition.js +44 -11
  111. package/src/actions/guides/polar/axes/labels.js +4 -2
  112. package/src/actions/guides/polar/axes/titles.js +7 -5
  113. package/src/actions/guides/polar/resolve.js +6 -14
  114. package/src/actions/guides/tickValues.js +8 -5
  115. package/src/actions/index.js +16 -16
  116. package/src/actions/marks/arc/actions.js +3 -10
  117. package/src/actions/marks/area/actions.js +8 -5
  118. package/src/actions/marks/area/materialize.js +8 -9
  119. package/src/actions/marks/bar/create.js +10 -4
  120. package/src/actions/marks/bar/edit.js +29 -14
  121. package/src/actions/marks/bar/materialize.js +15 -7
  122. package/src/actions/marks/line/actions.js +11 -4
  123. package/src/actions/marks/line/materialize.js +9 -5
  124. package/src/actions/marks/point/edit.js +1 -1
  125. package/src/actions/marks/point/materialize.js +5 -1
  126. package/src/actions/marks/rect/actions.js +3 -3
  127. package/src/actions/marks/remove.js +12 -10
  128. package/src/actions/marks/rule/actions.js +7 -4
  129. package/src/actions/marks/text/actions.js +17 -5
  130. package/src/actions/marks/text/layout.js +3 -0
  131. package/src/actions/primitives/createGraphics.js +3 -2
  132. package/src/actions/primitives/editGraphics.js +15 -11
  133. package/src/actions/primitives/graphicProperties.js +1 -6
  134. package/src/actions/primitives/semanticAction.js +27 -1
  135. package/src/actions/primitives/semanticValidation/guide.js +11 -1
  136. package/src/actions/primitives/semanticValidation/layer.js +8 -0
  137. package/src/actions/regression/create.js +1 -1
  138. package/src/actions/regression/edit.js +18 -6
  139. package/src/actions/regression/resolve.js +2 -6
  140. package/src/actions/scales/channels.js +9 -4
  141. package/src/actions/scales/consumers/families.js +16 -5
  142. package/src/actions/scales/create.js +10 -5
  143. package/src/actions/scales/definitions.js +1 -425
  144. package/src/actions/scales/edit.js +3 -3
  145. package/src/actions/scales/editPolicy.js +12 -3
  146. package/src/actions/scales/materialize.js +1 -1
  147. package/src/actions/scales/patch.js +1 -1
  148. package/src/actions/scales/preview.js +21 -1
  149. package/src/actions/scales/quantitativeColor.js +8 -3
  150. package/src/actions/selection/actions.js +1 -13
  151. package/src/actions/theme/reconcile.js +126 -45
  152. package/src/actions/theme/state.js +12 -0
  153. package/src/actions/titles/actions.js +5 -18
  154. package/src/actions/titles/resolve.js +41 -19
  155. package/src/actions/violinPlots/edit.js +3 -20
  156. package/src/core/compositionState.js +6 -3
  157. package/src/core/font.js +9 -2
  158. package/src/core/graphicProperties.js +1 -0
  159. package/src/core/optionRequirements.js +1 -0
  160. package/src/core/programState.js +4 -0
  161. package/src/core/resourceReferences.js +5 -2
  162. package/src/core/textMetricProfile.js +3 -2
  163. package/src/core/textMetrics.js +41 -4
  164. package/src/core/validation.js +35 -0
  165. package/src/core/vocabulary.js +7 -0
  166. package/src/grammar/aggregate.js +4 -18
  167. package/src/grammar/arcs.js +1 -386
  168. package/src/grammar/areaPaint.js +10 -0
  169. package/src/grammar/areaSeries.js +18 -10
  170. package/src/grammar/axisTextPlacement.js +1 -0
  171. package/src/grammar/bars/geometry.js +30 -3
  172. package/src/grammar/bars/policy.js +12 -1
  173. package/src/grammar/bin.js +2 -12
  174. package/src/grammar/bin2d.js +1 -6
  175. package/src/grammar/boxPlot.js +56 -9
  176. package/src/grammar/categoryOrder.js +1 -6
  177. package/src/grammar/colorSizeLegend.js +39 -0
  178. package/src/grammar/complete.js +15 -19
  179. package/src/grammar/computed.js +115 -26
  180. package/src/grammar/curveCommands.js +29 -16
  181. package/src/grammar/datasetSchema.js +13 -9
  182. package/src/grammar/displayLabels.js +36 -0
  183. package/src/grammar/ecdf.js +2 -9
  184. package/src/grammar/facets/dependencies.js +6 -2
  185. package/src/grammar/facets/guides.js +58 -30
  186. package/src/grammar/facets/index.js +2 -5
  187. package/src/grammar/facets/legendIntent.js +65 -0
  188. package/src/grammar/fold.js +2 -12
  189. package/src/grammar/gradientProfile.js +1 -6
  190. package/src/grammar/guideDash.js +1 -0
  191. package/src/grammar/impute.js +21 -48
  192. package/src/grammar/interval.js +2 -9
  193. package/src/grammar/legendBlocks.js +1 -0
  194. package/src/grammar/legendBorder.js +9 -0
  195. package/src/grammar/legendClip.js +19 -0
  196. package/src/grammar/legendCombinations.js +45 -0
  197. package/src/grammar/legendGradient.js +27 -0
  198. package/src/grammar/legendGroups.js +1 -0
  199. package/src/grammar/legendOpacity.js +6 -0
  200. package/src/grammar/legendTitleStyle.js +22 -0
  201. package/src/grammar/lineSeries.js +32 -17
  202. package/src/grammar/markLabels.js +5 -2
  203. package/src/grammar/normalize.js +4 -54
  204. package/src/grammar/numeric.js +1 -290
  205. package/src/grammar/parallelCoordinates.js +1 -6
  206. package/src/grammar/parseTime.js +41 -0
  207. package/src/grammar/pathCommands.js +11 -4
  208. package/src/grammar/pointShapes.js +16 -2
  209. package/src/grammar/polar.js +1 -184
  210. package/src/grammar/positionCompatibility.js +3 -3
  211. package/src/grammar/regression/derive.js +16 -2
  212. package/src/grammar/regression/models.js +142 -54
  213. package/src/grammar/regression/parameters.js +23 -4
  214. package/src/grammar/regression/statistics.js +64 -0
  215. package/src/grammar/roundedRect.js +42 -54
  216. package/src/grammar/scales/appearance.js +1 -206
  217. package/src/grammar/scales/color.js +1 -382
  218. package/src/grammar/scales/colorConsumers.js +5 -2
  219. package/src/grammar/scales/definition.js +1 -197
  220. package/src/grammar/scales/discretized.js +1 -195
  221. package/src/grammar/scales/size.js +1 -456
  222. package/src/grammar/scales/temporal.js +2 -13
  223. package/src/grammar/scales/transformed.js +1 -383
  224. package/src/grammar/scales/types.js +1 -1
  225. package/src/grammar/scales/validation.js +1 -66
  226. package/src/grammar/schemas/concreteGraphic.js +14 -0
  227. package/src/grammar/schemas/graphic.js +6 -0
  228. package/src/grammar/schemas/graphicBounds.js +31 -7
  229. package/src/grammar/schemas/semanticPath.js +19 -3
  230. package/src/grammar/stack.js +2 -10
  231. package/src/grammar/statisticalReference.js +1 -6
  232. package/src/grammar/summary.js +4 -27
  233. package/src/grammar/text.js +19 -0
  234. package/src/grammar/timeUnit.js +22 -11
  235. package/src/grammar/transformKeys.js +47 -0
  236. package/src/grammar/transformTopology.js +1 -0
  237. package/src/grammar/transforms.js +15 -2
  238. package/src/grammar/valueFormat.js +17 -5
  239. package/src/grammar/weightedStatistics.js +1 -6
  240. package/src/grammar/window.js +4 -58
  241. package/src/inspectionDescriptors.js +1 -1
  242. package/src/layout/canvas.js +1 -110
  243. package/src/layout/facets.js +1 -244
  244. package/src/layout/guideCollisions.js +9 -1
  245. package/src/layout/labels.js +1 -0
  246. package/src/layout/legend.js +13 -0
  247. package/src/layout/legendGroup.js +1 -0
  248. package/src/layout/legendItems.js +59 -15
  249. package/src/layout/legendLane.js +1 -441
  250. package/src/layout/legendText.js +1 -0
  251. package/src/layout/title.js +35 -13
  252. package/src/materialization/bars/aggregate.js +11 -5
  253. package/src/materialization/bars/histogram.js +4 -1
  254. package/src/materialization/bars/ranged.js +19 -6
  255. package/src/materialization/bars/resolve.js +22 -1
  256. package/src/materialization/compositionSnapshot.js +2 -7
  257. package/src/materialization/coordinateBounds.js +21 -0
  258. package/src/materialization/dependencies.js +4 -44
  259. package/src/materialization/facetGuides/edit.js +30 -0
  260. package/src/materialization/facetGuides/layout.js +1 -0
  261. package/src/materialization/facetGuides/owner.js +125 -0
  262. package/src/materialization/facetGuides/ownerLayout.js +71 -0
  263. package/src/materialization/facetGuides/placement.js +71 -14
  264. package/src/materialization/facetGuides/preparation.js +22 -7
  265. package/src/materialization/facetHeaders.js +1 -347
  266. package/src/materialization/facets.js +1 -185
  267. package/src/materialization/graphicHierarchy.js +5 -1
  268. package/src/materialization/graphicTranslation.js +73 -0
  269. package/src/materialization/guides/layout.js +1 -57
  270. package/src/materialization/guides/resources.js +1 -123
  271. package/src/materialization/layout.js +53 -0
  272. package/src/materialization/legendBorder.js +28 -0
  273. package/src/materialization/legendClip.js +76 -0
  274. package/src/materialization/legendGroups.js +1 -0
  275. package/src/materialization/legendText.js +1 -0
  276. package/src/materialization/legends.js +2 -2
  277. package/src/materialization/marks/capabilities.js +5 -6
  278. package/src/materialization/rect.js +1 -1
  279. package/src/materialization/scaleGuideDependencies.js +14 -15
  280. package/src/materialization/scales/map.js +6 -0
  281. package/src/materialization/scales/policies/arc.js +8 -7
  282. package/src/materialization/scales/policies/bar.js +19 -7
  283. package/src/materialization/scales/policies/series.js +2 -1
  284. package/src/materialization/scales/resolve.js +7 -3
  285. package/src/materialization/selection/items/arc.js +1 -1
  286. package/src/materialization/selection/items/bar.js +7 -6
  287. package/src/materialization/selection/items/path.js +7 -6
  288. package/src/materialization/selection/items/rect.js +2 -2
  289. package/src/materialization/text.js +13 -4
  290. package/src/materialization/textLines.js +15 -0
  291. package/src/materialization/typography.js +10 -2
  292. package/src/persistence/codec.js +37 -6
  293. package/src/persistence/validation.js +220 -0
  294. package/src/persistence.js +19 -6
  295. package/src/renderers/canvas/circle.js +6 -3
  296. package/src/renderers/canvas/fill.js +7 -1
  297. package/src/renderers/canvas/index.js +22 -11
  298. package/src/renderers/canvas/isolated.js +166 -0
  299. package/src/renderers/canvas/limits.js +3 -0
  300. package/src/renderers/canvas/line.js +1 -0
  301. package/src/renderers/canvas/path.js +1 -1
  302. package/src/renderers/canvas/rect.js +11 -8
  303. package/src/renderers/canvas/stroke.js +2 -1
  304. package/src/renderers/canvas/text.js +5 -3
  305. package/src/renderers/pdf.js +2 -2
  306. package/src/renderers/png.js +2 -2
  307. package/src/renderers/svg.js +14 -4
  308. package/src/selectors/axes.js +1 -0
  309. package/src/selectors/graphicCapacity.js +38 -0
  310. package/src/selectors/layers.js +19 -0
  311. package/src/theme/defaults.js +8 -2
  312. package/src/version.js +1 -1
  313. package/types/basic.d.ts +3 -0
  314. package/types/index.d.ts +12 -0
  315. package/types/program.d.ts +536 -129
@@ -1,195 +1 @@
1
- import { cloneAndFreeze } from "../../core/immutable.js";
2
- import { validateGeneratedItemLimit } from "../../core/validation.js";
3
- import { interpolateNumber } from "../numeric.js";
4
- import { formatValue, validateValueFormat } from "../valueFormat.js";
5
- import { resolveColorRange, validateColorRange } from "./appearance.js";
6
- import { SCALE_ROLES, validateScaleTypeForRole } from "./types.js";
7
-
8
- export const DISCRETIZED_COLOR_SCALE_TYPES = cloneAndFreeze([
9
- "quantize",
10
- "quantile",
11
- "threshold"
12
- ]);
13
-
14
- function finiteValues(values, label) {
15
- if (!Array.isArray(values) || values.length === 0 || !values.every(Number.isFinite)) {
16
- throw new TypeError(`${label} must contain finite numbers.`);
17
- }
18
- return values;
19
- }
20
-
21
- function ascending(values, label) {
22
- finiteValues(values, label);
23
- if (values.some((value, index) => index > 0 && value <= values[index - 1])) {
24
- throw new RangeError(`${label} must be strictly increasing.`);
25
- }
26
- return values;
27
- }
28
-
29
- function nondecreasing(values, label) {
30
- finiteValues(values, label);
31
- if (values.some((value, index) => index > 0 && value < values[index - 1])) {
32
- throw new RangeError(`${label} must be nondecreasing.`);
33
- }
34
- return values;
35
- }
36
-
37
- function quantile(sorted, probability) {
38
- const position = (sorted.length - 1) * probability;
39
- const lower = Math.floor(position);
40
- const upper = Math.ceil(position);
41
- return interpolateNumber(sorted[lower], sorted[upper], position - lower);
42
- }
43
-
44
- export function validateDiscretizedColorDomain(type, domain) {
45
- validateScaleTypeForRole(type, SCALE_ROLES.discretizedColor);
46
- if (domain === "auto") {
47
- if (type === "threshold") {
48
- throw new Error("Threshold color scale requires an explicit domain.");
49
- }
50
- return domain;
51
- }
52
- if (!Array.isArray(domain)) {
53
- throw new TypeError("Discretized color domain must be an array or auto.");
54
- }
55
- if (type === "quantize") {
56
- if (domain.length !== 2 || !domain.every(Number.isFinite) || domain[0] >= domain[1]) {
57
- throw new RangeError("Quantize color domain must be an increasing pair.");
58
- }
59
- } else if (type === "quantile") {
60
- finiteValues(domain, "Quantile color domain");
61
- } else {
62
- ascending(domain, "Threshold color domain");
63
- }
64
- return cloneAndFreeze(domain);
65
- }
66
-
67
- export function validateDiscretizedColorRange(range) {
68
- if (Array.isArray(range)) {
69
- validateGeneratedItemLimit(
70
- range.length,
71
- "Discretized color range length"
72
- );
73
- }
74
- const validated = validateColorRange(range);
75
- if (validated === "auto") return validated;
76
- if (Array.isArray(validated) && validated.length < 2) {
77
- throw new RangeError("Discretized color range requires at least two colors.");
78
- }
79
- return validated;
80
- }
81
-
82
- export function resolveDiscretizedColorScale({ type, domain, range, values }) {
83
- validateScaleTypeForRole(type, SCALE_ROLES.discretizedColor);
84
- finiteValues(values, "Discretized color values");
85
- const requestedDomain = validateDiscretizedColorDomain(type, domain);
86
- const sample = [...values].sort((left, right) => left - right);
87
- const validatedRange = validateDiscretizedColorRange(range);
88
- const colorCount = type === "threshold"
89
- ? requestedDomain.length + 1
90
- : Array.isArray(range) ? range.length : 5;
91
- const colors = resolveColorRange(
92
- validatedRange === "auto" ? { palette: "viridis" } : validatedRange,
93
- colorCount
94
- );
95
- if (colors.length < 2) {
96
- throw new RangeError("Discretized color range requires at least two colors.");
97
- }
98
- let resolvedDomain;
99
- let thresholds;
100
- if (type === "quantize") {
101
- resolvedDomain = requestedDomain === "auto"
102
- ? [sample[0], sample.at(-1)]
103
- : [...requestedDomain];
104
- if (resolvedDomain[0] === resolvedDomain[1]) {
105
- throw new RangeError("Quantize color scale requires a non-zero domain span.");
106
- }
107
- thresholds = Array.from(
108
- { length: colors.length - 1 },
109
- (_, index) => interpolateNumber(
110
- resolvedDomain[0],
111
- resolvedDomain[1],
112
- (index + 1) / colors.length
113
- )
114
- );
115
- if (thresholds.some((value, index) =>
116
- value <= (index === 0 ? resolvedDomain[0] : thresholds[index - 1]) ||
117
- value >= resolvedDomain[1]
118
- )) {
119
- throw new RangeError(
120
- "Quantize color range requests more classes than its numeric domain can represent."
121
- );
122
- }
123
- } else if (type === "quantile") {
124
- const source = requestedDomain === "auto"
125
- ? sample
126
- : [...requestedDomain].sort((left, right) => left - right);
127
- resolvedDomain = source;
128
- thresholds = Array.from(
129
- { length: colors.length - 1 },
130
- (_, index) => quantile(source, (index + 1) / colors.length)
131
- );
132
- } else {
133
- resolvedDomain = [...requestedDomain];
134
- thresholds = [...requestedDomain];
135
- if (colors.length !== thresholds.length + 1) {
136
- throw new RangeError(
137
- "Threshold color range must contain exactly one more color than its domain."
138
- );
139
- }
140
- }
141
- return cloneAndFreeze({
142
- type,
143
- domain: resolvedDomain,
144
- thresholds,
145
- range: colors
146
- });
147
- }
148
-
149
- export function discretizedColorIndex(value, thresholds) {
150
- if (!Number.isFinite(value)) {
151
- throw new TypeError("Discretized color values must be finite numbers.");
152
- }
153
- let index = 0;
154
- while (index < thresholds.length && value >= thresholds[index]) index += 1;
155
- return index;
156
- }
157
-
158
- export function mapDiscretizedColors(values, scale) {
159
- const hasUnknown = Object.hasOwn(scale, "unknown");
160
- return cloneAndFreeze(values.map(value => {
161
- if (!Number.isFinite(value) && hasUnknown) return scale.unknown;
162
- return scale.range[discretizedColorIndex(value, scale.thresholds)];
163
- }));
164
- }
165
-
166
- export function formatDiscretizedIntervals(thresholds, format = "auto") {
167
- nondecreasing(thresholds, "Discretized color thresholds");
168
- const resolvedFormat = validateValueFormat(format, "Legend label format");
169
- let resolution = Infinity;
170
- for (let index = 1; index < thresholds.length; index += 1) {
171
- const gap = thresholds[index] - thresholds[index - 1];
172
- if (Number.isFinite(gap) && gap > 0) resolution = Math.min(resolution, gap);
173
- }
174
- let labels = resolvedFormat === "auto"
175
- ? thresholds.map(value => Number.isInteger(value) ? String(value) : value.toFixed(1))
176
- : thresholds.map(value => formatValue(value, {
177
- format: resolvedFormat,
178
- valueType: "quantitative",
179
- label: "Legend label format"
180
- }));
181
- if (resolvedFormat === "auto" && thresholds.some((value, index) => {
182
- const rounded = Number(labels[index]);
183
- return value !== 0 && rounded === 0 ||
184
- index > 0 && value !== thresholds[index - 1] &&
185
- labels[index] === labels[index - 1] ||
186
- !Number.isInteger(value) && Math.abs(rounded - value) > resolution / 4;
187
- })) labels = thresholds.map(String);
188
- return cloneAndFreeze([
189
- `< ${labels[0]}`,
190
- ...labels.slice(0, -1).map((value, index) =>
191
- `${value}–${labels[index + 1]}`
192
- ),
193
- `≥ ${labels.at(-1)}`
194
- ]);
195
- }
1
+ import{cloneAndFreeze as c}from"../../core/immutable.js";import{validateGeneratedItemLimit as g}from"../../core/validation.js";import{interpolateNumber as h,quantileSorted as z}from"../numeric.js";import{formatValue as w,validateValueFormat as p}from"../valueFormat.js";import{resolveColorRange as D,validateColorRange as b}from"./appearance.js";import{SCALE_ROLES as m,validateScaleTypeForRole as f}from"./types.js";import{validatePair as E,validateFiniteScaleArray as u,validateIncreasingScaleArray as q}from"./validation.js";const Q=c(["quantize","quantile","threshold"]);function C(r,e){if(u(r,e),r.some((i,o)=>o>0&&i<r[o-1]))throw new RangeError(`${e} must be nondecreasing.`);return r}function R(r,e){return f(r,m.discretizedColor),v(r,e,"color")}function v(r,e,i){if(e==="auto"){if(r==="threshold")throw new Error(`Threshold ${i} scale requires an explicit domain.`);return e}if(i==="color"&&!Array.isArray(e))throw new TypeError("Discretized color domain must be an array or auto.");if(r==="quantize"){if(i==="size"){if(E(e,"Quantize size domain"),e[0]>=e[1])throw new RangeError("Quantize size domain must be a strictly increasing pair.")}else if(e.length!==2||!e.every(Number.isFinite)||e[0]>=e[1])throw new RangeError("Quantize color domain must be an increasing pair.")}else r==="quantile"?u(e,`Quantile ${i} domain`):q(e,`Threshold ${i} domain`);return c(e)}function A(r){Array.isArray(r)&&g(r.length,"Discretized color range length");const e=b(r);if(e==="auto")return e;if(Array.isArray(e)&&e.length<2)throw new RangeError("Discretized color range requires at least two colors.");return e}function y({type:r,domain:e,values:i,count:o,kind:a}){let t=e==="auto"?[...i].sort((s,l)=>s-l):[...e],n;if(r==="quantize"){if(e==="auto"){if(t.length===0)throw new Error("Cannot infer an automatic quantize size domain from no values.");t=[t[0],t.at(-1)]}if(t[0]===t[1])throw new RangeError(`Quantize ${a} scale requires a non-zero domain span.`);if(n=Array.from({length:o-1},(s,l)=>h(t[0],t[1],(l+1)/o)),n.some((s,l)=>s<=(l===0?t[0]:n[l-1])||s>=t[1]))throw new RangeError(a==="size"?"Quantize size range requests more buckets than its domain can represent.":"Quantize color range requests more classes than its numeric domain can represent.")}else if(r==="quantile"){if(t.length===0)throw new Error("Cannot infer automatic quantile size thresholds from no values.");t.sort((s,l)=>s-l),n=Array.from({length:o-1},(s,l)=>z(t,(l+1)/o))}else if(n=[...t],o!==n.length+1)throw new RangeError(`Threshold ${a} range must contain exactly one more ${a==="size"?"area":"color"} than its domain.`);return{domain:t,thresholds:n}}function _({type:r,domain:e,range:i,values:o}){f(r,m.discretizedColor),u(o,"Discretized color values");const a=R(r,e),t=A(i),n=r==="threshold"?a.length+1:Array.isArray(i)?i.length:5,s=D(t==="auto"?{palette:"viridis"}:t,n);if(s.length<2)throw new RangeError("Discretized color range requires at least two colors.");const{domain:l,thresholds:d}=y({type:r,domain:a,values:o,count:s.length,kind:"color"});return c({type:r,domain:l,thresholds:d,range:s})}function S(r,e,i="Discretized color"){if(!Number.isFinite(r))throw new TypeError(`${i} values must be finite numbers.`);let o=0;for(;o<e.length&&r>=e[o];)o+=1;return o}function O(r,e){const i=Object.hasOwn(e,"unknown");return c(r.map(o=>!Number.isFinite(o)&&i?e.unknown:e.range[S(o,e.thresholds)]))}function V(r,e="auto"){C(r,"Discretized color thresholds");const i=p(e,"Legend label format");let o=1/0;for(let t=1;t<r.length;t+=1){const n=r[t]-r[t-1];Number.isFinite(n)&&n>0&&(o=Math.min(o,n))}let a=i==="auto"?r.map(t=>Number.isInteger(t)?String(t):t.toFixed(1)):r.map(t=>w(t,{format:i,valueType:"quantitative",label:"Legend label format"}));return i==="auto"&&r.some((t,n)=>{const s=Number(a[n]);return t!==0&&s===0||n>0&&t!==r[n-1]&&a[n]===a[n-1]||!Number.isInteger(t)&&Math.abs(s-t)>o/4})&&(a=r.map(String)),c([`< ${a[0]}`,...a.slice(0,-1).map((t,n)=>`${t}\u2013${a[n+1]}`),`\u2265 ${a.at(-1)}`])}export{Q as DISCRETIZED_COLOR_SCALE_TYPES,S as discretizedColorIndex,V as formatDiscretizedIntervals,O as mapDiscretizedColors,_ as resolveDiscretizedColorScale,y as resolveDiscretizedDomain,R as validateDiscretizedColorDomain,A as validateDiscretizedColorRange,v as validateDiscretizedDomain};
@@ -1,456 +1 @@
1
- import { cloneAndFreeze } from "../../core/immutable.js";
2
- import { validateGeneratedItemLimit } from "../../core/validation.js";
3
- import { interpolateNumber } from "../numeric.js";
4
- import { validateSizeRange, resolveSizeRange } from "./appearance.js";
5
- import { mapLinearValues } from "./continuous.js";
6
- import { mapTransformedValues, resolveTransformedDomain } from "./transformed.js";
7
- import { validateScaleUnknown } from "./policies.js";
8
- import { validatePair } from "./validation.js";
9
-
10
- export const CONTINUOUS_SIZE_SCALE_TYPES = cloneAndFreeze([
11
- "linear", "log", "sqrt", "pow"
12
- ]);
13
- export const DISCRETE_SIZE_SCALE_TYPES = cloneAndFreeze([
14
- "quantize", "quantile", "threshold"
15
- ]);
16
- export const SIZE_SCALE_TYPES = cloneAndFreeze([
17
- ...CONTINUOUS_SIZE_SCALE_TYPES,
18
- ...DISCRETE_SIZE_SCALE_TYPES
19
- ]);
20
-
21
- export function isContinuousSizeScaleType(type) {
22
- return CONTINUOUS_SIZE_SCALE_TYPES.includes(type);
23
- }
24
-
25
- export function isDiscreteSizeScaleType(type) {
26
- return DISCRETE_SIZE_SCALE_TYPES.includes(type);
27
- }
28
-
29
- export function isSizeScaleType(type) {
30
- return SIZE_SCALE_TYPES.includes(type);
31
- }
32
-
33
- export function validateSizeScaleType(type) {
34
- if (!isSizeScaleType(type)) {
35
- throw new Error(`Scale type "${type}" is not valid for size.`);
36
- }
37
- return type;
38
- }
39
-
40
- function finiteArray(value, label, minimumLength = 1) {
41
- if (
42
- !Array.isArray(value) ||
43
- value.length < minimumLength ||
44
- !value.every(Number.isFinite)
45
- ) {
46
- throw new TypeError(`${label} must contain finite numbers.`);
47
- }
48
- return value;
49
- }
50
-
51
- function strictlyIncreasing(value, label) {
52
- finiteArray(value, label);
53
- if (value.some((item, index) => index > 0 && item <= value[index - 1])) {
54
- throw new RangeError(`${label} must be strictly increasing.`);
55
- }
56
- return value;
57
- }
58
-
59
- function validateContinuousDomain(type, domain) {
60
- const validated = validatePair(domain, "Size scale domain");
61
- if (type !== "linear" && validated[0] === validated[1]) {
62
- throw new RangeError(
63
- `Size ${type} scale domain values must be distinct.`
64
- );
65
- }
66
- if (type === "log" && validated.some(value => value <= 0)) {
67
- throw new RangeError("Size log scale domain must be strictly positive.");
68
- }
69
- if (["sqrt", "pow"].includes(type) && validated.some(value => value < 0)) {
70
- throw new RangeError(
71
- `Size ${type} scale domain must be non-negative.`
72
- );
73
- }
74
- return validated;
75
- }
76
-
77
- export function validateSizeScaleDomain(type, domain) {
78
- validateSizeScaleType(type);
79
- if (domain === "auto") {
80
- if (type === "threshold") {
81
- throw new Error("Threshold size scale requires an explicit domain.");
82
- }
83
- return domain;
84
- }
85
- if (isContinuousSizeScaleType(type)) {
86
- return validateContinuousDomain(type, domain);
87
- }
88
- if (type === "quantize") {
89
- const validated = validatePair(domain, "Quantize size domain");
90
- if (validated[0] >= validated[1]) {
91
- throw new RangeError(
92
- "Quantize size domain must be a strictly increasing pair."
93
- );
94
- }
95
- return validated;
96
- }
97
- if (type === "quantile") {
98
- return cloneAndFreeze(finiteArray(domain, "Quantile size domain"));
99
- }
100
- return cloneAndFreeze(
101
- strictlyIncreasing(domain, "Threshold size domain")
102
- );
103
- }
104
-
105
- export function validateDiscreteSizeRange(range) {
106
- finiteArray(range, "Discrete size range", 2);
107
- validateGeneratedItemLimit(range.length, "Discrete size range length");
108
- if (range.some(value => value < 0)) {
109
- throw new RangeError(
110
- "Discrete size range must contain non-negative areas."
111
- );
112
- }
113
- if (range.some((value, index) => index > 0 && value < range[index - 1])) {
114
- throw new RangeError("Discrete size range must be nondecreasing.");
115
- }
116
- return cloneAndFreeze(range);
117
- }
118
-
119
- export function validateSizeScaleRange(type, range) {
120
- validateSizeScaleType(type);
121
- if (isContinuousSizeScaleType(type)) return validateSizeRange(range);
122
- if (range === "auto") {
123
- throw new Error(`Size ${type} scale requires an explicit range.`);
124
- }
125
- return validateDiscreteSizeRange(range);
126
- }
127
-
128
- function sizeTypeFamily(type) {
129
- return isContinuousSizeScaleType(type) ? "continuous" : type;
130
- }
131
-
132
- function requireBoolean(value, label) {
133
- if (typeof value !== "boolean") {
134
- throw new TypeError(`${label} must be a boolean.`);
135
- }
136
- return value;
137
- }
138
-
139
- function positiveFinite(value, label) {
140
- if (!Number.isFinite(value) || value <= 0) {
141
- throw new RangeError(`${label} must be a positive finite number.`);
142
- }
143
- return value;
144
- }
145
-
146
- export function normalizeSizeScaleDefinition({ previous = {}, patch = {} } = {}) {
147
- const type = validateSizeScaleType(patch.type ?? previous.type ?? "linear");
148
- const hasPrevious = previous.type !== undefined;
149
- const typeChanged = hasPrevious && previous.type !== type;
150
- if (typeChanged && sizeTypeFamily(previous.type) !== sizeTypeFamily(type) &&
151
- !Object.hasOwn(patch, "domain")) {
152
- throw new Error(
153
- "Size scale type-family transition requires an explicit domain."
154
- );
155
- }
156
- if (typeChanged && isDiscreteSizeScaleType(type) &&
157
- !Object.hasOwn(patch, "range")) {
158
- throw new Error(
159
- `Size ${type} scale transition requires an explicit range.`
160
- );
161
- }
162
- if (typeChanged && isDiscreteSizeScaleType(previous.type) &&
163
- isContinuousSizeScaleType(type) && !Object.hasOwn(patch, "range")) {
164
- throw new Error(
165
- "Discrete-to-continuous size scale transition requires an explicit range."
166
- );
167
- }
168
- for (const property of [
169
- "nice", "zero", "constant", "padding", "paddingInner", "paddingOuter",
170
- "align", "palette", "interpolate", "midpoint", "radialMapping"
171
- ]) {
172
- if (Object.hasOwn(patch, property)) {
173
- throw new Error(`Size scale does not support ${property}.`);
174
- }
175
- }
176
-
177
- const rawDomain = Object.hasOwn(patch, "domain")
178
- ? patch.domain
179
- : Object.hasOwn(previous, "domain")
180
- ? previous.domain
181
- : "auto";
182
- const rawRange = Object.hasOwn(patch, "range")
183
- ? patch.range
184
- : Object.hasOwn(previous, "range")
185
- ? previous.range
186
- : "auto";
187
- const definition = {
188
- type,
189
- domain: validateSizeScaleDomain(type, rawDomain),
190
- range: validateSizeScaleRange(type, rawRange)
191
- };
192
-
193
- const reverse = Object.hasOwn(patch, "reverse")
194
- ? patch.reverse
195
- : previous.reverse;
196
- if (reverse !== undefined) {
197
- definition.reverse = requireBoolean(reverse, "Size scale reverse");
198
- }
199
-
200
- if (isContinuousSizeScaleType(type)) {
201
- const clamp = Object.hasOwn(patch, "clamp")
202
- ? patch.clamp
203
- : isContinuousSizeScaleType(previous.type)
204
- ? previous.clamp
205
- : undefined;
206
- if (clamp !== undefined) {
207
- definition.clamp = requireBoolean(clamp, "Size scale clamp");
208
- }
209
- } else if (Object.hasOwn(patch, "clamp")) {
210
- throw new Error(`Size ${type} scale does not support clamp.`);
211
- }
212
-
213
- if (type === "log") {
214
- const base = Object.hasOwn(patch, "base")
215
- ? patch.base
216
- : !typeChanged && previous.type === "log"
217
- ? previous.base
218
- : 10;
219
- definition.base = positiveFinite(base ?? 10, "Size log scale base");
220
- if (definition.base === 1) {
221
- throw new RangeError("Size log scale base must not equal 1.");
222
- }
223
- } else if (Object.hasOwn(patch, "base")) {
224
- throw new Error(`Size ${type} scale does not support base.`);
225
- }
226
-
227
- if (type === "pow") {
228
- const exponent = Object.hasOwn(patch, "exponent")
229
- ? patch.exponent
230
- : !typeChanged && previous.type === "pow"
231
- ? previous.exponent
232
- : undefined;
233
- if (exponent === undefined) {
234
- throw new Error("Size pow scale requires an explicit exponent.");
235
- }
236
- definition.exponent = positiveFinite(
237
- exponent,
238
- "Size pow scale exponent"
239
- );
240
- } else if (Object.hasOwn(patch, "exponent")) {
241
- throw new Error(`Size ${type} scale does not support exponent.`);
242
- }
243
-
244
- const unknown = Object.hasOwn(patch, "unknown")
245
- ? patch.unknown
246
- : previous.unknown;
247
- if (unknown !== undefined) {
248
- definition.unknown = validateScaleUnknown("size", unknown);
249
- }
250
- return cloneAndFreeze(definition);
251
- }
252
-
253
- function validateSizeValues(values, type) {
254
- if (!Array.isArray(values) || !values.every(Number.isFinite)) {
255
- throw new TypeError("Size scale values must be finite numbers.");
256
- }
257
- if (type === "log" && values.some(value => value <= 0)) {
258
- throw new RangeError("Size log scale values must be strictly positive.");
259
- }
260
- if (["sqrt", "pow"].includes(type) && values.some(value => value < 0)) {
261
- throw new RangeError(`Size ${type} scale values must be non-negative.`);
262
- }
263
- return values;
264
- }
265
-
266
- function numericExtent(values) {
267
- let minimum = values[0];
268
- let maximum = values[0];
269
- for (const value of values.slice(1)) {
270
- minimum = Math.min(minimum, value);
271
- maximum = Math.max(maximum, value);
272
- }
273
- return [minimum, maximum];
274
- }
275
-
276
- function resolveContinuousSizeDomain(definition, values) {
277
- validateSizeValues(values, definition.type);
278
- if (definition.domain !== "auto") {
279
- return validateSizeScaleDomain(definition.type, definition.domain);
280
- }
281
- if (values.length === 0) {
282
- throw new Error("Cannot infer an automatic size scale domain from no values.");
283
- }
284
- if (definition.type === "linear") {
285
- return cloneAndFreeze(numericExtent(values));
286
- }
287
- if (["sqrt", "pow"].includes(definition.type) && values.every(value => value === 0)) {
288
- return cloneAndFreeze([0, 1]);
289
- }
290
- const domain = resolveTransformedDomain({
291
- type: definition.type,
292
- domain: "auto",
293
- values,
294
- ...(definition.type === "log" ? { base: definition.base } : {}),
295
- ...(definition.type === "pow" ? { exponent: definition.exponent } : {})
296
- });
297
- return validateSizeScaleDomain(definition.type, domain);
298
- }
299
-
300
- function quantile(sorted, probability) {
301
- const position = (sorted.length - 1) * probability;
302
- const lower = Math.floor(position);
303
- const upper = Math.ceil(position);
304
- return interpolateNumber(
305
- sorted[lower],
306
- sorted[upper],
307
- position - lower
308
- );
309
- }
310
-
311
- export function resolveSizeScale({
312
- type,
313
- domain = "auto",
314
- range = "auto",
315
- values = [],
316
- ...options
317
- } = {}) {
318
- const definition = normalizeSizeScaleDefinition({
319
- patch: { type, domain, range, ...options }
320
- });
321
- validateSizeValues(values, definition.type);
322
- if (isContinuousSizeScaleType(definition.type)) {
323
- const resolvedDomain = resolveContinuousSizeDomain(definition, values);
324
- const resolvedRange = [...resolveSizeRange(definition.range)];
325
- if (definition.reverse === true) resolvedRange.reverse();
326
- return cloneAndFreeze({
327
- type: definition.type,
328
- domain: resolvedDomain,
329
- range: resolvedRange,
330
- ...(definition.clamp === undefined ? {} : { clamp: definition.clamp }),
331
- ...(definition.type === "log" ? { base: definition.base } : {}),
332
- ...(definition.type === "pow" ? { exponent: definition.exponent } : {}),
333
- ...(definition.unknown === undefined ? {} : { unknown: definition.unknown })
334
- });
335
- }
336
-
337
- const resolvedRange = [...definition.range];
338
- if (definition.reverse === true) resolvedRange.reverse();
339
- const sample = [...values].sort((left, right) => left - right);
340
- let resolvedDomain;
341
- let thresholds;
342
- if (definition.type === "quantize") {
343
- if (definition.domain === "auto") {
344
- if (sample.length === 0) {
345
- throw new Error(
346
- "Cannot infer an automatic quantize size domain from no values."
347
- );
348
- }
349
- resolvedDomain = numericExtent(sample);
350
- if (resolvedDomain[0] === resolvedDomain[1]) {
351
- throw new RangeError(
352
- "Quantize size scale requires a non-zero domain span."
353
- );
354
- }
355
- } else {
356
- resolvedDomain = [...definition.domain];
357
- }
358
- thresholds = Array.from(
359
- { length: resolvedRange.length - 1 },
360
- (_, index) => interpolateNumber(
361
- resolvedDomain[0],
362
- resolvedDomain[1],
363
- (index + 1) / resolvedRange.length
364
- )
365
- );
366
- if (thresholds.some((value, index) =>
367
- value <= (index === 0 ? resolvedDomain[0] : thresholds[index - 1]) ||
368
- value >= resolvedDomain[1]
369
- )) {
370
- throw new RangeError(
371
- "Quantize size range requests more buckets than its domain can represent."
372
- );
373
- }
374
- } else if (definition.type === "quantile") {
375
- const source = definition.domain === "auto"
376
- ? sample
377
- : [...definition.domain].sort((left, right) => left - right);
378
- if (source.length === 0) {
379
- throw new Error(
380
- "Cannot infer automatic quantile size thresholds from no values."
381
- );
382
- }
383
- resolvedDomain = source;
384
- thresholds = Array.from(
385
- { length: resolvedRange.length - 1 },
386
- (_, index) => quantile(
387
- source,
388
- (index + 1) / resolvedRange.length
389
- )
390
- );
391
- } else {
392
- resolvedDomain = [...definition.domain];
393
- thresholds = [...definition.domain];
394
- if (resolvedRange.length !== thresholds.length + 1) {
395
- throw new RangeError(
396
- "Threshold size range must contain exactly one more area than its domain."
397
- );
398
- }
399
- }
400
- return cloneAndFreeze({
401
- type: definition.type,
402
- domain: resolvedDomain,
403
- thresholds,
404
- range: resolvedRange,
405
- ...(definition.unknown === undefined ? {} : { unknown: definition.unknown })
406
- });
407
- }
408
-
409
- export function discretizedSizeIndex(value, thresholds) {
410
- if (!Number.isFinite(value)) {
411
- throw new TypeError("Discrete size values must be finite numbers.");
412
- }
413
- let index = 0;
414
- while (index < thresholds.length && value >= thresholds[index]) index += 1;
415
- return index;
416
- }
417
-
418
- function validateMappedAreas(areas) {
419
- if (areas.some(area => !Number.isFinite(area) || area < 0)) {
420
- throw new RangeError(
421
- "Size scale mapping must produce non-negative finite areas."
422
- );
423
- }
424
- return cloneAndFreeze(areas);
425
- }
426
-
427
- export function mapSizeValues(values, scale) {
428
- validateSizeScaleType(scale?.type);
429
- const hasUnknown = Object.hasOwn(scale, "unknown");
430
- const finite = values.filter(Number.isFinite);
431
- validateSizeValues(finite, scale.type);
432
- if (!hasUnknown && finite.length !== values.length) {
433
- throw new TypeError("Size scale values must be finite numbers.");
434
- }
435
- let mapped;
436
- if (isDiscreteSizeScaleType(scale.type)) {
437
- mapped = values.map(value => {
438
- if (!Number.isFinite(value)) return scale.unknown;
439
- return scale.range[discretizedSizeIndex(value, scale.thresholds)];
440
- });
441
- } else if (scale.type === "linear") {
442
- mapped = mapLinearValues(values, scale.domain, scale.range, {
443
- clamp: scale.clamp ?? false,
444
- ...(hasUnknown ? { unknown: scale.unknown } : {})
445
- });
446
- } else {
447
- mapped = mapTransformedValues(values, scale.domain, scale.range, {
448
- type: scale.type,
449
- clamp: scale.clamp ?? false,
450
- ...(hasUnknown ? { unknown: scale.unknown } : {}),
451
- ...(scale.type === "log" ? { base: scale.base } : {}),
452
- ...(scale.type === "pow" ? { exponent: scale.exponent } : {})
453
- });
454
- }
455
- return validateMappedAreas(mapped);
456
- }
1
+ import{cloneAndFreeze as u}from"../../core/immutable.js";import{validateGeneratedItemLimit as g,validatePositiveFinite as R}from"../../core/validation.js";import{interpolateNumber as $,numericExtent as q}from"../numeric.js";import{isNominalValue as A}from"./fields.js";import{resolveOrdinalDomain as C,validateOrdinalDomain as I}from"./ordinal.js";import{mapLinearValues as _}from"./continuous.js";import{mapTransformedValues as j,resolveTransformedDomain as F}from"./transformed.js";import{validateSizeRange as N,DEFAULT_SIZE_RANGE as P,mapOrdinalValues as L}from"./appearance.js";import{validateScaleUnknown as V}from"./policies.js";import{validatePair as U,validateFiniteScaleArray as E}from"./validation.js";import{resolveDiscretizedDomain as Z,validateDiscretizedDomain as Y,discretizedColorIndex as G}from"./discretized.js";const x=u(["linear","log","sqrt","pow"]),O=u(["quantize","quantile","threshold"]),M=u([...x,...O,"ordinal"]);function m(e){return x.includes(e)}function f(e){return O.includes(e)}function ce(e){return e==="ordinal"||f(e)}function B(e){return M.includes(e)}function w(e){if(!B(e))throw new Error(`Scale type "${e}" is not valid for size.`);return e}function v(e,n,t){if(n==="log"&&e.some(o=>o<=0))throw new RangeError(`Size log scale ${t} must be strictly positive.`);if(["sqrt","pow"].includes(n)&&e.some(o=>o<0))throw new RangeError(`Size ${n} scale ${t} must be non-negative.`);return e}function H(e,n){const t=U(n,"Size scale domain");if(e!=="linear"&&t[0]===t[1])throw new RangeError(`Size ${e} scale domain values must be distinct.`);return v(t,e,"domain")}function z(e,n){return w(e),e==="ordinal"?I(n):m(e)?n==="auto"?n:H(e,n):Y(e,n,"size")}function J(e){if(E(e,"Discrete size range",2),g(e.length,"Discrete size range length"),e.some(n=>n<0))throw new RangeError("Discrete size range must contain non-negative areas.");if(e.some((n,t)=>t>0&&n<e[t-1]))throw new RangeError("Discrete size range must be nondecreasing.");return u(e)}function K(e,n){if(w(e),m(e))return N(n);if(e==="ordinal")return n==="auto"?n:(E(n,"Ordinal size range"),g(n.length,"Ordinal size range length"),y(n));if(n==="auto")throw new Error(`Size ${e} scale requires an explicit range.`);return J(n)}function D(e){return m(e)?"continuous":e}function Q({previous:e={},patch:n={}}={}){const t=w(n.type??e.type??"linear"),s=e.type!==void 0&&e.type!==t;if(s&&D(e.type)!==D(t)&&!Object.hasOwn(n,"domain"))throw new Error("Size scale type-family transition requires an explicit domain.");if(s&&f(t)&&!Object.hasOwn(n,"range"))throw new Error(`Size ${t} scale transition requires an explicit range.`);if(s&&f(e.type)&&m(t)&&!Object.hasOwn(n,"range"))throw new Error("Discrete-to-continuous size scale transition requires an explicit range.");for(const i of["nice","zero","constant","padding","paddingInner","paddingOuter","align","palette","interpolate","midpoint","radialMapping"])if(Object.hasOwn(n,i))throw new Error(`Size scale does not support ${i}.`);const r={domain:"auto",range:"auto",...e,...n},a={type:t,domain:z(t,r.domain),range:K(t,r.range)};for(const i of["reverse","clamp"]){if(i==="clamp"&&!m(t)){if(Object.hasOwn(n,i))throw new Error(`Size ${t} scale does not support clamp.`);continue}const p=Object.hasOwn(n,i)?n[i]:i==="clamp"&&!m(e.type)?void 0:e[i];if(p!==void 0){if(typeof p!="boolean")throw new TypeError(`Size scale ${i} must be a boolean.`);a[i]=p}}for(const[i,p,c]of[["base","log",10],["exponent","pow"]]){if(t!==p){if(Object.hasOwn(n,i))throw new Error(`Size ${t} scale does not support ${i}.`);continue}const l=Object.hasOwn(n,i)?n[i]:!s&&e.type===p?e[i]:c;if(i==="exponent"&&l===void 0)throw new Error("Size pow scale requires an explicit exponent.");if(a[i]=R(i==="base"?l??c:l,`Size ${t} scale ${i}`),i==="base"&&a.base===1)throw new RangeError("Size log scale base must not equal 1.")}const d=Object.hasOwn(n,"unknown")?n.unknown:e.unknown;return d!==void 0&&(a.unknown=V("size",d)),u(a)}function k(e,n){if(!Array.isArray(e)||!e.every(Number.isFinite))throw new TypeError("Size scale values must be finite numbers.");return v(e,n,"values")}function W(e,n){if(e.domain!=="auto")return z(e.type,e.domain);if(n.length===0)throw new Error("Cannot infer an automatic size scale domain from no values.");if(e.type==="linear")return u(q(n));if(["sqrt","pow"].includes(e.type)&&n.every(o=>o===0))return u([0,1]);const t=F({type:e.type,domain:"auto",values:n,...e.type==="log"?{base:e.base}:{},...e.type==="pow"?{exponent:e.exponent}:{}});return z(e.type,t)}function fe({type:e,domain:n="auto",range:t="auto",values:o=[],...s}={}){const r=Q({patch:{type:e,domain:n,range:t,...s}}),a=r.type==="ordinal",d=a?o.filter(A):k(o,r.type);if(a&&d.length!==o.length&&r.unknown===void 0)throw new TypeError("Ordinal size values must be nominal values.");if(a||m(r.type)){const l=a?C(r.domain,d):W(r,o);a&&g(l.length,"Ordinal size domain length");const S=r.range==="auto"?P:r.range,h=a&&r.range==="auto"?l.map((ne,T)=>$(S[0],S[1],l.length===1?.5:T/(l.length-1))):[...S];r.reverse===!0&&h.reverse();const b=u({type:r.type,domain:l,range:h,...r.clamp===void 0?{}:{clamp:r.clamp},...r.type==="log"?{base:r.base}:{},...r.type==="pow"?{exponent:r.exponent}:{},...r.unknown===void 0?{}:{unknown:r.unknown}});return a&&ee(o,b),b}const i=[...r.range];r.reverse===!0&&i.reverse();const{domain:p,thresholds:c}=Z({type:r.type,domain:r.domain,values:o,count:i.length,kind:"size"});return u({type:r.type,domain:p,thresholds:c,range:i,...r.unknown===void 0?{}:{unknown:r.unknown}})}function X(e,n){return G(e,n,"Discrete size")}function y(e){if(e.some(n=>!Number.isFinite(n)||n<0))throw new RangeError("Size scale mapping must produce non-negative finite areas.");return u(e)}function ee(e,n){w(n?.type);const t=Object.hasOwn(n,"unknown");if(n.type==="ordinal")return y(L(e,n.domain,n.range,t?{unknown:n.unknown}:{}));const o=e.filter(Number.isFinite);if(k(o,n.type),!t&&o.length!==e.length)throw new TypeError("Size scale values must be finite numbers.");let s;return f(n.type)?s=e.map(r=>Number.isFinite(r)?n.range[X(r,n.thresholds)]:n.unknown):s=(n.type==="linear"?_:j)(e,n.domain,n.range,{type:n.type,clamp:n.clamp??!1,...t?{unknown:n.unknown}:{},...n.type==="log"?{base:n.base}:{},...n.type==="pow"?{exponent:n.exponent}:{}}),y(s)}export{x as CONTINUOUS_SIZE_SCALE_TYPES,O as DISCRETE_SIZE_SCALE_TYPES,M as SIZE_SCALE_TYPES,X as discretizedSizeIndex,m as isContinuousSizeScaleType,f as isDiscreteSizeScaleType,ce as isEnumeratedSizeScaleType,B as isSizeScaleType,ee as mapSizeValues,Q as normalizeSizeScaleDefinition,fe as resolveSizeScale,J as validateDiscreteSizeRange,z as validateSizeScaleDomain,K as validateSizeScaleRange,w as validateSizeScaleType};