@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.
- package/dist/index.es.js +16373 -0
- package/dist/index.js +43 -43
- package/package.json +10 -7
- package/src/data/collector.js +0 -183
- package/src/data/collector.test.js +0 -84
- package/src/data/dataFlow.js +0 -148
- package/src/data/dataFlow.test.js +0 -5
- package/src/data/facetNode.js +0 -17
- package/src/data/flow.test.js +0 -72
- package/src/data/flowBatch.d.ts +0 -40
- package/src/data/flowNode.js +0 -283
- package/src/data/flowNode.test.js +0 -50
- package/src/data/flowOptimizer.js +0 -123
- package/src/data/flowOptimizer.test.js +0 -193
- package/src/data/flowTestUtils.js +0 -63
- package/src/data/formats/fasta.js +0 -32
- package/src/data/formats/fasta.test.js +0 -27
- package/src/data/sources/dataSource.js +0 -22
- package/src/data/sources/dataSourceFactory.js +0 -24
- package/src/data/sources/dataUtils.js +0 -78
- package/src/data/sources/dynamicCallbackSource.js +0 -57
- package/src/data/sources/dynamicSource.js +0 -37
- package/src/data/sources/inlineSource.js +0 -67
- package/src/data/sources/inlineSource.test.js +0 -56
- package/src/data/sources/namedSource.js +0 -79
- package/src/data/sources/sequenceSource.js +0 -46
- package/src/data/sources/sequenceSource.test.js +0 -46
- package/src/data/sources/urlSource.js +0 -74
- package/src/data/transforms/aggregate.js +0 -70
- package/src/data/transforms/clone.js +0 -40
- package/src/data/transforms/clone.test.js +0 -11
- package/src/data/transforms/coverage.js +0 -187
- package/src/data/transforms/coverage.test.js +0 -123
- package/src/data/transforms/filter.js +0 -37
- package/src/data/transforms/filter.test.js +0 -18
- package/src/data/transforms/filterScoredLabels.js +0 -134
- package/src/data/transforms/flattenCompressedExons.js +0 -57
- package/src/data/transforms/flattenDelimited.js +0 -74
- package/src/data/transforms/flattenDelimited.test.js +0 -87
- package/src/data/transforms/flattenSequence.js +0 -39
- package/src/data/transforms/flattenSequence.test.js +0 -34
- package/src/data/transforms/formula.js +0 -39
- package/src/data/transforms/formula.test.js +0 -19
- package/src/data/transforms/identifier.js +0 -108
- package/src/data/transforms/identifier.test.js +0 -83
- package/src/data/transforms/linearizeGenomicCoordinate.js +0 -101
- package/src/data/transforms/measureText.js +0 -44
- package/src/data/transforms/pileup.js +0 -128
- package/src/data/transforms/pileup.test.js +0 -70
- package/src/data/transforms/project.js +0 -41
- package/src/data/transforms/project.test.js +0 -32
- package/src/data/transforms/regexExtract.js +0 -61
- package/src/data/transforms/regexExtract.test.js +0 -67
- package/src/data/transforms/regexFold.js +0 -141
- package/src/data/transforms/regexFold.test.js +0 -160
- package/src/data/transforms/sample.js +0 -101
- package/src/data/transforms/sample.test.js +0 -38
- package/src/data/transforms/stack.js +0 -137
- package/src/data/transforms/stack.test.js +0 -91
- package/src/data/transforms/transformFactory.js +0 -60
- package/src/embedApi.d.ts +0 -67
- package/src/encoder/accessor.js +0 -82
- package/src/encoder/accessor.test.js +0 -47
- package/src/encoder/encoder.js +0 -394
- package/src/encoder/encoder.test.js +0 -98
- package/src/fonts/Lato-Regular.json +0 -1267
- package/src/fonts/Lato-Regular.png +0 -0
- package/src/fonts/OFL.txt +0 -93
- package/src/fonts/README.md +0 -3
- package/src/fonts/bmFont.d.ts +0 -58
- package/src/fonts/bmFontManager.js +0 -357
- package/src/fonts/bmFontMetrics.js +0 -108
- package/src/genome/genome.js +0 -317
- package/src/genome/genome.test.js +0 -188
- package/src/genome/genomeStore.js +0 -54
- package/src/genome/locusFormat.js +0 -31
- package/src/genome/scaleIndex.d.ts +0 -38
- package/src/genome/scaleIndex.js +0 -166
- package/src/genome/scaleIndex.test.js +0 -78
- package/src/genome/scaleLocus.d.ts +0 -11
- package/src/genome/scaleLocus.js +0 -108
- package/src/genome/scaleLocus.test.js +0 -4
- package/src/genomeSpy.js +0 -785
- package/src/gl/arrayBuilder.js +0 -199
- package/src/gl/dataToVertices.js +0 -636
- package/src/gl/includes/common.glsl +0 -63
- package/src/gl/includes/picking.fragment.glsl +0 -1
- package/src/gl/includes/picking.vertex.glsl +0 -27
- package/src/gl/includes/sampleFacet.glsl +0 -107
- package/src/gl/includes/scales.glsl +0 -112
- package/src/gl/link.fragment.glsl +0 -18
- package/src/gl/link.vertex.glsl +0 -111
- package/src/gl/point.fragment.glsl +0 -123
- package/src/gl/point.vertex.glsl +0 -129
- package/src/gl/rect.fragment.glsl +0 -51
- package/src/gl/rect.vertex.glsl +0 -114
- package/src/gl/rule.fragment.glsl +0 -52
- package/src/gl/rule.vertex.glsl +0 -89
- package/src/gl/text.fragment.glsl +0 -31
- package/src/gl/text.vertex.glsl +0 -246
- package/src/gl/webGLHelper.js +0 -504
- package/src/img/bowtie.svg +0 -1
- package/src/img/genomespy-favicon.svg +0 -34
- package/src/index.html +0 -11
- package/src/index.js +0 -128
- package/src/marks/link.js +0 -175
- package/src/marks/mark.js +0 -975
- package/src/marks/markUtils.js +0 -125
- package/src/marks/pointMark.js +0 -251
- package/src/marks/rectMark.js +0 -241
- package/src/marks/rule.js +0 -250
- package/src/marks/text.js +0 -278
- package/src/node_modules/.vitest/results.json +0 -1
- package/src/scale/colorUtils.js +0 -184
- package/src/scale/glslScaleGenerator.js +0 -502
- package/src/scale/scale.js +0 -451
- package/src/scale/scale.test.js +0 -324
- package/src/scale/ticks.js +0 -203
- package/src/scale/ticks.test.js +0 -40
- package/src/singlePageApp.js +0 -13
- package/src/spec/axis.d.ts +0 -296
- package/src/spec/channel.d.ts +0 -430
- package/src/spec/data.d.ts +0 -196
- package/src/spec/font.d.ts +0 -15
- package/src/spec/genome.d.ts +0 -35
- package/src/spec/mark.d.ts +0 -429
- package/src/spec/root.d.ts +0 -17
- package/src/spec/sampleView.d.ts +0 -180
- package/src/spec/scale.d.ts +0 -273
- package/src/spec/title.d.ts +0 -102
- package/src/spec/tooltip.d.ts +0 -9
- package/src/spec/transform.d.ts +0 -479
- package/src/spec/view.d.ts +0 -201
- package/src/styles/genome-spy.scss +0 -153
- package/src/tooltip/dataTooltipHandler.js +0 -64
- package/src/tooltip/refseqGeneTooltipHandler.js +0 -78
- package/src/tooltip/tooltipHandler.ts +0 -12
- package/src/types/filetypes.d.ts +0 -14
- package/src/types/flatqueue.d.ts +0 -53
- package/src/types/glsl.d.ts +0 -4
- package/src/types/internmap.d.ts +0 -22
- package/src/types/object.d.ts +0 -21
- package/src/types/vega-loader.d.ts +0 -1
- package/src/types/vega-scale.d.ts +0 -60
- package/src/utils/addBaseUrl.js +0 -19
- package/src/utils/addBaseUrl.test.js +0 -22
- package/src/utils/animator.js +0 -83
- package/src/utils/arrayUtils.js +0 -61
- package/src/utils/binnedIndex.js +0 -167
- package/src/utils/binnedIndex.test.js +0 -155
- package/src/utils/clamp.js +0 -8
- package/src/utils/cloner.js +0 -34
- package/src/utils/cloner.test.js +0 -24
- package/src/utils/coalesce.js +0 -11
- package/src/utils/coalesce.test.js +0 -16
- package/src/utils/concatIterables.js +0 -26
- package/src/utils/concatIterables.test.js +0 -8
- package/src/utils/debounce.js +0 -37
- package/src/utils/domainArray.js +0 -216
- package/src/utils/domainArray.test.js +0 -130
- package/src/utils/eerp.js +0 -13
- package/src/utils/expression.js +0 -32
- package/src/utils/field.js +0 -28
- package/src/utils/formatObject.js +0 -31
- package/src/utils/indexer.js +0 -43
- package/src/utils/indexer.test.js +0 -47
- package/src/utils/inertia.js +0 -124
- package/src/utils/interactionEvent.js +0 -33
- package/src/utils/iterateNestedMaps.js +0 -21
- package/src/utils/iterateNestedMaps.test.js +0 -33
- package/src/utils/kWayMerge.js +0 -42
- package/src/utils/kWayMerge.test.js +0 -26
- package/src/utils/layout/flexLayout.js +0 -368
- package/src/utils/layout/flexLayout.test.js +0 -311
- package/src/utils/layout/grid.js +0 -95
- package/src/utils/layout/grid.test.js +0 -71
- package/src/utils/layout/padding.js +0 -120
- package/src/utils/layout/point.js +0 -23
- package/src/utils/layout/rectangle.js +0 -288
- package/src/utils/layout/rectangle.test.js +0 -172
- package/src/utils/mergeObjects.js +0 -99
- package/src/utils/mergeObjects.test.js +0 -42
- package/src/utils/numberExtractor.js +0 -24
- package/src/utils/numberExtractor.test.js +0 -6
- package/src/utils/point.js +0 -14
- package/src/utils/propertyCacher.js +0 -70
- package/src/utils/propertyCacher.test.js +0 -85
- package/src/utils/propertyCoalescer.js +0 -42
- package/src/utils/propertyCoalescer.test.js +0 -22
- package/src/utils/reservationMap.js +0 -103
- package/src/utils/reservationMap.test.js +0 -20
- package/src/utils/scaleNull.js +0 -19
- package/src/utils/setOperations.js +0 -75
- package/src/utils/smoothstep.js +0 -10
- package/src/utils/throttle.js +0 -34
- package/src/utils/topK.js +0 -76
- package/src/utils/topK.test.js +0 -64
- package/src/utils/transition.js +0 -74
- package/src/utils/ui/tooltip.js +0 -189
- package/src/utils/url.js +0 -22
- package/src/utils/variableTools.js +0 -24
- package/src/utils/variableTools.test.js +0 -13
- package/src/view/axisResolution.js +0 -140
- package/src/view/axisResolution.test.js +0 -201
- package/src/view/axisView.js +0 -747
- package/src/view/concatView.js +0 -45
- package/src/view/containerView.js +0 -159
- package/src/view/facetView.js +0 -491
- package/src/view/flowBuilder.js +0 -367
- package/src/view/flowBuilder.test.js +0 -125
- package/src/view/gridView.js +0 -786
- package/src/view/implicitRootView.js +0 -14
- package/src/view/importView.js +0 -19
- package/src/view/layerView.js +0 -74
- package/src/view/rendering.d.ts +0 -44
- package/src/view/renderingContext/compositeViewRenderingContext.js +0 -51
- package/src/view/renderingContext/deferredViewRenderingContext.js +0 -176
- package/src/view/renderingContext/layoutRecorderViewRenderingContext.js +0 -128
- package/src/view/renderingContext/simpleViewRenderingContext.js +0 -64
- package/src/view/renderingContext/svgViewRenderingContext.js +0 -125
- package/src/view/renderingContext/viewRenderingContext.js +0 -41
- package/src/view/scaleResolution.js +0 -797
- package/src/view/scaleResolution.test.js +0 -572
- package/src/view/scaleResolutionApi.d.ts +0 -40
- package/src/view/testUtils.js +0 -51
- package/src/view/title.js +0 -165
- package/src/view/unitView.js +0 -382
- package/src/view/view.js +0 -612
- package/src/view/view.test.js +0 -214
- package/src/view/viewContext.d.ts +0 -62
- package/src/view/viewFactory.js +0 -181
- package/src/view/viewFactory.test.js +0 -17
- package/src/view/viewUtils.js +0 -327
- package/src/view/zoom.js +0 -89
package/src/view/flowBuilder.js
DELETED
|
@@ -1,367 +0,0 @@
|
|
|
1
|
-
import Collector from "../data/collector";
|
|
2
|
-
import createTransform from "../data/transforms/transformFactory";
|
|
3
|
-
import createDataSource from "../data/sources/dataSourceFactory";
|
|
4
|
-
import UnitView from "./unitView";
|
|
5
|
-
import { BEHAVIOR_MODIFIES } from "../data/flowNode";
|
|
6
|
-
import CloneTransform from "../data/transforms/clone";
|
|
7
|
-
import { isDynamicCallbackData } from "../data/sources/dynamicCallbackSource";
|
|
8
|
-
import DataFlow from "../data/dataFlow";
|
|
9
|
-
import DataSource from "../data/sources/dataSource";
|
|
10
|
-
import {
|
|
11
|
-
isChannelDefWithScale,
|
|
12
|
-
isChromPosDef,
|
|
13
|
-
isDatumDef,
|
|
14
|
-
isFieldDef,
|
|
15
|
-
isPositionalChannel,
|
|
16
|
-
getPrimaryChannel,
|
|
17
|
-
} from "../encoder/encoder";
|
|
18
|
-
import LinearizeGenomicCoordinate from "../data/transforms/linearizeGenomicCoordinate";
|
|
19
|
-
import { isAggregateSamplesSpec } from "./viewFactory";
|
|
20
|
-
import { group } from "d3-array";
|
|
21
|
-
import IdentifierTransform from "../data/transforms/identifier";
|
|
22
|
-
import { invalidate } from "../utils/propertyCacher";
|
|
23
|
-
import NamedSource, { isNamedData } from "../data/sources/namedSource";
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* @typedef {import("./view").default} View
|
|
27
|
-
* @typedef {import("../data/flowNode").default} FlowNode
|
|
28
|
-
* @typedef {import("../spec/channel").Channel} Channel
|
|
29
|
-
* @typedef {import("../spec/channel").Encoding} Encoding
|
|
30
|
-
*
|
|
31
|
-
* @param {View} root
|
|
32
|
-
* @param {DataFlow<View>} [existingFlow] Add data flow
|
|
33
|
-
* graphs to an existing DataFlow object.
|
|
34
|
-
*/
|
|
35
|
-
export function buildDataFlow(root, existingFlow) {
|
|
36
|
-
/** @type {FlowNode[]} "Current nodes" on the path from view root to the current view */
|
|
37
|
-
const nodeStack = [];
|
|
38
|
-
|
|
39
|
-
/** @type {FlowNode} */
|
|
40
|
-
let currentNode;
|
|
41
|
-
|
|
42
|
-
/** @type {DataFlow<View>} */
|
|
43
|
-
const dataFlow = existingFlow ?? new DataFlow();
|
|
44
|
-
|
|
45
|
-
/** @type {(function():void)[]} */
|
|
46
|
-
const postProcessOps = [];
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* @param {FlowNode} node
|
|
50
|
-
* @param {function():Error} [onMissingParent]
|
|
51
|
-
* @returns {FlowNode} The appended node
|
|
52
|
-
*/
|
|
53
|
-
function appendNode(node, onMissingParent = () => undefined) {
|
|
54
|
-
if (!currentNode) {
|
|
55
|
-
throw (
|
|
56
|
-
onMissingParent() ||
|
|
57
|
-
new Error("Cannot append data flow node, no parent exist!")
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
currentNode.addChild(node);
|
|
61
|
-
currentNode = node;
|
|
62
|
-
return node;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* @param {FlowNode} transform
|
|
67
|
-
* @param {any} [params]
|
|
68
|
-
* @returns {FlowNode} The appended node
|
|
69
|
-
*/
|
|
70
|
-
function appendTransform(transform, params) {
|
|
71
|
-
return appendNode(
|
|
72
|
-
transform,
|
|
73
|
-
() =>
|
|
74
|
-
new Error(
|
|
75
|
-
`Cannot append a transform because no (inherited) data are available! ${
|
|
76
|
-
params ? JSON.stringify(params) : ""
|
|
77
|
-
}`
|
|
78
|
-
)
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
*
|
|
84
|
-
* @param {import("../spec/transform").TransformParams[]} transforms
|
|
85
|
-
* @param {View} view
|
|
86
|
-
*/
|
|
87
|
-
function createTransforms(transforms, view) {
|
|
88
|
-
for (const params of transforms) {
|
|
89
|
-
/** @type {FlowNode} */
|
|
90
|
-
let transform;
|
|
91
|
-
try {
|
|
92
|
-
transform = createTransform(params, view);
|
|
93
|
-
} catch (e) {
|
|
94
|
-
console.warn(e);
|
|
95
|
-
throw new Error(
|
|
96
|
-
`Cannot initialize "${params.type}" transform: ${e}`
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (transform.behavior & BEHAVIOR_MODIFIES) {
|
|
101
|
-
// Make defensive copies before every modifying transform to
|
|
102
|
-
// ensure that modifications don't inadvertently become visible
|
|
103
|
-
// in other branches of the flow.
|
|
104
|
-
// These can be later optimized away where possible.
|
|
105
|
-
appendTransform(new CloneTransform());
|
|
106
|
-
}
|
|
107
|
-
appendTransform(transform);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/** @param {View} view */
|
|
112
|
-
const processView = (view) => {
|
|
113
|
-
nodeStack.push(currentNode);
|
|
114
|
-
|
|
115
|
-
if (view.spec.data) {
|
|
116
|
-
const dataSource = isDynamicCallbackData(view.spec.data)
|
|
117
|
-
? view.getDynamicDataSource()
|
|
118
|
-
: isNamedData(view.spec.data)
|
|
119
|
-
? // TODO: Only one NamedSource instance per unique name should exists
|
|
120
|
-
new NamedSource(
|
|
121
|
-
view.spec.data,
|
|
122
|
-
view.context.getNamedDataFromProvider
|
|
123
|
-
)
|
|
124
|
-
: createDataSource(view.spec.data, view.getBaseUrl());
|
|
125
|
-
|
|
126
|
-
currentNode = dataSource;
|
|
127
|
-
dataFlow.addDataSource(dataSource, view);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (view.spec.transform) {
|
|
131
|
-
createTransforms(view.spec.transform, view);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (view instanceof UnitView) {
|
|
135
|
-
if (!currentNode) {
|
|
136
|
-
throw new Error("A unit view has no (inherited) data source");
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Support chrom/pos channelDefs
|
|
140
|
-
const linearize = linearizeLocusAccess(view);
|
|
141
|
-
if (linearize) {
|
|
142
|
-
postProcessOps.push(linearize.rewrite);
|
|
143
|
-
for (const transform of linearize.transforms) {
|
|
144
|
-
// TODO: Transforms should not be added if they already exist in the flow.
|
|
145
|
-
// Alternatively they should be optimized away.
|
|
146
|
-
// TODO: Add CloneTransform
|
|
147
|
-
appendTransform(transform);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
if (view.mark.isPickingParticipant()) {
|
|
152
|
-
// TODO: Add CloneTransform
|
|
153
|
-
appendTransform(
|
|
154
|
-
new IdentifierTransform({ type: "identifier" })
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const collector = new Collector({
|
|
159
|
-
type: "collect",
|
|
160
|
-
groupby: view.getFacetFields(),
|
|
161
|
-
sort: getCompareParamsForView(
|
|
162
|
-
view,
|
|
163
|
-
linearize?.rewrittenEncoding
|
|
164
|
-
),
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
appendNode(collector);
|
|
168
|
-
dataFlow.addCollector(collector, view);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
if (isAggregateSamplesSpec(view.spec)) {
|
|
172
|
-
// TODO: implement summarization of layer views
|
|
173
|
-
}
|
|
174
|
-
};
|
|
175
|
-
|
|
176
|
-
/** @param {View} view */
|
|
177
|
-
processView.postOrder = (view) => {
|
|
178
|
-
currentNode = nodeStack.pop();
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
root.visit(processView);
|
|
182
|
-
|
|
183
|
-
postProcessOps.forEach((op) => op());
|
|
184
|
-
|
|
185
|
-
return dataFlow;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Changes the ChromPos channelDefs into FieldDefs and returns
|
|
190
|
-
* LinearizeGenomicCoordinate transform(s) that should be inserted into
|
|
191
|
-
* the data flow.
|
|
192
|
-
*
|
|
193
|
-
* @param {View} view
|
|
194
|
-
*/
|
|
195
|
-
export function linearizeLocusAccess(view) {
|
|
196
|
-
/** @type {FlowNode[]} */
|
|
197
|
-
const transforms = [];
|
|
198
|
-
|
|
199
|
-
/** @type {Encoding} */
|
|
200
|
-
const rewrittenEncoding = {};
|
|
201
|
-
|
|
202
|
-
/** @type {{ channel: Channel, chromPosDef: import("../spec/channel").ChromPosDef}[]} */
|
|
203
|
-
const channelsAndChromPosDefs = [];
|
|
204
|
-
|
|
205
|
-
// Optimize the number of transforms. Use only a single transform for positions
|
|
206
|
-
// that share the chromosome field and channel.
|
|
207
|
-
for (const [c, channelDef] of Object.entries(view.getEncoding())) {
|
|
208
|
-
const channel = /** @type {Channel} */ (c);
|
|
209
|
-
if (isPositionalChannel(channel) && isChromPosDef(channelDef)) {
|
|
210
|
-
channelsAndChromPosDefs.push({ channel, chromPosDef: channelDef });
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// Nngh. group uses InternMap but doesn't have a way to define an interning function.
|
|
215
|
-
// Have to use multi-level grouping.
|
|
216
|
-
const grouped = group(
|
|
217
|
-
channelsAndChromPosDefs,
|
|
218
|
-
(d) => /** @type {"x" | "y"} */ (getPrimaryChannel(d.channel)),
|
|
219
|
-
(d) => d.chromPosDef.chrom
|
|
220
|
-
);
|
|
221
|
-
|
|
222
|
-
for (const [primaryChan, chromAndStuff] of grouped.entries()) {
|
|
223
|
-
for (const [chrom, chanChromPos] of chromAndStuff.entries()) {
|
|
224
|
-
/** @type {string[]} */
|
|
225
|
-
const pos = [];
|
|
226
|
-
/** @type {string[]} */
|
|
227
|
-
const as = [];
|
|
228
|
-
/** @type {number[]} */
|
|
229
|
-
const offset = [];
|
|
230
|
-
|
|
231
|
-
for (const { channel, chromPosDef } of chanChromPos) {
|
|
232
|
-
/** @param {string} str */
|
|
233
|
-
const strip = (str) => str.replace(/[^A-Za-z0-9_]/g, "");
|
|
234
|
-
const linearizedField = [
|
|
235
|
-
"_linearized_",
|
|
236
|
-
strip(chromPosDef.chrom),
|
|
237
|
-
"_",
|
|
238
|
-
strip(chromPosDef.pos),
|
|
239
|
-
].join("");
|
|
240
|
-
|
|
241
|
-
// Prefer using the spec directly because getEncoding() returns inherited props too.
|
|
242
|
-
// TODO: I think this is not robust enough. Needs more work...
|
|
243
|
-
/** @type {any} */
|
|
244
|
-
const newFieldDef = {
|
|
245
|
-
...(view.spec.encoding?.[channel] ??
|
|
246
|
-
view.getEncoding()[channel] ??
|
|
247
|
-
{}),
|
|
248
|
-
field: linearizedField,
|
|
249
|
-
};
|
|
250
|
-
delete newFieldDef.chrom;
|
|
251
|
-
delete newFieldDef.pos;
|
|
252
|
-
if (!newFieldDef.type && chromPosDef.type) {
|
|
253
|
-
newFieldDef.type = chromPosDef.type;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
rewrittenEncoding[channel] = newFieldDef;
|
|
257
|
-
|
|
258
|
-
pos.push(chromPosDef.pos);
|
|
259
|
-
offset.push(chromPosDef.offset ?? 0);
|
|
260
|
-
as.push(linearizedField);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
transforms.push(
|
|
264
|
-
new LinearizeGenomicCoordinate(
|
|
265
|
-
{
|
|
266
|
-
type: "linearizeGenomicCoordinate",
|
|
267
|
-
channel: primaryChan,
|
|
268
|
-
chrom: chrom,
|
|
269
|
-
pos,
|
|
270
|
-
offset,
|
|
271
|
-
as,
|
|
272
|
-
},
|
|
273
|
-
view
|
|
274
|
-
)
|
|
275
|
-
);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
return transforms.length
|
|
280
|
-
? {
|
|
281
|
-
transforms,
|
|
282
|
-
rewrittenEncoding,
|
|
283
|
-
/**
|
|
284
|
-
* Should be called after the whole flow has been created in order to
|
|
285
|
-
* not disrupt inheritance of encodings
|
|
286
|
-
*/
|
|
287
|
-
rewrite: () => {
|
|
288
|
-
view.spec.encoding = {
|
|
289
|
-
...view.spec.encoding,
|
|
290
|
-
...rewrittenEncoding,
|
|
291
|
-
};
|
|
292
|
-
// This is so ugly...
|
|
293
|
-
// @ts-ignore
|
|
294
|
-
invalidate(view.mark, "encoding");
|
|
295
|
-
},
|
|
296
|
-
}
|
|
297
|
-
: undefined;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* @param {View} view
|
|
302
|
-
* @param {Encoding} [encoding]
|
|
303
|
-
* @returns {import("../spec/transform").CompareParams}
|
|
304
|
-
*/
|
|
305
|
-
function getCompareParamsForView(view, encoding) {
|
|
306
|
-
// TODO: Should sort by min(x, x2).
|
|
307
|
-
const e = { ...view.getEncoding(), ...encoding }.x;
|
|
308
|
-
if (isChannelDefWithScale(e)) {
|
|
309
|
-
if (view.getScaleResolution("x")?.isZoomable()) {
|
|
310
|
-
if (isFieldDef(e)) {
|
|
311
|
-
return { field: e.field };
|
|
312
|
-
} else if (isDatumDef(e)) {
|
|
313
|
-
// Nop
|
|
314
|
-
} else {
|
|
315
|
-
// TODO: Support expr by inserting a Formula transform
|
|
316
|
-
throw new Error(
|
|
317
|
-
"A zoomable x channel must be mapped to a field."
|
|
318
|
-
);
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
* A helper function for creating linear data flows programmatically.
|
|
326
|
-
*
|
|
327
|
-
* @param {H} dataSource A data source or any other initial FlowNode.
|
|
328
|
-
* @param {...FlowNode} transforms
|
|
329
|
-
* @template {FlowNode} H
|
|
330
|
-
*/
|
|
331
|
-
export function createChain(dataSource, ...transforms) {
|
|
332
|
-
/** @type {FlowNode} */
|
|
333
|
-
let node = dataSource;
|
|
334
|
-
for (const transform of transforms) {
|
|
335
|
-
node.addChild(transform);
|
|
336
|
-
node = transform;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
/** @type {Collector} */
|
|
340
|
-
let collector;
|
|
341
|
-
|
|
342
|
-
if (node instanceof Collector) {
|
|
343
|
-
collector = node;
|
|
344
|
-
} else {
|
|
345
|
-
collector = new Collector();
|
|
346
|
-
node.addChild(collector);
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
/** @type {function():Promise<Iterable<import("../data/flowNode").Datum>>} */
|
|
350
|
-
let loadAndCollect;
|
|
351
|
-
if (dataSource instanceof DataSource) {
|
|
352
|
-
loadAndCollect = async () => {
|
|
353
|
-
await dataSource.load();
|
|
354
|
-
return collector.getData();
|
|
355
|
-
};
|
|
356
|
-
} else {
|
|
357
|
-
loadAndCollect = async () => {
|
|
358
|
-
throw new Error("The root node is not derived from DataSource!");
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
return {
|
|
363
|
-
dataSource,
|
|
364
|
-
collector,
|
|
365
|
-
loadAndCollect,
|
|
366
|
-
};
|
|
367
|
-
}
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "vitest";
|
|
2
|
-
import Collector from "../data/collector";
|
|
3
|
-
import FlowNode from "../data/flowNode";
|
|
4
|
-
import FilterTransform from "../data/transforms/filter";
|
|
5
|
-
import FormulaTransform from "../data/transforms/formula";
|
|
6
|
-
import InlineSource from "../data/sources/inlineSource";
|
|
7
|
-
import SequenceSource from "../data/sources/sequenceSource";
|
|
8
|
-
import { buildDataFlow } from "./flowBuilder";
|
|
9
|
-
import { create } from "./testUtils";
|
|
10
|
-
import CloneTransform from "../data/transforms/clone";
|
|
11
|
-
import LayerView from "./layerView";
|
|
12
|
-
import UnitView from "./unitView";
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
*
|
|
16
|
-
* @param {FlowNode} root
|
|
17
|
-
* @param {number[]} path
|
|
18
|
-
*/
|
|
19
|
-
function byPath(root, path) {
|
|
20
|
-
for (const elem of path) {
|
|
21
|
-
root = root.children[elem];
|
|
22
|
-
}
|
|
23
|
-
return root;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/** @type {import("../spec/mark").MarkConfigAndType} */
|
|
27
|
-
const mark = {
|
|
28
|
-
type: "rect",
|
|
29
|
-
tooltip: null,
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
test("Trivial flow", () => {
|
|
33
|
-
const root = create(
|
|
34
|
-
{
|
|
35
|
-
data: { values: [3.141] },
|
|
36
|
-
transform: [
|
|
37
|
-
{
|
|
38
|
-
type: "formula",
|
|
39
|
-
expr: "datum.data * 2",
|
|
40
|
-
as: "x",
|
|
41
|
-
},
|
|
42
|
-
],
|
|
43
|
-
mark,
|
|
44
|
-
},
|
|
45
|
-
UnitView
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
const flow = buildDataFlow(root);
|
|
49
|
-
const dataSource = flow.dataSources[0];
|
|
50
|
-
|
|
51
|
-
expect(dataSource).toBeInstanceOf(InlineSource);
|
|
52
|
-
expect(byPath(dataSource, [0])).toBeInstanceOf(CloneTransform);
|
|
53
|
-
expect(byPath(dataSource, [0, 0])).toBeInstanceOf(FormulaTransform);
|
|
54
|
-
expect(byPath(dataSource, [0, 0, 0])).toBeInstanceOf(Collector);
|
|
55
|
-
|
|
56
|
-
expect(flow.collectors[0]).toBe(byPath(dataSource, [0, 0, 0]));
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
test("Branching flow", () => {
|
|
60
|
-
const root = create(
|
|
61
|
-
{
|
|
62
|
-
data: { values: [3.141] },
|
|
63
|
-
layer: [
|
|
64
|
-
{
|
|
65
|
-
transform: [
|
|
66
|
-
{
|
|
67
|
-
type: "formula",
|
|
68
|
-
expr: "datum.data * 2",
|
|
69
|
-
as: "x",
|
|
70
|
-
},
|
|
71
|
-
],
|
|
72
|
-
mark,
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
transform: [
|
|
76
|
-
{
|
|
77
|
-
type: "filter",
|
|
78
|
-
expr: "datum.data > 4",
|
|
79
|
-
},
|
|
80
|
-
],
|
|
81
|
-
mark,
|
|
82
|
-
},
|
|
83
|
-
],
|
|
84
|
-
},
|
|
85
|
-
LayerView
|
|
86
|
-
);
|
|
87
|
-
|
|
88
|
-
const dataSource = buildDataFlow(root).dataSources[0];
|
|
89
|
-
|
|
90
|
-
expect(dataSource).toBeInstanceOf(InlineSource);
|
|
91
|
-
// Formula transform modifies data and it should be implicitly preceded by CloneTransform
|
|
92
|
-
expect(byPath(dataSource, [0])).toBeInstanceOf(CloneTransform);
|
|
93
|
-
expect(byPath(dataSource, [0, 0])).toBeInstanceOf(FormulaTransform);
|
|
94
|
-
expect(byPath(dataSource, [0, 0, 0])).toBeInstanceOf(Collector);
|
|
95
|
-
expect(byPath(dataSource, [1])).toBeInstanceOf(FilterTransform);
|
|
96
|
-
expect(byPath(dataSource, [1, 0])).toBeInstanceOf(Collector);
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
test("Nested data sources", () => {
|
|
100
|
-
const root = create(
|
|
101
|
-
{
|
|
102
|
-
data: { values: [1] },
|
|
103
|
-
transform: [{ type: "filter", expr: "datum.data > 0" }],
|
|
104
|
-
layer: [
|
|
105
|
-
{
|
|
106
|
-
data: { sequence: { start: 0, stop: 5 } },
|
|
107
|
-
transform: [{ type: "formula", expr: "3", as: "foo" }],
|
|
108
|
-
mark,
|
|
109
|
-
},
|
|
110
|
-
],
|
|
111
|
-
},
|
|
112
|
-
LayerView
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
const dataSources = buildDataFlow(root).dataSources;
|
|
116
|
-
|
|
117
|
-
expect(dataSources[0]).toBeInstanceOf(InlineSource);
|
|
118
|
-
expect(dataSources[0].children[0]).toBeInstanceOf(FilterTransform);
|
|
119
|
-
expect(dataSources[0].children[0].children.length).toEqual(0);
|
|
120
|
-
|
|
121
|
-
expect(byPath(dataSources[1], [])).toBeInstanceOf(SequenceSource);
|
|
122
|
-
expect(byPath(dataSources[1], [0])).toBeInstanceOf(CloneTransform);
|
|
123
|
-
expect(byPath(dataSources[1], [0, 0])).toBeInstanceOf(FormulaTransform);
|
|
124
|
-
expect(byPath(dataSources[1], [0, 0, 0])).toBeInstanceOf(Collector);
|
|
125
|
-
});
|