ggaction 0.0.12 → 0.0.15

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 (378) hide show
  1. package/CHANGELOG.md +127 -0
  2. package/README.md +20 -11
  3. package/knowledge/action-card.schema.json +1 -1
  4. package/knowledge/action-cards.json +1 -1
  5. package/knowledge/action-cards.schema.json +1 -1
  6. package/knowledge/extension-authoring.md +2 -1
  7. package/knowledge/intent-taxonomy.json +1 -1
  8. package/knowledge/mcp-resources.json +1 -1
  9. package/knowledge/task-resolver.js +1 -1
  10. package/package.json +10 -3
  11. package/src/actions/basic.js +4 -2
  12. package/src/actions/boxPlots/components.js +14 -4
  13. package/src/actions/boxPlots/edit.js +31 -5
  14. package/src/actions/boxPlots/materialize.js +13 -4
  15. package/src/actions/boxPlots/options.js +48 -16
  16. package/src/actions/canvas/actions.js +3 -1
  17. package/src/actions/canvas/fitting.js +211 -0
  18. package/src/actions/canvas/index.js +2 -0
  19. package/src/actions/categoryOrder/index.js +18 -6
  20. package/src/actions/charts/area.js +51 -0
  21. package/src/actions/charts/bar.js +13 -6
  22. package/src/actions/charts/beeswarm.js +70 -0
  23. package/src/actions/charts/density.js +48 -0
  24. package/src/actions/charts/ecdf.js +186 -0
  25. package/src/actions/charts/endpoints.js +473 -0
  26. package/src/actions/charts/heatmap.js +4 -3
  27. package/src/actions/charts/histogram.js +5 -4
  28. package/src/actions/charts/horizon.js +73 -0
  29. package/src/actions/charts/index.js +37 -0
  30. package/src/actions/charts/interval-regression.js +172 -0
  31. package/src/actions/charts/line.js +8 -6
  32. package/src/actions/charts/parallel.js +8 -2
  33. package/src/actions/charts/pie.js +52 -0
  34. package/src/actions/charts/polar.js +134 -0
  35. package/src/actions/charts/radar.js +305 -0
  36. package/src/actions/charts/radial.js +50 -0
  37. package/src/actions/charts/raincloud.js +422 -0
  38. package/src/actions/charts/rug-strip.js +283 -0
  39. package/src/actions/charts/scatter.js +11 -3
  40. package/src/actions/charts/shared.js +69 -10
  41. package/src/actions/composition/actions.js +129 -3
  42. package/src/actions/coordinates/actions.js +1 -1
  43. package/src/actions/coordinates/edit.js +76 -0
  44. package/src/actions/data/bin.js +29 -0
  45. package/src/actions/data/bin2d.js +57 -185
  46. package/src/actions/data/complete.js +26 -0
  47. package/src/actions/data/computed.js +24 -0
  48. package/src/actions/data/create.js +2 -2
  49. package/src/actions/data/density.js +12 -20
  50. package/src/actions/data/derived.js +111 -15
  51. package/src/actions/data/ecdf.js +38 -0
  52. package/src/actions/data/edit.js +539 -0
  53. package/src/actions/data/filter.js +226 -30
  54. package/src/actions/data/fold.js +24 -0
  55. package/src/actions/data/impute.js +26 -0
  56. package/src/actions/data/index.js +38 -0
  57. package/src/actions/data/interval.js +2 -0
  58. package/src/actions/data/intervalEdit.js +86 -4
  59. package/src/actions/data/normalize.js +27 -0
  60. package/src/actions/data/regression.js +19 -21
  61. package/src/actions/data/revisionBindings.js +145 -0
  62. package/src/actions/data/shared.js +20 -4
  63. package/src/actions/data/stack.js +26 -0
  64. package/src/actions/data/summary.js +26 -0
  65. package/src/actions/data/timeUnit.js +4 -1
  66. package/src/actions/data/window.js +1 -1
  67. package/src/actions/encodings/appearance.js +32 -13
  68. package/src/actions/encodings/barWidth.js +8 -0
  69. package/src/actions/encodings/basic.js +2 -0
  70. package/src/actions/encodings/channels.js +415 -0
  71. package/src/actions/encodings/color/continuous.js +19 -59
  72. package/src/actions/encodings/color/index.js +30 -23
  73. package/src/actions/encodings/color/layout.js +3 -97
  74. package/src/actions/encodings/color/policy.js +5 -8
  75. package/src/actions/encodings/density/resolve.js +37 -5
  76. package/src/actions/encodings/density.js +124 -34
  77. package/src/actions/encodings/histogram.js +3 -2
  78. package/src/actions/encodings/horizon/resolve.js +8 -4
  79. package/src/actions/encodings/horizon.js +18 -8
  80. package/src/actions/encodings/index.js +6 -0
  81. package/src/actions/encodings/offset.js +30 -29
  82. package/src/actions/encodings/parallel.js +2 -8
  83. package/src/actions/encodings/position/apply.js +63 -11
  84. package/src/actions/encodings/position/index.js +52 -6
  85. package/src/actions/encodings/position/policies/arc.js +14 -0
  86. package/src/actions/encodings/position/policies/area.js +4 -42
  87. package/src/actions/encodings/position/policies/bar.js +57 -13
  88. package/src/actions/encodings/position/resolve.js +88 -26
  89. package/src/actions/encodings/ranged.js +123 -97
  90. package/src/actions/encodings/remove.js +44 -34
  91. package/src/actions/encodings/ruleAppearance.js +24 -32
  92. package/src/actions/encodings/seriesLayout.js +105 -0
  93. package/src/actions/encodings/shared.js +107 -37
  94. package/src/actions/encodings/stroke.js +226 -0
  95. package/src/actions/encodings/strokeDash.js +9 -6
  96. package/src/actions/encodings/temporal.js +7 -0
  97. package/src/actions/encodings/text.js +30 -15
  98. package/src/actions/errorBands/create.js +41 -8
  99. package/src/actions/errorBands/edit.js +360 -25
  100. package/src/actions/errorBars/create.js +56 -17
  101. package/src/actions/errorBars/edit.js +372 -21
  102. package/src/actions/facets/actions.js +619 -41
  103. package/src/actions/facets/derive.js +139 -25
  104. package/src/actions/gradientPlots/components.js +43 -13
  105. package/src/actions/gradientPlots/edit.js +14 -4
  106. package/src/actions/gradientPlots/materialize.js +8 -8
  107. package/src/actions/gradientPlots/options.js +10 -2
  108. package/src/actions/guides/applicability.js +28 -19
  109. package/src/actions/guides/axes/axes.js +4 -3
  110. package/src/actions/guides/axes/axis.js +18 -18
  111. package/src/actions/guides/axes/components.js +43 -0
  112. package/src/actions/guides/axes/edit.js +16 -51
  113. package/src/actions/guides/axes/labels.js +184 -28
  114. package/src/actions/guides/axes/lines.js +13 -7
  115. package/src/actions/guides/axes/parallel/lifecycle.js +117 -0
  116. package/src/actions/guides/axes/parallel/policy.js +137 -0
  117. package/src/actions/guides/axes/parallel/resolve.js +50 -25
  118. package/src/actions/guides/axes/parallel.js +93 -217
  119. package/src/actions/guides/axes/policy.js +21 -67
  120. package/src/actions/guides/axes/tickGroups.js +15 -8
  121. package/src/actions/guides/axes/ticks.js +11 -6
  122. package/src/actions/guides/axes/titles.js +32 -11
  123. package/src/actions/guides/basic.js +2 -0
  124. package/src/actions/guides/facade.js +106 -0
  125. package/src/actions/guides/facadeAxes.js +200 -0
  126. package/src/actions/guides/facadeLegend.js +63 -0
  127. package/src/actions/guides/grids/grid.js +37 -33
  128. package/src/actions/guides/grids/resolve.js +17 -4
  129. package/src/actions/guides/guides.js +54 -31
  130. package/src/actions/guides/legends/blocks.js +426 -0
  131. package/src/actions/guides/legends/categorical/actions.js +309 -279
  132. package/src/actions/guides/legends/categorical/components.js +21 -17
  133. package/src/actions/guides/legends/categorical/index.js +37 -33
  134. package/src/actions/guides/legends/categorical/layout.js +123 -354
  135. package/src/actions/guides/legends/categorical/options.js +32 -16
  136. package/src/actions/guides/legends/categorical/recipes.js +114 -9
  137. package/src/actions/guides/legends/categorical/resolve.js +30 -15
  138. package/src/actions/guides/legends/categorical/symbols.js +87 -33
  139. package/src/actions/guides/legends/continuous/common.js +99 -26
  140. package/src/actions/guides/legends/continuous/gradient.js +120 -89
  141. package/src/actions/guides/legends/continuous/index.js +8 -2
  142. package/src/actions/guides/legends/continuous/interval.js +79 -95
  143. package/src/actions/guides/legends/continuous/opacity.js +113 -89
  144. package/src/actions/guides/legends/continuous/stroke.js +525 -0
  145. package/src/actions/guides/legends/creation.js +40 -0
  146. package/src/actions/guides/legends/edit.js +321 -90
  147. package/src/actions/guides/legends/focused.js +2 -2
  148. package/src/actions/guides/legends/index.js +2 -0
  149. package/src/actions/guides/legends/lane.js +149 -102
  150. package/src/actions/guides/legends/lifecycle.js +143 -0
  151. package/src/actions/guides/legends/remove.js +43 -78
  152. package/src/actions/guides/legends/sampling.js +140 -0
  153. package/src/actions/guides/legends/size.js +213 -116
  154. package/src/actions/guides/legends/strokeWidth.js +121 -73
  155. package/src/actions/guides/legends/target.js +123 -0
  156. package/src/actions/guides/legends/transition.js +192 -0
  157. package/src/actions/guides/polar/axes/facade.js +81 -66
  158. package/src/actions/guides/polar/axes/labels.js +28 -8
  159. package/src/actions/guides/polar/axes/lines.js +12 -5
  160. package/src/actions/guides/polar/axes/shared.js +22 -0
  161. package/src/actions/guides/polar/axes/ticks.js +6 -5
  162. package/src/actions/guides/polar/axes/titles.js +6 -5
  163. package/src/actions/guides/polar/grids.js +8 -8
  164. package/src/actions/guides/polar/resolve.js +12 -8
  165. package/src/actions/guides/reuse.js +44 -0
  166. package/src/actions/guides/tickValues.js +19 -21
  167. package/src/actions/index.js +15 -2
  168. package/src/actions/intervals/resolve.js +35 -15
  169. package/src/actions/marks/arc/actions.js +78 -20
  170. package/src/actions/marks/area/actions.js +51 -12
  171. package/src/actions/marks/area/materialize.js +22 -3
  172. package/src/actions/marks/bar/create.js +11 -2
  173. package/src/actions/marks/bar/edit.js +20 -3
  174. package/src/actions/marks/bar/materialize.js +33 -9
  175. package/src/actions/marks/index.js +14 -0
  176. package/src/actions/marks/line/actions.js +71 -113
  177. package/src/actions/marks/line/materialize.js +57 -56
  178. package/src/actions/marks/point/create.js +8 -2
  179. package/src/actions/marks/point/edit.js +29 -21
  180. package/src/actions/marks/point/index.js +1 -0
  181. package/src/actions/marks/point/jitter.js +3 -0
  182. package/src/actions/marks/point/materialize.js +154 -16
  183. package/src/actions/marks/point/packing.js +68 -0
  184. package/src/actions/marks/rect/actions.js +33 -12
  185. package/src/actions/marks/references.js +658 -0
  186. package/src/actions/marks/remove.js +87 -4
  187. package/src/actions/marks/rule/actions.js +77 -9
  188. package/src/actions/marks/rule/appearance.js +26 -0
  189. package/src/actions/marks/shared.js +13 -13
  190. package/src/actions/marks/text/actions.js +296 -13
  191. package/src/actions/marks/text/index.js +4 -0
  192. package/src/actions/marks/text/layout.js +156 -8
  193. package/src/actions/marks/text/removal.js +173 -0
  194. package/src/actions/marks/text/selection.js +73 -0
  195. package/src/actions/marks/tick/actions.js +22 -5
  196. package/src/actions/primitives/createGraphics.js +3 -1
  197. package/src/actions/primitives/editGraphics.js +26 -0
  198. package/src/actions/primitives/semantic.js +3 -2
  199. package/src/actions/primitives/semanticAction.js +120 -10
  200. package/src/actions/primitives/semanticValidation/guide.js +10 -0
  201. package/src/actions/primitives/semanticValidation/index.js +9 -1
  202. package/src/actions/primitives/semanticValidation/layer.js +23 -1
  203. package/src/actions/primitives/semanticValidation/scale.js +38 -8
  204. package/src/actions/regression/components.js +26 -11
  205. package/src/actions/regression/create.js +11 -3
  206. package/src/actions/regression/edit.js +40 -13
  207. package/src/actions/regression/resolve.js +1 -1
  208. package/src/actions/resources/index.js +7 -0
  209. package/src/actions/resources/remove.js +172 -0
  210. package/src/actions/scales/channels.js +212 -0
  211. package/src/actions/scales/consumers/common.js +21 -54
  212. package/src/actions/scales/consumers/families.js +28 -14
  213. package/src/actions/scales/consumers/index.js +42 -4
  214. package/src/actions/scales/consumers/seriesLayout.js +57 -12
  215. package/src/actions/scales/create.js +58 -26
  216. package/src/actions/scales/definitions.js +109 -39
  217. package/src/actions/scales/edit.js +101 -34
  218. package/src/actions/scales/editPolicy.js +95 -35
  219. package/src/actions/scales/index.js +6 -0
  220. package/src/actions/scales/materialize.js +14 -49
  221. package/src/actions/scales/offset.js +48 -0
  222. package/src/actions/scales/parallel.js +71 -0
  223. package/src/actions/scales/patch.js +1 -1
  224. package/src/actions/scales/preview.js +140 -0
  225. package/src/actions/scales/quantitativeColor.js +9 -5
  226. package/src/actions/selection/actions.js +154 -30
  227. package/src/actions/selection/index.js +3 -0
  228. package/src/actions/theme/actions.js +98 -0
  229. package/src/actions/theme/composition.js +238 -0
  230. package/src/actions/theme/index.js +16 -0
  231. package/src/actions/theme/reconcile.js +1130 -0
  232. package/src/actions/theme/state.js +160 -0
  233. package/src/actions/titles/actions.js +11 -10
  234. package/src/actions/titles/resolve.js +1 -40
  235. package/src/actions/violinPlots/create.js +90 -43
  236. package/src/actions/violinPlots/edit.js +192 -0
  237. package/src/actions/violinPlots/index.js +2 -0
  238. package/src/core/ChartProgram.js +7 -0
  239. package/src/core/action.js +32 -2
  240. package/src/core/compositionState.js +141 -8
  241. package/src/core/programState.js +20 -0
  242. package/src/core/resourceReferences.js +332 -0
  243. package/src/core/vocabulary.js +16 -3
  244. package/src/grammar/aggregate.js +66 -23
  245. package/src/grammar/arcs.js +58 -1
  246. package/src/grammar/areaEndpoints.js +46 -0
  247. package/src/grammar/areaSeries.js +87 -41
  248. package/src/grammar/bars/aggregate.js +37 -13
  249. package/src/grammar/bars/geometry.js +44 -0
  250. package/src/grammar/bars/policy.js +9 -7
  251. package/src/grammar/bin.js +226 -0
  252. package/src/grammar/categoryOrder.js +34 -0
  253. package/src/grammar/complete.js +279 -0
  254. package/src/grammar/computed.js +351 -0
  255. package/src/grammar/coordinates.js +37 -0
  256. package/src/grammar/density.js +239 -37
  257. package/src/grammar/displayLabels.js +57 -0
  258. package/src/grammar/ecdf.js +198 -0
  259. package/src/grammar/facets/dependencies.js +133 -1
  260. package/src/grammar/facets/guides.js +3 -0
  261. package/src/grammar/facets/index.js +123 -52
  262. package/src/grammar/facets/scales.js +15 -18
  263. package/src/grammar/fold.js +123 -0
  264. package/src/grammar/horizon.js +6 -4
  265. package/src/grammar/impute.js +340 -0
  266. package/src/grammar/interval.js +37 -20
  267. package/src/grammar/lineSeries.js +20 -63
  268. package/src/grammar/markFilter.js +22 -4
  269. package/src/grammar/markLabelSelection.js +57 -0
  270. package/src/grammar/markLabels.js +110 -0
  271. package/src/grammar/normalize.js +366 -0
  272. package/src/grammar/parallelAxisTitles.js +16 -0
  273. package/src/grammar/pathSeries.js +109 -0
  274. package/src/grammar/pointPacking.js +183 -0
  275. package/src/grammar/pointShapes.js +13 -4
  276. package/src/grammar/polar.js +90 -8
  277. package/src/grammar/positionDatum.js +12 -0
  278. package/src/grammar/rects.js +9 -1
  279. package/src/grammar/regression/derive.js +4 -0
  280. package/src/grammar/regression/index.js +8 -2
  281. package/src/grammar/regression/models.js +22 -7
  282. package/src/grammar/regression/parameters.js +63 -13
  283. package/src/grammar/rotation.js +29 -0
  284. package/src/grammar/roundedRect.js +180 -0
  285. package/src/grammar/rules.js +8 -21
  286. package/src/grammar/scales/color.js +23 -1
  287. package/src/grammar/scales/colorConsumers.js +57 -0
  288. package/src/grammar/scales/continuous.js +2 -2
  289. package/src/grammar/scales/definition.js +42 -5
  290. package/src/grammar/scales/discretized.js +11 -5
  291. package/src/grammar/scales/fields.js +38 -8
  292. package/src/grammar/scales/index.js +1 -0
  293. package/src/grammar/scales/mapping.js +2 -0
  294. package/src/grammar/scales/ordinal.js +12 -3
  295. package/src/grammar/scales/policies.js +2 -2
  296. package/src/grammar/scales/radial.js +55 -0
  297. package/src/grammar/scales/size.js +456 -0
  298. package/src/grammar/scales/types.js +1 -0
  299. package/src/grammar/schemas/concreteGraphic.js +14 -2
  300. package/src/grammar/schemas/graphic.js +15 -0
  301. package/src/grammar/schemas/graphicBounds.js +179 -30
  302. package/src/grammar/schemas/semanticPath.js +23 -4
  303. package/src/grammar/stack.js +170 -0
  304. package/src/grammar/statisticalReference.js +103 -0
  305. package/src/grammar/statistics/confidenceInterval.js +101 -0
  306. package/src/grammar/strokeStyle.js +77 -0
  307. package/src/grammar/summary.js +245 -0
  308. package/src/grammar/text.js +22 -16
  309. package/src/grammar/timeUnit.js +234 -13
  310. package/src/grammar/transformTopology.js +10 -0
  311. package/src/grammar/transforms.js +418 -16
  312. package/src/grammar/valueFormat.js +112 -0
  313. package/src/grammar/weightedStatistics.js +374 -0
  314. package/src/grammar/window.js +232 -21
  315. package/src/layout/aspect.js +80 -0
  316. package/src/layout/facets.js +100 -12
  317. package/src/layout/guideCollisions.js +12 -0
  318. package/src/layout/labels.js +343 -0
  319. package/src/layout/legend.js +2 -10
  320. package/src/layout/legendItems.js +102 -0
  321. package/src/layout/legendLane.js +100 -11
  322. package/src/materialization/bars/aggregate.js +56 -147
  323. package/src/materialization/bars/histogram.js +104 -20
  324. package/src/materialization/bars/ranged.js +19 -3
  325. package/src/materialization/bars/resolve.js +7 -4
  326. package/src/materialization/categorySlotOffset.js +40 -0
  327. package/src/materialization/composition.js +3 -1
  328. package/src/materialization/compositionSnapshot.js +1 -1
  329. package/src/materialization/coordinateBounds.js +204 -0
  330. package/src/materialization/dependencies.js +93 -16
  331. package/src/materialization/encodings.js +1 -1
  332. package/src/materialization/facetGuides/legacyCategorical.js +3 -0
  333. package/src/materialization/facetGuides/placement.js +8 -2
  334. package/src/materialization/facetGuides/preparation.js +12 -7
  335. package/src/materialization/facetHeaders.js +346 -0
  336. package/src/materialization/facets.js +23 -66
  337. package/src/materialization/guides/layout.js +57 -0
  338. package/src/materialization/guides/resources.js +28 -2
  339. package/src/materialization/legends.js +11 -2
  340. package/src/materialization/marks/capabilities.js +20 -5
  341. package/src/materialization/marks/grouping.js +52 -0
  342. package/src/materialization/marks/index.js +68 -27
  343. package/src/materialization/marks/policies.js +4 -1
  344. package/src/materialization/rect.js +55 -42
  345. package/src/materialization/rectConfig.js +5 -1
  346. package/src/materialization/rowEncoding.js +13 -13
  347. package/src/materialization/scaleGuideDependencies.js +8 -5
  348. package/src/materialization/scales/map.js +6 -3
  349. package/src/materialization/scales/policies/arc.js +42 -0
  350. package/src/materialization/scales/policies/binnedPosition.js +7 -4
  351. package/src/materialization/scales/policies/offset.js +50 -8
  352. package/src/materialization/scales/policies/series.js +5 -1
  353. package/src/materialization/scales/resolve.js +65 -17
  354. package/src/materialization/selection/compatibility.js +11 -0
  355. package/src/materialization/selection/items/arc.js +28 -4
  356. package/src/materialization/selection/items/bar.js +42 -71
  357. package/src/materialization/selection/items/common.js +27 -6
  358. package/src/materialization/selection/items/path.js +3 -13
  359. package/src/materialization/selection/items/rect.js +35 -8
  360. package/src/materialization/selection/path.js +1 -1
  361. package/src/materialization/selection/point.js +3 -1
  362. package/src/materialization/text.js +324 -14
  363. package/src/mcp/adapter.js +2 -2
  364. package/src/renderers/canvas/circle.js +2 -3
  365. package/src/renderers/canvas/line.js +2 -3
  366. package/src/renderers/canvas/native.js +4 -4
  367. package/src/renderers/canvas/path.js +2 -3
  368. package/src/renderers/canvas/rect.js +2 -3
  369. package/src/renderers/canvas/stroke.js +11 -0
  370. package/src/renderers/svg.js +19 -0
  371. package/src/selectors/datasets.js +44 -0
  372. package/src/selectors/layers.js +7 -2
  373. package/src/selectors/scales.js +6 -0
  374. package/src/theme/defaults.js +140 -0
  375. package/types/basic.d.ts +17 -2
  376. package/types/index.d.ts +211 -0
  377. package/types/program.d.ts +2182 -204
  378. package/src/materialization/bars/grouped.js +0 -144
@@ -1,12 +1,19 @@
1
+ import { isSourceOwnedText } from "../../grammar/text.js";
1
2
  import { action } from "../../core/action.js";
2
3
  import { validateUserId } from "../../core/identifiers.js";
3
4
  import { validateKeys } from "../../core/validation.js";
4
5
  import { findDataset } from "../../selectors/datasets.js";
5
6
  import { findLayer } from "../../selectors/layers.js";
7
+ import { applyDetachedScaleRematerialization } from "../../materialization/dependencies.js";
8
+ import { markLabelPlacementLeaderId } from "../../layout/labels.js";
6
9
  import {
7
10
  getPositionChannelDefinition,
8
11
  POSITION_CHANNELS
9
12
  } from "../../core/vocabulary.js";
13
+ import {
14
+ canonicalResourcePath,
15
+ collectResourceReferences
16
+ } from "../../core/resourceReferences.js";
10
17
 
11
18
  const OPTIONS = Object.freeze(["target"]);
12
19
  const REMOVE_AXIS = Object.freeze({
@@ -28,18 +35,32 @@ function ownedChildren(program, id) {
28
35
  config.boxPlot?.whiskerId,
29
36
  config.boxPlot?.medianId,
30
37
  config.boxPlot?.outlierId,
31
- config.gradientPlot?.centerId
38
+ config.gradientPlot?.centerId,
39
+ config.intervalPlot?.intervalId,
40
+ config.endpointPlot?.roles?.stemId,
41
+ config.endpointPlot?.roles?.startId,
42
+ config.endpointPlot?.roles?.connectorId,
43
+ ...(config.raincloudPlot?.ownedChildIds ?? [])
32
44
  ].concat(
33
45
  program.semanticSpec.layers
34
46
  .filter(layer => layer.source === id)
35
47
  .map(layer => layer.id)
36
- ).filter(child => child !== undefined && findLayer(program, child) !== undefined);
48
+ ).concat(
49
+ program.semanticSpec.layers
50
+ .filter(layer =>
51
+ program.markConfigs[layer.id]?.statisticalReference?.source === id
52
+ )
53
+ .map(layer => layer.id)
54
+ ).filter(child => child !== undefined && child !== id && findLayer(program, child) !== undefined);
37
55
  }
38
56
 
39
57
  function ownership(program) {
40
58
  const ownerByChild = new Map();
41
59
  for (const layer of program.semanticSpec.layers) {
42
60
  for (const child of ownedChildren(program, layer.id)) {
61
+ if (program.markConfigs[child]?.statisticalReference !== undefined) {
62
+ continue;
63
+ }
43
64
  ownerByChild.set(child, layer.id);
44
65
  }
45
66
  }
@@ -79,6 +100,37 @@ function collectClosure(program, root) {
79
100
  return result;
80
101
  }
81
102
 
103
+ function externalMarkReferences(program, ids) {
104
+ const closure = new Set(ids);
105
+ const references = ids.flatMap(id => collectResourceReferences(program, {
106
+ kind: "mark",
107
+ id
108
+ })).filter(reference => {
109
+ if (reference.strength === "context") return false;
110
+ if (["layer", "markConfig"].includes(reference.ownerKind)) {
111
+ return !closure.has(reference.ownerId);
112
+ }
113
+ if (["selection", "highlight", "legend"].includes(reference.ownerKind)) {
114
+ return false;
115
+ }
116
+ if (
117
+ reference.ownerKind === "axis" &&
118
+ reference.ownerId === "parallel.axes"
119
+ ) {
120
+ return false;
121
+ }
122
+ return true;
123
+ });
124
+ const unique = new Map(references.map(reference => [[
125
+ reference.ownerKind,
126
+ reference.ownerId,
127
+ canonicalResourcePath(reference.path)
128
+ ].join("\u0000"), reference]));
129
+ return [...unique.entries()]
130
+ .sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0)
131
+ .map(([, reference]) => reference);
132
+ }
133
+
82
134
  function ownedDerivedData(program, ids) {
83
135
  const candidates = new Set();
84
136
  for (const id of ids) {
@@ -90,7 +142,11 @@ function ownedDerivedData(program, ids) {
90
142
  config.regression?.dataId,
91
143
  config.boxPlot?.summaryId,
92
144
  config.boxPlot?.outlierDataId,
93
- config.gradientPlot?.profileId
145
+ config.gradientPlot?.profileId,
146
+ config.violinPlot?.materialized === true ? layer?.data : undefined,
147
+ config.ecdfPlot?.data,
148
+ config.endpointPlot?.data,
149
+ config.statisticalReference?.dataId
94
150
  ]) {
95
151
  if (candidate !== undefined) candidates.add(candidate);
96
152
  }
@@ -161,7 +217,7 @@ export function removeOwnedMark(program, id, partial = false) {
161
217
 
162
218
  function hasScaleConsumer(program, channel, scale) {
163
219
  return program.semanticSpec.layers.some(
164
- layer => layer.encoding?.[channel]?.scale === scale
220
+ layer => !isSourceOwnedText(layer) && layer.encoding?.[channel]?.scale === scale
165
221
  );
166
222
  }
167
223
 
@@ -198,10 +254,26 @@ export const removeMark = action(
198
254
  validateKeys(args, OPTIONS, "removeMark");
199
255
  const owner = resolveOwner(this, args.target);
200
256
  const ids = collectClosure(this, owner.id);
257
+ const external = externalMarkReferences(this, ids);
258
+ if (external.length > 0) {
259
+ throw new Error(
260
+ `removeMark cannot remove externally referenced marks: ${external.map(
261
+ reference => `${reference.ownerKind} "${reference.ownerId}" at ` +
262
+ canonicalResourcePath(reference.path)
263
+ ).join("; ")}.`
264
+ );
265
+ }
266
+ const previousLayers = ids.map(id => findLayer(this, id));
201
267
  const derived = ownedDerivedData(this, ids);
202
268
  const positionScales = usedPositionScales(this, ids);
203
269
  let next = this;
204
270
 
271
+ if (ids.includes(next.guideConfigs.axis?.parallel?.axes?.target)) {
272
+ next = next.removeParallelAxes({
273
+ target: next.guideConfigs.axis.parallel.axes.target
274
+ });
275
+ }
276
+
205
277
  const legendTargets = [...new Set(Object.values(next.guideConfigs.legend ?? {})
206
278
  .filter(config => ids.includes(config?.target))
207
279
  .map(config => config.target))];
@@ -219,6 +291,15 @@ export const removeMark = action(
219
291
  ) {
220
292
  next = next.editGraphics({ target: labelLayout.leaderId, remove: true });
221
293
  }
294
+ const placement = next.markConfigs[id]?.labelAuthoring?.placement;
295
+ const placementLeaderId = markLabelPlacementLeaderId(id);
296
+ if (
297
+ placement?.leader !== undefined &&
298
+ placement.leader !== false &&
299
+ next.graphicSpec.objects[placementLeaderId] !== undefined
300
+ ) {
301
+ next = next.editGraphics({ target: placementLeaderId, remove: true });
302
+ }
222
303
  if (findLayer(next, id) !== undefined) {
223
304
  next = next.editSemantic({ property: `layer[${id}]`, remove: true });
224
305
  }
@@ -227,6 +308,7 @@ export const removeMark = action(
227
308
  }
228
309
  next = next._withoutMaterializationConfig(["marks", id]);
229
310
  next = next._withoutMaterializationConfig(["jitters", id]);
311
+ next = next._withoutMaterializationConfig(["pointPacking", id]);
230
312
  next = next._withoutMaterializationConfig(["labelLayouts", id]);
231
313
  }
232
314
 
@@ -236,6 +318,7 @@ export const removeMark = action(
236
318
  next = next.releaseDerivedData({ id });
237
319
  }
238
320
  }
321
+ next = applyDetachedScaleRematerialization(next, previousLayers);
239
322
  return next._withContext({
240
323
  ...(ids.includes(this.context.currentMark) ? { currentMark: undefined } : {}),
241
324
  ...(selectionCleanup.selectionIds.includes(this.context.currentSelection)
@@ -9,10 +9,13 @@ import {
9
9
  normalizeStrokeDashPattern
10
10
  } from "../../../grammar/scales/index.js";
11
11
  import { deriveRuleValues, resolveRuleMode } from "../../../grammar/rules.js";
12
- import { resolveGraphicBounds } from "../../../layout/canvas.js";
12
+ import { resolveCoordinateBounds } from "../../../materialization/coordinateBounds.js";
13
+ import { readRectItemGeometry } from "../../../grammar/roundedRect.js";
13
14
  import { findDataset } from "../../../selectors/datasets.js";
14
- import { findLayer } from "../../../selectors/layers.js";
15
+ import { findLayer, resolveEligibleLayer } from "../../../selectors/layers.js";
16
+ import { applyRuleAppearance, planRuleAppearance } from "./appearance.js";
15
17
  import { DEFAULT_COLORS } from "../../../theme/defaults.js";
18
+ import { rematerializeExistingLegend } from "../../encodings/shared.js";
16
19
  import {
17
20
  assertMarkAvailable,
18
21
  applyLayeredMarkInheritance,
@@ -28,8 +31,21 @@ import { resolveMarkGraphicPlacement } from
28
31
  import { rematerializeHighlightBaseline } from "../lifecycle.js";
29
32
  import { applyOffsetPositionValues } from
30
33
  "../../../materialization/rowEncoding.js";
34
+ import { resolveCategorySlotOffset } from
35
+ "../../../materialization/categorySlotOffset.js";
36
+ import { mapScaleConsumerValues } from
37
+ "../../../materialization/scales/map.js";
38
+ import {
39
+ requestedStrokeDetails,
40
+ STROKE_STYLE_PROPERTIES
41
+ } from "../../../grammar/strokeStyle.js";
31
42
 
32
- const CREATE_OPTIONS = Object.freeze(["id", "data"]);
43
+ const APPEARANCE_OPTIONS = Object.freeze([
44
+ "stroke", "strokeWidth", "strokeDash", "opacity",
45
+ ...STROKE_STYLE_PROPERTIES
46
+ ]);
47
+ const CREATE_OPTIONS = Object.freeze(["id", "data", ...APPEARANCE_OPTIONS]);
48
+ const EDIT_OPTIONS = Object.freeze(["target", ...APPEARANCE_OPTIONS]);
33
49
  const REMATERIALIZE_OPTIONS = Object.freeze(["id"]);
34
50
  const SPAN_OPTIONS = Object.freeze(["id", "orientation", "size"]);
35
51
  const DEFAULT_RULE_CONFIG = Object.freeze({
@@ -83,6 +99,7 @@ const createRuleMark = action(
83
99
  },
84
100
  function (args = {}) {
85
101
  validateMarkOptions(args, CREATE_OPTIONS, "createRuleMark");
102
+ const strokeDetails = requestedStrokeDetails(args, "createRuleMark");
86
103
  const id = resolveMarkId(this, args.id, {
87
104
  defaultId: "rule",
88
105
  label: "Rule mark id",
@@ -96,6 +113,7 @@ const createRuleMark = action(
96
113
  inherited?.data !== undefined ? { data: inherited.data } : {})
97
114
  });
98
115
  assertMarkAvailable(this, id);
116
+ const appearance = planRuleAppearance(args, inherited);
99
117
 
100
118
  let created = this
101
119
  .editSemantic({ property: `layer[${id}].mark.type`, value: "rule" })
@@ -110,6 +128,7 @@ const createRuleMark = action(
110
128
  })
111
129
  ._withMarkConfig(id, {
112
130
  ...DEFAULT_RULE_CONFIG,
131
+ ...strokeDetails,
113
132
  ...(inherited === undefined
114
133
  ? {}
115
134
  : {
@@ -119,7 +138,33 @@ const createRuleMark = action(
119
138
  }
120
139
  })
121
140
  });
122
- return materializeInheritedMark(created, id);
141
+ return applyRuleAppearance(materializeInheritedMark(created, id), id, appearance);
142
+ }
143
+ );
144
+
145
+ const editRuleMark = action(
146
+ { op: "editRuleMark", description: "Edit constant rule appearance through its encoding owners." },
147
+ function (args = {}) {
148
+ validateMarkOptions(args, EDIT_OPTIONS, "editRuleMark");
149
+ const strokeDetails = requestedStrokeDetails(args, "editRuleMark");
150
+ if (args.target !== undefined) validateUserId(args.target, "Rule mark id");
151
+ const layer = resolveEligibleLayer(this, {
152
+ target: args.target,
153
+ predicate: candidate => candidate.mark?.type === "rule",
154
+ label: "rule mark"
155
+ });
156
+ const appearance = planRuleAppearance(args, layer);
157
+ if (appearance.length === 0 && Object.keys(strokeDetails).length === 0) {
158
+ throw new Error("editRuleMark requires an appearance change.");
159
+ }
160
+ const configured = this._withMarkConfig(layer.id, {
161
+ ...this.markConfigs[layer.id],
162
+ ...strokeDetails
163
+ });
164
+ const materialized = appearance.length === 0
165
+ ? configured.rematerializeRuleMark({ id: layer.id })
166
+ : applyRuleAppearance(configured, layer.id, appearance);
167
+ return rematerializeExistingLegend(materialized);
123
168
  }
124
169
  );
125
170
 
@@ -159,7 +204,7 @@ const rematerializeRuleMark = action(
159
204
  const scaleIds = [...new Set(
160
205
  [
161
206
  "x", "y", "x2", "y2", "xOffset", "yOffset",
162
- "strokeDash", "strokeWidth", "opacity"
207
+ "stroke", "strokeDash", "strokeWidth", "opacity"
163
208
  ]
164
209
  .map(channel => layer.encoding?.[channel]?.scale)
165
210
  .filter(scale => scale !== undefined)
@@ -203,7 +248,7 @@ const rematerializeRuleMark = action(
203
248
  channel
204
249
  });
205
250
  }
206
- const bounds = resolveGraphicBounds(resolved);
251
+ const bounds = resolveCoordinateBounds(resolved, layer.coordinate);
207
252
  const x1 = [];
208
253
  const y1 = [];
209
254
  const x2 = [];
@@ -231,7 +276,11 @@ const rematerializeRuleMark = action(
231
276
  startY = endY = mapped.y[index];
232
277
  } else if (mode === "box-span") {
233
278
  const owner = resolved.graphicSpec.objects[boxSpan];
234
- const box = owner?.items?.[index]?.properties;
279
+ const item = owner?.items?.[index];
280
+ const box = readRectItemGeometry({
281
+ type: item?.type ?? owner?.type,
282
+ properties: item?.properties
283
+ });
235
284
  if (box === undefined) throw new Error(`Rule mark "${id}" requires box span owner "${boxSpan}".`);
236
285
  if (layer.encoding?.x?.fieldType === "quantitative") {
237
286
  startX = endX = mapped.x[index];
@@ -263,12 +312,22 @@ const rematerializeRuleMark = action(
263
312
  x2.push(endX);
264
313
  y2.push(endY);
265
314
  }
315
+ const categoryOffset = resolveCategorySlotOffset(resolved, layer);
316
+ if (categoryOffset?.pixels) {
317
+ const targets = categoryOffset.channel === "x" ? [x1, x2] : [y1, y2];
318
+ for (const values of targets) {
319
+ for (let index = 0; index < values.length; index += 1) {
320
+ if (Number.isFinite(values[index])) values[index] += categoryOffset.pixels;
321
+ }
322
+ }
323
+ }
266
324
 
267
325
  const resolvedConfig = {
268
326
  ...DEFAULT_RULE_CONFIG,
269
327
  ...resolved.markConfigs[id]
270
328
  };
271
329
  const dashEncoding = layer.encoding?.strokeDash;
330
+ const strokeEncoding = layer.encoding?.stroke;
272
331
  const opacityEncoding = layer.encoding?.opacity;
273
332
  const strokeWidthEncoding = layer.encoding?.strokeWidth;
274
333
  const strokeDash = dashEncoding?.scale === undefined
@@ -295,6 +354,13 @@ const rematerializeRuleMark = action(
295
354
  derived.values.strokeWidth,
296
355
  resolved.resolvedScales[strokeWidthEncoding.scale]
297
356
  );
357
+ const stroke = strokeEncoding?.scale === undefined
358
+ ? resolvedConfig.stroke
359
+ : mapScaleConsumerValues(
360
+ derived.values.stroke,
361
+ resolved.resolvedScales[strokeEncoding.scale],
362
+ "stroke"
363
+ );
298
364
 
299
365
  return editMarkGraphic(resolved, id, {
300
366
  length: derived.length,
@@ -302,10 +368,11 @@ const rematerializeRuleMark = action(
302
368
  y1,
303
369
  x2,
304
370
  y2,
305
- stroke: resolvedConfig.stroke,
371
+ stroke,
306
372
  strokeWidth,
307
373
  strokeDash,
308
- opacity
374
+ opacity,
375
+ ...requestedStrokeDetails(resolvedConfig, "Rule mark")
309
376
  });
310
377
  }
311
378
  );
@@ -337,6 +404,7 @@ export const materializeRuleSpan = action(
337
404
  export function registerRuleMarkActions(ProgramClass) {
338
405
  Object.assign(ProgramClass.prototype, {
339
406
  createRuleMark,
407
+ editRuleMark,
340
408
  rematerializeRuleMark,
341
409
  materializeRuleSpan
342
410
  });
@@ -0,0 +1,26 @@
1
+ import { validateRuleStroke, validateRuleStrokeWidth } from "../../../grammar/ruleAppearance.js";
2
+ import { normalizeStrokeDashPattern, validateOpacityValue } from "../../../grammar/scales/index.js";
3
+
4
+ const STYLE_ACTIONS = Object.freeze({
5
+ stroke: ["encodeStroke", validateRuleStroke],
6
+ strokeWidth: ["encodeStrokeWidth", validateRuleStrokeWidth],
7
+ strokeDash: ["encodeStrokeDash", normalizeStrokeDashPattern],
8
+ opacity: ["encodeOpacity", validateOpacityValue]
9
+ });
10
+
11
+ export function planRuleAppearance(args, layer) {
12
+ return Object.entries(STYLE_ACTIONS).flatMap(([property, [op, validate]]) => {
13
+ if (!Object.hasOwn(args, property)) return [];
14
+ if (layer?.encoding?.[property]?.field !== undefined) {
15
+ throw new Error(`Rule ${property} conflicts with a field encoding; use ${op} with value to replace it.`);
16
+ }
17
+ validate(args[property], `Rule ${property}`);
18
+ return [{ op, value: args[property] }];
19
+ });
20
+ }
21
+
22
+ export function applyRuleAppearance(program, target, plan) {
23
+ let next = program;
24
+ for (const { op, value } of plan) next = next[op]({ target, value });
25
+ return next;
26
+ }
@@ -1,8 +1,9 @@
1
+ import { isSourceOwnedText } from "../../grammar/text.js";
1
2
  import {
2
3
  resolveOptionalUserId,
3
4
  validateUserId
4
5
  } from "../../core/identifiers.js";
5
- import { findDataset } from "../../selectors/datasets.js";
6
+ import { findDataset, requireMaterializedDataset } from "../../selectors/datasets.js";
6
7
  import { findLayer, hasLayer } from "../../selectors/layers.js";
7
8
  import { findSemanticScale } from "../../selectors/scales.js";
8
9
  import { resolveMarkPositionPolicy } from "../encodings/position/policies/index.js";
@@ -27,13 +28,8 @@ export function resolveMarkData(program, requested) {
27
28
  throw new Error("Mark creation requires data or a current dataset.");
28
29
  }
29
30
 
30
- const dataset = findDataset(program, data);
31
-
32
- if (dataset === undefined) {
33
- throw new Error(`Unknown dataset "${data}".`);
34
- }
35
-
36
- return { data, dataset };
31
+ const dataset = requireMaterializedDataset(program, data);
32
+ return { data: dataset.id, dataset };
37
33
  }
38
34
 
39
35
  export function resolveMarkId(program, requested, {
@@ -60,7 +56,7 @@ export function assertMarkAvailable(program, id) {
60
56
  throw new Error(`Mark "${id}" already exists.`);
61
57
  }
62
58
 
63
- if (program.graphicSpec.objects[id] !== undefined) {
59
+ if (Object.hasOwn(program.graphicSpec.objects, id)) {
64
60
  throw new Error(`Graphic "${id}" already exists.`);
65
61
  }
66
62
  }
@@ -78,9 +74,9 @@ const POSITION_POLICY_SUBSETS = Object.freeze([
78
74
  ]);
79
75
 
80
76
  function inheritedPositionEncodings(encoding) {
81
- if (encoding?.field === undefined) return undefined;
77
+ if (encoding?.field === undefined && encoding?.aggregate !== "count") return undefined;
82
78
  const base = Object.fromEntries(
83
- ["field", "fieldType", "scale", "title"]
79
+ ["field", "fieldType", "scale", "title", "temporalUnit"]
84
80
  .filter(property => Object.hasOwn(encoding, property))
85
81
  .map(property => [property, encoding[property]])
86
82
  );
@@ -104,6 +100,9 @@ function inheritedPositionEncodings(encoding) {
104
100
  function scaleSupportsEncoding(program, markType, channel, encoding) {
105
101
  const scale = findSemanticScale(program, encoding.scale);
106
102
  if (scale === undefined) return false;
103
+ if (scale.radialMapping !== undefined) {
104
+ return markType === "arc" && channel === "radius" && ["count", "sum"].includes(encoding.aggregate);
105
+ }
107
106
  const categorical = ["nominal", "ordinal"].includes(encoding.fieldType);
108
107
  if (categorical) {
109
108
  if (["bar", "rect"].includes(markType)) return scale.type === "band";
@@ -143,7 +142,8 @@ export function resolveCompatibleEncodings(program, source, markType) {
143
142
  layer: candidate,
144
143
  dataset,
145
144
  channel,
146
- args: encoding,
145
+ args: { ...encoding, ...(channel === "radius" && findSemanticScale(program, encoding.scale)?.radialMapping !== undefined
146
+ ? { mapping: findSemanticScale(program, encoding.scale).radialMapping } : {}) },
147
147
  field: encoding.field,
148
148
  fieldType: encoding.fieldType
149
149
  });
@@ -163,7 +163,7 @@ export function resolveCompatibleEncodings(program, source, markType) {
163
163
  }
164
164
 
165
165
  function eligibleLayeredSource(program, layer, requestedData, markType) {
166
- if (layer?.data === undefined) return false;
166
+ if (layer?.data === undefined || isSourceOwnedText(layer)) return false;
167
167
  if (requestedData !== undefined && layer.data !== requestedData) return false;
168
168
  return Object.keys(resolveCompatibleEncodings(program, layer, markType)).length > 0;
169
169
  }