@genome-spy/core 0.29.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 -784
- 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 -489
- 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 -488
- 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 -791
- 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/genome/genome.js
DELETED
|
@@ -1,317 +0,0 @@
|
|
|
1
|
-
import { bisect } from "d3-array";
|
|
2
|
-
import { tsvParseRows } from "d3-dsv";
|
|
3
|
-
import { loader } from "vega-loader";
|
|
4
|
-
import { isObject } from "vega-util";
|
|
5
|
-
import { formatRange } from "./locusFormat";
|
|
6
|
-
|
|
7
|
-
const defaultBaseUrl = "https://genomespy.app/data/genomes/";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* @typedef {import("../spec/genome").GenomeConfig} GenomeConfig
|
|
11
|
-
* @typedef {import("../spec/genome").ChromosomalLocus} ChromosomalLocus
|
|
12
|
-
*
|
|
13
|
-
* @typedef {object} Chromosome
|
|
14
|
-
* @prop {string} name
|
|
15
|
-
* @prop {number} size
|
|
16
|
-
*
|
|
17
|
-
* @typedef {object} ChromosomeAnnotation
|
|
18
|
-
* @prop {number} index 0-based index
|
|
19
|
-
* @prop {number} number 1-based index
|
|
20
|
-
* @prop {number} continuousStart zero-based start, inclusive
|
|
21
|
-
* @prop {number} continuousEnd zero-based end, exclusive
|
|
22
|
-
* @prop {number[]} continuousInterval
|
|
23
|
-
* @prop {boolean} odd true if odd chrom number
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
export default class Genome {
|
|
27
|
-
/**
|
|
28
|
-
* @param {GenomeConfig} config
|
|
29
|
-
*/
|
|
30
|
-
constructor(config) {
|
|
31
|
-
this.config = config;
|
|
32
|
-
|
|
33
|
-
if (!this.config.contigs && typeof this.config.name !== "string") {
|
|
34
|
-
throw new Error(
|
|
35
|
-
"No name has been defined for the genome assembly!"
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/** @type {(Chromosome & ChromosomeAnnotation)[]} */
|
|
40
|
-
this.chromosomes = [];
|
|
41
|
-
|
|
42
|
-
/** @type {Map<string | number, number>} */
|
|
43
|
-
this.cumulativeChromPositions = new Map();
|
|
44
|
-
|
|
45
|
-
/** @type {Map<string | number, Chromosome & ChromosomeAnnotation>} */
|
|
46
|
-
this.chromosomesByName = new Map();
|
|
47
|
-
|
|
48
|
-
/** @type {number[]} */
|
|
49
|
-
this.startByIndex = [];
|
|
50
|
-
|
|
51
|
-
this.totalSize = 0;
|
|
52
|
-
|
|
53
|
-
if (this.config.contigs) {
|
|
54
|
-
this.setChromSizes(this.config.contigs);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
get name() {
|
|
59
|
-
return this.config.name;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* @param {string} baseUrl
|
|
64
|
-
*/
|
|
65
|
-
async load(baseUrl) {
|
|
66
|
-
if (this.config.contigs) {
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (this.config.baseUrl) {
|
|
71
|
-
this.baseUrl = /^http(s)?/.test(this.config.baseUrl)
|
|
72
|
-
? this.config.baseUrl
|
|
73
|
-
: baseUrl + "/" + this.config.baseUrl;
|
|
74
|
-
} else {
|
|
75
|
-
this.baseUrl = defaultBaseUrl;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
try {
|
|
79
|
-
this.setChromSizes(
|
|
80
|
-
parseChromSizes(
|
|
81
|
-
await loader({ baseURL: this.baseUrl }).load(
|
|
82
|
-
`${this.config.name}/${this.name}.chrom.sizes`
|
|
83
|
-
)
|
|
84
|
-
)
|
|
85
|
-
);
|
|
86
|
-
} catch (e) {
|
|
87
|
-
throw new Error(`Could not load chrom sizes: ${e.message}`);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
*
|
|
93
|
-
* @param {Chromosome[]} chromSizes
|
|
94
|
-
*/
|
|
95
|
-
setChromSizes(chromSizes) {
|
|
96
|
-
let pos = 0;
|
|
97
|
-
this.startByIndex = [0];
|
|
98
|
-
|
|
99
|
-
for (let i = 0; i < chromSizes.length; i++) {
|
|
100
|
-
this.startByIndex.push(pos);
|
|
101
|
-
const size = chromSizes[i].size;
|
|
102
|
-
|
|
103
|
-
const chrom = {
|
|
104
|
-
...chromSizes[i],
|
|
105
|
-
continuousStart: pos,
|
|
106
|
-
continuousEnd: pos + size,
|
|
107
|
-
continuousInterval: [pos, pos + size],
|
|
108
|
-
index: i,
|
|
109
|
-
number: i + 1,
|
|
110
|
-
// eslint-disable-next-line no-bitwise
|
|
111
|
-
odd: !(i & 1),
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
this.chromosomes.push(chrom);
|
|
115
|
-
|
|
116
|
-
const plain = chrom.name.replace(/^chr/i, "");
|
|
117
|
-
for (const name of [
|
|
118
|
-
"chr" + plain,
|
|
119
|
-
"CHR" + plain,
|
|
120
|
-
"Chr" + plain,
|
|
121
|
-
// The number is a bit fragile because it depends on the order of the chromosomes.
|
|
122
|
-
// It probably works for autosomes, but X, Y, M, etc., not necessarily.
|
|
123
|
-
chrom.number,
|
|
124
|
-
"" + chrom.number,
|
|
125
|
-
plain,
|
|
126
|
-
chrom.name,
|
|
127
|
-
]) {
|
|
128
|
-
this.cumulativeChromPositions.set(name, pos);
|
|
129
|
-
this.chromosomesByName.set(name, chrom);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
pos += chrom.size;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
this.totalSize = pos;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
getExtent() {
|
|
139
|
-
return [0, this.totalSize];
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Returns a chromosomal locus in the continuous domain
|
|
144
|
-
*
|
|
145
|
-
* @param {string | number} chrom A number or name with or without a "chr" prefix. Examples: 23, chrX, X
|
|
146
|
-
* @param {number} pos zero-based coordinate
|
|
147
|
-
*/
|
|
148
|
-
toContinuous(chrom, pos) {
|
|
149
|
-
let offset = this.cumulativeChromPositions.get(chrom);
|
|
150
|
-
if (offset === undefined) {
|
|
151
|
-
throw new Error("Unknown chromosome/contig: " + chrom);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return offset + +pos;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
*
|
|
159
|
-
* @param {number} continuousPos
|
|
160
|
-
*/
|
|
161
|
-
toChromosome(continuousPos) {
|
|
162
|
-
if (continuousPos >= this.totalSize) {
|
|
163
|
-
return; // TODO: Consider displaying a warning
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
continuousPos = Math.floor(continuousPos);
|
|
167
|
-
|
|
168
|
-
// TODO: Fix the offset by one
|
|
169
|
-
const i = bisect(this.startByIndex, continuousPos) - 1;
|
|
170
|
-
if (i > 0 && i <= this.chromosomes.length) {
|
|
171
|
-
return this.chromosomes[i - 1];
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
*
|
|
177
|
-
* @param {number} continuousPos
|
|
178
|
-
* @returns {ChromosomalLocus}
|
|
179
|
-
*/
|
|
180
|
-
toChromosomal(continuousPos) {
|
|
181
|
-
const chrom = this.toChromosome(continuousPos);
|
|
182
|
-
if (!chrom) {
|
|
183
|
-
return undefined;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
return {
|
|
187
|
-
chrom: chrom.name,
|
|
188
|
-
pos: Math.floor(continuousPos) - chrom.continuousStart,
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
*
|
|
194
|
-
* @param {string} name
|
|
195
|
-
*/
|
|
196
|
-
getChromosome(name) {
|
|
197
|
-
return this.chromosomesByName.get(name);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Returns a UCSC Genome Browser -style string presentation of the interval.
|
|
202
|
-
* However, the interval may span multiple chromosomes, which is incompatible
|
|
203
|
-
* with UCSC.
|
|
204
|
-
*
|
|
205
|
-
* The inteval is shown as one-based closed-open range.
|
|
206
|
-
* See https://genome.ucsc.edu/FAQ/FAQtracks#tracks1
|
|
207
|
-
*
|
|
208
|
-
* @param {number[]} interval
|
|
209
|
-
* @returns {string}
|
|
210
|
-
*/
|
|
211
|
-
formatInterval(interval) {
|
|
212
|
-
return formatRange(...this.toChromosomalInterval(interval));
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* @param {number[]} interval
|
|
217
|
-
* @returns {[ChromosomalLocus, ChromosomalLocus]}
|
|
218
|
-
*/
|
|
219
|
-
toChromosomalInterval(interval) {
|
|
220
|
-
// Round the lower end
|
|
221
|
-
const begin = this.toChromosomal(interval[0] + 0.5);
|
|
222
|
-
// Because of the open upper bound, one is first subtracted from the upper bound and later added back.
|
|
223
|
-
const end = this.toChromosomal(interval[1] - 0.5);
|
|
224
|
-
end.pos += 1;
|
|
225
|
-
|
|
226
|
-
return [begin, end];
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* Returns a continuous interval. The optional position of the left end defaults to zero,
|
|
231
|
-
* the right end defaults to the size of the chromosome. Thus, the chromosome is inclusive
|
|
232
|
-
* when positions are omitted.
|
|
233
|
-
*
|
|
234
|
-
* @param {ChromosomalLocus[]} chromosomal
|
|
235
|
-
*/
|
|
236
|
-
toContinuousInterval(chromosomal) {
|
|
237
|
-
let [a, b] = chromosomal;
|
|
238
|
-
if (!b) {
|
|
239
|
-
// A shortcut for a single chromosome. { domain: [{ chrom: "chr3" }] }
|
|
240
|
-
b = a;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
return [
|
|
244
|
-
this.toContinuous(a.chrom, a.pos ?? 0),
|
|
245
|
-
this.toContinuous(
|
|
246
|
-
b.chrom,
|
|
247
|
-
b.pos ?? this.chromosomesByName.get(b.chrom)?.size
|
|
248
|
-
),
|
|
249
|
-
];
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
*
|
|
254
|
-
* @param {string} str
|
|
255
|
-
* @returns {[number, number]}
|
|
256
|
-
*/
|
|
257
|
-
parseInterval(str) {
|
|
258
|
-
// TODO: consider changing [0-9XY] to support other species besides humans
|
|
259
|
-
const matches = str.match(
|
|
260
|
-
/^(chr[0-9A-Z]+)(?::([0-9,]+)(?:-(?:(chr[0-9A-Z]+):)?([0-9,]+))?)?$/
|
|
261
|
-
);
|
|
262
|
-
|
|
263
|
-
if (matches) {
|
|
264
|
-
const startChr = matches[1];
|
|
265
|
-
|
|
266
|
-
if (matches.slice(2).every((x) => x === undefined)) {
|
|
267
|
-
const chrom = this.getChromosome(startChr);
|
|
268
|
-
if (chrom) {
|
|
269
|
-
return [chrom.continuousStart, chrom.continuousEnd];
|
|
270
|
-
}
|
|
271
|
-
return;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
const endChr = matches[3] || startChr;
|
|
275
|
-
|
|
276
|
-
const startIndex = parseInt(matches[2].replace(/,/g, ""));
|
|
277
|
-
const endIndex =
|
|
278
|
-
matches[4] !== undefined
|
|
279
|
-
? parseInt(matches[4].replace(/,/g, ""))
|
|
280
|
-
: startIndex;
|
|
281
|
-
|
|
282
|
-
return [
|
|
283
|
-
this.toContinuous(startChr, startIndex - 1),
|
|
284
|
-
this.toContinuous(endChr, endIndex),
|
|
285
|
-
];
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
*
|
|
292
|
-
* @param {string} chromSizesData
|
|
293
|
-
*/
|
|
294
|
-
export function parseChromSizes(chromSizesData) {
|
|
295
|
-
// TODO: Support other organisms too
|
|
296
|
-
return tsvParseRows(chromSizesData)
|
|
297
|
-
.filter((row) => /^chr[0-9A-Z]+$/.test(row[0]))
|
|
298
|
-
.map(([name, size]) => ({ name, size: parseInt(size) }));
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
*
|
|
303
|
-
* @param {any} value
|
|
304
|
-
* @return {value is ChromosomalLocus}
|
|
305
|
-
*/
|
|
306
|
-
export function isChromosomalLocus(value) {
|
|
307
|
-
return isObject(value) && "chrom" in value;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
/**
|
|
311
|
-
*
|
|
312
|
-
* @param {any[]} value
|
|
313
|
-
* @return {value is ChromosomalLocus[]}
|
|
314
|
-
*/
|
|
315
|
-
export function isChromosomalLocusInterval(value) {
|
|
316
|
-
return value.every(isChromosomalLocus);
|
|
317
|
-
}
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from "vitest";
|
|
2
|
-
import Genome from "./genome";
|
|
3
|
-
|
|
4
|
-
describe("Human genome, chromosome names prefixed with 'chr'", () => {
|
|
5
|
-
// Actually, the chromosomes are just named as in hg38, for example
|
|
6
|
-
const chromosomes = [
|
|
7
|
-
{ name: "chr1", size: 10 },
|
|
8
|
-
{ name: "chr2", size: 20 },
|
|
9
|
-
{ name: "chr3", size: 30 },
|
|
10
|
-
{ name: "chrX", size: 40 },
|
|
11
|
-
];
|
|
12
|
-
|
|
13
|
-
const g = new Genome({ name: "random", contigs: chromosomes });
|
|
14
|
-
|
|
15
|
-
test("Maps chromosome names to continuous", () => {
|
|
16
|
-
expect(() => g.toContinuous("chr0", 2)).toThrow();
|
|
17
|
-
expect(g.toContinuous("chr1", 0)).toEqual(0);
|
|
18
|
-
expect(g.toContinuous("chr1", 2)).toEqual(2);
|
|
19
|
-
expect(g.toContinuous("chr2", 2)).toEqual(12);
|
|
20
|
-
expect(g.toContinuous("chrX", 2)).toEqual(62);
|
|
21
|
-
// TODO: Should this throw to alert about invalid data..?
|
|
22
|
-
// TODO: expect(m.toContinuous("chrX", 40)).toBeUndefined();
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
test("Maps chromosome numbers to continuous", () => {
|
|
26
|
-
expect(() => g.toContinuous(0, 2)).toThrow();
|
|
27
|
-
expect(g.toContinuous(1, 2)).toEqual(2);
|
|
28
|
-
expect(g.toContinuous(2, 2)).toEqual(12);
|
|
29
|
-
expect(g.toContinuous(4, 2)).toEqual(62);
|
|
30
|
-
expect(() => g.toContinuous(5, 2)).toThrow();
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
test("Maps unprefixed names to continuous", () => {
|
|
34
|
-
expect(() => g.toContinuous("0", 2)).toThrow();
|
|
35
|
-
expect(g.toContinuous("1", 2)).toEqual(2);
|
|
36
|
-
expect(g.toContinuous("2", 2)).toEqual(12);
|
|
37
|
-
expect(g.toContinuous("X", 2)).toEqual(62);
|
|
38
|
-
expect(() => g.toContinuous("Y", 2)).toThrow();
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
test("Maps string positions to continuous", () => {
|
|
42
|
-
expect(g.toContinuous("2", /** @type {any} */ ("2"))).toEqual(12);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
test("Maps continuous to chromosome and locus", () => {
|
|
46
|
-
expect(g.toChromosomal(-1)).toBeUndefined();
|
|
47
|
-
expect(g.toChromosomal(0)).toEqual({ chrom: "chr1", pos: 0 });
|
|
48
|
-
expect(g.toChromosomal(12)).toEqual({ chrom: "chr2", pos: 2 });
|
|
49
|
-
expect(g.toChromosomal(29)).toEqual({ chrom: "chr2", pos: 19 });
|
|
50
|
-
expect(g.toChromosomal(30)).toEqual({ chrom: "chr3", pos: 0 });
|
|
51
|
-
expect(g.toChromosomal(62)).toEqual({ chrom: "chrX", pos: 2 });
|
|
52
|
-
expect(g.toChromosomal(99)).toEqual({ chrom: "chrX", pos: 39 });
|
|
53
|
-
expect(g.toChromosomal(100)).toBeUndefined();
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
// Testing half-open intervals
|
|
57
|
-
test("Maps continuous interval to chromosomal interval", () => {
|
|
58
|
-
expect(g.toChromosomalInterval([0, 10])).toEqual([
|
|
59
|
-
{ chrom: "chr1", pos: 0 },
|
|
60
|
-
{ chrom: "chr1", pos: 10 },
|
|
61
|
-
]);
|
|
62
|
-
expect(g.toChromosomalInterval([10, 100])).toEqual([
|
|
63
|
-
{ chrom: "chr2", pos: 0 },
|
|
64
|
-
{ chrom: "chrX", pos: 40 },
|
|
65
|
-
]);
|
|
66
|
-
expect(g.toChromosomalInterval([0, 100])).toEqual([
|
|
67
|
-
{ chrom: "chr1", pos: 0 },
|
|
68
|
-
{ chrom: "chrX", pos: 40 },
|
|
69
|
-
]);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
test("Maps interval with fractional parts to chromosomal interval", () => {
|
|
73
|
-
expect(g.toChromosomalInterval([0.1, 99.9])).toEqual([
|
|
74
|
-
{ chrom: "chr1", pos: 0 },
|
|
75
|
-
{ chrom: "chrX", pos: 40 },
|
|
76
|
-
]);
|
|
77
|
-
expect(g.toChromosomalInterval([0.6, 99.4])).toEqual([
|
|
78
|
-
{ chrom: "chr1", pos: 1 },
|
|
79
|
-
{ chrom: "chrX", pos: 39 },
|
|
80
|
-
]);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
test("Maps chromosomal interval to continuous interval", () => {
|
|
84
|
-
expect(
|
|
85
|
-
g.toContinuousInterval([
|
|
86
|
-
{ chrom: "chr1", pos: 0 },
|
|
87
|
-
{ chrom: "chr1", pos: 10 },
|
|
88
|
-
])
|
|
89
|
-
).toEqual([0, 10]);
|
|
90
|
-
expect(
|
|
91
|
-
g.toContinuousInterval([
|
|
92
|
-
{ chrom: "chr1", pos: 1 },
|
|
93
|
-
{ chrom: "chr1", pos: 9 },
|
|
94
|
-
])
|
|
95
|
-
).toEqual([1, 9]);
|
|
96
|
-
expect(
|
|
97
|
-
g.toContinuousInterval([
|
|
98
|
-
{ chrom: "chr2", pos: 0 },
|
|
99
|
-
{ chrom: "chrX", pos: 40 },
|
|
100
|
-
])
|
|
101
|
-
).toEqual([10, 100]);
|
|
102
|
-
expect(
|
|
103
|
-
g.toContinuousInterval([
|
|
104
|
-
{ chrom: "chr1", pos: 0 },
|
|
105
|
-
{ chrom: "chrX", pos: 40 },
|
|
106
|
-
])
|
|
107
|
-
).toEqual([0, 100]);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
test("Maps chromosomal interval without positions to continuous interval", () => {
|
|
111
|
-
expect(
|
|
112
|
-
g.toContinuousInterval([{ chrom: "chr1" }, { chrom: "chr1" }])
|
|
113
|
-
).toEqual([0, 10]);
|
|
114
|
-
expect(
|
|
115
|
-
g.toContinuousInterval([{ chrom: "chr2" }, { chrom: "chrX" }])
|
|
116
|
-
).toEqual([10, 100]);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
test("Returns a properly annotated chromosomes array", () => {
|
|
120
|
-
expect(g.chromosomes[1]).toEqual({
|
|
121
|
-
name: "chr2",
|
|
122
|
-
size: 20,
|
|
123
|
-
index: 1,
|
|
124
|
-
number: 2,
|
|
125
|
-
continuousStart: 10,
|
|
126
|
-
continuousEnd: 30,
|
|
127
|
-
continuousInterval: [10, 30],
|
|
128
|
-
odd: false,
|
|
129
|
-
});
|
|
130
|
-
});
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
describe("C. elegans genome, chromosome names prefixed with 'chr'", () => {
|
|
134
|
-
const chromosomes = [
|
|
135
|
-
{ name: "chrI", size: 15072434 },
|
|
136
|
-
{ name: "chrII", size: 15279421 },
|
|
137
|
-
{ name: "chrIII", size: 13783801 },
|
|
138
|
-
{ name: "chrIV", size: 17493829 },
|
|
139
|
-
{ name: "chrV", size: 20924180 },
|
|
140
|
-
{ name: "chrX", size: 17718942 },
|
|
141
|
-
{ name: "chrM", size: 13794 },
|
|
142
|
-
];
|
|
143
|
-
|
|
144
|
-
const g = new Genome({ name: "random", contigs: chromosomes });
|
|
145
|
-
|
|
146
|
-
test("Maps chromosome names to continuous", () => {
|
|
147
|
-
expect(g.toContinuous("chrIII", 10)).toEqual(30351865);
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
test("Maps unprefixed names to continuous", () => {
|
|
151
|
-
expect(g.toContinuous("III", 10)).toEqual(30351865);
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
describe("Parse interval strings", () => {
|
|
156
|
-
const chromosomes = [
|
|
157
|
-
{ name: "chr1", size: 1000 },
|
|
158
|
-
{ name: "chr2", size: 2000 },
|
|
159
|
-
{ name: "chr3", size: 3000 },
|
|
160
|
-
{ name: "chrX", size: 4000 },
|
|
161
|
-
];
|
|
162
|
-
|
|
163
|
-
const g = new Genome({ name: "random", contigs: chromosomes });
|
|
164
|
-
|
|
165
|
-
test("Parses a single chromosome, returns an interval spanning the chromosome", () => {
|
|
166
|
-
expect(g.parseInterval("chr2")).toEqual([1000, 3000]);
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
test("Returns undefined on unknown chromosome", () => {
|
|
170
|
-
expect(g.parseInterval("chrZ")).toBeUndefined();
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
test("Parses a single coordinate without a thousand separator", () => {
|
|
174
|
-
expect(g.parseInterval("chr2:1500")).toEqual([2499, 2500]);
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
test("Parses a single coordinate with a thousand separator", () => {
|
|
178
|
-
expect(g.parseInterval("chr2:1,500")).toEqual([2499, 2500]);
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
test("Parses an interval within a single chromosome", () => {
|
|
182
|
-
expect(g.parseInterval("chr2:1,500-1,700")).toEqual([2499, 2700]);
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
test("Parses an interval spanning multiple chromosomes", () => {
|
|
186
|
-
expect(g.parseInterval("chr2:1,500-chr3:1,500")).toEqual([2499, 4500]);
|
|
187
|
-
});
|
|
188
|
-
});
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import Genome from "./genome";
|
|
2
|
-
|
|
3
|
-
export default class GenomeStore {
|
|
4
|
-
/**
|
|
5
|
-
* @param {import("../genomeSpy").default} genomeSpy
|
|
6
|
-
*/
|
|
7
|
-
constructor(genomeSpy) {
|
|
8
|
-
/** @type {Map<string, Genome>} */
|
|
9
|
-
this.genomes = new Map();
|
|
10
|
-
this.genomeSpy = genomeSpy;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* @param {import("../spec/genome").GenomeConfig} genomeConfig
|
|
15
|
-
*/
|
|
16
|
-
// eslint-disable-next-line require-await
|
|
17
|
-
async initialize(genomeConfig) {
|
|
18
|
-
const genome = new Genome(genomeConfig);
|
|
19
|
-
this.genomes.set(genome.name, genome);
|
|
20
|
-
|
|
21
|
-
return Promise.all(
|
|
22
|
-
[...this.genomes.values()].map((genome) =>
|
|
23
|
-
genome.load(this.genomeSpy.spec.baseUrl)
|
|
24
|
-
)
|
|
25
|
-
);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* @param {string} [name] If not given, a default genome is returned.
|
|
30
|
-
* @returns {Genome}
|
|
31
|
-
*/
|
|
32
|
-
getGenome(name) {
|
|
33
|
-
if (!this.genomes.size) {
|
|
34
|
-
throw new Error("No genomes have been configured!");
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (name) {
|
|
38
|
-
const genome = this.genomes.get(name);
|
|
39
|
-
if (!genome) {
|
|
40
|
-
throw new Error(
|
|
41
|
-
`No genome with the name ${name} has been configured!`
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
return genome;
|
|
45
|
-
} else {
|
|
46
|
-
if (this.genomes.size > 1) {
|
|
47
|
-
throw new Error(
|
|
48
|
-
"Cannot pick a default genome! More than one have been configured!"
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
return this.genomes.values().next().value;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { format as d3format } from "d3-format";
|
|
2
|
-
|
|
3
|
-
const numberFormat = d3format(",d");
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* @typedef {import("./genome").ChromosomalLocus} ChromosomalLocus
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* @param {ChromosomalLocus} locus
|
|
11
|
-
*/
|
|
12
|
-
export function formatLocus(locus) {
|
|
13
|
-
return locus.chrom + ":" + numberFormat(Math.floor(locus.pos + 1));
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* @param {ChromosomalLocus} begin
|
|
18
|
-
* @param {ChromosomalLocus} end
|
|
19
|
-
*/
|
|
20
|
-
export function formatRange(begin, end) {
|
|
21
|
-
return (
|
|
22
|
-
begin.chrom +
|
|
23
|
-
":" +
|
|
24
|
-
numberFormat(Math.floor(begin.pos + 1)) +
|
|
25
|
-
"-" +
|
|
26
|
-
(begin.chrom != end.chrom ? end.chrom + ":" : "") +
|
|
27
|
-
numberFormat(Math.ceil(end.pos))
|
|
28
|
-
);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// TODO: parseLocus, parseRange
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
export default function scaleIndex(): ScaleIndex;
|
|
2
|
-
|
|
3
|
-
export interface ScaleIndex {
|
|
4
|
-
(value: number): number;
|
|
5
|
-
|
|
6
|
-
invert(x: number): number;
|
|
7
|
-
|
|
8
|
-
domain(): number[];
|
|
9
|
-
domain(_: Iterable<number>): this;
|
|
10
|
-
|
|
11
|
-
range(): number[];
|
|
12
|
-
range(_: Iterable<number>): this;
|
|
13
|
-
|
|
14
|
-
numberingOffset(): number;
|
|
15
|
-
numberingOffset(_: number): this;
|
|
16
|
-
|
|
17
|
-
padding(): number;
|
|
18
|
-
padding(_: number): this;
|
|
19
|
-
|
|
20
|
-
paddingInner(): number;
|
|
21
|
-
paddingInner(_: number): this;
|
|
22
|
-
|
|
23
|
-
paddingOuter(): number;
|
|
24
|
-
paddingOuter(_: number): this;
|
|
25
|
-
|
|
26
|
-
align(): number;
|
|
27
|
-
align(_: number): this;
|
|
28
|
-
|
|
29
|
-
step(): number;
|
|
30
|
-
|
|
31
|
-
bandwidth(): number;
|
|
32
|
-
|
|
33
|
-
ticks(count: number): number[];
|
|
34
|
-
|
|
35
|
-
tickFormat(count?: number, specifier?: string): (x: number) => string;
|
|
36
|
-
|
|
37
|
-
copy(): this;
|
|
38
|
-
}
|