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
@@ -18,7 +18,6 @@ import {
18
18
  resolveBarChannels,
19
19
  resolveBarGrain
20
20
  } from "../../grammar/bars/policy.js";
21
- import { normalizeOffsetPadding } from "../../grammar/bars/geometry.js";
22
21
 
23
22
  const ENCODING_OPTIONS = Object.freeze([
24
23
  "field", "target", "fieldType", "scale", "paddingInner", "paddingOuter"
@@ -69,30 +68,38 @@ function createOffsetEncoding(channel) {
69
68
  layer.encoding?.[channel],
70
69
  args.scale ?? {}
71
70
  );
72
- const scale = resolveOffsetScaleDefinition(this, requestedScale, channel);
71
+ const scaleOptions = {
72
+ ...requestedScale,
73
+ ...Object.fromEntries(
74
+ ["paddingInner", "paddingOuter"]
75
+ .filter(property => Object.hasOwn(args, property))
76
+ .map(property => [property, args[property]])
77
+ )
78
+ };
79
+ const scale = resolveOffsetScaleDefinition(this, scaleOptions, channel);
73
80
  if (Object.hasOwn(scale, "unknown")) {
74
81
  throw new Error(
75
82
  `${channel} scale unknown is not supported for offset positions.`
76
83
  );
77
84
  }
78
- const padding = normalizeOffsetPadding(
79
- args,
80
- this.markConfigs[target]?.[channel],
81
- channel
82
- );
83
85
 
84
86
  const grouped = layer.mark.type === "bar" ? inferSeriesGroup(this, layer, args.field, "offset") : this;
85
87
  let next = setEncodingProperties(grouped, target, channel, {
86
88
  field: args.field,
87
89
  fieldType,
88
90
  scale: scale.id
89
- })._withMarkConfig(target, {
90
- ...this.markConfigs[target],
91
- [channel]: padding
92
- });
93
- next = applyEncodingScale(next, scale, requestedScale, {
94
- reassignment: layer.encoding?.[channel]?.scale === scale.id
95
91
  });
92
+ next = applyEncodingScale(next, scale, {
93
+ ...Object.fromEntries(Object.entries(scaleOptions).filter(
94
+ ([property]) => property !== "range"
95
+ )),
96
+ paddingInner: scale.paddingInner,
97
+ paddingOuter: scale.paddingOuter,
98
+ align: scale.align
99
+ }, {
100
+ reassignment: findSemanticScale(this, scale.id) !== undefined
101
+ });
102
+ next = next._withoutMaterializationConfig(["marks", target, channel]);
96
103
  if (layer.mark.type === "bar") {
97
104
  if (findSemanticScale(this, scale.id) === undefined && args.scale?.id === undefined) next = next._withMarkConfig(target, { ...next.markConfigs[target], seriesOffsetScale: scale.id });
98
105
  if (layer.layout?.mode !== "group" || layer.encoding?.group?.field !== args.field) return next.layoutSeries({ target, mode: "group" });
@@ -103,8 +110,8 @@ function createOffsetEncoding(channel) {
103
110
  );
104
111
  }
105
112
 
106
- const encodeXOffset = createOffsetEncoding("xOffset");
107
- const encodeYOffset = createOffsetEncoding("yOffset");
113
+ const encodeXOffset = /* @__PURE__ */ createOffsetEncoding("xOffset");
114
+ const encodeYOffset = /* @__PURE__ */ createOffsetEncoding("yOffset");
108
115
 
109
116
  export function registerOffsetEncodingAction(ProgramClass) {
110
117
  ProgramClass.prototype.encodeXOffset = encodeXOffset;
@@ -1,5 +1,5 @@
1
- import { action } from "../../core/action.js";
2
- import { validateOptionObject } from "../../core/validation.js";
1
+ import { closedAction } from "../../core/action.js";
2
+
3
3
  import {
4
4
  normalizeParallelDimensions,
5
5
  validateParallelKeyField,
@@ -19,13 +19,12 @@ const OPTIONS = Object.freeze([
19
19
  "target", "coordinate", "dimensions", "key", "missing"
20
20
  ]);
21
21
 
22
- export const encodeParallelCoordinates = action(
22
+ export const encodeParallelCoordinates = /* @__PURE__ */ closedAction(
23
23
  {
24
24
  op: "encodeParallelCoordinates",
25
25
  description: "Atomically encode ordered Parallel-coordinate dimensions."
26
- },
26
+ }, OPTIONS,
27
27
  function (args = {}) {
28
- validateOptionObject(args, OPTIONS, "encodeParallelCoordinates");
29
28
  const { id: target, dataset, layer } = resolveTarget(
30
29
  this,
31
30
  args.target,
@@ -1,9 +1,6 @@
1
- import { action } from "../../core/action.js";
1
+ import { closedAction } from "../../core/action.js";
2
2
  import { validateUserId } from "../../core/identifiers.js";
3
- import {
4
- validateNonEmptyString,
5
- validateOptionObject
6
- } from "../../core/validation.js";
3
+ import { validateNonEmptyString } from "../../core/validation.js";
7
4
  import { readQuantitativeField } from "../../grammar/scales/index.js";
8
5
  import { validatePathOrderDirection } from "../../grammar/pathOrder.js";
9
6
  import {
@@ -76,13 +73,12 @@ function rematerializePath(program, layer) {
76
73
  : program;
77
74
  }
78
75
 
79
- const encodePathOrder = action(
76
+ const encodePathOrder = /* @__PURE__ */ closedAction(
80
77
  {
81
78
  op: "encodePathOrder",
82
79
  description: "Order vertices within each Cartesian path series."
83
- },
80
+ }, ENCODE_OPTIONS,
84
81
  function (args = {}) {
85
- validateOptionObject(args, ENCODE_OPTIONS, "encodePathOrder");
86
82
  const field = validateNonEmptyString(args.field, "Path order field");
87
83
  const fieldType = args.fieldType ?? "quantitative";
88
84
  if (fieldType !== "quantitative") {
@@ -102,13 +98,12 @@ const encodePathOrder = action(
102
98
  }
103
99
  );
104
100
 
105
- const removePathOrder = action(
101
+ const removePathOrder = /* @__PURE__ */ closedAction(
106
102
  {
107
103
  op: "removePathOrder",
108
104
  description: "Remove explicit path order and restore automatic ordering."
109
- },
105
+ }, REMOVE_OPTIONS,
110
106
  function (args = {}) {
111
- validateOptionObject(args, REMOVE_OPTIONS, "removePathOrder");
112
107
  const layer = resolvePathOrderLayer(this, args.target, { active: true });
113
108
  const next = this.editSemantic({
114
109
  property: `layer[${layer.id}].encoding.pathOrder`,
@@ -66,18 +66,35 @@ function applyBin(program, target, channel, previous, bin) {
66
66
  });
67
67
  }
68
68
 
69
- function applyArcThetaWeight(program, target, channel, previous, aggregate, weight) {
70
- if (channel !== "theta") return program;
71
- if (aggregate !== "sum") {
69
+ function applyPositionWeight(
70
+ program,
71
+ target,
72
+ channel,
73
+ previous,
74
+ bin,
75
+ aggregate,
76
+ weight
77
+ ) {
78
+ const histogram = channel === "x" && bin !== undefined;
79
+ const arcSum = channel === "theta" && aggregate === "sum";
80
+ if (!histogram && !arcSum) {
81
+ return previous?.weight === undefined
82
+ ? program
83
+ : program.editSemantic({
84
+ property: `layer[${target}].encoding.${channel}.weight`,
85
+ remove: true
86
+ });
87
+ }
88
+ if (weight === undefined) {
72
89
  return previous?.weight === undefined
73
90
  ? program
74
91
  : program.editSemantic({
75
- property: `layer[${target}].encoding.theta.weight`,
92
+ property: `layer[${target}].encoding.${channel}.weight`,
76
93
  remove: true
77
94
  });
78
95
  }
79
96
  return program.editSemantic({
80
- property: `layer[${target}].encoding.theta.weight`,
97
+ property: `layer[${target}].encoding.${channel}.weight`,
81
98
  value: weight
82
99
  });
83
100
  }
@@ -104,6 +121,26 @@ function removeStaleArcThetaAggregate(
104
121
  });
105
122
  }
106
123
 
124
+ function removeMeasuredRadiusAggregate(
125
+ program,
126
+ target,
127
+ channel,
128
+ previous,
129
+ clearRadialMapping
130
+ ) {
131
+ if (
132
+ channel !== "radius" ||
133
+ !clearRadialMapping ||
134
+ previous?.aggregate === undefined
135
+ ) {
136
+ return program;
137
+ }
138
+ return program.editSemantic({
139
+ property: `layer[${target}].encoding.radius.aggregate`,
140
+ remove: true
141
+ });
142
+ }
143
+
107
144
  export function applyPositionSemantics(program, {
108
145
  target,
109
146
  channel,
@@ -117,7 +154,8 @@ export function applyPositionSemantics(program, {
117
154
  bin,
118
155
  aggregate,
119
156
  stack,
120
- weight
157
+ weight,
158
+ clearRadialMapping
121
159
  }) {
122
160
  let next = reconcileInheritedRulePosition(program, {
123
161
  target,
@@ -160,11 +198,19 @@ export function applyPositionSemantics(program, {
160
198
  fieldType,
161
199
  aggregate
162
200
  );
163
- return applyArcThetaWeight(
201
+ next = removeMeasuredRadiusAggregate(
202
+ next,
203
+ target,
204
+ channel,
205
+ previous,
206
+ clearRadialMapping
207
+ );
208
+ return applyPositionWeight(
164
209
  next,
165
210
  target,
166
211
  channel,
167
212
  previous,
213
+ bin,
168
214
  aggregate,
169
215
  weight
170
216
  );
@@ -31,7 +31,8 @@ function encodePosition(program, channel, args, operation) {
31
31
  aggregate,
32
32
  stack,
33
33
  weight,
34
- companion
34
+ companion,
35
+ clearRadialMapping
35
36
  } = resolvePositionEncoding(program, channel, args, operation);
36
37
 
37
38
  let next = program
@@ -53,13 +54,20 @@ function encodePosition(program, channel, args, operation) {
53
54
  bin,
54
55
  aggregate,
55
56
  stack,
56
- weight
57
+ weight,
58
+ clearRadialMapping
57
59
  });
58
60
 
59
61
  next = next.editSemantic({
60
62
  property: `layer[${target}].encoding.${channel}.scale`,
61
63
  value: scale.id
62
64
  });
65
+ if (
66
+ clearRadialMapping &&
67
+ findSemanticScale(next, scale.id)?.radialMapping !== undefined
68
+ ) {
69
+ next = next.editScale({ id: scale.id, radialMapping: undefined });
70
+ }
63
71
  next = applyEncodingScale(next, scale, requestedScale, {
64
72
  reassignment: previous?.scale === scale.id,
65
73
  allowTypeChange: layer.mark.type === "area"
@@ -133,7 +141,7 @@ function encodePosition(program, channel, args, operation) {
133
141
  return applyDetachedScaleRematerialization(next, [layer]);
134
142
  }
135
143
 
136
- const encodeX = action(
144
+ const encodeX = /* @__PURE__ */ action(
137
145
  {
138
146
  op: "encodeX",
139
147
  description: "Encode a field as horizontal position."
@@ -143,7 +151,7 @@ const encodeX = action(
143
151
  }
144
152
  );
145
153
 
146
- const encodeY = action(
154
+ const encodeY = /* @__PURE__ */ action(
147
155
  {
148
156
  op: "encodeY",
149
157
  description: "Encode a field as vertical position."
@@ -153,7 +161,7 @@ const encodeY = action(
153
161
  }
154
162
  );
155
163
 
156
- const encodeTheta = action(
164
+ const encodeTheta = /* @__PURE__ */ action(
157
165
  {
158
166
  op: "encodeTheta",
159
167
  description: "Encode a field as Polar angle in clockwise degrees."
@@ -163,7 +171,7 @@ const encodeTheta = action(
163
171
  }
164
172
  );
165
173
 
166
- const encodeR = action(
174
+ const encodeR = /* @__PURE__ */ action(
167
175
  {
168
176
  op: "encodeR",
169
177
  description: "Encode a quantitative field as Polar radius."
@@ -10,6 +10,8 @@ import {
10
10
  resolveBarOrientation
11
11
  } from "../../../../grammar/bars/policy.js";
12
12
  import { resolveBin, validateStack } from "./common.js";
13
+ import { normalizeStatisticalWeight } from
14
+ "../../../../grammar/weightedStatistics.js";
13
15
 
14
16
  function resolveBarChannelPolicy({
15
17
  program,
@@ -37,6 +39,10 @@ function resolveBarChannelPolicy({
37
39
  throw new Error("Binned bar x encoding does not support aggregate or stack.");
38
40
  }
39
41
  bin = resolveBin(args.bin);
42
+ const weight = args.weight === undefined
43
+ ? undefined
44
+ : normalizeStatisticalWeight(args.weight, "Histogram weight");
45
+ return { bin, aggregate, stack, weight };
40
46
  } else if (
41
47
  fieldType === "quantitative" &&
42
48
  channel === "y" &&
@@ -89,6 +95,9 @@ function resolveBarChannelPolicy({
89
95
  );
90
96
  }
91
97
 
98
+ if (args.weight !== undefined) {
99
+ throw new Error("Bar weight is supported only for a binned x encoding.");
100
+ }
92
101
  return { bin, aggregate, stack };
93
102
  }
94
103
 
@@ -97,19 +97,26 @@ export function resolvePositionEncoding(program, channel, args, operation) {
97
97
  args.target,
98
98
  getPositionChannelDefinition(channel).markTypes
99
99
  );
100
+ const previous = layer.encoding?.[channel];
100
101
  if (isSourceOwnedText(layer)) {
101
102
  throw new Error(`${operation} cannot replace source-owned Text positions; edit the source, use dx/dy, or create independent Text with data.`);
102
103
  }
103
104
  if (
104
105
  Object.hasOwn(args, "weight") &&
105
- !(layer.mark.type === "arc" && channel === "theta")
106
+ !(layer.mark.type === "arc" && channel === "theta") &&
107
+ !(layer.mark.type === "bar" && channel === "x" &&
108
+ (args.bin !== undefined || previous?.bin !== undefined))
106
109
  ) {
107
- throw new Error(`${operation} weight is supported only for arc theta encoding.`);
110
+ throw new Error(
111
+ `${operation} weight is supported only for arc theta encoding or histogram x encoding.`
112
+ );
108
113
  }
109
114
  if (Object.hasOwn(args, "mapping") && (layer.mark.type !== "arc" || channel !== "radius")) {
110
115
  throw new Error(`${operation} mapping requires Arc radius.`);
111
116
  }
112
117
  validateCoordinateFamily(layer, channel, operation);
118
+ const clearRadialMapping =
119
+ layer.mark.type === "arc" && channel === "radius" && args.mapping === false;
113
120
  const hasField = Object.hasOwn(args, "field");
114
121
  const hasDatum = Object.hasOwn(args, "datum");
115
122
  if (["rule", "rect", "text", "point", "tick"].includes(layer.mark.type)) {
@@ -128,9 +135,10 @@ export function resolvePositionEncoding(program, channel, args, operation) {
128
135
  } else if (hasDatum) {
129
136
  throw new Error(`${operation} does not support datum for a ${layer.mark.type} mark.`);
130
137
  }
131
- const previous = layer.encoding?.[channel];
132
138
  const mapping = channel === "radius" && layer.mark.type === "arc"
133
- ? args.mapping ?? findSemanticScale(program, previous?.scale)?.radialMapping
139
+ ? clearRadialMapping
140
+ ? undefined
141
+ : args.mapping ?? findSemanticScale(program, previous?.scale)?.radialMapping
134
142
  : undefined;
135
143
  const countRadius = mapping !== undefined && (args.aggregate ?? previous?.aggregate) === "count";
136
144
  const requestedFieldType = args.fieldType ?? previous?.fieldType ?? (
@@ -165,7 +173,9 @@ export function resolvePositionEncoding(program, channel, args, operation) {
165
173
  validateAggregateFieldValues(dataset.values, field, fieldType);
166
174
  } else readScaleField(dataset.values, field, fieldType, { temporalUnit });
167
175
  }
168
- const effectiveArgs = { ...args, ...(mapping === undefined ? {} : { mapping }) };
176
+ const effectiveArgs = { ...args };
177
+ if (clearRadialMapping) delete effectiveArgs.mapping;
178
+ else if (mapping !== undefined) effectiveArgs.mapping = mapping;
169
179
  const directQuantitativeArcTheta =
170
180
  layer.mark.type === "arc" &&
171
181
  channel === "theta" &&
@@ -173,7 +183,8 @@ export function resolvePositionEncoding(program, channel, args, operation) {
173
183
  for (const property of ["aggregate", "bin", "stack"]) {
174
184
  if (!Object.hasOwn(effectiveArgs, property) && previous !== undefined &&
175
185
  Object.hasOwn(previous, property) &&
176
- !(directQuantitativeArcTheta && property === "aggregate")) {
186
+ !(directQuantitativeArcTheta && property === "aggregate") &&
187
+ !(clearRadialMapping && property === "aggregate")) {
177
188
  effectiveArgs[property] = previous[property];
178
189
  }
179
190
  }
@@ -201,7 +212,7 @@ export function resolvePositionEncoding(program, channel, args, operation) {
201
212
  previous,
202
213
  Object.hasOwn(args, "scale") ? args.scale : {}
203
214
  );
204
- const scale = resolvePositionScaleDefinition(
215
+ const resolvedScale = resolvePositionScaleDefinition(
205
216
  program,
206
217
  channel,
207
218
  aggregateOutput ? "quantitative" : fieldType,
@@ -229,6 +240,11 @@ export function resolvePositionEncoding(program, channel, args, operation) {
229
240
  }
230
241
  : {}
231
242
  );
243
+ const scale = clearRadialMapping
244
+ ? Object.fromEntries(
245
+ Object.entries(resolvedScale).filter(([property]) => property !== "radialMapping")
246
+ )
247
+ : resolvedScale;
232
248
  if (
233
249
  layer.mark.type === "bar" &&
234
250
  program.markConfigs[target]?.boxPlot === undefined &&
@@ -310,6 +326,7 @@ export function resolvePositionEncoding(program, channel, args, operation) {
310
326
  temporalUnit,
311
327
  scale,
312
328
  coordinate: resolveCoordinate(program, channel, layer, args.coordinate),
329
+ clearRadialMapping,
313
330
  ...policy
314
331
  };
315
332
  }
@@ -159,7 +159,7 @@ function encodeSecondaryPosition(program, channel, args, operation, types) {
159
159
  return next;
160
160
  }
161
161
 
162
- const encodeX2 = action(
162
+ const encodeX2 = /* @__PURE__ */ action(
163
163
  {
164
164
  op: "encodeX2",
165
165
  description: "Encode a secondary horizontal endpoint."
@@ -175,7 +175,7 @@ const encodeX2 = action(
175
175
  }
176
176
  );
177
177
 
178
- const encodeY2 = action(
178
+ const encodeY2 = /* @__PURE__ */ action(
179
179
  {
180
180
  op: "encodeY2",
181
181
  description: "Encode a secondary vertical endpoint."
@@ -222,10 +222,10 @@ function rangeAction(channel) {
222
222
  });
223
223
  }
224
224
 
225
- const encodeYRange = rangeAction("y");
226
- const encodeXRange = rangeAction("x");
225
+ const encodeYRange = /* @__PURE__ */ rangeAction("y");
226
+ const encodeXRange = /* @__PURE__ */ rangeAction("x");
227
227
 
228
- const encodeGroup = action(
228
+ const encodeGroup = /* @__PURE__ */ action(
229
229
  {
230
230
  op: "encodeGroup",
231
231
  description: "Split path geometry by nominal identity fields without a scale."
@@ -1,6 +1,6 @@
1
- import { action } from "../../core/action.js";
1
+ import { closedAction } from "../../core/action.js";
2
2
  import { validateUserId } from "../../core/identifiers.js";
3
- import { validateOptionObject } from "../../core/validation.js";
3
+
4
4
  import {
5
5
  getPositionChannelDefinition,
6
6
  POSITION_ENCODING_CHANNELS
@@ -25,11 +25,12 @@ import { applyDetachedScaleRematerialization } from "../../materialization/depen
25
25
  import { findDataset } from "../../selectors/datasets.js";
26
26
  import { assertPathGroupCompatible, validatePathGroupAppearance } from "../../materialization/marks/grouping.js";
27
27
  import { assertEncodingSelectionCompatibility } from "../../materialization/selection/compatibility.js";
28
+ import { planLegendBlockTransitions } from "../guides/legends/transition.js";
28
29
 
29
30
  const OPTIONS = Object.freeze(["target", "channel"]);
30
31
  const REMOVABLE_CHANNELS = Object.freeze([
31
32
  "x", "y", "x2", "y2", "xOffset", "yOffset", "theta", "radius",
32
- "color", "strokeDash", "strokeWidth", "size", "shape", "group",
33
+ "color", "stroke", "strokeDash", "strokeWidth", "size", "shape", "group",
33
34
  "angle", "opacity", "text"
34
35
  ]);
35
36
  const REMOVE_AXIS = Object.freeze({
@@ -40,6 +41,7 @@ const REMOVE_AXIS = Object.freeze({
40
41
  });
41
42
  const SPECIALIZED_LEGEND_KIND = Object.freeze({
42
43
  color: Object.freeze(["gradient", "interval"]),
44
+ stroke: Object.freeze(["strokeGradient", "strokeInterval"]),
43
45
  size: Object.freeze(["size"]),
44
46
  opacity: Object.freeze(["opacity"]),
45
47
  strokeWidth: Object.freeze(["strokeWidth"])
@@ -157,7 +159,7 @@ function cleanupPositionGuides(program, removed) {
157
159
  }
158
160
 
159
161
  function reconcileCategoricalLegend(program, target, channels) {
160
- const entry = ["series", "color"]
162
+ const entry = ["series", "color", "stroke"]
161
163
  .map(kind => [kind, program.guideConfigs.legend?.[kind]])
162
164
  .find(([, config]) =>
163
165
  config?.target === target &&
@@ -172,7 +174,10 @@ function reconcileCategoricalLegend(program, target, channels) {
172
174
  if (remaining.length === 0) {
173
175
  return removeLegendKinds(program, [kind]);
174
176
  }
175
- const revision = resolveCategoricalLegendRevision(program, kind, config, remaining);
177
+ const resolved = resolveCategoricalLegendRevision(program, kind, config, remaining);
178
+ const revision = planLegendBlockTransitions(program, target, [
179
+ { ...resolved, kind: resolved.config.kind }
180
+ ])[0];
176
181
  const next = removeLegendKinds(program, [kind]);
177
182
  return createCategoricalLegendFromConfig(next, revision.config, revision.order);
178
183
  }
@@ -198,13 +203,12 @@ function rematerializeTarget(program, target) {
198
203
  return next;
199
204
  }
200
205
 
201
- export const removeEncoding = action(
206
+ export const removeEncoding = /* @__PURE__ */ closedAction(
202
207
  {
203
208
  op: "removeEncoding",
204
209
  description: "Remove one semantic encoding and its owned materialized state."
205
- },
210
+ }, OPTIONS,
206
211
  function (args = {}) {
207
- validateOptionObject(args, OPTIONS, "removeEncoding");
208
212
  if (!REMOVABLE_CHANNELS.includes(args.channel)) {
209
213
  throw new Error(
210
214
  `Unsupported removable encoding channel "${args.channel}".`
@@ -218,7 +222,7 @@ export const removeEncoding = action(
218
222
  }
219
223
  const channels = activeCascade(layer, args.channel);
220
224
  assertEncodingSelectionCompatibility(this, layer.id, channels);
221
- for (const kind of ["series", "color"]) {
225
+ for (const kind of ["series", "color", "stroke"]) {
222
226
  const config = this.guideConfigs.legend?.[kind];
223
227
  const order = this.semanticSpec.guides.legend?.[kind]?.order;
224
228
  if (config?.target === layer.id && channels.includes(order?.channel) &&
@@ -1,8 +1,5 @@
1
1
  import { action } from "../../core/action.js";
2
- import {
3
- validateRuleStroke,
4
- validateRuleStrokeWidth
5
- } from "../../grammar/ruleAppearance.js";
2
+ import { validateRuleStrokeWidth } from "../../grammar/ruleAppearance.js";
6
3
  import { readQuantitativeField } from "../../grammar/scales/index.js";
7
4
  import { resolveStrokeWidthScaleDefinition } from "../scales/definitions.js";
8
5
  import {
@@ -18,29 +15,11 @@ import { findLayer } from "../../selectors/layers.js";
18
15
  import { validatePathSeriesAppearance } from "../../grammar/pathSeries.js";
19
16
  import { assertEncodingSelectionCompatibility } from "../../materialization/selection/compatibility.js";
20
17
 
21
- const STROKE_OPTIONS = Object.freeze(["target", "value"]);
22
18
  const WIDTH_OPTIONS = Object.freeze([
23
19
  "target", "value", "field", "fieldType", "scale"
24
20
  ]);
25
21
 
26
- const encodeStroke = action(
27
- {
28
- op: "encodeStroke",
29
- description: "Set a constant graphical stroke on a rule mark."
30
- },
31
- function (args = {}) {
32
- validateOptions(args, STROKE_OPTIONS, "encodeStroke");
33
- const { id } = resolveTarget(this, args.target, ["rule"], "rule mark");
34
- return this
35
- ._withMarkConfig(id, {
36
- ...this.markConfigs[id],
37
- stroke: validateRuleStroke(args.value)
38
- })
39
- .rematerializeRuleMark({ id });
40
- }
41
- );
42
-
43
- const encodeStrokeWidth = action(
22
+ const encodeStrokeWidth = /* @__PURE__ */ action(
44
23
  {
45
24
  op: "encodeStrokeWidth",
46
25
  description: "Assign constant or field-driven line or rule stroke width."
@@ -119,6 +98,5 @@ const encodeStrokeWidth = action(
119
98
  );
120
99
 
121
100
  export function registerRuleAppearanceEncodingActions(ProgramClass) {
122
- ProgramClass.prototype.encodeStroke = encodeStroke;
123
101
  ProgramClass.prototype.encodeStrokeWidth = encodeStrokeWidth;
124
102
  }
@@ -15,7 +15,7 @@ export function stackLayoutMode(stack) {
15
15
  return stack === "normalize" ? "fill" : stack === "center" ? "center" : stack === null ? "overlay" : "stack";
16
16
  }
17
17
 
18
- export const layoutSeries = action({ op: "layoutSeries", description: "Assign series placement independently of color." }, function (args = {}) {
18
+ export const layoutSeries = /* @__PURE__ */ action({ op: "layoutSeries", description: "Assign series placement independently of color." }, function (args = {}) {
19
19
  validateOptions(args, ["target", "mode"], "layoutSeries");
20
20
  const mode = validateColorLayout(args.mode);
21
21
  const { id: target, layer, dataset } = resolveTarget(this, args.target, ["bar", "area"], "series mark");
@@ -85,6 +85,7 @@ export const layoutSeries = action({ op: "layoutSeries", description: "Assign se
85
85
  next = offset.field === undefined
86
86
  ? setEncodingProperties(next, target, offsetChannel, offset).createScale(offsetScale)
87
87
  : next[offsetChannel === "xOffset" ? "encodeXOffset" : "encodeYOffset"]({ target, field: offset.field, fieldType: offset.fieldType, scale: offsetScale });
88
+ next = next._withoutMaterializationConfig(["marks", target, offsetChannel]);
88
89
  if (findSemanticScale(this, offsetScale.id) === undefined) next = next._withMarkConfig(target, { ...next.markConfigs[target], seriesOffsetScale: offsetScale.id });
89
90
  } else {
90
91
  const owned = next.markConfigs[target]?.seriesOffsetScale;