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
@@ -4,10 +4,14 @@ import { readQuantitativeField } from "../../grammar/scales/index.js";
4
4
  import { BAR_GRAINS, resolveBarGrain } from "../../grammar/bars/policy.js";
5
5
  import { resolveFacetScaleDomains } from "../../grammar/facets/scales.js";
6
6
  import {
7
+ applyLayerEmptyDataView,
7
8
  applyMaterializationPlan,
8
9
  planScaleGuideRematerialization
9
10
  } from "../../materialization/dependencies.js";
10
- import { getMarkMaterializationStep } from "../../materialization/marks/index.js";
11
+ import {
12
+ getLayerScaleIds,
13
+ getMarkMaterializationStep
14
+ } from "../../materialization/marks/index.js";
11
15
  import { buildMaterializationPlan } from "../../materialization/planner.js";
12
16
  import { requireDataset } from "../../selectors/datasets.js";
13
17
  import { requireLayer } from "../../selectors/layers.js";
@@ -56,19 +60,31 @@ function applySharedHistogramBoundaries(program, layerId, boundaries) {
56
60
  });
57
61
  }
58
62
 
59
- function deriveCellProgram(
63
+ function buildFacetCellCandidate(
60
64
  base,
61
65
  definition,
62
66
  cell,
63
67
  histogramBoundaries,
64
68
  scales
65
69
  ) {
66
- let child = base.filterData({
67
- id: cell.data,
68
- source: definition.data,
70
+ const filters = cell.filters ?? [{
69
71
  field: definition.field,
70
- oneOf: [cell.value]
71
- });
72
+ value: cell.value
73
+ }];
74
+ let child = base;
75
+ let source = definition.data;
76
+ for (const [index, filter] of filters.entries()) {
77
+ const id = index === filters.length - 1
78
+ ? cell.data
79
+ : `${cell.id}-partition-${index + 1}-data`;
80
+ child = child.filterData({
81
+ id,
82
+ source,
83
+ field: filter.field,
84
+ oneOf: [filter.value]
85
+ });
86
+ source = id;
87
+ }
72
88
  const datasets = new Map([[definition.data, cell.data]]);
73
89
  for (const replay of definition.dependencies.replay) {
74
90
  const source = datasets.get(replay.source);
@@ -90,6 +106,7 @@ function deriveCellProgram(
90
106
  });
91
107
  datasets.set(replay.id, id);
92
108
  }
109
+ const reboundData = new Map();
93
110
  for (const layer of definition.dependencies.layers) {
94
111
  const data = datasets.get(layer.data);
95
112
  if (data === undefined) {
@@ -97,6 +114,14 @@ function deriveCellProgram(
97
114
  `Facet layer "${layer.id}" has no replayed dataset in cell "${cell.id}".`
98
115
  );
99
116
  }
117
+ reboundData.set(layer.id, data);
118
+ const statistical = child.markConfigs[layer.id]?.statisticalReference;
119
+ if (statistical !== undefined) {
120
+ child = child._withMarkConfig(layer.id, {
121
+ ...child.markConfigs[layer.id],
122
+ statisticalReference: { ...statistical, dataId: data }
123
+ });
124
+ }
100
125
  child = child.rebindLayerData({ id: layer.id, data });
101
126
  child = applySharedHistogramBoundaries(
102
127
  child,
@@ -116,20 +141,35 @@ function deriveCellProgram(
116
141
  }
117
142
  child = child.rebindGradientPlotProfile({ id, profile, source });
118
143
  }
119
- const scaleIds = [...new Set(child.semanticSpec.layers.flatMap(layer =>
120
- Object.values(layer.encoding ?? {})
121
- .map(encoding => encoding?.scale)
122
- .filter(id => id !== undefined)
123
- ))];
124
- return applyMaterializationPlan(child, buildMaterializationPlan({
144
+ const primaryLayers = definition.dependencies.primaryLayers ??
145
+ definition.dependencies.layers.map(layer => layer.id);
146
+ const populated = primaryLayers.some(id => {
147
+ const data = reboundData.get(id);
148
+ return data !== undefined && requireDataset(child, data).values.length > 0;
149
+ });
150
+ if (!populated) {
151
+ for (const layer of definition.dependencies.layers) {
152
+ child = applyLayerEmptyDataView(child, layer.id);
153
+ }
154
+ return { program: child, populated: false };
155
+ }
156
+ const scaleIds = [...new Set(child.semanticSpec.layers.flatMap(getLayerScaleIds))];
157
+ const program = applyMaterializationPlan(child, buildMaterializationPlan({
125
158
  scales: scaleIds.map(id => ({
126
159
  op: "rematerializeScale",
127
160
  args: { id, guides: false, marks: false }
128
161
  }))
129
162
  }));
163
+ return { program, populated: true };
130
164
  }
131
165
 
132
- function applyResolvedDomains(program, childId, resolution, baseResolved) {
166
+ function applyResolvedDomains(
167
+ program,
168
+ childId,
169
+ resolution,
170
+ baseResolved,
171
+ { marks: materializeMarks = true } = {}
172
+ ) {
133
173
  let next = program;
134
174
  for (const [id, scaleResolution] of Object.entries(resolution.scales)) {
135
175
  const current = next.resolvedScales[id];
@@ -139,19 +179,22 @@ function applyResolvedDomains(program, childId, resolution, baseResolved) {
139
179
  const shared = scaleResolution.policy === "shared"
140
180
  ? baseResolved?.[id]
141
181
  : undefined;
182
+ const semanticDomain = findSemanticScale(next, id)?.domain;
183
+ const domain = scaleResolution.childDomains[childId] ??
184
+ scaleResolution.domain ?? semanticDomain;
142
185
  next = next._withResolvedScale(id, {
143
186
  ...current,
144
187
  ...shared,
145
- domain: scaleResolution.childDomains[childId]
188
+ domain
146
189
  });
147
190
  }
148
- const marks = next.semanticSpec.layers.flatMap(layer => {
191
+ const marks = materializeMarks ? next.semanticSpec.layers.flatMap(layer => {
149
192
  const step = getMarkMaterializationStep(next, layer);
150
193
  if (step === undefined) return [];
151
- return ["bar", "line", "area"].includes(layer.mark?.type)
194
+ return ["bar", "line", "area", "arc"].includes(layer.mark?.type)
152
195
  ? [{ ...step, args: { ...step.args, scales: false } }]
153
196
  : [step];
154
- });
197
+ }) : [];
155
198
  const guides = Object.keys(resolution.scales).flatMap(id =>
156
199
  planScaleGuideRematerialization(next, id)
157
200
  );
@@ -161,6 +204,22 @@ function applyResolvedDomains(program, childId, resolution, baseResolved) {
161
204
  );
162
205
  }
163
206
 
207
+ function materializeFacetCell(
208
+ child,
209
+ childId,
210
+ resolution,
211
+ baseResolved,
212
+ populated
213
+ ) {
214
+ return applyResolvedDomains(
215
+ child,
216
+ childId,
217
+ resolution,
218
+ baseResolved,
219
+ { marks: populated }
220
+ );
221
+ }
222
+
164
223
  export function deriveFacetChildren(
165
224
  base,
166
225
  definition,
@@ -178,34 +237,89 @@ export function deriveFacetChildren(
178
237
  const bins = xPolicy === "shared"
179
238
  ? sharedHistogramBoundaries(template)
180
239
  : new Map();
181
- const independentlyResolved = Object.fromEntries(definition.cells.map(cell => [
240
+ const candidates = Object.fromEntries(definition.cells.map(cell => [
182
241
  cell.id,
183
- deriveCellProgram(template, definition, cell, bins, scales)
242
+ buildFacetCellCandidate(template, definition, cell, bins, scales)
184
243
  ]));
244
+ const independentlyResolved = Object.fromEntries(Object.entries(candidates).map(
245
+ ([id, candidate]) => [id, candidate.program]
246
+ ));
247
+ const populatedIds = new Set(Object.entries(candidates).flatMap(
248
+ ([id, candidate]) => candidate.populated ? [id] : []
249
+ ));
250
+ return resolveFacetChildrenScales(
251
+ template,
252
+ definition.cells.map(cell => cell.id),
253
+ independentlyResolved,
254
+ scales,
255
+ closeInheritedAction,
256
+ populatedIds
257
+ );
258
+ }
259
+
260
+ export function resolveFacetChildrenScales(
261
+ template,
262
+ cellIds,
263
+ independentlyResolved,
264
+ scales = {},
265
+ closeInheritedAction = false,
266
+ populatedIds = undefined
267
+ ) {
268
+ const populated = Object.fromEntries(cellIds.flatMap(id => {
269
+ const child = independentlyResolved[id];
270
+ if (child === undefined) {
271
+ throw new Error(`Facet derivation is missing child "${id}".`);
272
+ }
273
+ const populated = populatedIds === undefined
274
+ ? child.semanticSpec.layers.length > 0
275
+ : populatedIds.has(id);
276
+ return populated ? [[id, child]] : [];
277
+ }));
278
+ if (Object.keys(populated).length === 0) {
279
+ throw new Error("Facet derivation requires at least one populated cell.");
280
+ }
185
281
  const resolution = resolveFacetScaleDomains(
186
282
  template.semanticSpec,
187
- Object.fromEntries(Object.entries(independentlyResolved).map(([id, child]) => [
283
+ Object.fromEntries(Object.entries(populated).map(([id, child]) => [
188
284
  id,
189
285
  child.resolvedScales
190
286
  ])),
191
287
  scales,
192
288
  template.resolvedScales
193
289
  );
290
+ const emptyIds = cellIds.filter(id => !Object.hasOwn(populated, id));
291
+ const scalesById = new Map(template.semanticSpec.scales.map(scale => [scale.id, scale]));
292
+ for (const childId of emptyIds) {
293
+ const unresolved = Object.entries(resolution.scales).find(([id, value]) =>
294
+ value.policy === "independent" && scalesById.get(id)?.domain === "auto"
295
+ );
296
+ if (unresolved !== undefined) {
297
+ throw new Error(
298
+ `Facet child "${childId}" cannot resolve independent scale "${unresolved[0]}" from an empty partition.`
299
+ );
300
+ }
301
+ }
194
302
  const resolvedChildren = Object.fromEntries(
195
- Object.entries(independentlyResolved).map(([id, child]) => {
196
- const resolved = applyResolvedDomains(
303
+ cellIds.map(id => {
304
+ const child = independentlyResolved[id];
305
+ if (child.semanticSpec.layers.length === 0) {
306
+ return [id, closeInheritedAction ? child._exitAction() : child];
307
+ }
308
+ const resolved = materializeFacetCell(
197
309
  child,
198
310
  id,
199
311
  resolution,
200
- template.resolvedScales
312
+ template.resolvedScales,
313
+ Object.hasOwn(populated, id)
201
314
  );
202
315
  return [id, closeInheritedAction ? resolved._exitAction() : resolved];
203
316
  })
204
317
  );
318
+ const firstPopulatedId = Object.keys(populated)[0];
205
319
  const sharedScales = Object.fromEntries(
206
320
  Object.entries(resolution.scales)
207
321
  .filter(([, value]) => value.policy === "shared")
208
- .map(([id]) => [id, resolvedChildren[definition.cells[0].id].resolvedScales[id]])
322
+ .map(([id]) => [id, resolvedChildren[firstPopulatedId].resolvedScales[id]])
209
323
  );
210
324
  return freezeOwned({
211
325
  children: freezeOwned(resolvedChildren),
@@ -1,6 +1,11 @@
1
+ import { assertGuideOptions, guideConflict } from "../guides/reuse.js";
1
2
  import { action } from "../../core/action.js";
2
3
  import { validateKeys } from "../../core/validation.js";
3
4
  import { GRADIENT_PROFILE_FIELDS } from "../../grammar/gradientProfile.js";
5
+ import {
6
+ requestedStrokeDetails,
7
+ STROKE_STYLE_PROPERTIES
8
+ } from "../../grammar/strokeStyle.js";
4
9
  import { resolveGraphicBounds } from "../../layout/canvas.js";
5
10
  import { findLayer } from "../../selectors/layers.js";
6
11
  import { createDensityLegendPaint } from "./paint.js";
@@ -8,7 +13,7 @@ import { createDensityLegendPaint } from "./paint.js";
8
13
  const CENTER_OPTIONS = Object.freeze([
9
14
  "id", "owner", "data", "category", "categoryType", "coordinate",
10
15
  "categoryScale", "measureScale", "orientation", "size", "stroke",
11
- "strokeWidth"
16
+ "strokeWidth", ...STROKE_STYLE_PROPERTIES
12
17
  ]);
13
18
  const LEGEND_OPTIONS = Object.freeze(["owner", "title", "position"]);
14
19
 
@@ -22,7 +27,11 @@ export const createGradientPlotCenter = action(
22
27
  const categoryAction = args.orientation === "vertical" ? "encodeX" : "encodeY";
23
28
  const measureAction = args.orientation === "vertical" ? "encodeY" : "encodeX";
24
29
  const spanOrientation = args.orientation === "vertical" ? "horizontal" : "vertical";
25
- let next = this.createRuleMark({ id: args.id, data: args.data });
30
+ let next = this.createRuleMark({
31
+ id: args.id,
32
+ data: args.data,
33
+ ...requestedStrokeDetails(args, "createGradientPlotCenter")
34
+ });
26
35
  next = next[categoryAction]({
27
36
  target: args.id,
28
37
  field: args.category,
@@ -120,23 +129,44 @@ export const rematerializeGradientPlotLegend = action(
120
129
  }
121
130
  );
122
131
 
132
+ function resolveDensityLegend(program, args) {
133
+ validateKeys(args, LEGEND_OPTIONS, "createGradientPlotLegend");
134
+ requireLegendOwner(program, args.owner);
135
+ if (args.position !== undefined && args.position !== "right") {
136
+ throw new Error('Gradient plot density legend currently requires position "right".');
137
+ }
138
+ if (args.title !== undefined && (typeof args.title !== "string" || args.title.length === 0)) {
139
+ throw new TypeError("Gradient plot density legend title must be a non-empty string.");
140
+ }
141
+ const ids = legendIds(args.owner);
142
+ const densityScale = `${args.owner}Density`;
143
+ const title = args.title ?? "Relative density";
144
+ return { ids, densityScale, title };
145
+ }
146
+
147
+ export function fulfillGradientPlotLegend(program, args) {
148
+ const { ids, densityScale } = resolveDensityLegend(program, args);
149
+ const occupied = program.semanticSpec.guides.legend?.color;
150
+ if (occupied !== undefined && occupied.scale !== densityScale) {
151
+ guideConflict("Gradient plot density legend uses a different scale or family");
152
+ }
153
+ const existing = Object.values(ids).filter(id => program.graphicSpec.objects[id] !== undefined);
154
+ if (existing.length === 0) return program.createGradientPlotLegend(args);
155
+ if (existing.length !== Object.keys(ids).length || occupied?.scale !== densityScale) {
156
+ guideConflict("Gradient plot density legend has incomplete ownership");
157
+ }
158
+ const { owner, ...explicit } = args;
159
+ assertGuideOptions(explicit, program.markConfigs[owner].gradientPlot.guides.legend, "Gradient plot density legend");
160
+ return program;
161
+ }
162
+
123
163
  export const createGradientPlotLegend = action(
124
164
  {
125
165
  op: "createGradientPlotLegend",
126
166
  description: "Create the neutral density legend owned by one gradient plot."
127
167
  },
128
168
  function (args = {}) {
129
- validateKeys(args, LEGEND_OPTIONS, "createGradientPlotLegend");
130
- requireLegendOwner(this, args.owner);
131
- if (args.position !== undefined && args.position !== "right") {
132
- throw new Error('Gradient plot density legend currently requires position "right".');
133
- }
134
- if (args.title !== undefined && (typeof args.title !== "string" || args.title.length === 0)) {
135
- throw new TypeError("Gradient plot density legend title must be a non-empty string.");
136
- }
137
- const ids = legendIds(args.owner);
138
- const densityScale = `${args.owner}Density`;
139
- const title = args.title ?? "Relative density";
169
+ const { ids, densityScale, title } = resolveDensityLegend(this, args);
140
170
  let next = this;
141
171
  for (const [property, value] of [
142
172
  [`scale[${densityScale}].type`, "sequential"],
@@ -7,6 +7,7 @@ import { findDataset } from "../../selectors/datasets.js";
7
7
  import { findLayer } from "../../selectors/layers.js";
8
8
  import { removeOwnedMark } from "../marks/remove.js";
9
9
  import { GRADIENT_PROFILE_FIELDS } from "../../grammar/gradientProfile.js";
10
+ import { requestedStrokeDetails } from "../../grammar/strokeStyle.js";
10
11
  import { removeGradientPlotLegend } from "./components.js";
11
12
  import {
12
13
  resolveDistributionRoles,
@@ -40,6 +41,13 @@ function removeCenter(program, id) {
40
41
  return removeOwnedMark(program, id, true);
41
42
  }
42
43
 
44
+ function editCenterStrokeDetails(program, id, center) {
45
+ const details = requestedStrokeDetails(center, "Gradient plot center");
46
+ return Object.keys(details).length === 0
47
+ ? program
48
+ : program.editRuleMark({ target: id, ...details });
49
+ }
50
+
43
51
  function roleCandidate(program, owner, current, args) {
44
52
  return {
45
53
  source: Object.hasOwn(args, "data")
@@ -219,10 +227,11 @@ export const editGradientPlot = action(
219
227
  orientation: candidate.orientation,
220
228
  size: spanSize,
221
229
  stroke: center.stroke,
222
- strokeWidth: center.strokeWidth
230
+ strokeWidth: center.strokeWidth,
231
+ ...requestedStrokeDetails(center, "Gradient plot center")
223
232
  });
224
233
  } else if (retainedCenter) {
225
- next = next
234
+ next = editCenterStrokeDetails(next, current.centerId, center)
226
235
  .encodeStroke({ target: current.centerId, value: center.stroke })
227
236
  .encodeStrokeWidth({
228
237
  target: current.centerId,
@@ -291,10 +300,11 @@ export const editGradientPlot = action(
291
300
  orientation: current.orientation,
292
301
  size: 1,
293
302
  stroke: center.stroke,
294
- strokeWidth: center.strokeWidth
303
+ strokeWidth: center.strokeWidth,
304
+ ...requestedStrokeDetails(center, "Gradient plot center")
295
305
  });
296
306
  } else if (center !== false) {
297
- next = next
307
+ next = editCenterStrokeDetails(next, current.centerId, center)
298
308
  .encodeStroke({ target: current.centerId, value: center.stroke })
299
309
  .encodeStrokeWidth({ target: current.centerId, value: center.strokeWidth });
300
310
  }
@@ -1,7 +1,10 @@
1
+ import { applyFacadeGuides } from "../charts/shared.js";
2
+ import { fulfillGradientPlotLegend } from "./components.js";
1
3
  import { action } from "../../core/action.js";
2
4
  import { validateUserId } from "../../core/identifiers.js";
3
5
  import { isPlainObject } from "../../core/immutable.js";
4
6
  import { GRADIENT_PROFILE_FIELDS } from "../../grammar/gradientProfile.js";
7
+ import { requestedStrokeDetails } from "../../grammar/strokeStyle.js";
5
8
  import {
6
9
  mapContinuousScaleValues,
7
10
  mapOrdinalPositionValues
@@ -246,26 +249,23 @@ export const materializeGradientPlot = action(
246
249
  orientation,
247
250
  size: Math.max(1, categoryScale.bandwidth * config.width.band - 16),
248
251
  stroke: config.center.stroke,
249
- strokeWidth: config.center.strokeWidth
252
+ strokeWidth: config.center.strokeWidth,
253
+ ...requestedStrokeDetails(config.center, "Gradient plot center")
250
254
  });
251
255
  }
252
256
  const guides = config.guides;
253
257
  if (guides !== false) {
254
258
  const wantsStandard = guides.axes !== false || guides.grid !== false;
255
259
  if (wantsStandard) {
256
- next = next.createGuides({
260
+ next = applyFacadeGuides(next, {
257
261
  axes: gradientAxesOptions(next.markConfigs[owner].gradientPlot),
258
262
  grid: guides.grid,
259
263
  legend: false
260
- });
264
+ }, owner, guides);
261
265
  }
262
266
  if (guides.legend !== false) {
263
267
  const legend = isPlainObject(guides.legend) ? guides.legend : {};
264
- next = next.createGradientPlotLegend({
265
- owner,
266
- title: legend.title ?? "Relative density",
267
- position: legend.position ?? "right"
268
- });
268
+ next = fulfillGradientPlotLegend(next, { owner, ...legend });
269
269
  }
270
270
  }
271
271
  return next._withContext({ currentMark: owner, currentData: layer.data });
@@ -5,6 +5,10 @@ import {
5
5
  validateUnitInterval
6
6
  } from "../../core/validation.js";
7
7
  import { normalizePalette } from "../../grammar/palettes.js";
8
+ import {
9
+ requestedStrokeDetails,
10
+ STROKE_STYLE_PROPERTIES
11
+ } from "../../grammar/strokeStyle.js";
8
12
 
9
13
  export const GRADIENT_PLOT_OPTIONS = Object.freeze([
10
14
  "id", "target", "data", "x", "y", "coordinate", "density", "width",
@@ -90,7 +94,7 @@ export function resolveGradientCenter(
90
94
  if (value === false) return false;
91
95
  const options = plain(
92
96
  value,
93
- ["type", "stroke", "strokeWidth"],
97
+ ["type", "stroke", "strokeWidth", ...STROKE_STYLE_PROPERTIES],
94
98
  "center",
95
99
  operation
96
100
  );
@@ -108,7 +112,11 @@ export function resolveGradientCenter(
108
112
  : validateNonNegativeFinite(
109
113
  options.strokeWidth,
110
114
  `${operation} center.strokeWidth`
111
- )
115
+ ),
116
+ ...requestedStrokeDetails(
117
+ { ...(previous ?? {}), ...options },
118
+ `${operation} center`
119
+ )
112
120
  });
113
121
  }
114
122
 
@@ -1,3 +1,4 @@
1
+ import { isSourceOwnedText } from "../../grammar/text.js";
1
2
  import {
2
3
  BAR_ORIENTATIONS,
3
4
  resolveBarOrientation
@@ -8,6 +9,7 @@ import {
8
9
  } from "../../core/vocabulary.js";
9
10
  import { findSemanticScale } from "../../selectors/scales.js";
10
11
  import { findDataset } from "../../selectors/datasets.js";
12
+ import { isOpacityLegendLayer } from "../../materialization/legends.js";
11
13
  import { findUpstreamTransform } from
12
14
  "../../materialization/dataProvenance.js";
13
15
 
@@ -19,8 +21,8 @@ function isHorizonLayer(program, layer) {
19
21
  ) !== undefined;
20
22
  }
21
23
 
22
- function hasEncoding(program, channel, { scaled = false, grid = false } = {}) {
23
- return program.semanticSpec.layers.some(layer => {
24
+ function hasEncoding(program, layers, channel, { scaled = false, grid = false } = {}) {
25
+ return layers.some(layer => {
24
26
  if (isHorizonLayer(program, layer) && channel !== "x") return false;
25
27
  const encoding = layer.encoding?.[channel];
26
28
  if (!scaled && !grid) return encoding !== undefined;
@@ -31,25 +33,26 @@ function hasEncoding(program, channel, { scaled = false, grid = false } = {}) {
31
33
  });
32
34
  }
33
35
 
34
- function positionalApplicability(program, channels) {
36
+ function positionalApplicability(program, layers, channels) {
35
37
  return Object.freeze(Object.fromEntries(
36
38
  channels.map(channel => [
37
39
  channel,
38
40
  Object.freeze({
39
- axis: hasEncoding(program, channel),
40
- grid: hasEncoding(program, channel, { grid: true })
41
+ axis: hasEncoding(program, layers, channel),
42
+ grid: hasEncoding(program, layers, channel, { grid: true })
41
43
  })
42
44
  ])
43
45
  ));
44
46
  }
45
47
 
46
- export function hasInferableLegend(program) {
47
- return program.semanticSpec.layers.some(layer =>
48
+ export function hasInferableLegend(program, layers = program.semanticSpec.layers) {
49
+ return layers.some(layer =>
48
50
  !isHorizonLayer(program, layer) && (
49
- (layer.mark?.type === "point" &&
50
- layer.encoding?.opacity?.scale !== undefined) ||
51
+ isOpacityLegendLayer(layer) ||
51
52
  (layer.mark?.type === "point" &&
52
53
  layer.encoding?.size?.scale !== undefined) ||
54
+ (layer.mark?.type === "point" &&
55
+ layer.encoding?.stroke?.scale !== undefined) ||
53
56
  (layer.mark?.type === "point" &&
54
57
  layer.encoding?.color?.scale !== undefined &&
55
58
  (layer.encoding?.shape?.scale !== undefined ||
@@ -57,22 +60,27 @@ export function hasInferableLegend(program) {
57
60
  findSemanticScale(program, layer.encoding.color.scale)?.type
58
61
  ))) ||
59
62
  (layer.mark?.type === "line" &&
60
- ["color", "strokeDash"].some(
63
+ ["color", "stroke", "strokeDash"].some(
61
64
  channel => layer.encoding?.[channel]?.scale !== undefined
62
65
  )) ||
63
66
  (["bar", "area", "arc", "rect"].includes(layer.mark?.type) &&
64
- layer.encoding?.color?.scale !== undefined)
67
+ ["color", "stroke"].some(
68
+ channel => layer.encoding?.[channel]?.scale !== undefined
69
+ )) ||
70
+ (["rule", "tick"].includes(layer.mark?.type) &&
71
+ layer.encoding?.stroke?.scale !== undefined)
65
72
  )
66
73
  );
67
74
  }
68
75
 
69
- export function resolveGuideApplicability(program) {
76
+ export function resolveGuideApplicability(program, layers = program.semanticSpec.layers) {
70
77
  const cartesian = positionalApplicability(
71
78
  program,
79
+ layers,
72
80
  CARTESIAN_POSITION_CHANNELS
73
81
  );
74
- const polar = positionalApplicability(program, POLAR_POSITION_CHANNELS);
75
- const parallel = program.semanticSpec.layers.some(layer =>
82
+ const polar = positionalApplicability(program, layers, POLAR_POSITION_CHANNELS);
83
+ const parallel = layers.some(layer =>
76
84
  layer.encoding?.parallel?.dimensions?.length >= 2
77
85
  );
78
86
  return Object.freeze({
@@ -101,12 +109,13 @@ export function resolveGuideApplicability(program) {
101
109
  radial: polar.radius.grid
102
110
  })
103
111
  }),
104
- legend: hasInferableLegend(program)
112
+ legend: hasInferableLegend(program, layers)
105
113
  });
106
114
  }
107
115
 
108
- export function resolveAutomaticGridOptions(program) {
109
- const applicability = resolveGuideApplicability(program);
116
+ export function resolveAutomaticGridOptions(program, layers = program.semanticSpec.layers) {
117
+ layers = layers.filter(layer => !isSourceOwnedText(layer));
118
+ const applicability = resolveGuideApplicability(program, layers);
110
119
  const directions = applicability.grid.directions;
111
120
  if (applicability.grid.polar && !applicability.grid.cartesian) {
112
121
  return Object.freeze({
@@ -118,10 +127,10 @@ export function resolveAutomaticGridOptions(program) {
118
127
  return Object.freeze({ horizontal: false, vertical: {} });
119
128
  }
120
129
 
121
- const barOrientations = program.semanticSpec.layers
130
+ const barOrientations = layers
122
131
  .map(resolveBarOrientation)
123
132
  .filter(Boolean);
124
- const positionedLayers = program.semanticSpec.layers.filter(
133
+ const positionedLayers = layers.filter(
125
134
  layer => layer.encoding?.x !== undefined && layer.encoding?.y !== undefined
126
135
  );
127
136
  const horizontalQuantitative = positionedLayers.length > 0 &&
@@ -1,3 +1,4 @@
1
+ import { isSourceOwnedText } from "../../../grammar/text.js";
1
2
  import { action } from "../../../core/action.js";
2
3
  import { isPlainObject } from "../../../core/immutable.js";
3
4
  import { validateUserId } from "../../../core/identifiers.js";
@@ -19,7 +20,7 @@ function validateAxisOption(value, channel) {
19
20
  }
20
21
  }
21
22
 
22
- function validateArgs(args) {
23
+ export function validateAxesArgs(args) {
23
24
  validateOptionObject(args, TOP_OPTIONS, "createAxes");
24
25
  validateAxisOption(args.x, "x");
25
26
  validateAxisOption(args.y, "y");
@@ -189,9 +190,9 @@ const createAxes = action(
189
190
  description: "Read a semantic coordinate and create its Cartesian axes."
190
191
  },
191
192
  function (args = {}) {
192
- const coordinateDescriptor = validateArgs(args);
193
+ const coordinateDescriptor = validateAxesArgs(args);
193
194
  const { cartesianLayers, polarLayers, parallelLayers } = inspectChannels(
194
- this.semanticSpec.layers
195
+ this.semanticSpec.layers.filter(layer => !isSourceOwnedText(layer))
195
196
  );
196
197
  const requestedCoordinateType = coordinateDescriptor.id === undefined
197
198
  ? undefined