ggaction 0.0.18 → 0.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +6 -2
  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/package.json +1 -1
  7. package/src/actions/canvas/fitting.js +6 -2
  8. package/src/actions/charts/heatmap.js +4 -3
  9. package/src/actions/data/derived.js +11 -1
  10. package/src/actions/data/edit.js +2 -0
  11. package/src/actions/data/index.js +4 -0
  12. package/src/actions/data/regression.js +24 -16
  13. package/src/actions/data/regressionStatistics.js +73 -0
  14. package/src/actions/data/shared.js +5 -2
  15. package/src/actions/distributions/revision.js +24 -18
  16. package/src/actions/encodings/remove.js +11 -6
  17. package/src/actions/encodings/shared.js +26 -24
  18. package/src/actions/facets/actions.js +18 -7
  19. package/src/actions/facets/guides.js +2 -1
  20. package/src/actions/guides/axes/axes.js +30 -11
  21. package/src/actions/guides/axes/axis.js +58 -8
  22. package/src/actions/guides/axes/components.js +13 -13
  23. package/src/actions/guides/axes/edit.js +36 -24
  24. package/src/actions/guides/axes/labels.js +37 -27
  25. package/src/actions/guides/axes/lines.js +22 -20
  26. package/src/actions/guides/axes/remove.js +10 -6
  27. package/src/actions/guides/axes/tickGroups.js +8 -7
  28. package/src/actions/guides/axes/ticks.js +31 -22
  29. package/src/actions/guides/axes/titles.js +53 -60
  30. package/src/actions/guides/facadeAxes.js +33 -24
  31. package/src/actions/guides/facadeLegend.js +3 -3
  32. package/src/actions/guides/grids/grid.js +1 -1
  33. package/src/actions/guides/grids/resolve.js +48 -51
  34. package/src/actions/guides/legends/blocks.js +43 -19
  35. package/src/actions/guides/legends/categorical/actions.js +30 -7
  36. package/src/actions/guides/legends/categorical/components.js +3 -10
  37. package/src/actions/guides/legends/categorical/index.js +2 -0
  38. package/src/actions/guides/legends/categorical/layout.js +9 -13
  39. package/src/actions/guides/legends/categorical/options.js +8 -2
  40. package/src/actions/guides/legends/categorical/recipes.js +7 -3
  41. package/src/actions/guides/legends/categorical/resolve.js +9 -2
  42. package/src/actions/guides/legends/categorical/symbols.js +22 -8
  43. package/src/actions/guides/legends/colorSize.js +110 -0
  44. package/src/actions/guides/legends/combine.js +37 -0
  45. package/src/actions/guides/legends/continuous/colorSymbols.js +1 -1
  46. package/src/actions/guides/legends/continuous/common.js +1 -1
  47. package/src/actions/guides/legends/continuous/gradient.js +27 -13
  48. package/src/actions/guides/legends/continuous/opacity.js +16 -11
  49. package/src/actions/guides/legends/creation.js +2 -0
  50. package/src/actions/guides/legends/edit.js +1 -1
  51. package/src/actions/guides/legends/focused.js +6 -5
  52. package/src/actions/guides/legends/lane.js +1 -1
  53. package/src/actions/guides/legends/lifecycle.js +2 -1
  54. package/src/actions/guides/legends/remove.js +6 -3
  55. package/src/actions/guides/legends/size.js +16 -6
  56. package/src/actions/guides/legends/strokeWidth.js +2 -0
  57. package/src/actions/guides/legends/target.js +2 -79
  58. package/src/actions/guides/legends/transition.js +24 -5
  59. package/src/actions/guides/tickValues.js +8 -5
  60. package/src/actions/marks/bar/edit.js +23 -12
  61. package/src/actions/marks/bar/materialize.js +6 -1
  62. package/src/actions/marks/point/materialize.js +5 -1
  63. package/src/actions/marks/remove.js +10 -10
  64. package/src/actions/primitives/createGraphics.js +3 -2
  65. package/src/actions/primitives/editGraphics.js +15 -11
  66. package/src/actions/primitives/graphicProperties.js +1 -6
  67. package/src/actions/primitives/semanticAction.js +27 -1
  68. package/src/actions/primitives/semanticValidation/guide.js +11 -1
  69. package/src/actions/primitives/semanticValidation/layer.js +4 -0
  70. package/src/actions/regression/edit.js +15 -3
  71. package/src/actions/scales/channels.js +2 -2
  72. package/src/actions/scales/create.js +3 -3
  73. package/src/actions/scales/definitions.js +1 -1
  74. package/src/actions/scales/edit.js +1 -1
  75. package/src/actions/scales/editPolicy.js +3 -0
  76. package/src/actions/scales/patch.js +1 -1
  77. package/src/actions/scales/quantitativeColor.js +8 -3
  78. package/src/actions/theme/reconcile.js +50 -23
  79. package/src/core/compositionState.js +2 -2
  80. package/src/core/graphicProperties.js +1 -0
  81. package/src/core/programState.js +4 -0
  82. package/src/core/resourceReferences.js +2 -2
  83. package/src/core/validation.js +9 -0
  84. package/src/core/vocabulary.js +3 -0
  85. package/src/grammar/axisTextPlacement.js +1 -0
  86. package/src/grammar/colorSizeLegend.js +39 -0
  87. package/src/grammar/computed.js +23 -1
  88. package/src/grammar/datasetSchema.js +10 -2
  89. package/src/grammar/displayLabels.js +8 -0
  90. package/src/grammar/facets/guides.js +54 -31
  91. package/src/grammar/facets/legendIntent.js +65 -0
  92. package/src/grammar/guideDash.js +1 -0
  93. package/src/grammar/legendBlocks.js +1 -0
  94. package/src/grammar/legendBorder.js +9 -0
  95. package/src/grammar/legendClip.js +19 -0
  96. package/src/grammar/legendCombinations.js +45 -0
  97. package/src/grammar/legendGradient.js +9 -0
  98. package/src/grammar/legendGroups.js +1 -1
  99. package/src/grammar/legendOpacity.js +6 -0
  100. package/src/grammar/pointShapes.js +16 -2
  101. package/src/grammar/regression/derive.js +9 -1
  102. package/src/grammar/regression/models.js +60 -0
  103. package/src/grammar/regression/parameters.js +9 -1
  104. package/src/grammar/regression/statistics.js +64 -0
  105. package/src/grammar/scales/color.js +1 -1
  106. package/src/grammar/scales/colorConsumers.js +1 -1
  107. package/src/grammar/scales/definition.js +1 -1
  108. package/src/grammar/scales/types.js +1 -1
  109. package/src/grammar/schemas/concreteGraphic.js +3 -0
  110. package/src/grammar/schemas/graphic.js +3 -0
  111. package/src/grammar/schemas/graphicBounds.js +31 -7
  112. package/src/grammar/schemas/semanticPath.js +17 -2
  113. package/src/grammar/summary.js +1 -1
  114. package/src/grammar/timeUnit.js +6 -4
  115. package/src/grammar/transformTopology.js +1 -0
  116. package/src/grammar/transforms.js +11 -1
  117. package/src/inspectionDescriptors.js +1 -1
  118. package/src/layout/guideCollisions.js +9 -1
  119. package/src/layout/legendGroup.js +1 -1
  120. package/src/materialization/compositionSnapshot.js +2 -7
  121. package/src/materialization/coordinateBounds.js +17 -4
  122. package/src/materialization/facetGuides/edit.js +30 -0
  123. package/src/materialization/facetGuides/layout.js +1 -1
  124. package/src/materialization/facetGuides/owner.js +125 -0
  125. package/src/materialization/facetGuides/ownerLayout.js +71 -0
  126. package/src/materialization/facetGuides/placement.js +52 -6
  127. package/src/materialization/facetGuides/preparation.js +7 -0
  128. package/src/materialization/facets.js +1 -1
  129. package/src/materialization/graphicHierarchy.js +5 -1
  130. package/src/materialization/graphicTranslation.js +73 -0
  131. package/src/materialization/guides/layout.js +1 -1
  132. package/src/materialization/guides/resources.js +1 -1
  133. package/src/materialization/legendBorder.js +28 -0
  134. package/src/materialization/legendClip.js +76 -0
  135. package/src/materialization/legendGroups.js +1 -1
  136. package/src/materialization/legends.js +1 -1
  137. package/src/materialization/scaleGuideDependencies.js +13 -14
  138. package/src/materialization/scales/map.js +3 -0
  139. package/src/materialization/scales/resolve.js +2 -0
  140. package/src/materialization/typography.js +10 -2
  141. package/src/persistence/validation.js +174 -1
  142. package/src/persistence.js +1 -1
  143. package/src/renderers/canvas/index.js +20 -10
  144. package/src/renderers/canvas/isolated.js +166 -0
  145. package/src/renderers/canvas/limits.js +3 -0
  146. package/src/renderers/canvas/rect.js +1 -1
  147. package/src/renderers/pdf.js +2 -2
  148. package/src/renderers/png.js +2 -2
  149. package/src/renderers/svg.js +10 -3
  150. package/src/selectors/axes.js +1 -0
  151. package/src/selectors/graphicCapacity.js +38 -0
  152. package/src/version.js +1 -1
  153. package/types/basic.d.ts +2 -0
  154. package/types/index.d.ts +5 -0
  155. package/types/program.d.ts +206 -61
@@ -376,7 +376,7 @@ function hasActiveStroke(properties) {
376
376
  (properties.strokeWidth ?? 0) > 0;
377
377
  }
378
378
 
379
- function primitiveBounds(type, properties = {}, profile) {
379
+ export function resolvePrimitiveGraphicBounds(type, properties = {}, profile) {
380
380
  const strokeExtent = hasActiveStroke(properties)
381
381
  ? properties.strokeWidth / 2
382
382
  : 0;
@@ -469,15 +469,34 @@ function ancestorOffset(graphicSpec, target) {
469
469
  }
470
470
  }
471
471
 
472
+ function intersectVisibleBounds(bounds,clip) {
473
+ if(bounds===undefined)return undefined;
474
+ const result={left:Math.max(bounds.left,clip.left),right:Math.min(bounds.right,clip.right),
475
+ top:Math.max(bounds.top,clip.top),bottom:Math.min(bounds.bottom,clip.bottom)};
476
+ return result.right<=result.left||result.bottom<=result.top?undefined:result;
477
+ }
478
+
479
+ function clipAncestorBounds(graphicSpec,id,bounds) {
480
+ let parent=findGraphicParent(graphicSpec,id);
481
+ while(parent!==undefined){
482
+ if(parent.object.type==="canvas"&&findGraphicParent(graphicSpec,parent.id)!==undefined){
483
+ const [x,y]=ancestorOffset(graphicSpec,parent.id),p=parent.object.properties;
484
+ bounds=intersectVisibleBounds(bounds,{left:x+(p.x??0),right:x+(p.x??0)+p.width,top:y+(p.y??0),bottom:y+(p.y??0)+p.height});
485
+ }
486
+ parent=findGraphicParent(graphicSpec,parent.id);
487
+ }
488
+ return bounds;
489
+ }
490
+
472
491
  function objectBounds(graphicSpec, id, object, ancestors, x, y, profile) {
473
492
  if (ancestors.has(id)) {
474
493
  throw new Error(`Graphic attachment cycle includes "${id}".`);
475
494
  }
476
495
  ancestors.add(id);
477
496
  let result = object.items === undefined
478
- ? translateBounds(primitiveBounds(object.type, object.properties, profile), x, y)
497
+ ? translateBounds(resolvePrimitiveGraphicBounds(object.type, object.properties, profile), x, y)
479
498
  : unionBounds(object.items.map(item => translateBounds(
480
- primitiveBounds(item.type ?? object.type, item.properties, profile),
499
+ resolvePrimitiveGraphicBounds(item.type ?? object.type, item.properties, profile),
481
500
  x,
482
501
  y
483
502
  )));
@@ -497,20 +516,25 @@ function objectBounds(graphicSpec, id, object, ancestors, x, y, profile) {
497
516
  );
498
517
  }
499
518
  }
519
+ if(object.type==="canvas"&&findGraphicParent(graphicSpec,id)!==undefined){
520
+ result=intersectVisibleBounds(result,{left:childX,right:childX+object.properties.width,
521
+ top:childY,bottom:childY+object.properties.height});
522
+ }
500
523
  ancestors.delete(id);
501
524
  return result;
502
525
  }
503
526
 
504
527
  export function resolveConcreteGraphicBounds(graphicSpec, target, profile) {
505
528
  const found = requireGraphic(graphicSpec, target);
506
- const [x, y] = ancestorOffset(graphicSpec, target);
507
- return requireFiniteBounds(found.kind === "item"
529
+ const anchor=found.kind==="item"?found.ownerId:found.id;
530
+ const [x, y] = ancestorOffset(graphicSpec, anchor);
531
+ return requireFiniteBounds(clipAncestorBounds(graphicSpec,anchor,found.kind === "item"
508
532
  ? translateBounds(
509
- primitiveBounds(found.object.type ?? found.owner.type, found.object.properties, profile),
533
+ resolvePrimitiveGraphicBounds(found.object.type ?? found.owner.type, found.object.properties, profile),
510
534
  x,
511
535
  y
512
536
  )
513
- : objectBounds(graphicSpec, found.id, found.object, new Set(), x, y, profile));
537
+ : objectBounds(graphicSpec, found.id, found.object, new Set(), x, y, profile)));
514
538
  }
515
539
 
516
540
  export function unionConcreteGraphicBounds(graphicSpec, targets, profile) {
@@ -1,5 +1,6 @@
1
1
  import { USER_ID_SOURCE } from "../../core/identifiers.js";
2
2
  import {
3
+ AXIS_RESOURCE_CHANNELS,
3
4
  CARTESIAN_POSITION_CHANNELS,
4
5
  ENCODING_CHANNELS,
5
6
  SCALED_ENCODING_CHANNELS
@@ -65,6 +66,7 @@ const ENTITY_PATHS = Object.freeze({
65
66
  "mark.type",
66
67
  "mark.missing",
67
68
  "mark.orientation",
69
+ "mark.blend",
68
70
  "derivedBindings.regression",
69
71
  "layout.mode",
70
72
  ...ENCODING_PATHS
@@ -74,7 +76,7 @@ const ENTITY_PATHS = Object.freeze({
74
76
  collection: "scales",
75
77
  properties: new Set([
76
78
  "type", "domain", "range", "emptyDomain", "nice", "zero", "clamp", "reverse",
77
- "unknown", "base", "exponent", "constant", "interpolate", "radialMapping", "midpoint",
79
+ "unknown", "base", "exponent", "constant", "interpolate", "whitePoint", "gamma", "radialMapping", "midpoint",
78
80
  "paddingInner", "paddingOuter", "padding", "align"
79
81
  ])
80
82
  },
@@ -101,6 +103,9 @@ const GUIDE_PATHS = new Set([
101
103
  "axis.parallel.coordinate",
102
104
  "axis.parallel.scales",
103
105
  "axis.parallel.titles",
106
+ "legend.colorSize.colorScale",
107
+ "legend.colorSize.sizeScale",
108
+ "legend.colorSize.title",
104
109
  "legend.color.scale",
105
110
  "legend.color.title",
106
111
  "legend.color.order",
@@ -137,6 +142,7 @@ const GUIDE_REMOVABLE_CONTAINERS = new Set([
137
142
  "grid.vertical",
138
143
  "grid.theta",
139
144
  "grid.radial",
145
+ "legend.colorSize",
140
146
  "legend.color",
141
147
  "legend.stroke",
142
148
  "legend.size",
@@ -147,6 +153,13 @@ const GUIDE_REMOVABLE_CONTAINERS = new Set([
147
153
 
148
154
  const TITLE_PATHS = new Set(["text", "subtitle"]);
149
155
 
156
+ function isNamedAxisPath(path, container = false) {
157
+ const match = path.match(new RegExp(container
158
+ ? `^axis\\.(${USER_ID_SOURCE})$`
159
+ : `^axis\\.(${USER_ID_SOURCE})\\.(scale|coordinate|title|channel|position)$`));
160
+ return match !== null && !AXIS_RESOURCE_CHANNELS.includes(match[1]);
161
+ }
162
+
150
163
  function splitPropertyPath(property) {
151
164
  return property.split(".");
152
165
  }
@@ -201,7 +214,9 @@ export function parseSemanticPath(property, { allowContainer = false } = {}) {
201
214
 
202
215
  if (
203
216
  !GUIDE_PATHS.has(propertyPath) &&
204
- !(allowContainer && GUIDE_REMOVABLE_CONTAINERS.has(propertyPath))
217
+ !isNamedAxisPath(propertyPath) &&
218
+ !(allowContainer && (GUIDE_REMOVABLE_CONTAINERS.has(propertyPath) ||
219
+ isNamedAxisPath(propertyPath, true)))
205
220
  ) {
206
221
  throw new Error(`Unknown semantic property "${property}".`);
207
222
  }
@@ -23,7 +23,7 @@ const TRANSFORM_KEYS = Object.freeze([
23
23
  ]);
24
24
  const AGGREGATE_KEYS = Object.freeze(["op", "field", "as"]);
25
25
  const NOMINAL_OPERATIONS = new Set(["distinct", "valid", "missing"]);
26
- const MAX_OUTPUT_ROWS = 10_000;
26
+ const MAX_OUTPUT_ROWS = 30_000;
27
27
 
28
28
  function normalizeGroupBy(value) {
29
29
  if (value === undefined) return [];
@@ -52,6 +52,7 @@ function formatter(timeZone) {
52
52
  try {
53
53
  value = new Intl.DateTimeFormat("en-US-u-ca-gregory-nu-latn", {
54
54
  timeZone,
55
+ era: "short",
55
56
  year: "numeric",
56
57
  month: "2-digit",
57
58
  day: "2-digit",
@@ -68,7 +69,7 @@ function formatter(timeZone) {
68
69
  return CALENDAR_FORMATTERS.get(timeZone);
69
70
  }
70
71
 
71
- function validateTimeZone(timeZone) {
72
+ export function validateTimeZone(timeZone) {
72
73
  if (typeof timeZone !== "string" || timeZone.length === 0) {
73
74
  throw new TypeError("Time-unit timeZone must be a non-empty IANA time-zone name.");
74
75
  }
@@ -178,17 +179,18 @@ export function calendarParts(timestamp, timeZone) {
178
179
  validateTimeZone(timeZone);
179
180
  const parts = Object.fromEntries(formatter(timeZone).formatToParts(timestamp)
180
181
  .filter(part => part.type !== "literal")
181
- .map(part => [part.type, Number(part.value)]));
182
+ .map(part => [part.type, part.type === "era" ? part.value : Number(part.value)]));
183
+ const year = parts.era === "BC" ? 1 - parts.year : parts.year;
182
184
  const millisecond = ((timestamp % 1000) + 1000) % 1000;
183
185
  return {
184
- year: parts.year,
186
+ year,
185
187
  month: parts.month,
186
188
  day: parts.day,
187
189
  hour: parts.hour,
188
190
  minute: parts.minute,
189
191
  second: parts.second,
190
192
  millisecond,
191
- weekday: weekdayFromDate(parts.year, parts.month, parts.day)
193
+ weekday: weekdayFromDate(year, parts.month, parts.day)
192
194
  };
193
195
  }
194
196
 
@@ -16,6 +16,7 @@ const TRANSFORM_TOPOLOGY = Object.freeze({
16
16
  markFilter: Object.freeze({ provenanceTransparent: true }),
17
17
  normalize: Object.freeze({ facetTopology: "statistical" }),
18
18
  regression: Object.freeze({ facetTopology: "statistical" }),
19
+ regressionStatistics: Object.freeze({ facetTopology: "statistical" }),
19
20
  sort: Object.freeze({ facetTopology: "statistical" }),
20
21
  summary: Object.freeze({ facetTopology: "statistical" }),
21
22
  stack: Object.freeze({ facetTopology: "statistical" }),
@@ -1,4 +1,5 @@
1
1
  import { cloneAndFreeze, isPlainObject } from "../core/immutable.js";
2
+ import { validateRegressionStatisticsTransform } from "./regression/statistics.js";
2
3
  import { validateBoxTransform } from "./boxPlot.js";
3
4
  import { normalizeBinTransform, validateBinTransform } from "./bin.js";
4
5
  import {
@@ -203,7 +204,7 @@ function normalizeRegressionEdit(transform, patch) {
203
204
  delete base.span;
204
205
  delete base.robustIterations;
205
206
  }
206
- if (method === "loess" || base.method === "loess") {
207
+ if (["loess", "exp"].includes(method) || ["loess", "exp"].includes(base.method)) {
207
208
  for (const key of [
208
209
  "confidenceMethod", "level", "confidence", "interval"
209
210
  ]) delete base[key];
@@ -446,6 +447,15 @@ const TRANSFORM_POLICIES = Object.freeze({
446
447
  normalizeEdit: normalizeRegressionEdit,
447
448
  outputRoles: () => ({})
448
449
  }),
450
+ regressionStatistics: Object.freeze({
451
+ ...findTransformTopology("regressionStatistics"),
452
+ validate: validateRegressionStatisticsTransform,
453
+ materializeOp: "materializeRegressionStatisticsData",
454
+ replayTransform: requestedTransform,
455
+ editable: true,
456
+ normalizeEdit: (transform, patch) => validateRegressionStatisticsTransform({ ...transform, ...patch }),
457
+ outputRoles: () => ({ count: "count", intercept: "intercept", slope: "slope", rSquared: "rSquared" })
458
+ }),
449
459
  sort: Object.freeze({
450
460
  ...findTransformTopology("sort"),
451
461
  validate: validateSortTransform,