@genome-spy/core 0.30.0 → 0.30.2

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 (234) hide show
  1. package/dist/index.es.js +16373 -0
  2. package/dist/index.js +43 -43
  3. package/package.json +10 -7
  4. package/src/data/collector.js +0 -183
  5. package/src/data/collector.test.js +0 -84
  6. package/src/data/dataFlow.js +0 -148
  7. package/src/data/dataFlow.test.js +0 -5
  8. package/src/data/facetNode.js +0 -17
  9. package/src/data/flow.test.js +0 -72
  10. package/src/data/flowBatch.d.ts +0 -40
  11. package/src/data/flowNode.js +0 -283
  12. package/src/data/flowNode.test.js +0 -50
  13. package/src/data/flowOptimizer.js +0 -123
  14. package/src/data/flowOptimizer.test.js +0 -193
  15. package/src/data/flowTestUtils.js +0 -63
  16. package/src/data/formats/fasta.js +0 -32
  17. package/src/data/formats/fasta.test.js +0 -27
  18. package/src/data/sources/dataSource.js +0 -22
  19. package/src/data/sources/dataSourceFactory.js +0 -24
  20. package/src/data/sources/dataUtils.js +0 -78
  21. package/src/data/sources/dynamicCallbackSource.js +0 -57
  22. package/src/data/sources/dynamicSource.js +0 -37
  23. package/src/data/sources/inlineSource.js +0 -67
  24. package/src/data/sources/inlineSource.test.js +0 -56
  25. package/src/data/sources/namedSource.js +0 -79
  26. package/src/data/sources/sequenceSource.js +0 -46
  27. package/src/data/sources/sequenceSource.test.js +0 -46
  28. package/src/data/sources/urlSource.js +0 -74
  29. package/src/data/transforms/aggregate.js +0 -70
  30. package/src/data/transforms/clone.js +0 -40
  31. package/src/data/transforms/clone.test.js +0 -11
  32. package/src/data/transforms/coverage.js +0 -187
  33. package/src/data/transforms/coverage.test.js +0 -123
  34. package/src/data/transforms/filter.js +0 -37
  35. package/src/data/transforms/filter.test.js +0 -18
  36. package/src/data/transforms/filterScoredLabels.js +0 -134
  37. package/src/data/transforms/flattenCompressedExons.js +0 -57
  38. package/src/data/transforms/flattenDelimited.js +0 -74
  39. package/src/data/transforms/flattenDelimited.test.js +0 -87
  40. package/src/data/transforms/flattenSequence.js +0 -39
  41. package/src/data/transforms/flattenSequence.test.js +0 -34
  42. package/src/data/transforms/formula.js +0 -39
  43. package/src/data/transforms/formula.test.js +0 -19
  44. package/src/data/transforms/identifier.js +0 -108
  45. package/src/data/transforms/identifier.test.js +0 -83
  46. package/src/data/transforms/linearizeGenomicCoordinate.js +0 -101
  47. package/src/data/transforms/measureText.js +0 -44
  48. package/src/data/transforms/pileup.js +0 -128
  49. package/src/data/transforms/pileup.test.js +0 -70
  50. package/src/data/transforms/project.js +0 -41
  51. package/src/data/transforms/project.test.js +0 -32
  52. package/src/data/transforms/regexExtract.js +0 -61
  53. package/src/data/transforms/regexExtract.test.js +0 -67
  54. package/src/data/transforms/regexFold.js +0 -141
  55. package/src/data/transforms/regexFold.test.js +0 -160
  56. package/src/data/transforms/sample.js +0 -101
  57. package/src/data/transforms/sample.test.js +0 -38
  58. package/src/data/transforms/stack.js +0 -137
  59. package/src/data/transforms/stack.test.js +0 -91
  60. package/src/data/transforms/transformFactory.js +0 -60
  61. package/src/embedApi.d.ts +0 -67
  62. package/src/encoder/accessor.js +0 -82
  63. package/src/encoder/accessor.test.js +0 -47
  64. package/src/encoder/encoder.js +0 -394
  65. package/src/encoder/encoder.test.js +0 -98
  66. package/src/fonts/Lato-Regular.json +0 -1267
  67. package/src/fonts/Lato-Regular.png +0 -0
  68. package/src/fonts/OFL.txt +0 -93
  69. package/src/fonts/README.md +0 -3
  70. package/src/fonts/bmFont.d.ts +0 -58
  71. package/src/fonts/bmFontManager.js +0 -357
  72. package/src/fonts/bmFontMetrics.js +0 -108
  73. package/src/genome/genome.js +0 -317
  74. package/src/genome/genome.test.js +0 -188
  75. package/src/genome/genomeStore.js +0 -54
  76. package/src/genome/locusFormat.js +0 -31
  77. package/src/genome/scaleIndex.d.ts +0 -38
  78. package/src/genome/scaleIndex.js +0 -166
  79. package/src/genome/scaleIndex.test.js +0 -78
  80. package/src/genome/scaleLocus.d.ts +0 -11
  81. package/src/genome/scaleLocus.js +0 -108
  82. package/src/genome/scaleLocus.test.js +0 -4
  83. package/src/genomeSpy.js +0 -785
  84. package/src/gl/arrayBuilder.js +0 -199
  85. package/src/gl/dataToVertices.js +0 -636
  86. package/src/gl/includes/common.glsl +0 -63
  87. package/src/gl/includes/picking.fragment.glsl +0 -1
  88. package/src/gl/includes/picking.vertex.glsl +0 -27
  89. package/src/gl/includes/sampleFacet.glsl +0 -107
  90. package/src/gl/includes/scales.glsl +0 -112
  91. package/src/gl/link.fragment.glsl +0 -18
  92. package/src/gl/link.vertex.glsl +0 -111
  93. package/src/gl/point.fragment.glsl +0 -123
  94. package/src/gl/point.vertex.glsl +0 -129
  95. package/src/gl/rect.fragment.glsl +0 -51
  96. package/src/gl/rect.vertex.glsl +0 -114
  97. package/src/gl/rule.fragment.glsl +0 -52
  98. package/src/gl/rule.vertex.glsl +0 -89
  99. package/src/gl/text.fragment.glsl +0 -31
  100. package/src/gl/text.vertex.glsl +0 -246
  101. package/src/gl/webGLHelper.js +0 -504
  102. package/src/img/bowtie.svg +0 -1
  103. package/src/img/genomespy-favicon.svg +0 -34
  104. package/src/index.html +0 -11
  105. package/src/index.js +0 -128
  106. package/src/marks/link.js +0 -175
  107. package/src/marks/mark.js +0 -975
  108. package/src/marks/markUtils.js +0 -125
  109. package/src/marks/pointMark.js +0 -251
  110. package/src/marks/rectMark.js +0 -241
  111. package/src/marks/rule.js +0 -250
  112. package/src/marks/text.js +0 -278
  113. package/src/node_modules/.vitest/results.json +0 -1
  114. package/src/scale/colorUtils.js +0 -184
  115. package/src/scale/glslScaleGenerator.js +0 -502
  116. package/src/scale/scale.js +0 -451
  117. package/src/scale/scale.test.js +0 -324
  118. package/src/scale/ticks.js +0 -203
  119. package/src/scale/ticks.test.js +0 -40
  120. package/src/singlePageApp.js +0 -13
  121. package/src/spec/axis.d.ts +0 -296
  122. package/src/spec/channel.d.ts +0 -430
  123. package/src/spec/data.d.ts +0 -196
  124. package/src/spec/font.d.ts +0 -15
  125. package/src/spec/genome.d.ts +0 -35
  126. package/src/spec/mark.d.ts +0 -429
  127. package/src/spec/root.d.ts +0 -17
  128. package/src/spec/sampleView.d.ts +0 -180
  129. package/src/spec/scale.d.ts +0 -273
  130. package/src/spec/title.d.ts +0 -102
  131. package/src/spec/tooltip.d.ts +0 -9
  132. package/src/spec/transform.d.ts +0 -479
  133. package/src/spec/view.d.ts +0 -201
  134. package/src/styles/genome-spy.scss +0 -153
  135. package/src/tooltip/dataTooltipHandler.js +0 -64
  136. package/src/tooltip/refseqGeneTooltipHandler.js +0 -78
  137. package/src/tooltip/tooltipHandler.ts +0 -12
  138. package/src/types/filetypes.d.ts +0 -14
  139. package/src/types/flatqueue.d.ts +0 -53
  140. package/src/types/glsl.d.ts +0 -4
  141. package/src/types/internmap.d.ts +0 -22
  142. package/src/types/object.d.ts +0 -21
  143. package/src/types/vega-loader.d.ts +0 -1
  144. package/src/types/vega-scale.d.ts +0 -60
  145. package/src/utils/addBaseUrl.js +0 -19
  146. package/src/utils/addBaseUrl.test.js +0 -22
  147. package/src/utils/animator.js +0 -83
  148. package/src/utils/arrayUtils.js +0 -61
  149. package/src/utils/binnedIndex.js +0 -167
  150. package/src/utils/binnedIndex.test.js +0 -155
  151. package/src/utils/clamp.js +0 -8
  152. package/src/utils/cloner.js +0 -34
  153. package/src/utils/cloner.test.js +0 -24
  154. package/src/utils/coalesce.js +0 -11
  155. package/src/utils/coalesce.test.js +0 -16
  156. package/src/utils/concatIterables.js +0 -26
  157. package/src/utils/concatIterables.test.js +0 -8
  158. package/src/utils/debounce.js +0 -37
  159. package/src/utils/domainArray.js +0 -216
  160. package/src/utils/domainArray.test.js +0 -130
  161. package/src/utils/eerp.js +0 -13
  162. package/src/utils/expression.js +0 -32
  163. package/src/utils/field.js +0 -28
  164. package/src/utils/formatObject.js +0 -31
  165. package/src/utils/indexer.js +0 -43
  166. package/src/utils/indexer.test.js +0 -47
  167. package/src/utils/inertia.js +0 -124
  168. package/src/utils/interactionEvent.js +0 -33
  169. package/src/utils/iterateNestedMaps.js +0 -21
  170. package/src/utils/iterateNestedMaps.test.js +0 -33
  171. package/src/utils/kWayMerge.js +0 -42
  172. package/src/utils/kWayMerge.test.js +0 -26
  173. package/src/utils/layout/flexLayout.js +0 -368
  174. package/src/utils/layout/flexLayout.test.js +0 -311
  175. package/src/utils/layout/grid.js +0 -95
  176. package/src/utils/layout/grid.test.js +0 -71
  177. package/src/utils/layout/padding.js +0 -120
  178. package/src/utils/layout/point.js +0 -23
  179. package/src/utils/layout/rectangle.js +0 -288
  180. package/src/utils/layout/rectangle.test.js +0 -172
  181. package/src/utils/mergeObjects.js +0 -99
  182. package/src/utils/mergeObjects.test.js +0 -42
  183. package/src/utils/numberExtractor.js +0 -24
  184. package/src/utils/numberExtractor.test.js +0 -6
  185. package/src/utils/point.js +0 -14
  186. package/src/utils/propertyCacher.js +0 -70
  187. package/src/utils/propertyCacher.test.js +0 -85
  188. package/src/utils/propertyCoalescer.js +0 -42
  189. package/src/utils/propertyCoalescer.test.js +0 -22
  190. package/src/utils/reservationMap.js +0 -103
  191. package/src/utils/reservationMap.test.js +0 -20
  192. package/src/utils/scaleNull.js +0 -19
  193. package/src/utils/setOperations.js +0 -75
  194. package/src/utils/smoothstep.js +0 -10
  195. package/src/utils/throttle.js +0 -34
  196. package/src/utils/topK.js +0 -76
  197. package/src/utils/topK.test.js +0 -64
  198. package/src/utils/transition.js +0 -74
  199. package/src/utils/ui/tooltip.js +0 -189
  200. package/src/utils/url.js +0 -22
  201. package/src/utils/variableTools.js +0 -24
  202. package/src/utils/variableTools.test.js +0 -13
  203. package/src/view/axisResolution.js +0 -140
  204. package/src/view/axisResolution.test.js +0 -201
  205. package/src/view/axisView.js +0 -747
  206. package/src/view/concatView.js +0 -45
  207. package/src/view/containerView.js +0 -159
  208. package/src/view/facetView.js +0 -491
  209. package/src/view/flowBuilder.js +0 -367
  210. package/src/view/flowBuilder.test.js +0 -125
  211. package/src/view/gridView.js +0 -786
  212. package/src/view/implicitRootView.js +0 -14
  213. package/src/view/importView.js +0 -19
  214. package/src/view/layerView.js +0 -74
  215. package/src/view/rendering.d.ts +0 -44
  216. package/src/view/renderingContext/compositeViewRenderingContext.js +0 -51
  217. package/src/view/renderingContext/deferredViewRenderingContext.js +0 -176
  218. package/src/view/renderingContext/layoutRecorderViewRenderingContext.js +0 -128
  219. package/src/view/renderingContext/simpleViewRenderingContext.js +0 -64
  220. package/src/view/renderingContext/svgViewRenderingContext.js +0 -125
  221. package/src/view/renderingContext/viewRenderingContext.js +0 -41
  222. package/src/view/scaleResolution.js +0 -797
  223. package/src/view/scaleResolution.test.js +0 -572
  224. package/src/view/scaleResolutionApi.d.ts +0 -40
  225. package/src/view/testUtils.js +0 -51
  226. package/src/view/title.js +0 -165
  227. package/src/view/unitView.js +0 -382
  228. package/src/view/view.js +0 -612
  229. package/src/view/view.test.js +0 -214
  230. package/src/view/viewContext.d.ts +0 -62
  231. package/src/view/viewFactory.js +0 -181
  232. package/src/view/viewFactory.test.js +0 -17
  233. package/src/view/viewUtils.js +0 -327
  234. package/src/view/zoom.js +0 -89
@@ -1,70 +0,0 @@
1
- import { group as d3group } from "d3-array";
2
- import FlowNode, { BEHAVIOR_CLONES } from "../flowNode";
3
- import { field } from "../../utils/field";
4
- import iterateNestedMaps from "../../utils/iterateNestedMaps";
5
-
6
- /**
7
- * A minimal aggregate transform that just counts grouped (by a single field) data items.
8
- * Work in progress.
9
- *
10
- * Eventually this will implement the most of Vega's aggregate transform:
11
- * https://vega.github.io/vega/docs/transforms/aggregate/
12
- *
13
- * @typedef {import("../../spec/transform").AggregateParams} AggregateParams
14
- */
15
-
16
- export default class AggregateTransform extends FlowNode {
17
- get behavior() {
18
- return BEHAVIOR_CLONES;
19
- }
20
-
21
- /**
22
- * @param {AggregateParams} params
23
- */
24
- constructor(params) {
25
- super();
26
- this.params = params;
27
-
28
- /** @type {any[]} */
29
- this.buffer = [];
30
- }
31
-
32
- reset() {
33
- this.buffer = [];
34
- }
35
-
36
- /**
37
- *
38
- * @param {import("../flowNode").Datum} datum
39
- */
40
- handle(datum) {
41
- this.buffer.push(datum);
42
- }
43
-
44
- complete() {
45
- const params = this.params;
46
-
47
- const groupby = params.groupby;
48
-
49
- const groupFieldAccessors = groupby.map((f) => field(f));
50
-
51
- // TODO: Fix case where no group fields are specified
52
- // @ts-expect-error
53
- const groups = d3group(this.buffer, ...groupFieldAccessors);
54
-
55
- for (const [group, data] of iterateNestedMaps(groups)) {
56
- /** @type {any} */
57
- const datum = {
58
- count: data.length,
59
- };
60
-
61
- for (let i = 0; i < groupby.length; i++) {
62
- datum[groupby[i]] = group[i];
63
- }
64
-
65
- this._propagate(datum);
66
- }
67
-
68
- super.complete();
69
- }
70
- }
@@ -1,40 +0,0 @@
1
- import createCloner from "../../utils/cloner";
2
- import FlowNode, { BEHAVIOR_CLONES, isFileBatch } from "../flowNode";
3
-
4
- /**
5
- * Clones the data objects that pass through.
6
- */
7
- export default class CloneTransform extends FlowNode {
8
- get behavior() {
9
- return BEHAVIOR_CLONES;
10
- }
11
-
12
- constructor() {
13
- super();
14
-
15
- /** @param {any} datum */
16
- const setupCloner = (datum) => {
17
- const clone = createCloner(datum);
18
-
19
- /** @param {any} datum */
20
- this.handle = (datum) => this._propagate(clone(datum));
21
-
22
- this.handle(datum);
23
- };
24
-
25
- this.handle = setupCloner;
26
-
27
- /**
28
- * Signals that a new batch of data will be propagated.
29
- *
30
- * @param {import("../flowNode").FlowBatch} [flowBatch]
31
- */
32
- this.beginBatch = (flowBatch) => {
33
- if (isFileBatch(flowBatch)) {
34
- // TODO: Only create new cloner if the props change
35
- this.handle = setupCloner;
36
- }
37
- super.beginBatch(flowBatch);
38
- };
39
- }
40
- }
@@ -1,11 +0,0 @@
1
- import { expect, test } from "vitest";
2
- import { processData } from "../flowTestUtils";
3
- import CloneTransform from "./clone";
4
-
5
- test("CloneTransform clones the data objects", () => {
6
- const data = [{ x: 1 }, { x: 2 }];
7
- const clonedData = processData(new CloneTransform(), data);
8
-
9
- expect(clonedData).toEqual(data);
10
- expect(clonedData[0]).not.toBe(data[0]);
11
- });
@@ -1,187 +0,0 @@
1
- import FlatQueue from "flatqueue";
2
-
3
- import { field } from "../../utils/field";
4
- import FlowNode, { BEHAVIOR_CLONES } from "../flowNode";
5
-
6
- /**
7
- * @typedef {import("../../spec/transform").CoverageParams} CoverageParams
8
- */
9
-
10
- /**
11
- * Computes coverage for sorted segments
12
- *
13
- * TODO: Binned coverage
14
- */
15
- export default class CoverageTransform extends FlowNode {
16
- get behavior() {
17
- return BEHAVIOR_CLONES;
18
- }
19
-
20
- /**
21
- * @param {CoverageParams} params
22
- */
23
- constructor(params) {
24
- super();
25
- this.params = params;
26
-
27
- this.startAccessor = field(params.start);
28
- this.endAccessor = field(params.end);
29
-
30
- /** @type {function(any):string} */
31
- this.chromAccessor = params.chrom
32
- ? field(params.chrom)
33
- : (d) => undefined;
34
- /** @type {function(any):number} */
35
- this.weightAccessor = params.weight ? field(params.weight) : (d) => 1;
36
-
37
- this.as = {
38
- coverage: params.as || "coverage",
39
- start: params.asStart || params.start,
40
- end: params.asEnd || params.end,
41
- chrom: params.asChrom || params.chrom,
42
- };
43
-
44
- // eslint-disable-next-line no-new-func
45
- this.createSegment = /** @type {function} */ (
46
- new Function(
47
- "start",
48
- "end",
49
- "coverage",
50
- "chrom",
51
- "return {" +
52
- Object.entries(this.as)
53
- .filter(([param, prop]) => prop)
54
- .map(
55
- ([param, prop]) =>
56
- `${JSON.stringify(prop)}: ${param}`
57
- )
58
- .join(", ") +
59
- "};"
60
- )
61
- );
62
-
63
- // End pos as priority, weight as value
64
- this.ends = new FlatQueue();
65
- }
66
-
67
- reset() {
68
- super.reset();
69
- this.initialize();
70
- }
71
-
72
- initialize() {
73
- const asCoverage = this.as.coverage;
74
- const asEnd = this.as.end;
75
- const asChrom = this.as.chrom;
76
-
77
- const startAccessor = this.startAccessor;
78
- const endAccessor = this.endAccessor;
79
- const chromAccessor = this.chromAccessor;
80
- const weightAccessor = this.weightAccessor;
81
-
82
- /** @type {Record<string, number|string>} used for merging adjacent segment */
83
- let bufferedSegment;
84
-
85
- /** @type {string} */
86
- let prevChrom;
87
-
88
- /** @type {string} */
89
- let chrom;
90
-
91
- // TODO: Whattabout cumulative error when float weights are used?
92
- // Howabout https://github.com/d3/d3-array#fsum ?
93
- let coverage = 0;
94
-
95
- /** @type {number} */
96
- let prevEdge;
97
-
98
- // End pos as priority, weight as value
99
- const ends = this.ends;
100
- ends.clear();
101
-
102
- /**
103
- * @param {number} start
104
- * @param {number} end
105
- * @param {number} coverage
106
- */
107
- const pushSegment = (start, end, coverage) => {
108
- if (start == end) {
109
- return;
110
- }
111
-
112
- let extended = false;
113
- if (bufferedSegment) {
114
- if (bufferedSegment[asCoverage] === coverage) {
115
- // Extend it
116
- bufferedSegment[asEnd] = end;
117
- extended = true;
118
- } else if (bufferedSegment[asCoverage] != 0) {
119
- this._propagate(bufferedSegment);
120
- }
121
- }
122
-
123
- if (!extended) {
124
- bufferedSegment = this.createSegment(
125
- start,
126
- end,
127
- coverage,
128
- chrom
129
- );
130
- }
131
- };
132
-
133
- const flushQueue = () => {
134
- // Flush queue
135
- /** @type {number} */
136
- let edge;
137
- while ((edge = ends.peekValue()) !== undefined) {
138
- pushSegment(prevEdge, edge, coverage);
139
- prevEdge = edge;
140
- coverage -= ends.pop();
141
- }
142
- prevEdge = undefined;
143
-
144
- if (bufferedSegment) {
145
- this._propagate(bufferedSegment);
146
- bufferedSegment = undefined;
147
- }
148
- };
149
-
150
- /** @param {Record<string, any>} datum */
151
- this.handle = (datum) => {
152
- const start = startAccessor(datum);
153
-
154
- /** @type {number} */
155
- let edge;
156
- while ((edge = ends.peekValue()) !== undefined && edge < start) {
157
- pushSegment(prevEdge, edge, coverage);
158
- prevEdge = edge;
159
- coverage -= ends.pop();
160
- }
161
-
162
- if (asChrom) {
163
- let newChrom = chromAccessor(datum);
164
- if (newChrom !== prevChrom) {
165
- flushQueue();
166
- chrom = newChrom;
167
- prevChrom = chrom;
168
- }
169
- }
170
-
171
- if (prevEdge !== undefined) {
172
- pushSegment(prevEdge, start, coverage);
173
- }
174
- prevEdge = start;
175
-
176
- const weight = weightAccessor(datum);
177
- coverage += weight;
178
-
179
- ends.push(weight, endAccessor(datum));
180
- };
181
-
182
- this.complete = () => {
183
- flushQueue();
184
- super.complete();
185
- };
186
- }
187
- }
@@ -1,123 +0,0 @@
1
- import { expect, test } from "vitest";
2
- import CoverageTransform from "./coverage";
3
- import { processData } from "../flowTestUtils";
4
-
5
- /**
6
- * @typedef {import("../../spec/transform").CoverageParams} CoverageParams
7
- */
8
-
9
- /**
10
- * @param {CoverageParams} params
11
- * @param {any[]} data
12
- */
13
- function transform(params, data) {
14
- const t = new CoverageTransform(params);
15
- t.initialize();
16
- return processData(t, data);
17
- }
18
-
19
- test("Coverage transform produces correct coverage segments", () => {
20
- const reads = [
21
- [0, 4],
22
- [1, 3],
23
- [2, 6],
24
- [4, 8],
25
- [8, 10],
26
- [11, 14],
27
- [11, 13],
28
- [11, 12],
29
- [15, 18],
30
- [16, 18],
31
- [17, 18],
32
- ].map((d) => ({
33
- start: d[0],
34
- end: d[1],
35
- }));
36
-
37
- const coverageSegments = [
38
- [0, 1, 1],
39
- [1, 2, 2],
40
- [2, 3, 3],
41
- [3, 6, 2],
42
- [6, 10, 1],
43
- [11, 12, 3],
44
- [12, 13, 2],
45
- [13, 14, 1],
46
- [15, 16, 1],
47
- [16, 17, 2],
48
- [17, 18, 3],
49
- ].map((d) => ({
50
- start: d[0],
51
- end: d[1],
52
- coverage: d[2],
53
- }));
54
-
55
- /** @type {CoverageParams} */
56
- const coverageConfig = {
57
- type: "coverage",
58
- start: "start",
59
- end: "end",
60
- };
61
- expect(transform(coverageConfig, reads)).toEqual(coverageSegments);
62
- });
63
-
64
- test("Coverage transform handles chromosomes", () => {
65
- const reads = [
66
- { chrom: "chr1", start: 0, end: 1 },
67
- { chrom: "chr2", start: 0, end: 1 },
68
- { chrom: "chr3", start: 1, end: 3 },
69
- ];
70
-
71
- const coverageSegments = [
72
- { chrom: "chr1", start: 0, end: 1, coverage: 1 },
73
- { chrom: "chr2", start: 0, end: 1, coverage: 1 },
74
- { chrom: "chr3", start: 1, end: 3, coverage: 1 },
75
- ];
76
-
77
- /** @type {CoverageParams} */
78
- const coverageConfig = {
79
- type: "coverage",
80
- chrom: "chrom",
81
- start: "start",
82
- end: "end",
83
- };
84
-
85
- expect(transform(coverageConfig, reads)).toEqual(coverageSegments);
86
- });
87
-
88
- test("Coverage transform handles weights", () => {
89
- const reads = [
90
- [0, 4, 1],
91
- [1, 3, 2],
92
- [2, 6, 3],
93
- [8, 10, -1],
94
- ].map((d) => ({
95
- start: d[0],
96
- end: d[1],
97
- weight: d[2],
98
- }));
99
-
100
- const coverageSegments = [
101
- [0, 1, 1],
102
- [1, 2, 3],
103
- [2, 3, 6],
104
- [3, 4, 4],
105
- [4, 6, 3],
106
- [8, 10, -1],
107
- ].map((d) => ({
108
- start: d[0],
109
- end: d[1],
110
- coverage: d[2],
111
- }));
112
-
113
- /** @type {CoverageParams} */
114
- const coverageConfig = {
115
- type: "coverage",
116
- chrom: "chrom",
117
- start: "start",
118
- end: "end",
119
- weight: "weight",
120
- };
121
-
122
- expect(transform(coverageConfig, reads)).toEqual(coverageSegments);
123
- });
@@ -1,37 +0,0 @@
1
- import createFunction from "../../utils/expression";
2
- import FlowNode from "../flowNode";
3
-
4
- /**
5
- * @typedef {import("../../spec/transform").FilterParams} FilterParams
6
- */
7
-
8
- export default class FilterTransform extends FlowNode {
9
- /**
10
- *
11
- * @param {FilterParams} params
12
- */
13
- constructor(params) {
14
- super();
15
- this.params = params;
16
-
17
- /** @type {(datum: any) => boolean} */
18
- this.predicate = undefined;
19
- }
20
-
21
- initialize() {
22
- this.predicate = createFunction(
23
- this.params.expr,
24
- this.getGlobalObject()
25
- );
26
- }
27
-
28
- /**
29
- *
30
- * @param {import("../flowNode").Datum} datum
31
- */
32
- handle(datum) {
33
- if (this.predicate(datum)) {
34
- this._propagate(datum);
35
- }
36
- }
37
- }
@@ -1,18 +0,0 @@
1
- import { expect, test } from "vitest";
2
- import { processData } from "../flowTestUtils";
3
- import FilterTransform from "./filter";
4
-
5
- test("FilterTransform filter rows", () => {
6
- const data = [1, 2, 3, 4, 5, 6].map((x) => ({ x }));
7
-
8
- /** @type {import("../../spec/transform").FilterParams} */
9
- const filterParams = {
10
- type: "filter",
11
- expr: "datum.x > 3 && datum.x != 5",
12
- };
13
-
14
- const t = new FilterTransform(filterParams);
15
- t.initialize();
16
-
17
- expect(processData(t, data)).toEqual([4, 6].map((x) => ({ x })));
18
- });
@@ -1,134 +0,0 @@
1
- import { bisector } from "d3-array";
2
- import FlowNode from "../flowNode";
3
- import { topKSlice } from "../../utils/topK";
4
- import ReservationMap from "../../utils/reservationMap";
5
- import { field } from "../../utils/field";
6
-
7
- /**
8
- * @typedef {import("../../spec/transform").FilterScoredLabelsParams} Params
9
- * @typedef {import("../../view/view").default} View
10
- */
11
- export default class FilterScoredLabelsTransform extends FlowNode {
12
- /**
13
- *
14
- * @param {Params} params
15
- * @param {View} view
16
- */
17
- constructor(params, view) {
18
- super();
19
-
20
- this.params = params;
21
-
22
- /** @type {any[]} */
23
- this._data = [];
24
-
25
- this.channel = params.channel ?? "x";
26
-
27
- if (!["x", "y"].includes(this.channel)) {
28
- throw new Error("Invalid channel: " + this.channel);
29
- }
30
-
31
- this.posAccessor = field(this.params.pos);
32
- this.posBisector = bisector(this.posAccessor);
33
- this.scoreAccessor = field(this.params.score);
34
- this.widthAccessor = field(this.params.width);
35
- /** @type {function(any):any} */
36
- this.laneAccessor = this.params.lane
37
- ? field(this.params.lane)
38
- : (d) => 0;
39
- this.padding = this.params.padding ?? 0;
40
-
41
- /** @type {Map<any, ReservationMap>} */
42
- this.reservationMaps = new Map();
43
-
44
- this.resolution = view.getScaleResolution(this.channel);
45
-
46
- // Synchronize propagation with rendering because we need both the domain and the range (length of the axis).
47
- const callback = () => this._filterAndPropagate();
48
- this.schedule = () => view.context.animator.requestTransition(callback);
49
-
50
- // Propagate when the domain changes
51
- this.resolution.addEventListener("domain", (scale) => this.schedule());
52
-
53
- // Propagate when layout changes. Abusing a "private" method.
54
- // TODO: Provide another attachment point, in view context for example
55
- view._addBroadcastHandler("layoutComputed", () => this.schedule());
56
-
57
- // TODO: Remove observers when this FlowNode is thrown away.
58
- }
59
-
60
- complete() {
61
- const posAccessor = this.posAccessor;
62
- this._data.sort((a, b) => posAccessor(a) - posAccessor(b));
63
-
64
- this._scores = this._data.map(this.scoreAccessor);
65
-
66
- for (const lane of new Set(this._data.map(this.laneAccessor))) {
67
- this.reservationMaps.set(lane, new ReservationMap(200));
68
- }
69
-
70
- this.schedule();
71
-
72
- super.complete();
73
- }
74
-
75
- _filterAndPropagate() {
76
- super.reset();
77
-
78
- const scale = this.resolution.getScale();
79
- const rangeSpan =
80
- this.resolution.members[0].view.coords?.[
81
- this.channel == "x" ? "width" : "height"
82
- ];
83
- if (!rangeSpan) {
84
- // The view size is not (yet) available
85
- return;
86
- }
87
-
88
- for (const reservationMap of this.reservationMaps.values()) {
89
- reservationMap.reset();
90
- }
91
-
92
- const domain = scale.domain();
93
- const k = 70; // TODO: Configurable
94
-
95
- // Find the maximum of k elements from the visible domain in priority order
96
- const topIndices = topKSlice(
97
- this._scores,
98
- k,
99
- this.posBisector.left(this._data, domain[0]),
100
- this.posBisector.right(this._data, domain[1])
101
- );
102
-
103
- // Try to fit the elements on the available lanes and propagate if there was room
104
- for (const i of topIndices) {
105
- const datum = this._data[i];
106
- const pos = scale(this.posAccessor(datum)) * rangeSpan;
107
- const halfWidth = this.widthAccessor(datum) / 2 + this.padding;
108
-
109
- if (
110
- this.reservationMaps
111
- .get(this.laneAccessor(datum))
112
- .reserve(pos - halfWidth, pos + halfWidth)
113
- ) {
114
- this._propagate(datum);
115
- }
116
- }
117
-
118
- super.complete();
119
- }
120
-
121
- reset() {
122
- super.reset();
123
- this._data = [];
124
- this.groups = new Map();
125
- }
126
-
127
- /**
128
- *
129
- * @param {import("../flowNode").Datum} datum
130
- */
131
- handle(datum) {
132
- this._data.push(datum);
133
- }
134
- }
@@ -1,57 +0,0 @@
1
- import { field } from "../../utils/field";
2
- import numberExtractor from "../../utils/numberExtractor";
3
- import FlowNode, { BEHAVIOR_CLONES } from "../flowNode";
4
-
5
- /**
6
- * @typedef {import("../../spec/transform").FlattenCompressedExonsParams} FlattenCompressedExonsParams
7
- */
8
-
9
- /**
10
- * Flattens "run-length encoded" exons. The transforms inputs the start
11
- * coordinate of the gene body and a comma-delimited string of alternating
12
- * intron and exon lengths. A new datum is created for each exon.
13
- */
14
- export default class FlattenCompressedExonsTransform extends FlowNode {
15
- get behavior() {
16
- return BEHAVIOR_CLONES;
17
- }
18
-
19
- /**
20
- *
21
- * @param {FlattenCompressedExonsParams} params
22
- */
23
- constructor(params) {
24
- super();
25
-
26
- const exonsAccessor = field(params.exons ?? "exons");
27
- const startAccessor = field(params.start ?? "start");
28
- const [exonStart, exonEnd] = params.as || ["exonStart", "exonEnd"];
29
-
30
- /**
31
- *
32
- * @param {any} datum
33
- */
34
- this.handle = (datum) => {
35
- let upper = startAccessor(datum);
36
- let lower = upper;
37
-
38
- let inExon = true;
39
- const exons = exonsAccessor(datum);
40
- for (const token of numberExtractor(exons)) {
41
- if (inExon) {
42
- lower = upper + token;
43
- } else {
44
- upper = lower + token;
45
-
46
- const newRow = Object.assign({}, datum);
47
- newRow[exonStart] = lower;
48
- newRow[exonEnd] = upper;
49
-
50
- this._propagate(newRow);
51
- }
52
-
53
- inExon = !inExon;
54
- }
55
- };
56
- }
57
- }