@genome-spy/core 0.48.1 → 0.49.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.
- package/dist/bundle/index.es.js +7485 -7097
- package/dist/bundle/index.js +124 -111
- package/dist/schema.json +838 -344
- package/dist/src/data/collector.d.ts +10 -8
- package/dist/src/data/collector.d.ts.map +1 -1
- package/dist/src/data/collector.js +131 -33
- package/dist/src/data/collector.test.d.ts +2 -0
- package/dist/src/data/collector.test.d.ts.map +1 -0
- package/dist/src/data/collector.test.js +55 -1
- package/dist/src/data/dataFlow.test.d.ts +2 -0
- package/dist/src/data/dataFlow.test.d.ts.map +1 -0
- package/dist/src/data/flow.test.d.ts +2 -0
- package/dist/src/data/flow.test.d.ts.map +1 -0
- package/dist/src/data/flow.test.js +19 -14
- package/dist/src/data/flowNode.test.d.ts +2 -0
- package/dist/src/data/flowNode.test.d.ts.map +1 -0
- package/dist/src/data/flowOptimizer.test.d.ts +2 -0
- package/dist/src/data/flowOptimizer.test.d.ts.map +1 -0
- package/dist/src/data/flowOptimizer.test.js +9 -10
- package/dist/src/data/formats/fasta.test.d.ts +2 -0
- package/dist/src/data/formats/fasta.test.d.ts.map +1 -0
- package/dist/src/data/sources/inlineSource.test.d.ts +2 -0
- package/dist/src/data/sources/inlineSource.test.d.ts.map +1 -0
- package/dist/src/data/sources/inlineSource.test.js +23 -16
- package/dist/src/data/sources/sequenceSource.test.d.ts +2 -0
- package/dist/src/data/sources/sequenceSource.test.d.ts.map +1 -0
- package/dist/src/data/sources/sequenceSource.test.js +59 -42
- package/dist/src/data/transforms/clone.test.d.ts +2 -0
- package/dist/src/data/transforms/clone.test.d.ts.map +1 -0
- package/dist/src/data/transforms/coverage.test.d.ts +2 -0
- package/dist/src/data/transforms/coverage.test.d.ts.map +1 -0
- package/dist/src/data/transforms/coverage.test.js +1 -1
- package/dist/src/data/transforms/filter.d.ts +10 -0
- package/dist/src/data/transforms/filter.d.ts.map +1 -1
- package/dist/src/data/transforms/filter.js +30 -1
- package/dist/src/data/transforms/filter.test.d.ts +2 -0
- package/dist/src/data/transforms/filter.test.d.ts.map +1 -0
- package/dist/src/data/transforms/flatten.test.d.ts +2 -0
- package/dist/src/data/transforms/flatten.test.d.ts.map +1 -0
- package/dist/src/data/transforms/flatten.test.js +10 -7
- package/dist/src/data/transforms/flattenDelimited.test.d.ts +2 -0
- package/dist/src/data/transforms/flattenDelimited.test.d.ts.map +1 -0
- package/dist/src/data/transforms/flattenDelimited.test.js +16 -13
- package/dist/src/data/transforms/flattenSequence.test.d.ts +2 -0
- package/dist/src/data/transforms/flattenSequence.test.d.ts.map +1 -0
- package/dist/src/data/transforms/flattenSequence.test.js +1 -1
- package/dist/src/data/transforms/formula.test.d.ts +2 -0
- package/dist/src/data/transforms/formula.test.d.ts.map +1 -0
- package/dist/src/data/transforms/formula.test.js +1 -1
- package/dist/src/data/transforms/identifier.d.ts +1 -1
- package/dist/src/data/transforms/identifier.d.ts.map +1 -1
- package/dist/src/data/transforms/identifier.js +2 -2
- package/dist/src/data/transforms/identifier.test.d.ts +2 -0
- package/dist/src/data/transforms/identifier.test.d.ts.map +1 -0
- package/dist/src/data/transforms/identifier.test.js +23 -14
- package/dist/src/data/transforms/pileup.test.d.ts +2 -0
- package/dist/src/data/transforms/pileup.test.d.ts.map +1 -0
- package/dist/src/data/transforms/project.test.d.ts +2 -0
- package/dist/src/data/transforms/project.test.d.ts.map +1 -0
- package/dist/src/data/transforms/project.test.js +1 -1
- package/dist/src/data/transforms/regexExtract.test.d.ts +2 -0
- package/dist/src/data/transforms/regexExtract.test.d.ts.map +1 -0
- package/dist/src/data/transforms/regexExtract.test.js +6 -3
- package/dist/src/data/transforms/regexFold.test.d.ts +2 -0
- package/dist/src/data/transforms/regexFold.test.d.ts.map +1 -0
- package/dist/src/data/transforms/sample.test.d.ts +2 -0
- package/dist/src/data/transforms/sample.test.d.ts.map +1 -0
- package/dist/src/data/transforms/stack.test.d.ts +2 -0
- package/dist/src/data/transforms/stack.test.d.ts.map +1 -0
- package/dist/src/data/transforms/stack.test.js +8 -8
- package/dist/src/encoder/accessor.d.ts +17 -14
- package/dist/src/encoder/accessor.d.ts.map +1 -1
- package/dist/src/encoder/accessor.js +127 -56
- package/dist/src/encoder/accessor.test.d.ts +2 -0
- package/dist/src/encoder/accessor.test.d.ts.map +1 -0
- package/dist/src/encoder/accessor.test.js +145 -31
- package/dist/src/encoder/encoder.d.ts +26 -13
- package/dist/src/encoder/encoder.d.ts.map +1 -1
- package/dist/src/encoder/encoder.js +98 -114
- package/dist/src/encoder/encoder.test.d.ts +2 -0
- package/dist/src/encoder/encoder.test.d.ts.map +1 -0
- package/dist/src/encoder/encoder.test.js +85 -82
- package/dist/src/fonts/bmFontManager.d.ts.map +1 -1
- package/dist/src/fonts/bmFontManager.js +10 -4
- package/dist/src/genome/genome.test.d.ts +2 -0
- package/dist/src/genome/genome.test.d.ts.map +1 -0
- package/dist/src/genome/scaleIndex.test.d.ts +2 -0
- package/dist/src/genome/scaleIndex.test.d.ts.map +1 -0
- package/dist/src/genome/scaleLocus.test.d.ts +2 -0
- package/dist/src/genome/scaleLocus.test.d.ts.map +1 -0
- package/dist/src/genomeSpy.d.ts +3 -2
- package/dist/src/genomeSpy.d.ts.map +1 -1
- package/dist/src/genomeSpy.js +29 -21
- package/dist/src/gl/dataToVertices.d.ts +5 -7
- package/dist/src/gl/dataToVertices.d.ts.map +1 -1
- package/dist/src/gl/dataToVertices.js +42 -30
- package/dist/src/gl/glslScaleGenerator.d.ts +84 -15
- package/dist/src/gl/glslScaleGenerator.d.ts.map +1 -1
- package/dist/src/gl/glslScaleGenerator.js +260 -73
- package/dist/src/gl/includes/picking.vertex.glsl.js +1 -1
- package/dist/src/marks/link.common.glsl.js +1 -1
- package/dist/src/marks/link.d.ts.map +1 -1
- package/dist/src/marks/link.js +10 -0
- package/dist/src/marks/link.vertex.glsl.js +1 -1
- package/dist/src/marks/mark.d.ts +6 -9
- package/dist/src/marks/mark.d.ts.map +1 -1
- package/dist/src/marks/mark.js +212 -95
- package/dist/src/marks/point.d.ts.map +1 -1
- package/dist/src/marks/point.js +5 -1
- package/dist/src/marks/rect.d.ts.map +1 -1
- package/dist/src/marks/rect.js +9 -4
- package/dist/src/marks/rule.d.ts.map +1 -1
- package/dist/src/marks/rule.js +4 -0
- package/dist/src/marks/text.d.ts.map +1 -1
- package/dist/src/marks/text.js +5 -1
- package/dist/src/scale/scale.test.d.ts +2 -0
- package/dist/src/scale/scale.test.d.ts.map +1 -0
- package/dist/src/scale/scale.test.js +2 -0
- package/dist/src/scale/ticks.test.d.ts +2 -0
- package/dist/src/scale/ticks.test.d.ts.map +1 -0
- package/dist/src/scale/ticks.test.js +6 -0
- package/dist/src/selection/selection.d.ts +39 -0
- package/dist/src/selection/selection.d.ts.map +1 -0
- package/dist/src/selection/selection.js +78 -0
- package/dist/src/spec/channel.d.ts +137 -83
- package/dist/src/spec/mark.d.ts +9 -0
- package/dist/src/spec/parameter.d.ts +112 -3
- package/dist/src/spec/root.d.ts +0 -1
- package/dist/src/spec/transform.d.ts +19 -1
- package/dist/src/spec/view.d.ts +3 -3
- package/dist/src/tooltip/dataTooltipHandler.js +1 -1
- package/dist/src/types/encoder.d.ts +80 -26
- package/dist/src/types/rendering.d.ts +1 -0
- package/dist/src/types/selectionTypes.d.ts +44 -0
- package/dist/src/types/viewContext.d.ts +1 -4
- package/dist/src/utils/addBaseUrl.test.d.ts +2 -0
- package/dist/src/utils/addBaseUrl.test.d.ts.map +1 -0
- package/dist/src/utils/animator.d.ts.map +1 -1
- package/dist/src/utils/animator.js +3 -1
- package/dist/src/utils/binnedIndex.test.d.ts +2 -0
- package/dist/src/utils/binnedIndex.test.d.ts.map +1 -0
- package/dist/src/utils/cloner.test.d.ts +2 -0
- package/dist/src/utils/cloner.test.d.ts.map +1 -0
- package/dist/src/utils/coalesce.test.d.ts +2 -0
- package/dist/src/utils/coalesce.test.d.ts.map +1 -0
- package/dist/src/utils/concatIterables.test.d.ts +2 -0
- package/dist/src/utils/concatIterables.test.d.ts.map +1 -0
- package/dist/src/utils/domainArray.test.d.ts +2 -0
- package/dist/src/utils/domainArray.test.d.ts.map +1 -0
- package/dist/src/utils/expression.d.ts +2 -2
- package/dist/src/utils/expression.d.ts.map +1 -1
- package/dist/src/utils/expression.js +11 -2
- package/dist/src/utils/indexer.test.d.ts +2 -0
- package/dist/src/utils/indexer.test.d.ts.map +1 -0
- package/dist/src/utils/inertia.d.ts.map +1 -1
- package/dist/src/utils/inertia.js +4 -0
- package/dist/src/utils/inputBinding.d.ts.map +1 -1
- package/dist/src/utils/inputBinding.js +4 -0
- package/dist/src/utils/iterateNestedMaps.d.ts +4 -3
- package/dist/src/utils/iterateNestedMaps.d.ts.map +1 -1
- package/dist/src/utils/iterateNestedMaps.js +3 -2
- package/dist/src/utils/iterateNestedMaps.test.d.ts +2 -0
- package/dist/src/utils/iterateNestedMaps.test.d.ts.map +1 -0
- package/dist/src/utils/kWayMerge.test.d.ts +2 -0
- package/dist/src/utils/kWayMerge.test.d.ts.map +1 -0
- package/dist/src/utils/mergeObjects.test.d.ts +2 -0
- package/dist/src/utils/mergeObjects.test.d.ts.map +1 -0
- package/dist/src/utils/numberExtractor.test.d.ts +2 -0
- package/dist/src/utils/numberExtractor.test.d.ts.map +1 -0
- package/dist/src/utils/propertyCacher.test.d.ts +2 -0
- package/dist/src/utils/propertyCacher.test.d.ts.map +1 -0
- package/dist/src/utils/propertyCoalescer.test.d.ts +2 -0
- package/dist/src/utils/propertyCoalescer.test.d.ts.map +1 -0
- package/dist/src/utils/propertyCoalescer.test.js +3 -0
- package/dist/src/utils/radixSort.d.ts +9 -0
- package/dist/src/utils/radixSort.d.ts.map +1 -0
- package/dist/src/utils/radixSort.js +130 -0
- package/dist/src/utils/radixSort.test.d.ts +2 -0
- package/dist/src/utils/radixSort.test.d.ts.map +1 -0
- package/dist/src/utils/radixSort.test.js +51 -0
- package/dist/src/utils/reservationMap.test.d.ts +2 -0
- package/dist/src/utils/reservationMap.test.d.ts.map +1 -0
- package/dist/src/utils/ringBuffer.test.d.ts +2 -0
- package/dist/src/utils/ringBuffer.test.d.ts.map +1 -0
- package/dist/src/utils/topK.test.d.ts +2 -0
- package/dist/src/utils/topK.test.d.ts.map +1 -0
- package/dist/src/utils/trees.test.d.ts +2 -0
- package/dist/src/utils/trees.test.d.ts.map +1 -0
- package/dist/src/utils/trees.test.js +8 -3
- package/dist/src/utils/variableTools.test.d.ts +2 -0
- package/dist/src/utils/variableTools.test.d.ts.map +1 -0
- package/dist/src/view/axisResolution.d.ts +19 -6
- package/dist/src/view/axisResolution.d.ts.map +1 -1
- package/dist/src/view/axisResolution.js +16 -7
- package/dist/src/view/axisResolution.test.d.ts +2 -0
- package/dist/src/view/axisResolution.test.d.ts.map +1 -0
- package/dist/src/view/axisResolution.test.js +16 -11
- package/dist/src/view/facetView.d.ts +1 -1
- package/dist/src/view/facetView.d.ts.map +1 -1
- package/dist/src/view/flowBuilder.d.ts +1 -1
- package/dist/src/view/flowBuilder.d.ts.map +1 -1
- package/dist/src/view/flowBuilder.js +34 -5
- package/dist/src/view/flowBuilder.test.d.ts +2 -0
- package/dist/src/view/flowBuilder.test.d.ts.map +1 -0
- package/dist/src/view/gridView.d.ts +0 -6
- package/dist/src/view/gridView.d.ts.map +1 -1
- package/dist/src/view/layerView.d.ts +0 -6
- package/dist/src/view/layerView.d.ts.map +1 -1
- package/dist/src/view/layout/flexLayout.test.d.ts +2 -0
- package/dist/src/view/layout/flexLayout.test.d.ts.map +1 -0
- package/dist/src/view/layout/grid.test.d.ts +2 -0
- package/dist/src/view/layout/grid.test.d.ts.map +1 -0
- package/dist/src/view/layout/rectangle.test.d.ts +2 -0
- package/dist/src/view/layout/rectangle.test.d.ts.map +1 -0
- package/dist/src/view/paramMediator.d.ts +32 -5
- package/dist/src/view/paramMediator.d.ts.map +1 -1
- package/dist/src/view/paramMediator.js +97 -9
- package/dist/src/view/paramMediator.test.d.ts +2 -0
- package/dist/src/view/paramMediator.test.d.ts.map +1 -0
- package/dist/src/view/paramMediator.test.js +17 -1
- package/dist/src/view/scaleResolution.d.ts +17 -9
- package/dist/src/view/scaleResolution.d.ts.map +1 -1
- package/dist/src/view/scaleResolution.js +51 -34
- package/dist/src/view/scaleResolution.test.d.ts +2 -0
- package/dist/src/view/scaleResolution.test.d.ts.map +1 -0
- package/dist/src/view/scaleResolution.test.js +2 -0
- package/dist/src/view/testUtils.d.ts.map +1 -1
- package/dist/src/view/testUtils.js +15 -3
- package/dist/src/view/unitView.d.ts +5 -15
- package/dist/src/view/unitView.d.ts.map +1 -1
- package/dist/src/view/unitView.js +81 -101
- package/dist/src/view/view.d.ts +1 -1
- package/dist/src/view/view.d.ts.map +1 -1
- package/dist/src/view/view.test.d.ts +2 -0
- package/dist/src/view/view.test.d.ts.map +1 -0
- package/dist/src/view/view.test.js +73 -55
- package/dist/src/view/viewFactory.test.d.ts +2 -0
- package/dist/src/view/viewFactory.test.d.ts.map +1 -0
- package/dist/src/view/viewFactory.test.js +2 -2
- package/dist/src/view/zoom.js +2 -2
- package/package.json +5 -2
|
@@ -12,25 +12,27 @@ export default class Collector extends FlowNode {
|
|
|
12
12
|
params: import("../spec/transform.js").CollectParams;
|
|
13
13
|
/** @type {(function(Collector):void)[]} */
|
|
14
14
|
observers: ((arg0: Collector) => void)[];
|
|
15
|
-
/** @type {Map<
|
|
16
|
-
facetBatches: Map<
|
|
17
|
-
_init(): void;
|
|
18
|
-
/** @type {import("./flowNode.js").Data} */
|
|
19
|
-
_data: import("./flowNode.js").Data;
|
|
15
|
+
/** @type {Map<import("../spec/channel.js").Scalar[], Data>} TODO: proper type for key */
|
|
16
|
+
facetBatches: Map<import("../spec/channel.js").Scalar[], import("./flowNode.js").Data>;
|
|
20
17
|
/**
|
|
21
|
-
* @returns {Iterable<
|
|
18
|
+
* @returns {Iterable<Datum>}
|
|
22
19
|
*/
|
|
23
20
|
getData(): Iterable<import("./flowNode.js").Datum>;
|
|
24
21
|
/**
|
|
25
22
|
*
|
|
26
|
-
* @param {(datum:
|
|
23
|
+
* @param {(datum: Datum) => void} visitor
|
|
27
24
|
*/
|
|
28
25
|
visitData(visitor: (datum: import("./flowNode.js").Datum) => void): void;
|
|
29
26
|
/**
|
|
30
27
|
* Returns the total number of data items collected.
|
|
31
28
|
*/
|
|
32
29
|
getItemCount(): number;
|
|
33
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Use an index to find a datum by its unique id.
|
|
32
|
+
*
|
|
33
|
+
* @param {number} uniqueId
|
|
34
|
+
*/
|
|
35
|
+
findDatumByUniqueId(uniqueId: number): import("./flowNode.js").Datum;
|
|
34
36
|
#private;
|
|
35
37
|
}
|
|
36
38
|
import FlowNode from "./flowNode.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../../../src/data/collector.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../../../src/data/collector.js"],"names":[],"mappings":"AAUA;;;;;GAKG;AACH;IA8BI;;OAEG;IACH,qBAFW,OAAO,sBAAsB,EAAE,aAAa,EAetD;IAVG,qDAA2C;IAE3C,2CAA2C;IAC3C,WADW,QAAU,SAAS,KAAE,IAAI,CAAC,EAAE,CACpB;IAGnB,yFAAyF;IACzF,cADW,IAAI,OAAO,oBAAoB,EAAE,MAAM,EAAE,+BAAO,CACN;IAuHzD;;OAEG;IACH,mDAmBC;IAED;;;OAGG;IACH,6DAF6B,IAAI,QAUhC;IAED;;OAEG;IACH,uBAMC;IA8CD;;;;OAIG;IACH,8BAFW,MAAM,iCA4BhB;;CACJ;qBA3SyD,eAAe"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { InternMap } from "internmap";
|
|
2
|
-
import { group } from "d3-array";
|
|
2
|
+
import { bisector, group } from "d3-array";
|
|
3
3
|
import { compare } from "vega-util";
|
|
4
4
|
import iterateNestedMaps from "../utils/iterateNestedMaps.js";
|
|
5
5
|
import FlowNode, { BEHAVIOR_COLLECTS, isFacetBatch } from "./flowNode.js";
|
|
6
6
|
import { field } from "../utils/field.js";
|
|
7
7
|
import { asArray } from "../utils/arrayUtils.js";
|
|
8
|
+
import { radixSortIntoLookupArray } from "../utils/radixSort.js";
|
|
9
|
+
import { UNIQUE_ID_KEY } from "./transforms/identifier.js";
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Collects (materializes) the data that flows through this node.
|
|
@@ -13,6 +15,31 @@ import { asArray } from "../utils/arrayUtils.js";
|
|
|
13
15
|
* Grouping is primarily intended for handling faceted data.
|
|
14
16
|
*/
|
|
15
17
|
export default class Collector extends FlowNode {
|
|
18
|
+
/**
|
|
19
|
+
* @typedef {import("./flowNode.js").Datum} Datum
|
|
20
|
+
* @typedef {import("./flowNode.js").Data} Data
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Current batch that is being collected.
|
|
25
|
+
* @type {Data}
|
|
26
|
+
*/
|
|
27
|
+
#buffer = [];
|
|
28
|
+
|
|
29
|
+
#uniqueIdAccessor = field(UNIQUE_ID_KEY);
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @type {number[]}
|
|
33
|
+
*/
|
|
34
|
+
#uniqueIdIndex = [];
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Start and end indices of all facets if they are concatenated into a single array.
|
|
38
|
+
* Used together with the uniqueIdIndex for looking up data items by their unique id.
|
|
39
|
+
* @type {{start: number, stop: number, facetId: import("../spec/channel.js").Scalar[]}[]}
|
|
40
|
+
*/
|
|
41
|
+
#facetIndices;
|
|
42
|
+
|
|
16
43
|
get behavior() {
|
|
17
44
|
return BEHAVIOR_COLLECTS;
|
|
18
45
|
}
|
|
@@ -28,32 +55,30 @@ export default class Collector extends FlowNode {
|
|
|
28
55
|
/** @type {(function(Collector):void)[]} */
|
|
29
56
|
this.observers = [];
|
|
30
57
|
|
|
31
|
-
|
|
32
|
-
|
|
58
|
+
// TODO: Consider nested maps instead of InternMap
|
|
59
|
+
/** @type {Map<import("../spec/channel.js").Scalar[], Data>} TODO: proper type for key */
|
|
60
|
+
this.facetBatches = new InternMap([], JSON.stringify);
|
|
33
61
|
|
|
34
|
-
this
|
|
62
|
+
this.#init();
|
|
35
63
|
}
|
|
36
64
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
this._data = [];
|
|
65
|
+
#init() {
|
|
66
|
+
this.#buffer = [];
|
|
40
67
|
|
|
41
|
-
|
|
42
|
-
this.facetBatches
|
|
43
|
-
this.facetBatches.set(undefined, this._data);
|
|
68
|
+
this.facetBatches.clear();
|
|
69
|
+
this.facetBatches.set(undefined, this.#buffer);
|
|
44
70
|
}
|
|
45
71
|
|
|
46
72
|
reset() {
|
|
47
73
|
super.reset();
|
|
48
|
-
this
|
|
74
|
+
this.#init();
|
|
49
75
|
}
|
|
50
76
|
|
|
51
77
|
/**
|
|
52
|
-
*
|
|
53
|
-
* @param {import("./flowNode.js").Datum} datum
|
|
78
|
+
* @param {Datum} datum
|
|
54
79
|
*/
|
|
55
80
|
handle(datum) {
|
|
56
|
-
this.
|
|
81
|
+
this.#buffer.push(datum);
|
|
57
82
|
}
|
|
58
83
|
|
|
59
84
|
/**
|
|
@@ -61,12 +86,15 @@ export default class Collector extends FlowNode {
|
|
|
61
86
|
*/
|
|
62
87
|
beginBatch(flowBatch) {
|
|
63
88
|
if (isFacetBatch(flowBatch)) {
|
|
64
|
-
this
|
|
65
|
-
this.facetBatches.set(asArray(flowBatch.facetId), this
|
|
89
|
+
this.#buffer = [];
|
|
90
|
+
this.facetBatches.set(asArray(flowBatch.facetId), this.#buffer);
|
|
66
91
|
}
|
|
67
92
|
}
|
|
68
93
|
|
|
69
94
|
complete() {
|
|
95
|
+
// Free some memory
|
|
96
|
+
this.#buffer = [];
|
|
97
|
+
|
|
70
98
|
const sort = this.params?.sort;
|
|
71
99
|
// Vega's "compare" function is incredibly slow (uses megamorphic field accessor)
|
|
72
100
|
// TODO: Implement a replacement for static data types
|
|
@@ -84,6 +112,8 @@ export default class Collector extends FlowNode {
|
|
|
84
112
|
throw new Error("TODO: Support faceted data!");
|
|
85
113
|
}
|
|
86
114
|
|
|
115
|
+
const data = this.facetBatches.get(undefined);
|
|
116
|
+
|
|
87
117
|
const accessors = this.params.groupby.map((fieldName) =>
|
|
88
118
|
field(fieldName)
|
|
89
119
|
);
|
|
@@ -91,10 +121,10 @@ export default class Collector extends FlowNode {
|
|
|
91
121
|
accessors.length > 1
|
|
92
122
|
? // There's something strange in d3-array's typings
|
|
93
123
|
/** @type {Map<any, any>} */ /** @type {any} */ (
|
|
94
|
-
group(
|
|
124
|
+
group(data, ...accessors)
|
|
95
125
|
)
|
|
96
126
|
: // D3's group is SLOW!
|
|
97
|
-
groupBy(
|
|
127
|
+
groupBy(data, accessors[0]);
|
|
98
128
|
|
|
99
129
|
this.facetBatches.clear();
|
|
100
130
|
for (const [key, data] of iterateNestedMaps(groups)) {
|
|
@@ -107,6 +137,7 @@ export default class Collector extends FlowNode {
|
|
|
107
137
|
sortData(data);
|
|
108
138
|
}
|
|
109
139
|
|
|
140
|
+
this.#buildUniqueIdIndex();
|
|
110
141
|
this.#propagateToChildren();
|
|
111
142
|
|
|
112
143
|
super.complete();
|
|
@@ -118,16 +149,16 @@ export default class Collector extends FlowNode {
|
|
|
118
149
|
|
|
119
150
|
#propagateToChildren() {
|
|
120
151
|
if (this.children.length) {
|
|
121
|
-
for (const [
|
|
122
|
-
if (
|
|
152
|
+
for (const [facetId, data] of this.facetBatches.entries()) {
|
|
153
|
+
if (facetId) {
|
|
123
154
|
/** @type {import("../types/flowBatch.js").FacetBatch} */
|
|
124
|
-
const facetBatch = { type: "facet", facetId
|
|
155
|
+
const facetBatch = { type: "facet", facetId };
|
|
125
156
|
for (const child of this.children) {
|
|
126
157
|
child.beginBatch(facetBatch);
|
|
127
158
|
}
|
|
128
159
|
}
|
|
129
|
-
for (
|
|
130
|
-
this._propagate(
|
|
160
|
+
for (let i = 0, n = data.length; i < n; i++) {
|
|
161
|
+
this._propagate(data[i]);
|
|
131
162
|
}
|
|
132
163
|
}
|
|
133
164
|
}
|
|
@@ -146,10 +177,10 @@ export default class Collector extends FlowNode {
|
|
|
146
177
|
}
|
|
147
178
|
|
|
148
179
|
/**
|
|
149
|
-
* @returns {Iterable<
|
|
180
|
+
* @returns {Iterable<Datum>}
|
|
150
181
|
*/
|
|
151
182
|
getData() {
|
|
152
|
-
this
|
|
183
|
+
this.#checkStatus();
|
|
153
184
|
|
|
154
185
|
switch (this.facetBatches.size) {
|
|
155
186
|
case 0:
|
|
@@ -161,9 +192,7 @@ export default class Collector extends FlowNode {
|
|
|
161
192
|
return {
|
|
162
193
|
[Symbol.iterator]: function* generator() {
|
|
163
194
|
for (const data of groups.values()) {
|
|
164
|
-
|
|
165
|
-
yield data[i];
|
|
166
|
-
}
|
|
195
|
+
yield* data;
|
|
167
196
|
}
|
|
168
197
|
},
|
|
169
198
|
};
|
|
@@ -173,10 +202,10 @@ export default class Collector extends FlowNode {
|
|
|
173
202
|
|
|
174
203
|
/**
|
|
175
204
|
*
|
|
176
|
-
* @param {(datum:
|
|
205
|
+
* @param {(datum: Datum) => void} visitor
|
|
177
206
|
*/
|
|
178
207
|
visitData(visitor) {
|
|
179
|
-
this
|
|
208
|
+
this.#checkStatus();
|
|
180
209
|
|
|
181
210
|
for (const data of this.facetBatches.values()) {
|
|
182
211
|
for (let i = 0; i < data.length; i++) {
|
|
@@ -196,21 +225,90 @@ export default class Collector extends FlowNode {
|
|
|
196
225
|
return count;
|
|
197
226
|
}
|
|
198
227
|
|
|
199
|
-
|
|
228
|
+
#checkStatus() {
|
|
200
229
|
if (!this.completed) {
|
|
201
230
|
throw new Error(
|
|
202
231
|
"Data propagation is not completed! No data are available."
|
|
203
232
|
);
|
|
204
233
|
}
|
|
205
234
|
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Builds an index for looking up data items by their unique id.
|
|
238
|
+
* Using a sorted index and binary search for O(log n) complexity.
|
|
239
|
+
*/
|
|
240
|
+
#buildUniqueIdIndex() {
|
|
241
|
+
this.#facetIndices = [];
|
|
242
|
+
|
|
243
|
+
/** @type {Datum} */
|
|
244
|
+
const obj = this.facetBatches.values().next().value?.[0];
|
|
245
|
+
if (obj == null || !(UNIQUE_ID_KEY in obj)) {
|
|
246
|
+
return; // No unique ids in the data
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
let cumulativePos = 0;
|
|
250
|
+
|
|
251
|
+
/** @type {number[]} */
|
|
252
|
+
const ids = [];
|
|
253
|
+
|
|
254
|
+
const a = this.#uniqueIdAccessor;
|
|
255
|
+
|
|
256
|
+
for (const [facetId, data] of this.facetBatches) {
|
|
257
|
+
this.#facetIndices.push({
|
|
258
|
+
start: cumulativePos,
|
|
259
|
+
stop: cumulativePos + data.length,
|
|
260
|
+
facetId,
|
|
261
|
+
});
|
|
262
|
+
cumulativePos += data.length;
|
|
263
|
+
|
|
264
|
+
for (let i = 0, n = data.length; i < n; i++) {
|
|
265
|
+
ids.push(a(data[i]));
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
this.#uniqueIdIndex = radixSortIntoLookupArray(ids);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Use an index to find a datum by its unique id.
|
|
274
|
+
*
|
|
275
|
+
* @param {number} uniqueId
|
|
276
|
+
*/
|
|
277
|
+
findDatumByUniqueId(uniqueId) {
|
|
278
|
+
if (!this.#uniqueIdIndex.length) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const facetBisector = bisector((f) => f.start).right;
|
|
283
|
+
const a = this.#uniqueIdAccessor;
|
|
284
|
+
const indexBisector = bisector((i) => a(getDatum(i))).left;
|
|
285
|
+
|
|
286
|
+
const getDatum = (/** @type {number} */ i) => {
|
|
287
|
+
const fi = facetBisector(this.#facetIndices, i);
|
|
288
|
+
const facet = this.#facetIndices[fi - 1];
|
|
289
|
+
if (!facet || i >= facet.stop) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
const data = this.facetBatches.get(facet.facetId);
|
|
293
|
+
return data[i - facet.start];
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
const index = indexBisector(this.#uniqueIdIndex, uniqueId);
|
|
297
|
+
if (index >= 0) {
|
|
298
|
+
const datum = getDatum(this.#uniqueIdIndex[index]);
|
|
299
|
+
if (datum && a(datum) === uniqueId) {
|
|
300
|
+
return datum;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
206
304
|
}
|
|
207
305
|
|
|
208
306
|
/**
|
|
209
307
|
* Like D3's group but without InternMap, which is slow.
|
|
210
308
|
* TODO: Implement multi-level grouping
|
|
211
309
|
*
|
|
212
|
-
* @param {
|
|
213
|
-
* @param {(data:
|
|
310
|
+
* @param {Datum[]} data
|
|
311
|
+
* @param {(data: Datum) => import("../spec/channel.js").Scalar} accessor
|
|
214
312
|
*/
|
|
215
313
|
function groupBy(data, accessor) {
|
|
216
314
|
const groups = new Map();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collector.test.d.ts","sourceRoot":"","sources":["../../../src/data/collector.test.js"],"names":[],"mappings":""}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { expect, test } from "vitest";
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
2
|
|
|
3
3
|
import Collector from "./collector.js";
|
|
4
|
+
import { UNIQUE_ID_KEY } from "./transforms/identifier.js";
|
|
4
5
|
|
|
5
6
|
const data = [1, 5, 2, 4, 3].map((x) => ({ x }));
|
|
6
7
|
|
|
@@ -82,3 +83,56 @@ test("Collector throws on incomplete flow", () => {
|
|
|
82
83
|
|
|
83
84
|
expect(() => collector.getData()).toThrow();
|
|
84
85
|
});
|
|
86
|
+
|
|
87
|
+
describe("Indexing unique ids", () => {
|
|
88
|
+
test("Collector builds a working index when ids are available", () => {
|
|
89
|
+
const collector = new Collector({
|
|
90
|
+
type: "collect",
|
|
91
|
+
groupby: ["a"],
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const data = [
|
|
95
|
+
{ a: 1, x: 1, [UNIQUE_ID_KEY]: 8 },
|
|
96
|
+
{ a: 1, x: 2, [UNIQUE_ID_KEY]: 2 },
|
|
97
|
+
{ a: 1, x: 3, [UNIQUE_ID_KEY]: 4 },
|
|
98
|
+
{ a: 1, x: 4, [UNIQUE_ID_KEY]: 6 },
|
|
99
|
+
{ a: 2, x: 5, [UNIQUE_ID_KEY]: 9 },
|
|
100
|
+
{ a: 2, x: 6, [UNIQUE_ID_KEY]: 7 },
|
|
101
|
+
{ a: 2, x: 7, [UNIQUE_ID_KEY]: 3 },
|
|
102
|
+
{ a: 2, x: 8, [UNIQUE_ID_KEY]: 1 },
|
|
103
|
+
];
|
|
104
|
+
|
|
105
|
+
for (const d of data) {
|
|
106
|
+
collector.handle(d);
|
|
107
|
+
}
|
|
108
|
+
collector.complete();
|
|
109
|
+
|
|
110
|
+
expect(collector.findDatumByUniqueId(8)).toEqual(data[0]);
|
|
111
|
+
expect(collector.findDatumByUniqueId(2)).toEqual(data[1]);
|
|
112
|
+
expect(collector.findDatumByUniqueId(4)).toEqual(data[2]);
|
|
113
|
+
expect(collector.findDatumByUniqueId(6)).toEqual(data[3]);
|
|
114
|
+
expect(collector.findDatumByUniqueId(9)).toEqual(data[4]);
|
|
115
|
+
expect(collector.findDatumByUniqueId(7)).toEqual(data[5]);
|
|
116
|
+
expect(collector.findDatumByUniqueId(3)).toEqual(data[6]);
|
|
117
|
+
expect(collector.findDatumByUniqueId(1)).toEqual(data[7]);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test("Collector returns undefined when ids are not available", () => {
|
|
121
|
+
const collector = new Collector({
|
|
122
|
+
type: "collect",
|
|
123
|
+
groupby: ["a"],
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const data = [
|
|
127
|
+
{ a: 1, x: 1 },
|
|
128
|
+
{ a: 2, x: 5 },
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
for (const d of data) {
|
|
132
|
+
collector.handle(d);
|
|
133
|
+
}
|
|
134
|
+
collector.complete();
|
|
135
|
+
|
|
136
|
+
expect(collector.findDatumByUniqueId(0)).toBeUndefined();
|
|
137
|
+
});
|
|
138
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataFlow.test.d.ts","sourceRoot":"","sources":["../../../src/data/dataFlow.test.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow.test.d.ts","sourceRoot":"","sources":["../../../src/data/flow.test.js"],"names":[],"mappings":""}
|
|
@@ -2,7 +2,10 @@ import { describe, expect, test } from "vitest";
|
|
|
2
2
|
import FilterTransform from "./transforms/filter.js";
|
|
3
3
|
import FormulaTransform from "./transforms/formula.js";
|
|
4
4
|
import Collector from "./collector.js";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
SynchronousSequenceSource,
|
|
7
|
+
makeParamMediatorProvider,
|
|
8
|
+
} from "./flowTestUtils.js";
|
|
6
9
|
|
|
7
10
|
describe("Test flow graphs", () => {
|
|
8
11
|
test("Trivial graph: sequence to collector", () => {
|
|
@@ -28,8 +31,6 @@ describe("Test flow graphs", () => {
|
|
|
28
31
|
|
|
29
32
|
source.dispatch();
|
|
30
33
|
|
|
31
|
-
expect(collector1.getData()).not.toBe(collector2._data);
|
|
32
|
-
|
|
33
34
|
expect(collector1.getData()).toEqual(
|
|
34
35
|
[0, 1, 2, 3, 4].map((d) => ({
|
|
35
36
|
data: d,
|
|
@@ -45,18 +46,23 @@ describe("Test flow graphs", () => {
|
|
|
45
46
|
|
|
46
47
|
test.skip("Implement stub for ParamMediator");
|
|
47
48
|
|
|
48
|
-
/*
|
|
49
49
|
test("Longer chain of nodes", () => {
|
|
50
50
|
const source = new SynchronousSequenceSource(10);
|
|
51
|
-
const filter = new FilterTransform(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
51
|
+
const filter = new FilterTransform(
|
|
52
|
+
{
|
|
53
|
+
type: "filter",
|
|
54
|
+
expr: "datum.data < 5",
|
|
55
|
+
},
|
|
56
|
+
makeParamMediatorProvider()
|
|
57
|
+
);
|
|
58
|
+
const formula = new FormulaTransform(
|
|
59
|
+
{
|
|
60
|
+
type: "formula",
|
|
61
|
+
expr: "datum.data * 2",
|
|
62
|
+
as: "data",
|
|
63
|
+
},
|
|
64
|
+
makeParamMediatorProvider()
|
|
65
|
+
);
|
|
60
66
|
const collector = new Collector();
|
|
61
67
|
|
|
62
68
|
source.addChild(filter);
|
|
@@ -72,5 +78,4 @@ describe("Test flow graphs", () => {
|
|
|
72
78
|
}))
|
|
73
79
|
);
|
|
74
80
|
});
|
|
75
|
-
*/
|
|
76
81
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flowNode.test.d.ts","sourceRoot":"","sources":["../../../src/data/flowNode.test.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flowOptimizer.test.d.ts","sourceRoot":"","sources":["../../../src/data/flowOptimizer.test.js"],"names":[],"mappings":""}
|
|
@@ -10,6 +10,7 @@ import DataFlow from "./dataFlow.js";
|
|
|
10
10
|
import { combineIdenticalDataSources } from "./flowOptimizer.js";
|
|
11
11
|
import InlineSource from "./sources/inlineSource.js";
|
|
12
12
|
import UrlSource from "./sources/urlSource.js";
|
|
13
|
+
import { makeParamMediatorProvider } from "./flowTestUtils.js";
|
|
13
14
|
|
|
14
15
|
test("validateLinks() detects broken graph", () => {
|
|
15
16
|
const root = new FlowNode();
|
|
@@ -132,14 +133,12 @@ describe("removeRedundantCloneTransforms", () => {
|
|
|
132
133
|
});
|
|
133
134
|
});
|
|
134
135
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
getBaseUrl: () => "",
|
|
142
|
-
};
|
|
136
|
+
/** @type {import("../view/view.js").default} */
|
|
137
|
+
const viewStub = /** @type {any} */ (
|
|
138
|
+
Object.assign(makeParamMediatorProvider(), {
|
|
139
|
+
getBaseUrl: () => "",
|
|
140
|
+
})
|
|
141
|
+
);
|
|
143
142
|
|
|
144
143
|
describe("Merge indentical data sources", () => {
|
|
145
144
|
test("Merges correctly", () => {
|
|
@@ -191,8 +190,8 @@ describe("Merge indentical data sources", () => {
|
|
|
191
190
|
/** @type {DataFlow<string>} */
|
|
192
191
|
const dataFlow = new DataFlow();
|
|
193
192
|
|
|
194
|
-
const a = new InlineSource({ values: [1, 2, 3] });
|
|
195
|
-
const b = new InlineSource({ values: [1, 2, 3] });
|
|
193
|
+
const a = new InlineSource({ values: [1, 2, 3] }, viewStub);
|
|
194
|
+
const b = new InlineSource({ values: [1, 2, 3] }, viewStub);
|
|
196
195
|
|
|
197
196
|
dataFlow.addDataSource(a, "a");
|
|
198
197
|
dataFlow.addDataSource(b, "b");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fasta.test.d.ts","sourceRoot":"","sources":["../../../../src/data/formats/fasta.test.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inlineSource.test.d.ts","sourceRoot":"","sources":["../../../../src/data/sources/inlineSource.test.js"],"names":[],"mappings":""}
|
|
@@ -15,33 +15,37 @@ async function collectSource(source) {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
test("InlineSource propagates an object", async () => {
|
|
18
|
-
expect(
|
|
19
|
-
|
|
20
|
-
);
|
|
18
|
+
expect(
|
|
19
|
+
await collectSource(new InlineSource({ values: { x: 1 } }, undefined))
|
|
20
|
+
).toEqual([{ x: 1 }]);
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
test("InlineSource propagates an array of objects", async () => {
|
|
24
24
|
expect(
|
|
25
|
-
await collectSource(
|
|
25
|
+
await collectSource(
|
|
26
|
+
new InlineSource({ values: [{ x: 1 }, { x: 2 }] }, undefined)
|
|
27
|
+
)
|
|
26
28
|
).toEqual([{ x: 1 }, { x: 2 }]);
|
|
27
29
|
});
|
|
28
30
|
|
|
29
31
|
test("InlineSource wraps scalars to objects", async () => {
|
|
30
|
-
expect(
|
|
31
|
-
{
|
|
32
|
-
|
|
33
|
-
]);
|
|
32
|
+
expect(
|
|
33
|
+
await collectSource(new InlineSource({ values: [1, 2] }, undefined))
|
|
34
|
+
).toEqual([{ data: 1 }, { data: 2 }]);
|
|
34
35
|
});
|
|
35
36
|
|
|
36
37
|
test("InlineSource parses a string", async () => {
|
|
37
38
|
expect(
|
|
38
39
|
await collectSource(
|
|
39
|
-
new InlineSource(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
new InlineSource(
|
|
41
|
+
{
|
|
42
|
+
values: "a\n1\n2\n3",
|
|
43
|
+
format: {
|
|
44
|
+
type: "csv",
|
|
45
|
+
},
|
|
43
46
|
},
|
|
44
|
-
|
|
47
|
+
undefined
|
|
48
|
+
)
|
|
45
49
|
)
|
|
46
50
|
).toEqual([{ a: 1 }, { a: 2 }, { a: 3 }]);
|
|
47
51
|
});
|
|
@@ -49,8 +53,11 @@ test("InlineSource parses a string", async () => {
|
|
|
49
53
|
test("InlineSource throws on a string and a missing format specifier", () => {
|
|
50
54
|
expect(
|
|
51
55
|
() =>
|
|
52
|
-
new InlineSource(
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
new InlineSource(
|
|
57
|
+
{
|
|
58
|
+
values: "a\n1\n2\n3",
|
|
59
|
+
},
|
|
60
|
+
undefined
|
|
61
|
+
)
|
|
55
62
|
).toThrow();
|
|
56
63
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sequenceSource.test.d.ts","sourceRoot":"","sources":["../../../../src/data/sources/sequenceSource.test.js"],"names":[],"mappings":""}
|