@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
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { asArray } from "../../utils/arrayUtils";
|
|
2
|
-
import { field } from "../../utils/field";
|
|
3
|
-
import FlowNode, { BEHAVIOR_CLONES } from "../flowNode";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @typedef {import("../../spec/transform").FlattenDelimitedParams} FlattenDelimitedParams
|
|
7
|
-
* @prop {string[]} separators
|
|
8
|
-
* @prop {string[]} fields
|
|
9
|
-
* @prop {string[]} [as]
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
export default class FlattenDelimitedTransform extends FlowNode {
|
|
13
|
-
get behavior() {
|
|
14
|
-
return BEHAVIOR_CLONES;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
*
|
|
19
|
-
* @param {FlattenDelimitedParams} params
|
|
20
|
-
*/
|
|
21
|
-
constructor(params) {
|
|
22
|
-
super();
|
|
23
|
-
|
|
24
|
-
// TODO: Validate config. string elements, etc...
|
|
25
|
-
|
|
26
|
-
const accessors = asArray(params.field).map((f) => field(f));
|
|
27
|
-
const separators = asArray(params.separator);
|
|
28
|
-
const as = asArray(params.as || params.field);
|
|
29
|
-
|
|
30
|
-
if (
|
|
31
|
-
accessors.length !== separators.length ||
|
|
32
|
-
accessors.length !== as.length
|
|
33
|
-
) {
|
|
34
|
-
throw new Error(
|
|
35
|
-
`Lengths of "separator" (${separators.length}), "fields" (${accessors.length}), and "as" (${as.length}) do not match!`
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/** @param {any[]} datum */
|
|
40
|
-
this.handle = (datum) => {
|
|
41
|
-
if (accessors.some((a) => !a(datum))) return;
|
|
42
|
-
|
|
43
|
-
const splitFields = accessors.map((accessor, i) =>
|
|
44
|
-
accessor(datum).split(separators[i])
|
|
45
|
-
);
|
|
46
|
-
validateSplit(splitFields, datum);
|
|
47
|
-
const flatLen = splitFields[0].length;
|
|
48
|
-
|
|
49
|
-
for (let ri = 0; ri < flatLen; ri++) {
|
|
50
|
-
/** @type {import("../flowNode").Datum} */
|
|
51
|
-
const newRow = Object.assign({}, datum);
|
|
52
|
-
for (let fi = 0; fi < accessors.length; fi++) {
|
|
53
|
-
newRow[as[fi]] = splitFields[fi][ri];
|
|
54
|
-
}
|
|
55
|
-
this._propagate(newRow);
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
*
|
|
63
|
-
* @param {any[]} splitFields
|
|
64
|
-
* @param {unknown} row
|
|
65
|
-
*/
|
|
66
|
-
function validateSplit(splitFields, row) {
|
|
67
|
-
const splitLengths = splitFields.map((f) => f.length);
|
|
68
|
-
if (!splitLengths.every((x) => x == splitLengths[0])) {
|
|
69
|
-
throw new Error(
|
|
70
|
-
"Mismatching number of elements in the fields to be split: " +
|
|
71
|
-
JSON.stringify(row)
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from "vitest";
|
|
2
|
-
import { processData } from "../flowTestUtils";
|
|
3
|
-
import FlattenDelimitedTransform from "./flattenDelimited";
|
|
4
|
-
|
|
5
|
-
const sampleData = [
|
|
6
|
-
{ id: 1, a: "q, w, e", b: "a-s-d" },
|
|
7
|
-
{ id: 2, a: "r, t, y", b: "f-g-h" },
|
|
8
|
-
{ id: 3, a: "u", b: "j" },
|
|
9
|
-
];
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* @param {import("./flattenDelimited").FlattenDelimitedParams} params
|
|
13
|
-
* @param {any[]} data
|
|
14
|
-
*/
|
|
15
|
-
function transform(params, data) {
|
|
16
|
-
return processData(new FlattenDelimitedTransform(params), data);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
describe("FlattenDelimited transform", () => {
|
|
20
|
-
test("With a single field", () => {
|
|
21
|
-
/** @type {import("./flattenDelimited").FlattenDelimitedParams} */
|
|
22
|
-
const config = {
|
|
23
|
-
type: "flattenDelimited",
|
|
24
|
-
field: "a",
|
|
25
|
-
separator: ", ",
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
expect(transform(config, sampleData)).toEqual([
|
|
29
|
-
{ id: 1, a: "q", b: "a-s-d" },
|
|
30
|
-
{ id: 1, a: "w", b: "a-s-d" },
|
|
31
|
-
{ id: 1, a: "e", b: "a-s-d" },
|
|
32
|
-
{ id: 2, a: "r", b: "f-g-h" },
|
|
33
|
-
{ id: 2, a: "t", b: "f-g-h" },
|
|
34
|
-
{ id: 2, a: "y", b: "f-g-h" },
|
|
35
|
-
{ id: 3, a: "u", b: "j" },
|
|
36
|
-
]);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
test("With two fields", () => {
|
|
40
|
-
/** @type {import("./flattenDelimited").FlattenDelimitedParams} */
|
|
41
|
-
const config = {
|
|
42
|
-
type: "flattenDelimited",
|
|
43
|
-
field: ["a", "b"],
|
|
44
|
-
as: ["a", "c"],
|
|
45
|
-
separator: [", ", "-"],
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
expect(transform(config, sampleData)).toEqual([
|
|
49
|
-
{ id: 1, a: "q", b: "a-s-d", c: "a" },
|
|
50
|
-
{ id: 1, a: "w", b: "a-s-d", c: "s" },
|
|
51
|
-
{ id: 1, a: "e", b: "a-s-d", c: "d" },
|
|
52
|
-
{ id: 2, a: "r", b: "f-g-h", c: "f" },
|
|
53
|
-
{ id: 2, a: "t", b: "f-g-h", c: "g" },
|
|
54
|
-
{ id: 2, a: "y", b: "f-g-h", c: "h" },
|
|
55
|
-
{ id: 3, a: "u", b: "j", c: "j" },
|
|
56
|
-
]);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
test("Throws on differing field lengths", () => {
|
|
60
|
-
const data = [
|
|
61
|
-
{
|
|
62
|
-
a: "1-2",
|
|
63
|
-
b: "1-2-3",
|
|
64
|
-
},
|
|
65
|
-
];
|
|
66
|
-
|
|
67
|
-
/** @type {import("./flattenDelimited").FlattenDelimitedParams} */
|
|
68
|
-
const config = {
|
|
69
|
-
type: "flattenDelimited",
|
|
70
|
-
field: ["a", "b"],
|
|
71
|
-
separator: ["-", "-"],
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
expect(() => transform(config, data)).toThrow();
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
test("Throws on mismatching spec lengths", () => {
|
|
78
|
-
/** @type {import("./flattenDelimited").FlattenDelimitedParams} */
|
|
79
|
-
const config = {
|
|
80
|
-
type: "flattenDelimited",
|
|
81
|
-
field: ["a", "b"],
|
|
82
|
-
separator: ["a"],
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
expect(() => transform(config, sampleData)).toThrow();
|
|
86
|
-
});
|
|
87
|
-
});
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { field } from "../../utils/field";
|
|
2
|
-
import FlowNode, { BEHAVIOR_CLONES } from "../flowNode";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @typedef {import("../../spec/transform").FlattenSequenceParams} FlattenSequenceParams
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export default class FlattenSequenceTransform extends FlowNode {
|
|
9
|
-
get behavior() {
|
|
10
|
-
return BEHAVIOR_CLONES;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
*
|
|
15
|
-
* @param {FlattenSequenceParams} params
|
|
16
|
-
*/
|
|
17
|
-
constructor(params) {
|
|
18
|
-
super();
|
|
19
|
-
|
|
20
|
-
const accessor = field(params.field ?? "sequence");
|
|
21
|
-
const [asPos, asSequence] = params.as ?? ["pos", "sequence"];
|
|
22
|
-
|
|
23
|
-
/** @param {any[]} datum */
|
|
24
|
-
this.handle = (datum) => {
|
|
25
|
-
// TODO: Use code generation
|
|
26
|
-
const template = Object.assign({}, datum, {
|
|
27
|
-
[asSequence]: "",
|
|
28
|
-
[asPos]: 0,
|
|
29
|
-
});
|
|
30
|
-
const sequence = /** @type {string} */ (accessor(datum));
|
|
31
|
-
for (let i = 0; i < sequence.length; i++) {
|
|
32
|
-
const newObject = Object.assign({}, template);
|
|
33
|
-
newObject[asPos] = i;
|
|
34
|
-
newObject[asSequence] = sequence.charAt(i);
|
|
35
|
-
this._propagate(newObject);
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "vitest";
|
|
2
|
-
import { processData } from "../flowTestUtils";
|
|
3
|
-
import FlattenSequenceTransform from "./flattenSequence";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @param {import("./flattenSequence").FlattenSequenceParams} params
|
|
7
|
-
* @param {any[]} data
|
|
8
|
-
*/
|
|
9
|
-
function transform(params, data) {
|
|
10
|
-
return processData(new FlattenSequenceTransform(params), data);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
test("FlattenSequenece", () => {
|
|
14
|
-
expect(
|
|
15
|
-
transform(
|
|
16
|
-
{
|
|
17
|
-
type: "flattenSequence",
|
|
18
|
-
field: "seq",
|
|
19
|
-
as: ["p", "seq"],
|
|
20
|
-
},
|
|
21
|
-
[
|
|
22
|
-
{ identifier: "A", seq: "TCG" },
|
|
23
|
-
{ identifier: "B", seq: "AAT" },
|
|
24
|
-
]
|
|
25
|
-
)
|
|
26
|
-
).toEqual([
|
|
27
|
-
{ identifier: "A", seq: "T", p: 0 },
|
|
28
|
-
{ identifier: "A", seq: "C", p: 1 },
|
|
29
|
-
{ identifier: "A", seq: "G", p: 2 },
|
|
30
|
-
{ identifier: "B", seq: "A", p: 0 },
|
|
31
|
-
{ identifier: "B", seq: "A", p: 1 },
|
|
32
|
-
{ identifier: "B", seq: "T", p: 2 },
|
|
33
|
-
]);
|
|
34
|
-
});
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import createFunction from "../../utils/expression";
|
|
2
|
-
import FlowNode, { BEHAVIOR_MODIFIES } from "../flowNode";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @typedef {import("../../spec/transform").FormulaParams} FormulaParams
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export default class FormulaTransform extends FlowNode {
|
|
9
|
-
get behavior() {
|
|
10
|
-
return BEHAVIOR_MODIFIES;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
*
|
|
15
|
-
* @param {FormulaParams} params
|
|
16
|
-
*/
|
|
17
|
-
constructor(params) {
|
|
18
|
-
super();
|
|
19
|
-
this.params = params;
|
|
20
|
-
|
|
21
|
-
this.as = params.as;
|
|
22
|
-
|
|
23
|
-
/** @type {(datum: any) => any} */
|
|
24
|
-
this.fn = undefined;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
initialize() {
|
|
28
|
-
this.fn = createFunction(this.params.expr, this.getGlobalObject());
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
*
|
|
33
|
-
* @param {import("../flowNode").Datum} datum
|
|
34
|
-
*/
|
|
35
|
-
handle(datum) {
|
|
36
|
-
datum[this.as] = this.fn(datum);
|
|
37
|
-
this._propagate(datum);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "vitest";
|
|
2
|
-
import { processData } from "../flowTestUtils";
|
|
3
|
-
import FormulaTransform from "./formula";
|
|
4
|
-
|
|
5
|
-
test("FormulaTransform", () => {
|
|
6
|
-
const data = [{ a: 2 }, { a: 3 }];
|
|
7
|
-
|
|
8
|
-
const t = new FormulaTransform({
|
|
9
|
-
type: "formula",
|
|
10
|
-
expr: "datum.a * 2",
|
|
11
|
-
as: "b",
|
|
12
|
-
});
|
|
13
|
-
t.initialize();
|
|
14
|
-
|
|
15
|
-
expect(processData(t, data)).toEqual([
|
|
16
|
-
{ a: 2, b: 4 },
|
|
17
|
-
{ a: 3, b: 6 },
|
|
18
|
-
]);
|
|
19
|
-
});
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import FlowNode, { BEHAVIOR_MODIFIES } from "../flowNode";
|
|
2
|
-
|
|
3
|
-
export const DEFAULT_AS = "_uniqueId";
|
|
4
|
-
|
|
5
|
-
export const BLOCK_SIZE = 10000;
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* TODO: The reservation map should be bound to GenomeSpy instances.
|
|
9
|
-
* Because it's now global, there's a higher risk that we run out of ids.
|
|
10
|
-
*
|
|
11
|
-
* TODO: Identifier transforms should be removed from the reservation map
|
|
12
|
-
* when a transform is removed from the flow.
|
|
13
|
-
*
|
|
14
|
-
* The first block is reserved for "none".
|
|
15
|
-
*
|
|
16
|
-
* @type {IdentifierTransform[]}
|
|
17
|
-
*/
|
|
18
|
-
const reservationMap = [null];
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Assigns unique identifiers for tuples that pass through this transform.
|
|
22
|
-
*
|
|
23
|
-
* The identifiers are reserved in equally sized blocks, allowing for
|
|
24
|
-
* quick lookup of the IdentifierTransform instance that assigned the id.
|
|
25
|
-
* This is mainly used for creating ids that can be used for picking, i.e.,
|
|
26
|
-
* selecting rendered data items by hovering or clicking.
|
|
27
|
-
*
|
|
28
|
-
* @typedef {import("../../spec/transform").IdentifierParams} IdentifierParams
|
|
29
|
-
*/
|
|
30
|
-
export default class IdentifierTransform extends FlowNode {
|
|
31
|
-
get behavior() {
|
|
32
|
-
return BEHAVIOR_MODIFIES;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
*
|
|
37
|
-
* @param {IdentifierParams} params
|
|
38
|
-
*/
|
|
39
|
-
constructor(params) {
|
|
40
|
-
super();
|
|
41
|
-
this.params = params;
|
|
42
|
-
|
|
43
|
-
this.as = params.as ?? DEFAULT_AS;
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* The block indexes reserved by this transform instance.
|
|
47
|
-
* @type {number[]}
|
|
48
|
-
*/
|
|
49
|
-
this._blocks = [];
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* The number of blocks used
|
|
53
|
-
*/
|
|
54
|
-
this._usedBlocks = 0;
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* The next advancement allocates the initial block for this instance
|
|
58
|
-
*/
|
|
59
|
-
this._id = -1;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
initialize() {
|
|
63
|
-
//
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
reset() {
|
|
67
|
-
super.reset();
|
|
68
|
-
|
|
69
|
-
this._usedBlocks = 0;
|
|
70
|
-
this._id = -1;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
*
|
|
75
|
-
* @param {import("../flowNode").Datum} datum
|
|
76
|
-
*/
|
|
77
|
-
handle(datum) {
|
|
78
|
-
datum[this.as] = this._nextId();
|
|
79
|
-
this._propagate(datum);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* @returns {number}
|
|
84
|
-
*/
|
|
85
|
-
_nextId() {
|
|
86
|
-
if (++this._id % BLOCK_SIZE == 0) {
|
|
87
|
-
this._id = this._getBlock() * BLOCK_SIZE;
|
|
88
|
-
}
|
|
89
|
-
return this._id;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
_getBlock() {
|
|
93
|
-
if (this._usedBlocks < this._blocks.length) {
|
|
94
|
-
return this._blocks[this._usedBlocks++];
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return this._reserveBlock();
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
_reserveBlock() {
|
|
101
|
-
const blockId = reservationMap.length;
|
|
102
|
-
reservationMap[blockId] = this;
|
|
103
|
-
this._blocks.push(blockId);
|
|
104
|
-
this._usedBlocks++;
|
|
105
|
-
|
|
106
|
-
return blockId;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "vitest";
|
|
2
|
-
import { range } from "d3-array";
|
|
3
|
-
import { processData } from "../flowTestUtils";
|
|
4
|
-
import IdentifierTransform, { BLOCK_SIZE, DEFAULT_AS } from "./identifier";
|
|
5
|
-
|
|
6
|
-
test("An IdentifierTransform adds identifiers correctly", () => {
|
|
7
|
-
const data = range(BLOCK_SIZE * 2).map((x) => ({ data: x }));
|
|
8
|
-
|
|
9
|
-
const identifiedData = processData(
|
|
10
|
-
new IdentifierTransform({ type: "identifier" }),
|
|
11
|
-
data
|
|
12
|
-
);
|
|
13
|
-
|
|
14
|
-
// The fist block is skipped
|
|
15
|
-
const firstId = BLOCK_SIZE;
|
|
16
|
-
|
|
17
|
-
expect(identifiedData[0]).toEqual({ data: 0, [DEFAULT_AS]: firstId });
|
|
18
|
-
expect(identifiedData[1]).toEqual({ data: 1, [DEFAULT_AS]: firstId + 1 });
|
|
19
|
-
expect(identifiedData[BLOCK_SIZE]).toEqual({
|
|
20
|
-
data: BLOCK_SIZE,
|
|
21
|
-
[DEFAULT_AS]: firstId + BLOCK_SIZE,
|
|
22
|
-
});
|
|
23
|
-
expect(identifiedData[BLOCK_SIZE + 1]).toEqual({
|
|
24
|
-
data: BLOCK_SIZE + 1,
|
|
25
|
-
[DEFAULT_AS]: firstId + BLOCK_SIZE + 1,
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
test("Another transform instance adds identifiers correctly", () => {
|
|
30
|
-
const data = range(BLOCK_SIZE * 2).map((x) => ({ data: x }));
|
|
31
|
-
// Another instance
|
|
32
|
-
const identifiedData = processData(
|
|
33
|
-
new IdentifierTransform({ type: "identifier" }),
|
|
34
|
-
data
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
// The fist block was skipped and the previous test case consumed two blocks
|
|
38
|
-
const firstId = BLOCK_SIZE * 3;
|
|
39
|
-
|
|
40
|
-
expect(identifiedData[0]).toEqual({ data: 0, [DEFAULT_AS]: firstId });
|
|
41
|
-
expect(identifiedData[1]).toEqual({ data: 1, [DEFAULT_AS]: firstId + 1 });
|
|
42
|
-
expect(identifiedData[BLOCK_SIZE]).toEqual({
|
|
43
|
-
data: BLOCK_SIZE,
|
|
44
|
-
[DEFAULT_AS]: firstId + BLOCK_SIZE,
|
|
45
|
-
});
|
|
46
|
-
expect(identifiedData[BLOCK_SIZE + 1]).toEqual({
|
|
47
|
-
data: BLOCK_SIZE + 1,
|
|
48
|
-
[DEFAULT_AS]: firstId + BLOCK_SIZE + 1,
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test("IdentifierTransform recycles allocated blocks", () => {
|
|
53
|
-
let data = range(BLOCK_SIZE * 2).map((x) => ({ data: x }));
|
|
54
|
-
|
|
55
|
-
const transform = new IdentifierTransform({ type: "identifier" });
|
|
56
|
-
let identifiedData = processData(transform, data);
|
|
57
|
-
|
|
58
|
-
let firstId = BLOCK_SIZE * 5;
|
|
59
|
-
|
|
60
|
-
expect(identifiedData[0]).toEqual({ data: 0, [DEFAULT_AS]: firstId });
|
|
61
|
-
expect(identifiedData[BLOCK_SIZE]).toEqual({
|
|
62
|
-
data: BLOCK_SIZE,
|
|
63
|
-
[DEFAULT_AS]: firstId + BLOCK_SIZE,
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
data = range(BLOCK_SIZE * 3).map((x) => ({ data: x }));
|
|
67
|
-
|
|
68
|
-
// Resetting the transform. It should now reuse the allocated blocks.
|
|
69
|
-
transform.reset();
|
|
70
|
-
identifiedData = processData(transform, data);
|
|
71
|
-
|
|
72
|
-
expect(identifiedData[0]).toEqual({ data: 0, [DEFAULT_AS]: firstId });
|
|
73
|
-
expect(identifiedData[BLOCK_SIZE]).toEqual({
|
|
74
|
-
data: BLOCK_SIZE,
|
|
75
|
-
[DEFAULT_AS]: firstId + BLOCK_SIZE,
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
// ... and reserve one extra
|
|
79
|
-
expect(identifiedData[BLOCK_SIZE * 2]).toEqual({
|
|
80
|
-
data: BLOCK_SIZE * 2,
|
|
81
|
-
[DEFAULT_AS]: firstId + BLOCK_SIZE * 2,
|
|
82
|
-
});
|
|
83
|
-
});
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import { asArray } from "../../utils/arrayUtils";
|
|
2
|
-
import { field } from "../../utils/field";
|
|
3
|
-
import FlowNode, { BEHAVIOR_MODIFIES } from "../flowNode";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @typedef {import("../../spec/transform").LinearizeGenomicCoordinateParams} LinearizeGenomicCoordinateParams
|
|
7
|
-
* @typedef {import("../../view/view").default} View
|
|
8
|
-
*/
|
|
9
|
-
export default class LinearizeGenomicCoordinate extends FlowNode {
|
|
10
|
-
get behavior() {
|
|
11
|
-
return BEHAVIOR_MODIFIES;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
*
|
|
16
|
-
* @param {LinearizeGenomicCoordinateParams} params
|
|
17
|
-
* @param {View} view
|
|
18
|
-
*/
|
|
19
|
-
constructor(params, view) {
|
|
20
|
-
super();
|
|
21
|
-
|
|
22
|
-
const channel = params.channel ?? "x";
|
|
23
|
-
|
|
24
|
-
if (!["x", "y"].includes(channel)) {
|
|
25
|
-
throw new Error("Invalid channel: " + channel);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const genome = view.getScaleResolution(channel).getGenome();
|
|
29
|
-
if (!genome) {
|
|
30
|
-
throw new Error(
|
|
31
|
-
"LinearizeGenomicCoordinate transform requires a locus scale!"
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const chromAccessor = field(params.chrom);
|
|
36
|
-
const posAccessors = asArray(params.pos).map((pos) => field(pos));
|
|
37
|
-
const as = asArray(params.as);
|
|
38
|
-
|
|
39
|
-
if (posAccessors.length != as.length) {
|
|
40
|
-
throw new Error(
|
|
41
|
-
'The number of "pos" and "as" elements must be equal!'
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const offsetParam = asArray(params.offset);
|
|
46
|
-
|
|
47
|
-
/** @type {number[]} */
|
|
48
|
-
let posOffsets;
|
|
49
|
-
|
|
50
|
-
if (offsetParam.length == 0) {
|
|
51
|
-
posOffsets = new Array(posAccessors.length).fill(0);
|
|
52
|
-
} else if (offsetParam.length == 1) {
|
|
53
|
-
posOffsets = new Array(posAccessors.length).fill(offsetParam[0]);
|
|
54
|
-
} else if (offsetParam.length == posAccessors.length) {
|
|
55
|
-
posOffsets = offsetParam;
|
|
56
|
-
} else {
|
|
57
|
-
throw new Error(
|
|
58
|
-
`Invalid "offset" parameter: ${JSON.stringify(params.offset)}!`
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const setter = new Function(
|
|
63
|
-
"datum",
|
|
64
|
-
"chromOffset",
|
|
65
|
-
"posAccessors",
|
|
66
|
-
as
|
|
67
|
-
.map(
|
|
68
|
-
(a, i) =>
|
|
69
|
-
`datum[${JSON.stringify(
|
|
70
|
-
a
|
|
71
|
-
)}] = chromOffset + +posAccessors[${i}](datum) - ${
|
|
72
|
-
posOffsets[i]
|
|
73
|
-
};`
|
|
74
|
-
)
|
|
75
|
-
.join("\n")
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
/** @type {any} */
|
|
79
|
-
let lastChrom;
|
|
80
|
-
let chromOffset = 0;
|
|
81
|
-
|
|
82
|
-
/** @param {string | number} chrom */
|
|
83
|
-
const getChromOffset = (chrom) => {
|
|
84
|
-
if (chrom !== lastChrom) {
|
|
85
|
-
chromOffset = genome.cumulativeChromPositions.get(chrom);
|
|
86
|
-
if (chromOffset === undefined) {
|
|
87
|
-
throw new Error("Unknown chromosome/contig: " + chrom);
|
|
88
|
-
}
|
|
89
|
-
lastChrom = chrom;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return chromOffset;
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
/** @param {Record<string, any>} datum */
|
|
96
|
-
this.handle = (datum) => {
|
|
97
|
-
setter(datum, getChromOffset(chromAccessor(datum)), posAccessors);
|
|
98
|
-
this._propagate(datum);
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import FlowNode, { BEHAVIOR_MODIFIES } from "../flowNode";
|
|
2
|
-
import fontMetadata from "../../fonts/Lato-Regular.json";
|
|
3
|
-
import getMetrics from "../../fonts/bmFontMetrics";
|
|
4
|
-
import { field } from "../../utils/field";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Measures text length. This is mainly intended for reading-direction arrows
|
|
8
|
-
* in gene annotations.
|
|
9
|
-
*
|
|
10
|
-
* @typedef {import("../../spec/transform").MeasureTextParams} MeasureTextParams
|
|
11
|
-
*/
|
|
12
|
-
export default class MeasureTextTransform extends FlowNode {
|
|
13
|
-
get behavior() {
|
|
14
|
-
return BEHAVIOR_MODIFIES;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
*
|
|
19
|
-
* @param {MeasureTextParams} config
|
|
20
|
-
*/
|
|
21
|
-
constructor(config) {
|
|
22
|
-
super();
|
|
23
|
-
|
|
24
|
-
const metrics = getMetrics(fontMetadata);
|
|
25
|
-
const accessor = field(config.field);
|
|
26
|
-
const as = config.as;
|
|
27
|
-
// TODO: Support custom fonts.
|
|
28
|
-
const size = config.fontSize;
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
*
|
|
32
|
-
* @param {any} datum
|
|
33
|
-
*/
|
|
34
|
-
this.handle = (datum) => {
|
|
35
|
-
const text = accessor(datum);
|
|
36
|
-
if (text !== undefined) {
|
|
37
|
-
datum[as] = metrics.measureWidth(text, size);
|
|
38
|
-
} else {
|
|
39
|
-
datum[as] = 0;
|
|
40
|
-
}
|
|
41
|
-
this._propagate(datum);
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
}
|