@jbrowse/bandage-core 10.3.1 → 11.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/dist/chunks/{chunk-DBLV7PGG.js → chunk-3XSRT7RQ.js} +16 -2
- package/dist/chunks/{chunk-BS6HPYCZ.js → chunk-77EGQQJU.js} +3 -1
- package/dist/chunks/chunk-7BTO7MZS.js +46 -0
- package/dist/chunks/{chunk-BKEZLETL.js → chunk-AI5PTOSV.js} +1 -1
- package/dist/chunks/{chunk-CGFPFBT2.js → chunk-D4ZFRBB4.js} +11 -2
- package/dist/chunks/{chunk-OOIOX36I.js → chunk-DEDD7TFJ.js} +40 -9
- package/dist/chunks/{chunk-YZQI35UJ.js → chunk-DR24UTRS.js} +23 -2
- package/dist/chunks/{chunk-Z6XZWPXK.js → chunk-DZR37KXT.js} +51 -2
- package/dist/chunks/chunk-EIY2SKD3.js +164 -0
- package/dist/chunks/{chunk-NZTYV3JL.js → chunk-FFHJGWDK.js} +5 -1
- package/dist/chunks/{chunk-QH2MIXBA.js → chunk-IVOK5V3H.js} +6 -6
- package/dist/chunks/{chunk-SFP3E4RI.js → chunk-IZ6Y5D23.js} +2 -2
- package/dist/chunks/{chunk-EWLXU3UG.js → chunk-JFHYG25O.js} +13 -13
- package/dist/chunks/{chunk-KMBE2Q42.js → chunk-KDU4EF66.js} +3 -3
- package/dist/chunks/{chunk-FW2R7UDZ.js → chunk-LMH5KVJZ.js} +1 -1
- package/dist/chunks/{chunk-AZ4EEF6Q.js → chunk-NGUM77EP.js} +5 -5
- package/dist/chunks/{chunk-GIHTHYXY.js → chunk-NMWQUFPF.js} +1 -1
- package/dist/chunks/{chunk-CHNESV7L.js → chunk-OI4YVAMM.js} +56 -9
- package/dist/chunks/{chunk-R2PJKD3Y.js → chunk-RETNT73O.js} +1 -1
- package/dist/chunks/{chunk-OXRUPNSV.js → chunk-RNYPCQZ3.js} +1 -1
- package/dist/chunks/{chunk-DO62DG26.js → chunk-TABI4JEU.js} +6 -4
- package/dist/chunks/{chunk-M5NPD55W.js → chunk-TUQKGAK3.js} +1 -1
- package/dist/chunks/{chunk-MWOVW4AH.js → chunk-V5MAL7LU.js} +1 -1
- package/dist/chunks/{chunk-D7WIYPG3.js → chunk-W6EXQDV5.js} +1 -1
- package/dist/chunks/{chunk-ZJBOM73S.js → chunk-XZ6PQBU6.js} +58 -12
- package/dist/chunks/{chunk-AQCOIE5R.js → chunk-Y3FDMDNT.js} +1 -1
- package/dist/chunks/{chunk-A2TJ5UX6.js → chunk-YHJ5JLBI.js} +1 -1
- package/dist/chunks/{chunk-WYJQIC75.js → chunk-ZUL52ZX2.js} +4 -4
- package/dist/cli/figure.js +42 -67
- package/dist/cli/fold.js +5 -4
- package/dist/figure.js +18 -17
- package/dist/figureData.js +21 -19
- package/dist/figureScene.js +12 -11
- package/dist/figureSettings.js +6 -5
- package/dist/gbzCut.js +4 -3
- package/dist/gbzWindow.js +3 -2
- package/dist/genes/backboneGenes.js +12 -0
- package/dist/genes/genePins.js +1 -1
- package/dist/gfa/gfaConverter.js +2 -1
- package/dist/gfa/gfaTables.js +2 -1
- package/dist/gfa/graphTables.js +2 -1
- package/dist/gfa/walkStops.js +28 -0
- package/dist/index.js +60 -38
- package/dist/layout/forceCache.js +6 -5
- package/dist/layout/tubeMapLayout.js +3 -2
- package/dist/layout/walkRowDraw.js +10 -1
- package/dist/layout/walkRowLayout.js +3 -2
- package/dist/layout/walkRows.js +2 -1
- package/dist/layout/walkStrip.js +5 -4
- package/dist/layoutModes.js +6 -5
- package/dist/pipeline.js +5 -4
- package/dist/tubeMap/bundle.js +4 -3
- package/dist/tubeMap/coarsen.js +4 -3
- package/dist/tubeMap/deviations.js +4 -3
- package/dist/tubeMap/draw.js +4 -3
- package/dist/types/figureData.d.ts +31 -2
- package/dist/types/genes/backboneGenes.d.ts +25 -0
- package/dist/types/genes/genePins.d.ts +1 -0
- package/dist/types/gfa/graphTables.d.ts +3 -0
- package/dist/types/gfa/walkStops.d.ts +59 -0
- package/dist/types/index.d.ts +7 -3
- package/dist/types/layout/walkRowDraw.d.ts +14 -1
- package/dist/types/layout/walkRows.d.ts +10 -1
- package/dist/types/types.d.ts +19 -0
- package/dist/types/version.d.ts +1 -1
- package/dist/types/walkEncoding.d.ts +1 -0
- package/dist/types/walkHighlight.d.ts +2 -0
- package/dist/types/walkKey.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/viewport.js +6 -5
- package/dist/walkEncoding.js +1 -1
- package/dist/walkHighlight.js +3 -2
- package/dist/walkKey.js +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,6 +10,11 @@ npm install @jbrowse/bandage-core
|
|
|
10
10
|
|
|
11
11
|
- GFA and rGFA text in (`loadGraph`), or the same graph as typed arrays a worker
|
|
12
12
|
can transfer (`GraphTables`)
|
|
13
|
+
- A walk-file cut's W lines tag what lies past each fragment's start and end as
|
|
14
|
+
`ws:Z:`/`we:Z:`, such as `break,bp=19021` or
|
|
15
|
+
`elsewhere,trimmed=400,chunk=GRCh38#0#chr22:20316160`
|
|
16
|
+
(`src/gfa/walkStops.ts`). Walk rows split each gap by those stops into parts
|
|
17
|
+
that name their cause
|
|
13
18
|
- Layouts: Bandage's FMMM engine as WASM from
|
|
14
19
|
[@jbrowse/graph-fmmm-layout](https://github.com/GMOD/graph-fmmm-layout)
|
|
15
20
|
(`loadBandage`, `forceLayout`), ordered, anchored, sample rows, walk rows,
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
stopAt,
|
|
3
|
+
stopFields,
|
|
4
|
+
walkStopTags
|
|
5
|
+
} from "./chunk-EIY2SKD3.js";
|
|
1
6
|
import {
|
|
2
7
|
PathVisits
|
|
3
8
|
} from "./chunk-ZPZ7GNBT.js";
|
|
@@ -209,7 +214,16 @@ function graphFromTables({ nodes: n, links: l, walks: w }, name = "Imported GFA"
|
|
|
209
214
|
}
|
|
210
215
|
prev = node;
|
|
211
216
|
}
|
|
212
|
-
paths.push({
|
|
217
|
+
paths.push({
|
|
218
|
+
name: pathName,
|
|
219
|
+
nodeIds,
|
|
220
|
+
start,
|
|
221
|
+
...fields,
|
|
222
|
+
...fields ? stopFields(
|
|
223
|
+
w.before && stopAt(w.before, p),
|
|
224
|
+
w.after && stopAt(w.after, p)
|
|
225
|
+
) : {}
|
|
226
|
+
});
|
|
213
227
|
anchorPaths.push({
|
|
214
228
|
name: visitName,
|
|
215
229
|
sample: visitSample,
|
|
@@ -272,7 +286,7 @@ function graphTablesGFA({ nodes, links, walks }) {
|
|
|
272
286
|
steps.push([names[walks.steps[s]], walks.reversed[s]]);
|
|
273
287
|
}
|
|
274
288
|
lines.push(
|
|
275
|
-
fields ? `W ${fields.sample} ${fields.haplotype} ${fields.contig} ${start} ${end} ${steps.map(([id, rev]) => (rev ? "<" : ">") + id).join("")}` : `P ${pLineName(name, start, end)} ${steps.map(([id, rev]) => id + (rev ? "-" : "+")).join(",")} *`
|
|
289
|
+
fields ? `W ${fields.sample} ${fields.haplotype} ${fields.contig} ${start} ${end} ${steps.map(([id, rev]) => (rev ? "<" : ">") + id).join("")}${walkStopTags(walks, p)}` : `P ${pLineName(name, start, end)} ${steps.map(([id, rev]) => id + (rev ? "-" : "+")).join(",")} *`
|
|
276
290
|
);
|
|
277
291
|
}
|
|
278
292
|
return lines.join("\n");
|
|
@@ -50,6 +50,7 @@ function genePins(graph, genes, positions) {
|
|
|
50
50
|
nodeIds.add(node.id);
|
|
51
51
|
covered += Math.min(nodeEnd, gene.end) - Math.max(nodeStart, gene.start);
|
|
52
52
|
const nodeParts = [];
|
|
53
|
+
const stretches = [];
|
|
53
54
|
for (const exon of gene.exons) {
|
|
54
55
|
const a = Math.max(exon.start, nodeStart);
|
|
55
56
|
const b = Math.min(exon.end, nodeEnd);
|
|
@@ -65,10 +66,11 @@ function genePins(graph, genes, positions) {
|
|
|
65
66
|
stretch.push({ ...stretch[0] });
|
|
66
67
|
}
|
|
67
68
|
nodeParts.push(svgPath(stretch));
|
|
69
|
+
stretches.push(stretch);
|
|
68
70
|
}
|
|
69
71
|
if (nodeParts.length > 0) {
|
|
70
72
|
parts.push(...nodeParts);
|
|
71
|
-
exonsByNode.push({ nodeId: node.id, d: nodeParts.join("") });
|
|
73
|
+
exonsByNode.push({ nodeId: node.id, d: nodeParts.join(""), stretches });
|
|
72
74
|
}
|
|
73
75
|
const pinBp = Math.min(Math.max(mid, nodeStart), nodeEnd);
|
|
74
76
|
const distance = Math.abs(pinBp - mid);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import {
|
|
2
|
+
genesFromText
|
|
3
|
+
} from "./chunk-G6UIYQZR.js";
|
|
4
|
+
import {
|
|
5
|
+
featuresOnBackbone,
|
|
6
|
+
graphBackbone,
|
|
7
|
+
refNameBinding
|
|
8
|
+
} from "./chunk-234NFZS4.js";
|
|
9
|
+
|
|
10
|
+
// src/genes/backboneGenes.ts
|
|
11
|
+
async function backboneGenes(graph, source) {
|
|
12
|
+
const backbone = graphBackbone(graph);
|
|
13
|
+
if (!backbone) {
|
|
14
|
+
return { genes: [] };
|
|
15
|
+
}
|
|
16
|
+
const bind = refNameBinding(
|
|
17
|
+
backbone.contigs.map((c) => c.refName),
|
|
18
|
+
source.refNames
|
|
19
|
+
);
|
|
20
|
+
let names;
|
|
21
|
+
let features;
|
|
22
|
+
if ("indexed" in source) {
|
|
23
|
+
names = await source.indexed.getReferenceSequenceNames();
|
|
24
|
+
const lines = [];
|
|
25
|
+
for (const contig of backbone.contigs) {
|
|
26
|
+
const name = names.find((n) => bind(n) === contig.refName);
|
|
27
|
+
if (name !== void 0) {
|
|
28
|
+
await source.indexed.getLines(name, contig.start, contig.end, {
|
|
29
|
+
lineCallback: (line) => lines.push(line)
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
features = genesFromText(lines.join("\n"), source.format);
|
|
34
|
+
} else {
|
|
35
|
+
features = genesFromText(source.text, source.format);
|
|
36
|
+
names = [...new Set(features.map((f) => f.refName))];
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
genes: featuresOnBackbone(features, backbone, source.refNames),
|
|
40
|
+
unbound: names.some((name) => bind(name) !== void 0) ? void 0 : { names, contigs: backbone.contigs.map((c) => c.contig) }
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export {
|
|
45
|
+
backboneGenes
|
|
46
|
+
};
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
GAP_CAUSE_TEXT,
|
|
3
|
+
OUTSIDE_TEXT
|
|
4
|
+
} from "./chunk-EIY2SKD3.js";
|
|
1
5
|
import {
|
|
2
6
|
formatBp,
|
|
3
7
|
groupDigits
|
|
@@ -14,10 +18,15 @@ function walkKey(walk, reference) {
|
|
|
14
18
|
const own = walk.range ? rangeText(walk.range.contig, walk.range.start, walk.range.end) : void 0;
|
|
15
19
|
const scale = field === "progress" ? own : field === "reference" && reference ? rangeText(reference.name, reference.start, reference.end) : void 0;
|
|
16
20
|
const spanned = walk.range ? walk.range.end - walk.range.start : walk.bp;
|
|
17
|
-
const outside = spanned - walk.bp;
|
|
21
|
+
const outside = spanned - walk.bp - walk.missingBp - walk.unknownBp;
|
|
22
|
+
const gaps = [
|
|
23
|
+
[walk.missingBp, GAP_CAUSE_TEXT.missing],
|
|
24
|
+
[walk.unknownBp, GAP_CAUSE_TEXT.unknown],
|
|
25
|
+
[outside, OUTSIDE_TEXT]
|
|
26
|
+
];
|
|
18
27
|
return {
|
|
19
28
|
delta: walk.referenceBp === void 0 || spanned === walk.referenceBp ? "" : ` ${spanned > walk.referenceBp ? "+" : "\u2212"}${formatBp(Math.abs(spanned - walk.referenceBp))}`,
|
|
20
|
-
|
|
29
|
+
gaps: gaps.filter(([bp]) => bp > 0).map(([bp, text]) => `, ${formatBp(bp)} ${text}`).join(""),
|
|
21
30
|
reversed: walk.reversedBp > 0 ? `, ${formatBp(walk.reversedBp)} reversed` : "",
|
|
22
31
|
shades: field !== "walk",
|
|
23
32
|
scale,
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
pathOrigin
|
|
3
3
|
} from "./chunk-B5X2RLJG.js";
|
|
4
|
+
import {
|
|
5
|
+
gapParts
|
|
6
|
+
} from "./chunk-EIY2SKD3.js";
|
|
4
7
|
import {
|
|
5
8
|
groupBy
|
|
6
9
|
} from "./chunk-BSOZW3FC.js";
|
|
@@ -19,6 +22,7 @@ function labelOf(path) {
|
|
|
19
22
|
var NodeTable = class {
|
|
20
23
|
constructor(graph) {
|
|
21
24
|
this.index = /* @__PURE__ */ new Map();
|
|
25
|
+
this.ids = [];
|
|
22
26
|
this.lengths = [];
|
|
23
27
|
this.onReference = new Uint8Array(0);
|
|
24
28
|
this.referenceStart = new Float64Array(0);
|
|
@@ -32,6 +36,7 @@ var NodeTable = class {
|
|
|
32
36
|
if (i === void 0) {
|
|
33
37
|
i = this.lengths.length;
|
|
34
38
|
this.index.set(id, i);
|
|
39
|
+
this.ids.push(id);
|
|
35
40
|
this.lengths.push(0);
|
|
36
41
|
}
|
|
37
42
|
return i;
|
|
@@ -50,10 +55,13 @@ var NodeTable = class {
|
|
|
50
55
|
};
|
|
51
56
|
function stepsOf(pieces, table) {
|
|
52
57
|
const out = [];
|
|
58
|
+
const gaps = [];
|
|
53
59
|
let end;
|
|
60
|
+
let previous;
|
|
54
61
|
for (const piece of pieces) {
|
|
55
62
|
if (end !== void 0 && piece.start !== void 0 && piece.start > end) {
|
|
56
|
-
|
|
63
|
+
gaps.push(gapParts(piece.start - end, previous?.after, piece.before));
|
|
64
|
+
out.push(-gaps.length);
|
|
57
65
|
}
|
|
58
66
|
let bp = 0;
|
|
59
67
|
for (const node of piece.nodes) {
|
|
@@ -61,8 +69,9 @@ function stepsOf(pieces, table) {
|
|
|
61
69
|
bp += table.lengths[node];
|
|
62
70
|
}
|
|
63
71
|
end = piece.start === void 0 ? void 0 : piece.start + bp;
|
|
72
|
+
previous = piece;
|
|
64
73
|
}
|
|
65
|
-
return Float64Array.from(out);
|
|
74
|
+
return { steps: Float64Array.from(out), gaps };
|
|
66
75
|
}
|
|
67
76
|
function stepSpan(pieces, table, k) {
|
|
68
77
|
let end;
|
|
@@ -203,10 +212,13 @@ function walkRows(graph, region, unit) {
|
|
|
203
212
|
const path = paths2[0];
|
|
204
213
|
const pieces = paths2.map((piece, p) => ({
|
|
205
214
|
start: piece.start,
|
|
206
|
-
nodes: nodes?.[p] ?? table.nodesOf(piece)
|
|
215
|
+
nodes: nodes?.[p] ?? table.nodesOf(piece),
|
|
216
|
+
before: piece.before,
|
|
217
|
+
after: piece.after
|
|
207
218
|
})).sort((a, b) => (a.start ?? 0) - (b.start ?? 0));
|
|
219
|
+
const { steps, gaps } = stepsOf(pieces, table);
|
|
208
220
|
const { ids, complete, from, to, stop } = sliceBetween(
|
|
209
|
-
|
|
221
|
+
steps,
|
|
210
222
|
table,
|
|
211
223
|
cut,
|
|
212
224
|
flanked
|
|
@@ -214,24 +226,42 @@ function walkRows(graph, region, unit) {
|
|
|
214
226
|
const contig = path.contig ?? panSNContig(pathOrigin(path.name).name);
|
|
215
227
|
const axisSpan = stepSpan(pieces, table, from < 0 ? 0 : from);
|
|
216
228
|
const axis = !axisSpan ? void 0 : from < 0 ? { contig, start: axisSpan.start, reversed: false } : from < to ? { contig, start: axisSpan.end, reversed: false } : { contig, start: axisSpan.start, reversed: true };
|
|
217
|
-
const {
|
|
229
|
+
const {
|
|
230
|
+
ids: nodeIds,
|
|
231
|
+
lengths,
|
|
232
|
+
onReference,
|
|
233
|
+
referenceStart: referenceStart2,
|
|
234
|
+
referenceEnd
|
|
235
|
+
} = table;
|
|
218
236
|
const runs = [];
|
|
237
|
+
const visits = [];
|
|
219
238
|
let last;
|
|
220
239
|
let bp = 0;
|
|
221
240
|
let offReferenceBp = 0;
|
|
222
241
|
let gapBp = 0;
|
|
223
242
|
let step = 0;
|
|
243
|
+
const backwards = from >= 0 && from > to;
|
|
224
244
|
for (const node of ids) {
|
|
225
245
|
if (node < 0) {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
246
|
+
const parts = gaps[-node - 1];
|
|
247
|
+
for (const { bp: partBp, ...why } of backwards ? [...parts].reverse() : parts) {
|
|
248
|
+
last = {
|
|
249
|
+
start: bp,
|
|
250
|
+
bp: partBp,
|
|
251
|
+
onReference: false,
|
|
252
|
+
gap: true,
|
|
253
|
+
...why
|
|
254
|
+
};
|
|
255
|
+
runs.push(last);
|
|
256
|
+
bp += partBp;
|
|
257
|
+
gapBp += partBp;
|
|
258
|
+
}
|
|
230
259
|
step = 0;
|
|
231
260
|
continue;
|
|
232
261
|
}
|
|
233
262
|
const len = lengths[node];
|
|
234
263
|
const on = onReference[node] === 1;
|
|
264
|
+
visits.push({ node: nodeIds[node], start: bp, onReference: on });
|
|
235
265
|
const at = last?.referenceStart;
|
|
236
266
|
const forward = on && at !== void 0 && step >= 0 && at + last.bp === referenceStart2[node];
|
|
237
267
|
const backward = on && at !== void 0 && step <= 0 && referenceEnd[node] === at;
|
|
@@ -270,6 +300,7 @@ function walkRows(graph, region, unit) {
|
|
|
270
300
|
complete,
|
|
271
301
|
stop,
|
|
272
302
|
runs,
|
|
303
|
+
visits,
|
|
273
304
|
axis
|
|
274
305
|
};
|
|
275
306
|
};
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
encodedColor,
|
|
3
3
|
resolveEncoding
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-TABI4JEU.js";
|
|
5
5
|
import {
|
|
6
6
|
pathOrigin
|
|
7
7
|
} from "./chunk-B5X2RLJG.js";
|
|
8
|
+
import {
|
|
9
|
+
gapParts
|
|
10
|
+
} from "./chunk-EIY2SKD3.js";
|
|
8
11
|
import {
|
|
9
12
|
panSNContig
|
|
10
13
|
} from "./chunk-4XWZNPQ2.js";
|
|
@@ -68,6 +71,22 @@ function highlightOf(graph, name, { byId, edgeAt }) {
|
|
|
68
71
|
before += length;
|
|
69
72
|
});
|
|
70
73
|
}
|
|
74
|
+
let missingBp = 0;
|
|
75
|
+
let unknownBp = 0;
|
|
76
|
+
let end;
|
|
77
|
+
pieces.forEach((piece, p) => {
|
|
78
|
+
if (end !== void 0 && piece.start !== void 0 && piece.start > end) {
|
|
79
|
+
for (const part of gapParts(
|
|
80
|
+
piece.start - end,
|
|
81
|
+
pieces[p - 1].after,
|
|
82
|
+
piece.before
|
|
83
|
+
)) {
|
|
84
|
+
missingBp += part.cause === "missing" ? part.bp : 0;
|
|
85
|
+
unknownBp += part.cause === "unknown" ? part.bp : 0;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
end = piece.start === void 0 ? void 0 : piece.start + bpOf(piece);
|
|
89
|
+
});
|
|
71
90
|
const reference = isReference(graph, name);
|
|
72
91
|
const referenceSpan = () => {
|
|
73
92
|
const referencePieces = reference ? [] : (graph.paths ?? []).filter((p) => isReference(graph, p.name));
|
|
@@ -86,7 +105,9 @@ function highlightOf(graph, name, { byId, edgeAt }) {
|
|
|
86
105
|
progress,
|
|
87
106
|
steps: pieces.reduce((sum, piece) => sum + piece.nodeIds.length, 0),
|
|
88
107
|
bp,
|
|
89
|
-
referenceBp: referenceSpan()
|
|
108
|
+
referenceBp: referenceSpan(),
|
|
109
|
+
missingBp,
|
|
110
|
+
unknownBp
|
|
90
111
|
};
|
|
91
112
|
}
|
|
92
113
|
function laneColors(byId, walk, encoding, ramp) {
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
END_STOP_TAG,
|
|
3
|
+
START_STOP_TAG,
|
|
4
|
+
StopColumns,
|
|
5
|
+
parseStopTag
|
|
6
|
+
} from "./chunk-EIY2SKD3.js";
|
|
1
7
|
import {
|
|
2
8
|
Column
|
|
3
9
|
} from "./chunk-ZPZ7GNBT.js";
|
|
@@ -103,6 +109,7 @@ function readWalkBody(line, from, segments, steps) {
|
|
|
103
109
|
}
|
|
104
110
|
}
|
|
105
111
|
finish(i);
|
|
112
|
+
return i;
|
|
106
113
|
}
|
|
107
114
|
function walkFields(line) {
|
|
108
115
|
const fields = [];
|
|
@@ -159,6 +166,8 @@ function gfaTables(text) {
|
|
|
159
166
|
const walkEnds = [];
|
|
160
167
|
const offsets = [0];
|
|
161
168
|
const steps = stepColumns();
|
|
169
|
+
const before = new StopColumns();
|
|
170
|
+
const after = new StopColumns();
|
|
162
171
|
for (const raw of lines) {
|
|
163
172
|
if (raw.startsWith("L ")) {
|
|
164
173
|
const [, source, strand1, target, strand2] = trimCR(raw).split(" ");
|
|
@@ -174,7 +183,17 @@ function gfaTables(text) {
|
|
|
174
183
|
names.push(`${w.sample}#${w.haplotype}#${w.contig}`);
|
|
175
184
|
walkStarts.push(w.start === "*" ? 0 : +w.start);
|
|
176
185
|
walkEnds.push(w.end === "*" ? -1 : +w.end);
|
|
177
|
-
readWalkBody(line, w.body, segments, steps);
|
|
186
|
+
const end = readWalkBody(line, w.body, segments, steps);
|
|
187
|
+
const tags = walkTags(line, end);
|
|
188
|
+
if (tags === void 0) {
|
|
189
|
+
return void 0;
|
|
190
|
+
}
|
|
191
|
+
if (tags.before) {
|
|
192
|
+
before.push(tags.before);
|
|
193
|
+
}
|
|
194
|
+
if (tags.after) {
|
|
195
|
+
after.push(tags.after);
|
|
196
|
+
}
|
|
178
197
|
if (steps.nodes.length === offsets.at(-1)) {
|
|
179
198
|
return void 0;
|
|
180
199
|
}
|
|
@@ -182,6 +201,11 @@ function gfaTables(text) {
|
|
|
182
201
|
}
|
|
183
202
|
}
|
|
184
203
|
}
|
|
204
|
+
if ([before.kinds.length, after.kinds.length].some(
|
|
205
|
+
(n) => n > 0 && n < names.length
|
|
206
|
+
)) {
|
|
207
|
+
return void 0;
|
|
208
|
+
}
|
|
185
209
|
return {
|
|
186
210
|
nodes: {
|
|
187
211
|
names: segments.names,
|
|
@@ -202,8 +226,33 @@ function gfaTables(text) {
|
|
|
202
226
|
ends: Float64Array.from(walkEnds),
|
|
203
227
|
offsets: Int32Array.from(offsets),
|
|
204
228
|
steps: steps.nodes.data.slice(0, steps.nodes.length),
|
|
205
|
-
reversed: steps.reversed.data.slice(0, steps.reversed.length)
|
|
229
|
+
reversed: steps.reversed.data.slice(0, steps.reversed.length),
|
|
230
|
+
...stopColumns(names.length, before, after)
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function walkTags(line, from) {
|
|
235
|
+
const out = {};
|
|
236
|
+
for (const tag of from < line.length ? line.slice(from + 1).split(" ") : []) {
|
|
237
|
+
const value = tag.slice(5);
|
|
238
|
+
if (tag.startsWith(`${START_STOP_TAG}:Z:`)) {
|
|
239
|
+
out.before = parseStopTag(value);
|
|
240
|
+
if (!out.before) {
|
|
241
|
+
return void 0;
|
|
242
|
+
}
|
|
243
|
+
} else if (tag.startsWith(`${END_STOP_TAG}:Z:`)) {
|
|
244
|
+
out.after = parseStopTag(value);
|
|
245
|
+
if (!out.after) {
|
|
246
|
+
return void 0;
|
|
247
|
+
}
|
|
206
248
|
}
|
|
249
|
+
}
|
|
250
|
+
return out;
|
|
251
|
+
}
|
|
252
|
+
function stopColumns(walks, before, after) {
|
|
253
|
+
return {
|
|
254
|
+
...before.kinds.length === walks && walks > 0 ? { before: before.table() } : {},
|
|
255
|
+
...after.kinds.length === walks && walks > 0 ? { after: after.table() } : {}
|
|
207
256
|
};
|
|
208
257
|
}
|
|
209
258
|
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// src/gfa/walkStops.ts
|
|
2
|
+
var START_STOP_TAG = "ws";
|
|
3
|
+
var END_STOP_TAG = "we";
|
|
4
|
+
var STOP_KINDS = ["elsewhere", "break", "end"];
|
|
5
|
+
var GAP_CAUSE_TEXT = {
|
|
6
|
+
missing: "not in the graph",
|
|
7
|
+
elsewhere: "on nodes filed elsewhere",
|
|
8
|
+
unknown: "gap, cause unknown"
|
|
9
|
+
};
|
|
10
|
+
var OUTSIDE_TEXT = "outside the extracted subgraph";
|
|
11
|
+
function gapParts(bp, after, before) {
|
|
12
|
+
if (!after && !before) {
|
|
13
|
+
return [{ bp }];
|
|
14
|
+
}
|
|
15
|
+
const left = Math.min(after?.trimmed ?? 0, bp);
|
|
16
|
+
const right = Math.min(before?.trimmed ?? 0, bp - left);
|
|
17
|
+
let rest = bp - left - right;
|
|
18
|
+
const lead = after?.kind === "break" ? Math.min(after.bp, rest) : 0;
|
|
19
|
+
rest -= lead;
|
|
20
|
+
const trail = before?.kind === "break" ? Math.min(before.bp, rest) : 0;
|
|
21
|
+
rest -= trail;
|
|
22
|
+
const elsewhere = [after, before].find((s) => s?.kind === "elsewhere");
|
|
23
|
+
const parts = [
|
|
24
|
+
{ bp: left },
|
|
25
|
+
{ bp: lead, cause: "missing" },
|
|
26
|
+
elsewhere?.kind === "elsewhere" ? { bp: rest, cause: "elsewhere", chunk: elsewhere.chunk } : { bp: rest, cause: "unknown" },
|
|
27
|
+
{ bp: trail, cause: "missing" },
|
|
28
|
+
{ bp: right }
|
|
29
|
+
];
|
|
30
|
+
return parts.filter((part) => part.bp > 0);
|
|
31
|
+
}
|
|
32
|
+
function stopAt(table, i) {
|
|
33
|
+
const bp = table.bp[i];
|
|
34
|
+
const ref = table.chunkRefs[i];
|
|
35
|
+
return stopOf(
|
|
36
|
+
table.kindNames[table.kinds[i]],
|
|
37
|
+
Number.isNaN(bp) ? void 0 : bp,
|
|
38
|
+
table.trimmed[i],
|
|
39
|
+
ref < 0 ? void 0 : { refName: table.chunkRefNames[ref], start: table.chunkStarts[i] }
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
function stopOf(kind, bp, trimmed, chunk) {
|
|
43
|
+
const cut = trimmed > 0 ? { trimmed } : {};
|
|
44
|
+
if (kind === "elsewhere" && chunk) {
|
|
45
|
+
return { kind, chunk, ...bp === void 0 ? {} : { bp }, ...cut };
|
|
46
|
+
}
|
|
47
|
+
if (kind === "break" && bp !== void 0) {
|
|
48
|
+
return { kind, bp, ...chunk ? { chunk } : {}, ...cut };
|
|
49
|
+
}
|
|
50
|
+
return kind === "end" ? { kind, ...cut } : void 0;
|
|
51
|
+
}
|
|
52
|
+
function stopTag(stop) {
|
|
53
|
+
const parts = [stop.kind];
|
|
54
|
+
if ("bp" in stop && stop.bp !== void 0) {
|
|
55
|
+
parts.push(`bp=${stop.bp}`);
|
|
56
|
+
}
|
|
57
|
+
if (stop.trimmed) {
|
|
58
|
+
parts.push(`trimmed=${stop.trimmed}`);
|
|
59
|
+
}
|
|
60
|
+
if ("chunk" in stop && stop.chunk) {
|
|
61
|
+
parts.push(`chunk=${stop.chunk.refName}:${stop.chunk.start}`);
|
|
62
|
+
}
|
|
63
|
+
return parts.join(",");
|
|
64
|
+
}
|
|
65
|
+
function parseStopTag(value) {
|
|
66
|
+
const [kind, ...fields] = value.split(",");
|
|
67
|
+
let bp;
|
|
68
|
+
let trimmed = 0;
|
|
69
|
+
let chunk;
|
|
70
|
+
for (const field of fields) {
|
|
71
|
+
if (field.startsWith("bp=")) {
|
|
72
|
+
bp = +field.slice(3);
|
|
73
|
+
} else if (field.startsWith("trimmed=")) {
|
|
74
|
+
trimmed = +field.slice(8);
|
|
75
|
+
} else if (field.startsWith("chunk=")) {
|
|
76
|
+
const at = field.lastIndexOf(":");
|
|
77
|
+
chunk = { refName: field.slice(6, at), start: +field.slice(at + 1) };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return stopOf(kind, bp, trimmed, chunk);
|
|
81
|
+
}
|
|
82
|
+
function stopFields(before, after) {
|
|
83
|
+
return {
|
|
84
|
+
...before ? { before } : {},
|
|
85
|
+
...after ? { after } : {}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function walkStopFields(tags) {
|
|
89
|
+
const before = tags[START_STOP_TAG];
|
|
90
|
+
const after = tags[END_STOP_TAG];
|
|
91
|
+
return stopFields(
|
|
92
|
+
typeof before === "string" ? parseStopTag(before) : void 0,
|
|
93
|
+
typeof after === "string" ? parseStopTag(after) : void 0
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
function walkStopTags(walks, p) {
|
|
97
|
+
const tags = [];
|
|
98
|
+
for (const [tag, table] of [
|
|
99
|
+
[START_STOP_TAG, walks.before],
|
|
100
|
+
[END_STOP_TAG, walks.after]
|
|
101
|
+
]) {
|
|
102
|
+
const stop = table && stopAt(table, p);
|
|
103
|
+
if (stop) {
|
|
104
|
+
tags.push(` ${tag}:Z:${stopTag(stop)}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return tags.join("");
|
|
108
|
+
}
|
|
109
|
+
var StopColumns = class {
|
|
110
|
+
constructor() {
|
|
111
|
+
this.kinds = [];
|
|
112
|
+
this.bp = [];
|
|
113
|
+
this.trimmed = [];
|
|
114
|
+
this.chunkRefs = [];
|
|
115
|
+
this.chunkStarts = [];
|
|
116
|
+
this.chunkRefNames = [];
|
|
117
|
+
this.refIndex = /* @__PURE__ */ new Map();
|
|
118
|
+
}
|
|
119
|
+
push(stop) {
|
|
120
|
+
this.kinds.push(STOP_KINDS.indexOf(stop.kind));
|
|
121
|
+
this.bp.push("bp" in stop && stop.bp !== void 0 ? stop.bp : NaN);
|
|
122
|
+
this.trimmed.push(stop.trimmed ?? 0);
|
|
123
|
+
const chunk = "chunk" in stop ? stop.chunk : void 0;
|
|
124
|
+
if (chunk) {
|
|
125
|
+
let ref = this.refIndex.get(chunk.refName);
|
|
126
|
+
if (ref === void 0) {
|
|
127
|
+
ref = this.chunkRefNames.length;
|
|
128
|
+
this.refIndex.set(chunk.refName, ref);
|
|
129
|
+
this.chunkRefNames.push(chunk.refName);
|
|
130
|
+
}
|
|
131
|
+
this.chunkRefs.push(ref);
|
|
132
|
+
this.chunkStarts.push(chunk.start);
|
|
133
|
+
} else {
|
|
134
|
+
this.chunkRefs.push(-1);
|
|
135
|
+
this.chunkStarts.push(NaN);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
table() {
|
|
139
|
+
return {
|
|
140
|
+
kinds: Uint8Array.from(this.kinds),
|
|
141
|
+
kindNames: [...STOP_KINDS],
|
|
142
|
+
bp: Float64Array.from(this.bp),
|
|
143
|
+
trimmed: Float64Array.from(this.trimmed),
|
|
144
|
+
chunkRefs: Int32Array.from(this.chunkRefs),
|
|
145
|
+
chunkStarts: Float64Array.from(this.chunkStarts),
|
|
146
|
+
chunkRefNames: this.chunkRefNames
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
export {
|
|
152
|
+
START_STOP_TAG,
|
|
153
|
+
END_STOP_TAG,
|
|
154
|
+
GAP_CAUSE_TEXT,
|
|
155
|
+
OUTSIDE_TEXT,
|
|
156
|
+
gapParts,
|
|
157
|
+
stopAt,
|
|
158
|
+
stopTag,
|
|
159
|
+
parseStopTag,
|
|
160
|
+
stopFields,
|
|
161
|
+
walkStopFields,
|
|
162
|
+
walkStopTags,
|
|
163
|
+
StopColumns
|
|
164
|
+
};
|
|
@@ -5,6 +5,9 @@ import {
|
|
|
5
5
|
pathOrigin,
|
|
6
6
|
surveyPaths
|
|
7
7
|
} from "./chunk-B5X2RLJG.js";
|
|
8
|
+
import {
|
|
9
|
+
walkStopFields
|
|
10
|
+
} from "./chunk-EIY2SKD3.js";
|
|
8
11
|
|
|
9
12
|
// src/gfa/gfaConverter.ts
|
|
10
13
|
function surveySegments(gfaGraph, pathSteps) {
|
|
@@ -152,7 +155,8 @@ function convertGFAToGraph(gfaGraph, name = "Imported GFA") {
|
|
|
152
155
|
start: walkStart(walk),
|
|
153
156
|
sample: walk.sample,
|
|
154
157
|
haplotype: walk.haplotype,
|
|
155
|
-
contig: walk.contig
|
|
158
|
+
contig: walk.contig,
|
|
159
|
+
...walkStopFields(walk.tags)
|
|
156
160
|
});
|
|
157
161
|
recordPathEdges(nodeIds2, name2);
|
|
158
162
|
}
|
|
@@ -4,27 +4,27 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
facetLifts,
|
|
6
6
|
walkLift
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-DR24UTRS.js";
|
|
8
8
|
import {
|
|
9
9
|
walkKey
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-D4ZFRBB4.js";
|
|
11
11
|
import {
|
|
12
12
|
buildGeometry,
|
|
13
13
|
computeReferenceRamp
|
|
14
14
|
} from "./chunk-SWCULW6S.js";
|
|
15
15
|
import {
|
|
16
16
|
walkRowsExtent
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-YHJ5JLBI.js";
|
|
18
18
|
import {
|
|
19
19
|
pathLegend,
|
|
20
20
|
walkLabelsOf
|
|
21
21
|
} from "./chunk-3GP3KT5L.js";
|
|
22
22
|
import {
|
|
23
23
|
FIGURE_DEFAULTS
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-W6EXQDV5.js";
|
|
25
25
|
import {
|
|
26
26
|
drawingBounds
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-KDU4EF66.js";
|
|
28
28
|
import {
|
|
29
29
|
referenceLabel
|
|
30
30
|
} from "./chunk-234NFZS4.js";
|
|
@@ -97,7 +97,7 @@ function figureScene(graph, layout, o) {
|
|
|
97
97
|
referenceName,
|
|
98
98
|
keyText: (walk) => {
|
|
99
99
|
const key = walkKey(walk, reference);
|
|
100
|
-
return { note: key.delta + key.
|
|
100
|
+
return { note: key.delta + key.gaps + key.reversed, scale: key.scale };
|
|
101
101
|
},
|
|
102
102
|
contigThickness,
|
|
103
103
|
nodeWidth,
|
|
@@ -3,14 +3,14 @@ import {
|
|
|
3
3
|
boxesGenes,
|
|
4
4
|
rowPitch,
|
|
5
5
|
rowSpan
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-XZ6PQBU6.js";
|
|
7
7
|
import {
|
|
8
8
|
el
|
|
9
9
|
} from "./chunk-H2H4Y3TV.js";
|
|
10
10
|
import {
|
|
11
11
|
READOUT_ROOM,
|
|
12
12
|
longestBar
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-YHJ5JLBI.js";
|
|
14
14
|
import {
|
|
15
15
|
pathOrigin
|
|
16
16
|
} from "./chunk-B5X2RLJG.js";
|