@genome-spy/core 0.19.0 → 0.21.0

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 (101) hide show
  1. package/dist/index.js +46 -119
  2. package/dist/schema.json +213 -25
  3. package/package.json +4 -3
  4. package/src/data/collector.test.js +2 -0
  5. package/src/data/dataFlow.test.js +2 -0
  6. package/src/data/flow.test.js +1 -0
  7. package/src/data/flowNode.test.js +1 -0
  8. package/src/data/flowOptimizer.test.js +1 -0
  9. package/src/data/formats/fasta.test.js +1 -0
  10. package/src/data/sources/inlineSource.test.js +1 -0
  11. package/src/data/sources/sequenceSource.test.js +1 -0
  12. package/src/data/transforms/clone.test.js +1 -0
  13. package/src/data/transforms/coverage.test.js +1 -0
  14. package/src/data/transforms/filter.test.js +1 -0
  15. package/src/data/transforms/flattenDelimited.test.js +1 -0
  16. package/src/data/transforms/flattenSequence.test.js +1 -0
  17. package/src/data/transforms/formula.test.js +1 -0
  18. package/src/data/transforms/identifier.test.js +1 -0
  19. package/src/data/transforms/pileup.test.js +1 -0
  20. package/src/data/transforms/project.test.js +1 -0
  21. package/src/data/transforms/regexExtract.test.js +1 -0
  22. package/src/data/transforms/regexFold.test.js +1 -0
  23. package/src/data/transforms/sample.test.js +1 -0
  24. package/src/data/transforms/stack.test.js +1 -0
  25. package/src/encoder/accessor.test.js +1 -0
  26. package/src/encoder/encoder.test.js +1 -0
  27. package/src/genome/genome.test.js +1 -0
  28. package/src/genome/scaleIndex.js +3 -2
  29. package/src/genome/scaleIndex.test.js +23 -6
  30. package/src/genome/scaleLocus.test.js +1 -0
  31. package/src/genomeSpy.js +16 -11
  32. package/src/gl/dataToVertices.js +52 -52
  33. package/src/gl/includes/common.glsl +12 -12
  34. package/src/gl/includes/picking.fragment.glsl +0 -2
  35. package/src/gl/includes/picking.vertex.glsl +0 -2
  36. package/src/gl/includes/scales.glsl +33 -2
  37. package/src/gl/point.vertex.glsl +0 -2
  38. package/src/gl/rule.vertex.glsl +1 -1
  39. package/src/gl/webGLHelper.js +0 -3
  40. package/src/marks/link.js +32 -39
  41. package/src/marks/mark.js +176 -106
  42. package/src/marks/pointMark.js +28 -59
  43. package/src/marks/rectMark.js +38 -33
  44. package/src/marks/rule.js +31 -21
  45. package/src/marks/text.js +18 -14
  46. package/src/scale/glslScaleGenerator.js +56 -17
  47. package/src/scale/scale.test.js +1 -0
  48. package/src/scale/ticks.test.js +1 -0
  49. package/src/spec/mark.d.ts +0 -3
  50. package/src/spec/scale.d.ts +0 -9
  51. package/src/spec/title.d.ts +102 -0
  52. package/src/spec/view.d.ts +6 -4
  53. package/src/tooltip/dataTooltipHandler.js +3 -2
  54. package/src/utils/addBaseUrl.test.js +1 -0
  55. package/src/utils/binnedIndex.js +147 -0
  56. package/src/utils/binnedIndex.test.js +73 -0
  57. package/src/utils/cloner.test.js +1 -0
  58. package/src/utils/coalesce.test.js +1 -0
  59. package/src/utils/concatIterables.test.js +1 -0
  60. package/src/utils/domainArray.test.js +1 -0
  61. package/src/utils/indexer.test.js +1 -0
  62. package/src/utils/iterateNestedMaps.test.js +1 -0
  63. package/src/utils/kWayMerge.test.js +1 -0
  64. package/src/utils/layout/flexLayout.js +35 -3
  65. package/src/utils/layout/flexLayout.test.js +15 -0
  66. package/src/utils/layout/grid.js +95 -0
  67. package/src/utils/layout/grid.test.js +71 -0
  68. package/src/utils/layout/padding.js +13 -0
  69. package/src/utils/layout/rectangle.js +6 -0
  70. package/src/utils/layout/rectangle.test.js +1 -0
  71. package/src/utils/mergeObjects.test.js +1 -0
  72. package/src/utils/numberExtractor.test.js +1 -0
  73. package/src/utils/propertyCacher.test.js +1 -0
  74. package/src/utils/propertyCoalescer.test.js +1 -0
  75. package/src/utils/reservationMap.test.js +1 -0
  76. package/src/utils/topK.test.js +1 -0
  77. package/src/utils/variableTools.test.js +1 -0
  78. package/src/view/axisResolution.test.js +1 -0
  79. package/src/view/axisView.js +3 -5
  80. package/src/view/concatView.js +24 -275
  81. package/src/view/flowBuilder.test.js +1 -0
  82. package/src/view/gridView.js +774 -0
  83. package/src/view/implicitRootView.js +14 -0
  84. package/src/view/layerView.js +15 -1
  85. package/src/view/renderingContext/deferredViewRenderingContext.js +3 -1
  86. package/src/view/renderingContext/simpleViewRenderingContext.js +3 -1
  87. package/src/view/scaleResolution.js +5 -11
  88. package/src/view/scaleResolution.test.js +1 -0
  89. package/src/view/title.js +165 -0
  90. package/src/view/unitView.js +9 -5
  91. package/src/view/view.js +35 -14
  92. package/src/view/view.test.js +1 -0
  93. package/src/view/viewContext.d.ts +6 -1
  94. package/src/view/viewFactory.test.js +1 -0
  95. package/src/view/viewUtils.js +1 -93
  96. package/src/view/zoom.js +89 -0
  97. package/src/gl/includes/fp64-arithmetic.glsl +0 -187
  98. package/src/gl/includes/fp64-utils.js +0 -142
  99. package/src/gl/includes/scales_fp64.glsl +0 -30
  100. package/src/utils/binnedRangeIndex.js +0 -83
  101. package/src/view/decoratorView.js +0 -513
@@ -0,0 +1,73 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import { createBinningRangeIndexer } from "./binnedIndex.js";
3
+
4
+ describe("Binning Indexer", () => {
5
+ test("Points are binned correctly", () => {
6
+ const items = [0, 1, 4, 10, 35, 36, 80];
7
+ const indexer = createBinningRangeIndexer(10, [0, 100], (x) => x);
8
+
9
+ items.forEach((i) => indexer(i, i, i + 1));
10
+
11
+ const index = indexer.getIndex();
12
+
13
+ expect(index(0, 1)).toEqual([0, 5]);
14
+ expect(index(1, 2)).toEqual([0, 5]);
15
+ expect(index(1, 15)).toEqual([0, 11]);
16
+ expect(index(10, 15)).toEqual([10, 11]);
17
+ expect(index(11, 38)).toEqual([10, 37]);
18
+ expect(index(11, 45)).toEqual([10, 37]);
19
+ expect(index(40, 85)).toEqual([80, 81]);
20
+ expect(index(90, 100)).toEqual([81, 81]);
21
+ });
22
+
23
+ test("Non-overlapping ranges are binned correctly", () => {
24
+ const items = [
25
+ [0, 5],
26
+ [25, 50],
27
+ [50, 55],
28
+ ];
29
+ const indexer = createBinningRangeIndexer(
30
+ 10,
31
+ [0, 100],
32
+ (x) => x[0],
33
+ (x) => x[1]
34
+ );
35
+
36
+ items.forEach((x) => indexer(x, x[0], x[1]));
37
+
38
+ const index = indexer.getIndex();
39
+
40
+ // TODO: More tests. Doesn't work 100%
41
+
42
+ expect(index(0, 1)).toEqual([0, 5]);
43
+ expect(index(3, 40)).toEqual([0, 50]);
44
+ expect(index(6, 40)).toEqual([0, 50]);
45
+ // fails: expect(index(50, 57)).toEqual([50, 55]);
46
+ });
47
+
48
+ test("Overlapping ranges are binned correctly", () => {
49
+ const items = [
50
+ [10, 30],
51
+ [25, 50],
52
+ ];
53
+ const indexer = createBinningRangeIndexer(
54
+ 10,
55
+ [0, 100],
56
+ (x) => x[0],
57
+ (x) => x[1]
58
+ );
59
+
60
+ items.forEach((x) => indexer(x, x[0], x[1]));
61
+
62
+ const index = indexer.getIndex();
63
+
64
+ // TODO: More tests. Doesn't work 100%
65
+
66
+ expect(index(0, 5)).toEqual([10, 10]);
67
+ expect(index(0, 15)).toEqual([10, 30]);
68
+ expect(index(27, 40)).toEqual([10, 50]);
69
+ expect(index(40, 50)).toEqual([25, 50]);
70
+ expect(index(40, 80)).toEqual([25, 50]);
71
+ expect(index(10, 29)).toEqual([10, 50]);
72
+ });
73
+ });
@@ -1,3 +1,4 @@
1
+ import { expect, test } from "vitest";
1
2
  import createCloner from "./cloner";
2
3
 
3
4
  const template = {
@@ -1,3 +1,4 @@
1
+ import { expect, test } from "vitest";
1
2
  import coalesce from "./coalesce";
2
3
 
3
4
  test("Coalesce returns first defined value", () => {
@@ -1,3 +1,4 @@
1
+ import { expect, test } from "vitest";
1
2
  import concatIterables from "./concatIterables";
2
3
 
3
4
  test("ConcatIterables yields all elements in the correct order", () => {
@@ -1,3 +1,4 @@
1
+ import { describe, expect, test } from "vitest";
1
2
  import createDomain, {
2
3
  toRegularArray as r,
3
4
  PiecewiseDomain,
@@ -1,3 +1,4 @@
1
+ import { expect, test } from "vitest";
1
2
  import createIndexer from "./indexer";
2
3
 
3
4
  test("Index values one by one", () => {
@@ -1,3 +1,4 @@
1
+ import { expect, test } from "vitest";
1
2
  import { group } from "d3-array";
2
3
  import iterateNestedMaps from "./iterateNestedMaps";
3
4
 
@@ -1,3 +1,4 @@
1
+ import { expect, test } from "vitest";
1
2
  import kWayMerge from "./kWayMerge";
2
3
 
3
4
  test("k-way merge merges multiple sorted arrays", () => {
@@ -133,7 +133,7 @@ export function mapToPixelCoords(
133
133
  /**
134
134
  * Returns the minimum size (the sum of pixels sizes) for the flex items
135
135
  *
136
- * @param {SizeDef[]} items
136
+ * @param {Iterable<SizeDef>} items
137
137
  * @param {FlexOptions} [options]
138
138
  */
139
139
  export function getMinimumSize(items, { spacing } = { spacing: 0 }) {
@@ -144,6 +144,21 @@ export function getMinimumSize(items, { spacing } = { spacing: 0 }) {
144
144
  return Math.max(0, minimumSize - spacing);
145
145
  }
146
146
 
147
+ /**
148
+ * @param {Iterable<SizeDef>} items
149
+ * @returns {SizeDef}
150
+ */
151
+ export function getLargestSize(items) {
152
+ let px = 0;
153
+ let grow = 0;
154
+ for (const s of items) {
155
+ px = Math.max(px, s.px ?? 0);
156
+ grow = Math.max(grow, s.grow ?? 0);
157
+ }
158
+
159
+ return { px, grow };
160
+ }
161
+
147
162
  /**
148
163
  * Returns true if relative (stretching) elements are present
149
164
  * @param {SizeDef[]} items
@@ -172,13 +187,30 @@ export class FlexDimensions {
172
187
  * @param {import("./padding").default} padding
173
188
  */
174
189
  addPadding(padding) {
190
+ return this.#addPx(padding.width, padding.height);
191
+ }
192
+
193
+ /**
194
+ * Subtracts padding from absolute (px) dimensions
195
+ *
196
+ * @param {import("./padding").default} padding
197
+ */
198
+ subtractPadding(padding) {
199
+ return this.#addPx(-padding.width, -padding.height);
200
+ }
201
+
202
+ /**
203
+ * @param {number} width
204
+ * @param {number} height
205
+ */
206
+ #addPx(width, height) {
175
207
  return new FlexDimensions(
176
208
  {
177
- px: (this.width.px || 0) + padding.width,
209
+ px: (this.width.px ?? 0) + width,
178
210
  grow: this.width.grow,
179
211
  },
180
212
  {
181
- px: (this.height.px || 0) + padding.height,
213
+ px: (this.height.px ?? 0) + height,
182
214
  grow: this.height.grow,
183
215
  }
184
216
  );
@@ -1,6 +1,8 @@
1
+ import { describe, expect, test } from "vitest";
1
2
  import {
2
3
  mapToPixelCoords,
3
4
  getMinimumSize,
5
+ getLargestSize,
4
6
  isStretching,
5
7
  parseSizeDef,
6
8
  } from "./flexLayout";
@@ -289,6 +291,19 @@ describe("Utility fuctions", () => {
289
291
  expect(getMinimumSize(items, { spacing: 10 })).toEqual(330);
290
292
  });
291
293
 
294
+ test("getLargestSize", () => {
295
+ const items = [
296
+ { px: 100 },
297
+ { px: 0, grow: 0 },
298
+ { grow: 1 },
299
+ { grow: 9 },
300
+ { px: 200 },
301
+ { px: 50 },
302
+ ];
303
+
304
+ expect(getLargestSize(items)).toEqual({ px: 200, grow: 9 });
305
+ });
306
+
292
307
  test("isStretching", () => {
293
308
  expect(isStretching([{ grow: 1 }])).toBeTruthy();
294
309
  expect(isStretching([{ px: 1 }])).toBeFalsy();
@@ -0,0 +1,95 @@
1
+ /**
2
+ * An utility class for indexing cells in a wrapping grid layout
3
+ */
4
+ export default class Grid {
5
+ /**
6
+ *
7
+ * @param {number} nChildren
8
+ * @param {number} [maxCols]
9
+ */
10
+ constructor(nChildren, maxCols) {
11
+ this.n = nChildren;
12
+ this.maxCols = maxCols ?? Infinity;
13
+ }
14
+
15
+ get nRows() {
16
+ return this.maxCols == Infinity ? 1 : Math.ceil(this.n / this.maxCols);
17
+ }
18
+
19
+ get nCols() {
20
+ return Math.min(this.n, this.maxCols);
21
+ }
22
+
23
+ get rowIndices() {
24
+ /** @type {number[][]} */
25
+ const rows = [];
26
+
27
+ const nCols = this.nCols;
28
+ const nRows = this.nRows;
29
+
30
+ for (let row = 0; row < nRows; row++) {
31
+ /** @type {number[]} */
32
+ const arr = [];
33
+ rows.push(arr);
34
+ for (let col = 0; col < nCols; col++) {
35
+ const i = row * nCols + col;
36
+ if (i < this.n) {
37
+ arr.push(i);
38
+ }
39
+ }
40
+ }
41
+ return rows;
42
+ }
43
+
44
+ get colIndices() {
45
+ /** @type {number[][]} */
46
+ const cols = [];
47
+
48
+ const nCols = this.nCols;
49
+ const nRows = this.nRows;
50
+
51
+ for (let col = 0; col < nCols; col++) {
52
+ /** @type {number[]} */
53
+ const arr = [];
54
+ cols.push(arr);
55
+ for (let row = 0; row < nRows; row++) {
56
+ const i = row * nCols + col;
57
+ if (i < this.n) {
58
+ arr.push(i);
59
+ }
60
+ }
61
+ }
62
+ return cols;
63
+ }
64
+
65
+ /**
66
+ * @param {number} col
67
+ * @param {number} row
68
+ */
69
+ getCellIndex(col, row) {
70
+ let i = 0;
71
+
72
+ if (this.maxCols == Infinity) {
73
+ i = row == 0 ? col : undefined;
74
+ } else if (col >= this.maxCols) {
75
+ return undefined;
76
+ } else {
77
+ i = row * this.nCols + col;
78
+ }
79
+
80
+ return i < this.n ? i : undefined;
81
+ }
82
+
83
+ /**
84
+ *
85
+ * @param {number} index
86
+ * @returns {[number, number]}
87
+ */
88
+ getCellCoords(index) {
89
+ if (index < 0 || index >= this.n) {
90
+ return undefined;
91
+ }
92
+
93
+ return [index % this.nCols, Math.floor(index / this.nCols)];
94
+ }
95
+ }
@@ -0,0 +1,71 @@
1
+ import { expect, test, describe } from "vitest";
2
+
3
+ import Grid from "./grid";
4
+
5
+ describe("Grid indexing", () => {
6
+ test("Single row", () => {
7
+ const g = new Grid(3);
8
+
9
+ expect(g.maxCols).toEqual(Infinity);
10
+ expect(g.nCols).toEqual(3);
11
+ expect(g.nRows).toEqual(1);
12
+ expect(g.colIndices).toEqual([[0], [1], [2]]);
13
+ expect(g.rowIndices).toEqual([[0, 1, 2]]);
14
+ expect(g.getCellIndex(1, 0)).toEqual(1);
15
+ expect(g.getCellIndex(1, 1)).toBeUndefined();
16
+ expect(g.getCellCoords(1)).toEqual([1, 0]);
17
+ expect(g.getCellCoords(-1)).toBeUndefined();
18
+ expect(g.getCellCoords(3)).toBeUndefined();
19
+ });
20
+
21
+ test("Single column", () => {
22
+ const g = new Grid(3, 1);
23
+
24
+ expect(g.maxCols).toEqual(1);
25
+ expect(g.nCols).toEqual(1);
26
+ expect(g.nRows).toEqual(3);
27
+ expect(g.colIndices).toEqual([[0, 1, 2]]);
28
+ expect(g.rowIndices).toEqual([[0], [1], [2]]);
29
+ expect(g.getCellIndex(0, 1)).toEqual(1);
30
+ expect(g.getCellIndex(1, 1)).toBeUndefined();
31
+ expect(g.getCellCoords(1)).toEqual([0, 1]);
32
+ });
33
+
34
+ test("Two columns", () => {
35
+ const g = new Grid(6, 2);
36
+
37
+ expect(g.maxCols).toEqual(2);
38
+ expect(g.nCols).toEqual(2);
39
+ expect(g.nRows).toEqual(3);
40
+ expect(g.colIndices).toEqual([
41
+ [0, 2, 4],
42
+ [1, 3, 5],
43
+ ]);
44
+ expect(g.rowIndices).toEqual([
45
+ [0, 1],
46
+ [2, 3],
47
+ [4, 5],
48
+ ]);
49
+ expect(g.getCellIndex(1, 0)).toEqual(1);
50
+ expect(g.getCellIndex(0, 1)).toEqual(2);
51
+ expect(g.getCellIndex(1, 1)).toEqual(3);
52
+ expect(g.getCellCoords(3)).toEqual([1, 1]);
53
+ });
54
+
55
+ test("Two columns, second is partial", () => {
56
+ const g = new Grid(5, 2);
57
+
58
+ expect(g.maxCols).toEqual(2);
59
+ expect(g.nCols).toEqual(2);
60
+ expect(g.nRows).toEqual(3);
61
+ expect(g.colIndices).toEqual([
62
+ [0, 2, 4],
63
+ [1, 3],
64
+ ]);
65
+ expect(g.rowIndices).toEqual([[0, 1], [2, 3], [4]]);
66
+ expect(g.getCellIndex(1, 0)).toEqual(1);
67
+ expect(g.getCellIndex(0, 1)).toEqual(2);
68
+ expect(g.getCellIndex(1, 2)).toBeUndefined();
69
+ expect(g.getCellCoords(3)).toEqual([1, 1]);
70
+ });
71
+ });
@@ -61,6 +61,19 @@ export default class Padding {
61
61
  );
62
62
  }
63
63
 
64
+ /**
65
+ *
66
+ * @param {Padding} padding padding to subtract
67
+ */
68
+ subtract(padding) {
69
+ return new Padding(
70
+ this.top - padding.top,
71
+ this.right - padding.right,
72
+ this.bottom - padding.bottom,
73
+ this.left - padding.left
74
+ );
75
+ }
76
+
64
77
  /**
65
78
  *
66
79
  * @param {PaddingConfig} config
@@ -31,6 +31,8 @@ export default class Rectangle {
31
31
  );
32
32
  }
33
33
 
34
+ static ZERO = Rectangle.create(0, 0, 0, 0);
35
+
34
36
  /**
35
37
  * @param {Prop} prop
36
38
  * @param {number | function():number} value
@@ -279,4 +281,8 @@ export default class Rectangle {
279
281
  y: (y - this.y) / this.height,
280
282
  };
281
283
  }
284
+
285
+ toString() {
286
+ return `Rectangle: x: ${this.x}, y: ${this.y}, width: ${this.width}, height: ${this.height}`;
287
+ }
282
288
  }
@@ -1,3 +1,4 @@
1
+ import { expect, test } from "vitest";
1
2
  import Rectangle from "./rectangle";
2
3
  import Padding from "./padding";
3
4
 
@@ -1,3 +1,4 @@
1
+ import { expect, test } from "vitest";
1
2
  import mergeObjects from "./mergeObjects";
2
3
 
3
4
  test("Merges non-conflicting properties", () => {
@@ -1,3 +1,4 @@
1
+ import { expect, test } from "vitest";
1
2
  import numberExtractor from "./numberExtractor";
2
3
 
3
4
  test("NumberExtractor parses delimited integers", () => {
@@ -1,3 +1,4 @@
1
+ import { expect, test } from "vitest";
1
2
  import { getCachedOrCall, invalidate, invalidateAll } from "./propertyCacher";
2
3
 
3
4
  class TestClass {
@@ -1,3 +1,4 @@
1
+ import { expect, test } from "vitest";
1
2
  import coalesceProperties from "./propertyCoalescer";
2
3
 
3
4
  test("CoalesceProperties works as expected", () => {
@@ -1,3 +1,4 @@
1
+ import { expect, test } from "vitest";
1
2
  import ReservationMap from "./reservationMap";
2
3
 
3
4
  test("ReservationMap works correctly", () => {
@@ -1,3 +1,4 @@
1
+ import { expect, test } from "vitest";
1
2
  import { range } from "d3-array";
2
3
  import { topK, topKSlice } from "./topK";
3
4
 
@@ -1,3 +1,4 @@
1
+ import { expect, test } from "vitest";
1
2
  import * as vt from "./variableTools";
2
3
 
3
4
  test("InferNumerality", () => {
@@ -1,3 +1,4 @@
1
+ import { describe, expect, test } from "vitest";
1
2
  import { createAndInitialize } from "./testUtils";
2
3
  import UnitView from "./unitView";
3
4
  import View from "./view";
@@ -31,7 +31,7 @@ function getPerpendicularChannel(channel) {
31
31
  }
32
32
 
33
33
  /** @type {Record<PositionalChannel, AxisOrient[]>} */
34
- const CHANNEL_ORIENTS = {
34
+ export const CHANNEL_ORIENTS = {
35
35
  x: ["bottom", "top"],
36
36
  y: ["left", "right"],
37
37
  };
@@ -120,6 +120,8 @@ export default class AxisView extends LayerView {
120
120
  this.findChildByName(CHROM_LAYER_NAME).getDynamicDataSource = () =>
121
121
  new DynamicCallbackSource(() => genome.chromosomes);
122
122
  }
123
+
124
+ this.blockEncodingInheritance = true;
123
125
  }
124
126
 
125
127
  getOrient() {
@@ -427,7 +429,6 @@ function createAxis(axisProps) {
427
429
  size: ap.labelFontSize,
428
430
  color: ap.labelColor,
429
431
  minBufferSize: 1500, // to prevent GPU buffer reallocation when zooming
430
- dynamicData: true,
431
432
  },
432
433
  encoding: {
433
434
  [main]: { field: "value", type: "quantitative" },
@@ -448,7 +449,6 @@ function createAxis(axisProps) {
448
449
  color: ap.tickColor,
449
450
  size: ap.tickWidth,
450
451
  minBufferSize: 300,
451
- dynamicData: true,
452
452
  },
453
453
  encoding: {
454
454
  [secondary]: { value: anchor },
@@ -574,7 +574,6 @@ export function createGenomeAxis(axisProps) {
574
574
  anchor - (ap.chromTickSize / ap.extent) * (anchor ? 1 : -1),
575
575
  color: axisProps.chromTickColor,
576
576
  size: ap.chromTickWidth,
577
- dynamicData: true,
578
577
  },
579
578
  });
580
579
 
@@ -647,7 +646,6 @@ export function createGenomeAxis(axisProps) {
647
646
  align: axisProps.chromLabelAlign,
648
647
  baseline: "alphabetic",
649
648
  clip: false,
650
- dynamicData: true,
651
649
  ...chromLabelMarkProps,
652
650
  },
653
651
  encoding: {