@jbrowse/bandage-core 9.1.0 → 9.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bubbles/bubbleHalos.js +3 -1
- package/dist/bubbles/superbubbles.js +3 -5
- package/dist/chunks/{chunk-GJMC3PGM.js → chunk-3FOOZ5VL.js} +15 -14
- package/dist/chunks/{chunk-FFFQNQUI.js → chunk-A4MYLGKG.js} +1 -1
- package/dist/chunks/{chunk-2AWUWGAD.js → chunk-ABOZYAN5.js} +4 -0
- package/dist/chunks/chunk-B4645SM2.js +358 -0
- package/dist/chunks/chunk-B4YH42OP.js +24 -0
- package/dist/chunks/{chunk-XLCTQHBE.js → chunk-BLRJ6IGK.js} +1 -1
- package/dist/chunks/{chunk-UID3QBWH.js → chunk-BTMPPLDF.js} +1 -1
- package/dist/chunks/{chunk-RRZMMYBG.js → chunk-BV64PQ2C.js} +1 -1
- package/dist/chunks/{chunk-W253V6RR.js → chunk-CVYDR2OP.js} +1 -1
- package/dist/chunks/{chunk-MIW3HYPE.js → chunk-GFRPX6M2.js} +2 -2
- package/dist/chunks/{chunk-MBB7ATM6.js → chunk-LFKMASER.js} +1 -1
- package/dist/chunks/{chunk-6ZNQJ5ZD.js → chunk-OXTR3BVF.js} +1 -1
- package/dist/chunks/{chunk-FUVI4WQP.js → chunk-ROYHPOYF.js} +7 -7
- package/dist/chunks/{chunk-3TGUKQWQ.js → chunk-TL3TYSCP.js} +22 -22
- package/dist/chunks/{chunk-WDTXW7T2.js → chunk-UD5FOCI2.js} +1 -1
- package/dist/chunks/{chunk-MXDQGA7A.js → chunk-XKM5OHQQ.js} +1 -1
- package/dist/chunks/{chunk-DPV2CUIE.js → chunk-XPT66H6H.js} +1 -1
- package/dist/cli/figure.js +27 -27
- package/dist/cli/fold.js +72 -0
- package/dist/figure.js +17 -17
- package/dist/figureSettings.js +4 -4
- package/dist/foldVariants.js +9 -0
- package/dist/gfa/writeRgfa.js +6 -0
- package/dist/index.js +63 -63
- package/dist/labelLayout.js +1 -1
- package/dist/layout/forceCache.js +4 -4
- package/dist/layout/trimToWindow.js +13 -0
- package/dist/layout/walkRowDraw.js +4 -4
- package/dist/layout/walkStrip.js +5 -5
- package/dist/layoutModes.js +2 -2
- package/dist/pipeline.js +3 -3
- package/dist/referenceRampCss.js +3 -3
- package/dist/referenceStrip.js +3 -3
- package/dist/renderer/GeometryBuilder.js +2 -2
- package/dist/tubeMap/nodeColors.js +3 -3
- package/dist/types/bubbles/bubbleHalos.d.ts +2 -0
- package/dist/types/bubbles/superbubbles.d.ts +0 -1
- package/dist/types/cli/fold.d.ts +1 -0
- package/dist/types/foldVariants.d.ts +2 -0
- package/dist/types/gfa/writeRgfa.d.ts +2 -0
- package/dist/types/labelLayout.d.ts +6 -0
- package/dist/types/layout/trimToWindow.d.ts +4 -0
- package/dist/types/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/viewport.js +4 -4
- package/dist/walkEncoding.js +3 -3
- package/dist/walkHighlight.js +4 -4
- package/package.json +3 -2
- package/dist/chunks/{chunk-HBEKUQO4.js → chunk-BR25DGIJ.js} +4 -4
- package/dist/chunks/{chunk-WNUZP3WQ.js → chunk-M7SRZJ32.js} +3 -3
- package/dist/chunks/{chunk-OOXIMURX.js → chunk-ZGRYFUXE.js} +8 -8
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
|
+
SMALL_VARIANT_BP,
|
|
2
3
|
WHOLE_FRACTION,
|
|
3
4
|
bubbleHalos,
|
|
4
5
|
coversGraph
|
|
5
|
-
} from "../chunks/chunk-
|
|
6
|
+
} from "../chunks/chunk-ABOZYAN5.js";
|
|
6
7
|
import "../chunks/chunk-XKWD2RY3.js";
|
|
7
8
|
import "../chunks/chunk-FX4RDMDN.js";
|
|
8
9
|
import "../chunks/chunk-2CVHXFK7.js";
|
|
9
10
|
import "../chunks/chunk-CPMHA4W5.js";
|
|
10
11
|
import "../chunks/chunk-FYQWPEEY.js";
|
|
11
12
|
export {
|
|
13
|
+
SMALL_VARIANT_BP,
|
|
12
14
|
WHOLE_FRACTION,
|
|
13
15
|
bubbleHalos,
|
|
14
16
|
coversGraph
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
|
-
MAX_SUPERBUBBLES,
|
|
3
2
|
graphBubbles,
|
|
4
3
|
superbubblesFromGraph
|
|
5
|
-
} from "../chunks/chunk-
|
|
4
|
+
} from "../chunks/chunk-ROYHPOYF.js";
|
|
6
5
|
import "../chunks/chunk-VHW7FDHU.js";
|
|
7
|
-
import "../chunks/chunk-
|
|
8
|
-
import "../chunks/chunk-GOZYKNQ2.js";
|
|
6
|
+
import "../chunks/chunk-ABOZYAN5.js";
|
|
9
7
|
import "../chunks/chunk-XKWD2RY3.js";
|
|
8
|
+
import "../chunks/chunk-GOZYKNQ2.js";
|
|
10
9
|
import "../chunks/chunk-FX4RDMDN.js";
|
|
11
10
|
import "../chunks/chunk-HNQPEMYE.js";
|
|
12
11
|
import "../chunks/chunk-ST2IBUAN.js";
|
|
@@ -15,7 +14,6 @@ import "../chunks/chunk-2CVHXFK7.js";
|
|
|
15
14
|
import "../chunks/chunk-CPMHA4W5.js";
|
|
16
15
|
import "../chunks/chunk-FYQWPEEY.js";
|
|
17
16
|
export {
|
|
18
|
-
MAX_SUPERBUBBLES,
|
|
19
17
|
graphBubbles,
|
|
20
18
|
superbubblesFromGraph
|
|
21
19
|
};
|
|
@@ -92,24 +92,24 @@ function layoutLabels(m) {
|
|
|
92
92
|
const onRows = m.drawnRowLabels.length > 0;
|
|
93
93
|
const rowsTop = onRows ? Math.min(...m.drawnRowLabels.map((r) => r.y)) : Infinity;
|
|
94
94
|
const halo = m.contigThickness * HALO_FACTOR;
|
|
95
|
-
const
|
|
95
|
+
const above = (h, gap) => {
|
|
96
|
+
const { x, y } = screen({
|
|
97
|
+
x: h.labelAt.x,
|
|
98
|
+
y: Math.min(h.labelAt.y, rowsTop)
|
|
99
|
+
});
|
|
100
|
+
const baseline = y - halo / 2 - gap;
|
|
101
|
+
return { x, y: onRows ? Math.max(baseline, TOPMOST_BASELINE) : baseline };
|
|
102
|
+
};
|
|
103
|
+
const byBubble = byExtent(
|
|
104
|
+
m.bubbleHalos.filter((h) => !h.tick),
|
|
105
|
+
(h) => h.members
|
|
106
|
+
);
|
|
96
107
|
const bubbles = placeLabels(
|
|
97
|
-
byBubble.map((h) => {
|
|
98
|
-
const { x, y } = screen({
|
|
99
|
-
x: h.labelAt.x,
|
|
100
|
-
y: Math.min(h.labelAt.y, rowsTop)
|
|
101
|
-
});
|
|
102
|
-
const baseline = y - halo / 2 - 6;
|
|
103
|
-
return {
|
|
104
|
-
item: h,
|
|
105
|
-
x,
|
|
106
|
-
y: onRows ? Math.max(baseline, TOPMOST_BASELINE) : baseline,
|
|
107
|
-
text: h.label
|
|
108
|
-
};
|
|
109
|
-
}),
|
|
108
|
+
byBubble.map((h) => ({ item: h, ...above(h, 6), text: h.label })),
|
|
110
109
|
frame,
|
|
111
110
|
take
|
|
112
111
|
);
|
|
112
|
+
const ticks = m.bubbleHalos.filter((h) => h.tick && !h.whole).map((h) => ({ item: h, ...above(h, 2) })).filter((t) => t.x >= 0 && t.x <= width && t.y >= 0 && t.y <= height);
|
|
113
113
|
const genes = placeLabels(
|
|
114
114
|
geneLabelCandidates(
|
|
115
115
|
m.genePins,
|
|
@@ -162,6 +162,7 @@ function layoutLabels(m) {
|
|
|
162
162
|
);
|
|
163
163
|
return {
|
|
164
164
|
bubbles,
|
|
165
|
+
ticks,
|
|
165
166
|
genes,
|
|
166
167
|
routes,
|
|
167
168
|
sizes: [...deletionLabels, ...nodeLabels]
|
|
@@ -15,6 +15,7 @@ var WHOLE_FRACTION = 0.9;
|
|
|
15
15
|
function coversGraph(members, nodes) {
|
|
16
16
|
return members + 2 >= nodes || members >= WHOLE_FRACTION * nodes;
|
|
17
17
|
}
|
|
18
|
+
var SMALL_VARIANT_BP = 50;
|
|
18
19
|
var NAMED_WALKS = 2;
|
|
19
20
|
var MIN_CHIPPED_BP = 1e3;
|
|
20
21
|
function bubbleHalos(graph, bubbles, positions, walkLabel = (name) => name, repeats = []) {
|
|
@@ -95,6 +96,8 @@ function bubbleHalos(graph, bubbles, positions, walkLabel = (name) => name, repe
|
|
|
95
96
|
members: nodeIds.length,
|
|
96
97
|
nodeIds,
|
|
97
98
|
whole: coversGraph(nodeIds.length, graph.nodes.length),
|
|
99
|
+
// a partial bubble's lengths are a floor, so it may be no small variant
|
|
100
|
+
tick: !bubble.partial && bubble.longestAlleleLength < SMALL_VARIANT_BP,
|
|
98
101
|
routes
|
|
99
102
|
});
|
|
100
103
|
}
|
|
@@ -110,5 +113,6 @@ function routeText(route, walkLabel) {
|
|
|
110
113
|
export {
|
|
111
114
|
WHOLE_FRACTION,
|
|
112
115
|
coversGraph,
|
|
116
|
+
SMALL_VARIANT_BP,
|
|
113
117
|
bubbleHalos
|
|
114
118
|
};
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ownStrand
|
|
3
|
+
} from "./chunk-2CVHXFK7.js";
|
|
4
|
+
import {
|
|
5
|
+
isBackbone
|
|
6
|
+
} from "./chunk-FYQWPEEY.js";
|
|
7
|
+
|
|
8
|
+
// src/foldVariants.ts
|
|
9
|
+
function foldVariants(graph, belowBp) {
|
|
10
|
+
if (!(belowBp > 0) || graph.paths?.length || !graph.nodes.some((node) => isBackbone(node))) {
|
|
11
|
+
return graph;
|
|
12
|
+
}
|
|
13
|
+
const { nodes, edges } = graph;
|
|
14
|
+
const index = new Map(nodes.map((node, i) => [node.id, i]));
|
|
15
|
+
const sides = edges.map(forwardSides);
|
|
16
|
+
const links = linksAt(nodes.length, edges, sides, index);
|
|
17
|
+
const allele = alleleOf(nodes, edges, sides, index);
|
|
18
|
+
const members = groupBy(allele);
|
|
19
|
+
const kept = new Uint8Array(nodes.length);
|
|
20
|
+
const big = [];
|
|
21
|
+
for (const group of members.values()) {
|
|
22
|
+
if (alleleContent(group, nodes, links, allele) >= belowBp) {
|
|
23
|
+
for (const i of group) {
|
|
24
|
+
kept[i] = 1;
|
|
25
|
+
}
|
|
26
|
+
if (!isBackbone(nodes[group[0]])) {
|
|
27
|
+
big.push(group);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const { dist, pred } = distancesFromBackbone(nodes, links);
|
|
32
|
+
for (const group of big) {
|
|
33
|
+
for (const [i, side] of alleleEnds(group, nodes, links, allele)) {
|
|
34
|
+
let next = nearestOutside(i, side, links, allele, dist, nodes);
|
|
35
|
+
while (next !== void 0 && !kept[next]) {
|
|
36
|
+
kept[next] = 1;
|
|
37
|
+
next = isBackbone(nodes[next]) ? void 0 : pred[next];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const keptEdges = edges.filter((edge, k) => {
|
|
42
|
+
const a = index.get(edge.from);
|
|
43
|
+
const b = index.get(edge.to);
|
|
44
|
+
if (a === void 0 || b === void 0) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
const skip = skipped(nodes[a], sides[k].from, nodes[b], sides[k].to);
|
|
48
|
+
return kept[a] && kept[b] && !(skip > 0 && skip < belowBp);
|
|
49
|
+
});
|
|
50
|
+
return mergeAlleleRuns({ ...graph, edges: keptEdges }, kept, allele);
|
|
51
|
+
}
|
|
52
|
+
function forwardSides(edge) {
|
|
53
|
+
return {
|
|
54
|
+
from: (edge.fromStrand ?? ownStrand(edge.from)) === "+" ? "e" : "s",
|
|
55
|
+
to: (edge.toStrand ?? ownStrand(edge.to)) === "+" ? "s" : "e"
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function linksAt(count, edges, sides, index) {
|
|
59
|
+
const links = Array.from({ length: count }, () => []);
|
|
60
|
+
edges.forEach((edge, k) => {
|
|
61
|
+
const a = index.get(edge.from);
|
|
62
|
+
const b = index.get(edge.to);
|
|
63
|
+
if (a !== void 0 && b !== void 0) {
|
|
64
|
+
links[a].push({ other: b, side: sides[k].from });
|
|
65
|
+
links[b].push({ other: a, side: sides[k].to });
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
return links;
|
|
69
|
+
}
|
|
70
|
+
function onOneSequence(a, b) {
|
|
71
|
+
const sa = a.stable;
|
|
72
|
+
const sb = b.stable;
|
|
73
|
+
return sa && sb?.refName === sa.refName && sb.rank === sa.rank ? [sa, sb] : void 0;
|
|
74
|
+
}
|
|
75
|
+
function continues(a, aSide, b, bSide) {
|
|
76
|
+
const pair = onOneSequence(a, b);
|
|
77
|
+
if (!pair || aSide === bSide) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
const [sa, sb] = pair;
|
|
81
|
+
return sa.start + a.length === sb.start || sb.start + b.length === sa.start;
|
|
82
|
+
}
|
|
83
|
+
function skipped(a, aSide, b, bSide) {
|
|
84
|
+
const pair = onOneSequence(a, b);
|
|
85
|
+
if (!pair || continues(a, aSide, b, bSide)) {
|
|
86
|
+
return 0;
|
|
87
|
+
}
|
|
88
|
+
const [sa, sb] = pair;
|
|
89
|
+
return Math.max(
|
|
90
|
+
sb.start - (sa.start + a.length),
|
|
91
|
+
sa.start - (sb.start + b.length)
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
function alleleOf(nodes, edges, sides, index) {
|
|
95
|
+
const parent = nodes.map((_, i) => i);
|
|
96
|
+
const find = (i) => {
|
|
97
|
+
while (parent[i] !== i) {
|
|
98
|
+
parent[i] = parent[parent[i]];
|
|
99
|
+
i = parent[i];
|
|
100
|
+
}
|
|
101
|
+
return i;
|
|
102
|
+
};
|
|
103
|
+
edges.forEach((edge, k) => {
|
|
104
|
+
const a = index.get(edge.from);
|
|
105
|
+
const b = index.get(edge.to);
|
|
106
|
+
if (a !== void 0 && b !== void 0 && continues(nodes[a], sides[k].from, nodes[b], sides[k].to)) {
|
|
107
|
+
parent[find(a)] = find(b);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
return nodes.map((_, i) => find(i));
|
|
111
|
+
}
|
|
112
|
+
function groupBy(allele) {
|
|
113
|
+
const groups = /* @__PURE__ */ new Map();
|
|
114
|
+
allele.forEach((root, i) => {
|
|
115
|
+
const group = groups.get(root);
|
|
116
|
+
if (group) {
|
|
117
|
+
group.push(i);
|
|
118
|
+
} else {
|
|
119
|
+
groups.set(root, [i]);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
return groups;
|
|
123
|
+
}
|
|
124
|
+
function alleleContent(group, nodes, links, allele) {
|
|
125
|
+
if (isBackbone(nodes[group[0]])) {
|
|
126
|
+
return Infinity;
|
|
127
|
+
}
|
|
128
|
+
let length = 0;
|
|
129
|
+
let refName;
|
|
130
|
+
let lo = Infinity;
|
|
131
|
+
let hi = -Infinity;
|
|
132
|
+
let oneSequence = true;
|
|
133
|
+
for (const i of group) {
|
|
134
|
+
length += nodes[i].length;
|
|
135
|
+
for (const { other } of links[i]) {
|
|
136
|
+
const node = nodes[other];
|
|
137
|
+
if (allele[other] !== allele[i] && isBackbone(node)) {
|
|
138
|
+
refName ??= node.stable.refName;
|
|
139
|
+
oneSequence &&= node.stable.refName === refName;
|
|
140
|
+
lo = Math.min(lo, node.stable.start + node.length);
|
|
141
|
+
hi = Math.max(hi, node.stable.start);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return oneSequence && hi > lo ? Math.max(length, hi - lo) : length;
|
|
146
|
+
}
|
|
147
|
+
function alleleEnds(group, nodes, links, allele) {
|
|
148
|
+
const start = (i) => nodes[i].stable?.start ?? 0;
|
|
149
|
+
const end = (i) => start(i) + nodes[i].length;
|
|
150
|
+
let first = group[0];
|
|
151
|
+
let last = group[0];
|
|
152
|
+
for (const i of group) {
|
|
153
|
+
if (start(i) < start(first)) {
|
|
154
|
+
first = i;
|
|
155
|
+
}
|
|
156
|
+
if (end(i) > end(last)) {
|
|
157
|
+
last = i;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const ends = [];
|
|
161
|
+
for (const i of /* @__PURE__ */ new Set([first, last])) {
|
|
162
|
+
for (const side of ["s", "e"]) {
|
|
163
|
+
if (!links[i].some(
|
|
164
|
+
(link) => link.side === side && allele[link.other] === allele[i]
|
|
165
|
+
)) {
|
|
166
|
+
ends.push([i, side]);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return ends;
|
|
171
|
+
}
|
|
172
|
+
function nearestOutside(i, side, links, allele, dist, nodes) {
|
|
173
|
+
let best;
|
|
174
|
+
for (const link of links[i]) {
|
|
175
|
+
const j = link.other;
|
|
176
|
+
if (link.side === side && allele[j] !== allele[i] && Number.isFinite(dist[j]) && (best === void 0 || dist[j] < dist[best] || dist[j] === dist[best] && nodes[j].id < nodes[best].id)) {
|
|
177
|
+
best = j;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return best;
|
|
181
|
+
}
|
|
182
|
+
function distancesFromBackbone(nodes, links) {
|
|
183
|
+
const dist = new Float64Array(nodes.length).fill(Infinity);
|
|
184
|
+
const pred = new Int32Array(nodes.length).fill(-1);
|
|
185
|
+
const heap = new MinHeap(
|
|
186
|
+
([da, a], [db, b]) => da - db || cmp(nodes[a].id, nodes[b].id)
|
|
187
|
+
);
|
|
188
|
+
nodes.forEach((node, i) => {
|
|
189
|
+
if (isBackbone(node)) {
|
|
190
|
+
dist[i] = 0;
|
|
191
|
+
heap.push([0, i]);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
for (let top = heap.pop(); top !== void 0; top = heap.pop()) {
|
|
195
|
+
const [d0, i] = top;
|
|
196
|
+
if (d0 > dist[i]) {
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
for (const { other } of links[i]) {
|
|
200
|
+
if (isBackbone(nodes[other])) {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
const d = d0 + nodes[other].length;
|
|
204
|
+
if (d < dist[other]) {
|
|
205
|
+
dist[other] = d;
|
|
206
|
+
pred[other] = i;
|
|
207
|
+
heap.push([d, other]);
|
|
208
|
+
} else if (d === dist[other] && cmp(nodes[i].id, nodes[pred[other]].id) < 0) {
|
|
209
|
+
pred[other] = i;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return { dist, pred: Array.from(pred, (p) => p < 0 ? void 0 : p) };
|
|
214
|
+
}
|
|
215
|
+
function cmp(a, b) {
|
|
216
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
217
|
+
}
|
|
218
|
+
var MinHeap = class {
|
|
219
|
+
constructor(order) {
|
|
220
|
+
this.order = order;
|
|
221
|
+
this.items = [];
|
|
222
|
+
}
|
|
223
|
+
push(item) {
|
|
224
|
+
const { items } = this;
|
|
225
|
+
items.push(item);
|
|
226
|
+
let i = items.length - 1;
|
|
227
|
+
while (i > 0) {
|
|
228
|
+
const up = i - 1 >> 1;
|
|
229
|
+
if (this.order(items[i], items[up]) >= 0) {
|
|
230
|
+
break;
|
|
231
|
+
}
|
|
232
|
+
;
|
|
233
|
+
[items[i], items[up]] = [items[up], items[i]];
|
|
234
|
+
i = up;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
pop() {
|
|
238
|
+
const { items } = this;
|
|
239
|
+
const top = items[0];
|
|
240
|
+
const last = items.pop();
|
|
241
|
+
if (items.length > 0 && last !== void 0) {
|
|
242
|
+
items[0] = last;
|
|
243
|
+
let i = 0;
|
|
244
|
+
for (; ; ) {
|
|
245
|
+
const l = 2 * i + 1;
|
|
246
|
+
const r = l + 1;
|
|
247
|
+
let m = i;
|
|
248
|
+
if (l < items.length && this.order(items[l], items[m]) < 0) {
|
|
249
|
+
m = l;
|
|
250
|
+
}
|
|
251
|
+
if (r < items.length && this.order(items[r], items[m]) < 0) {
|
|
252
|
+
m = r;
|
|
253
|
+
}
|
|
254
|
+
if (m === i) {
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
;
|
|
258
|
+
[items[i], items[m]] = [items[m], items[i]];
|
|
259
|
+
i = m;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return top;
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
function mergeAlleleRuns(graph, kept, allele) {
|
|
266
|
+
const { nodes, edges } = graph;
|
|
267
|
+
const index = new Map(nodes.map((node, i) => [node.id, i]));
|
|
268
|
+
const sides = edges.map(forwardSides);
|
|
269
|
+
const ends = edges.map((edge, k) => [
|
|
270
|
+
{ i: index.get(edge.from), side: sides[k].from },
|
|
271
|
+
{ i: index.get(edge.to), side: sides[k].to }
|
|
272
|
+
]);
|
|
273
|
+
const degree = /* @__PURE__ */ new Map();
|
|
274
|
+
const sideKey = (i, side) => `${i}${side}`;
|
|
275
|
+
for (const pair of ends) {
|
|
276
|
+
for (const { i, side } of pair) {
|
|
277
|
+
degree.set(sideKey(i, side), (degree.get(sideKey(i, side)) ?? 0) + 1);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
const next = /* @__PURE__ */ new Map();
|
|
281
|
+
const hasPrev = /* @__PURE__ */ new Set();
|
|
282
|
+
const internal = /* @__PURE__ */ new Set();
|
|
283
|
+
ends.forEach(([a, b], k) => {
|
|
284
|
+
if (a.i !== b.i && allele[a.i] === allele[b.i] && continues(nodes[a.i], a.side, nodes[b.i], b.side) && degree.get(sideKey(a.i, a.side)) === 1 && degree.get(sideKey(b.i, b.side)) === 1) {
|
|
285
|
+
const [left, right] = nodes[a.i].stable.start < nodes[b.i].stable.start ? [a, b] : [b, a];
|
|
286
|
+
next.set(left.i, { j: right.i, out: left.side, in: right.side });
|
|
287
|
+
hasPrev.add(right.i);
|
|
288
|
+
internal.add(k);
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
const headOf = nodes.map((_, i) => i);
|
|
292
|
+
const outer = /* @__PURE__ */ new Map();
|
|
293
|
+
const merged = /* @__PURE__ */ new Map();
|
|
294
|
+
nodes.forEach((_, i) => {
|
|
295
|
+
if (!kept[i] || hasPrev.has(i) || !next.has(i)) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const run = [i];
|
|
299
|
+
let into = flip(next.get(i).out);
|
|
300
|
+
outer.set(sideKey(i, into), "s");
|
|
301
|
+
for (let step = next.get(i); step; step = next.get(step.j)) {
|
|
302
|
+
run.push(step.j);
|
|
303
|
+
into = step.in;
|
|
304
|
+
}
|
|
305
|
+
outer.set(sideKey(run.at(-1), flip(into)), "e");
|
|
306
|
+
for (const j of run) {
|
|
307
|
+
headOf[j] = i;
|
|
308
|
+
}
|
|
309
|
+
merged.set(i, mergedNode(run.map((j) => nodes[j])));
|
|
310
|
+
});
|
|
311
|
+
const endpoint = ({ i, side }) => ({
|
|
312
|
+
id: nodes[headOf[i]].id,
|
|
313
|
+
side: headOf[i] === i && !merged.has(i) ? side : outer.get(sideKey(i, side))
|
|
314
|
+
});
|
|
315
|
+
return {
|
|
316
|
+
...graph,
|
|
317
|
+
nodes: nodes.flatMap(
|
|
318
|
+
(node, i) => !kept[i] || headOf[i] !== i ? [] : [merged.get(i) ?? node]
|
|
319
|
+
),
|
|
320
|
+
edges: edges.flatMap((edge, k) => {
|
|
321
|
+
if (internal.has(k)) {
|
|
322
|
+
return [];
|
|
323
|
+
}
|
|
324
|
+
const [a, b] = ends[k];
|
|
325
|
+
if (!merged.has(headOf[a.i]) && !merged.has(headOf[b.i])) {
|
|
326
|
+
return [edge];
|
|
327
|
+
}
|
|
328
|
+
const from = endpoint(a);
|
|
329
|
+
const to = endpoint(b);
|
|
330
|
+
return [
|
|
331
|
+
{
|
|
332
|
+
...edge,
|
|
333
|
+
from: from.id,
|
|
334
|
+
to: to.id,
|
|
335
|
+
fromStrand: from.side === "e" ? "+" : "-",
|
|
336
|
+
toStrand: to.side === "s" ? "+" : "-"
|
|
337
|
+
}
|
|
338
|
+
];
|
|
339
|
+
})
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
function flip(side) {
|
|
343
|
+
return side === "s" ? "e" : "s";
|
|
344
|
+
}
|
|
345
|
+
function mergedNode(run) {
|
|
346
|
+
const { samples: firstSamples, ...first } = run[0];
|
|
347
|
+
const length = run.reduce((sum, node) => sum + node.length, 0);
|
|
348
|
+
const depth = length > 0 ? run.reduce((sum, node) => sum + node.depth * node.length, 0) / length : first.depth;
|
|
349
|
+
const samples = run.every((node) => node.samples) ? run.reduce(
|
|
350
|
+
(common, node) => common.filter((s) => node.samples.includes(s)),
|
|
351
|
+
firstSamples
|
|
352
|
+
) : void 0;
|
|
353
|
+
return samples ? { ...first, length, depth, samples } : { ...first, length, depth };
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
export {
|
|
357
|
+
foldVariants
|
|
358
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// src/gfa/writeRgfa.ts
|
|
2
|
+
function writeRgfa(graph) {
|
|
3
|
+
const nameOf = new Map(graph.nodes.map((n) => [n.id, n.name]));
|
|
4
|
+
return [
|
|
5
|
+
"H VN:Z:1.0",
|
|
6
|
+
...graph.nodes.map(segmentLine),
|
|
7
|
+
...graph.edges.map(
|
|
8
|
+
(e) => `L ${nameOf.get(e.from)} ${e.fromStrand ?? "+"} ${nameOf.get(e.to)} ${e.toStrand ?? "+"} 0M`
|
|
9
|
+
),
|
|
10
|
+
""
|
|
11
|
+
].join("\n");
|
|
12
|
+
}
|
|
13
|
+
function segmentLine(node) {
|
|
14
|
+
const { stable } = node;
|
|
15
|
+
if (!stable) {
|
|
16
|
+
throw new Error(`segment ${node.name} has no stable coordinate to file`);
|
|
17
|
+
}
|
|
18
|
+
const samples = node.samples?.length ? ` SM:Z:${node.samples.join(",")}` : "";
|
|
19
|
+
return `S ${node.name} * LN:i:${node.length} SN:Z:${stable.refName} SO:i:${stable.start} SR:i:${stable.rank}${samples}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export {
|
|
23
|
+
writeRgfa
|
|
24
|
+
};
|
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
RAMP_GRADIENT_STOPS,
|
|
4
4
|
rampHueCss,
|
|
5
5
|
rampStops
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-OXTR3BVF.js";
|
|
7
7
|
import {
|
|
8
8
|
REFERENCE_RAMP_ALT_CSS
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-BR25DGIJ.js";
|
|
10
10
|
import {
|
|
11
11
|
LABEL_CHAR_PX
|
|
12
12
|
} from "./chunk-AB35TJST.js";
|
|
@@ -3,15 +3,15 @@ import {
|
|
|
3
3
|
} from "./chunk-VHW7FDHU.js";
|
|
4
4
|
import {
|
|
5
5
|
coversGraph
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-ABOZYAN5.js";
|
|
7
|
+
import {
|
|
8
|
+
bubbleSegmentIds
|
|
9
|
+
} from "./chunk-XKWD2RY3.js";
|
|
7
10
|
import {
|
|
8
11
|
bubblesFromGraph,
|
|
9
12
|
walkIndexOf,
|
|
10
13
|
walkRoutes
|
|
11
14
|
} from "./chunk-GOZYKNQ2.js";
|
|
12
|
-
import {
|
|
13
|
-
bubbleSegmentIds
|
|
14
|
-
} from "./chunk-XKWD2RY3.js";
|
|
15
15
|
import {
|
|
16
16
|
SATURATED_PATH_COUNT
|
|
17
17
|
} from "./chunk-FX4RDMDN.js";
|
|
@@ -23,7 +23,6 @@ import {
|
|
|
23
23
|
} from "./chunk-FYQWPEEY.js";
|
|
24
24
|
|
|
25
25
|
// src/bubbles/superbubbles.ts
|
|
26
|
-
var MAX_SUPERBUBBLES = 50;
|
|
27
26
|
function slotGraph(graph, index) {
|
|
28
27
|
const slots = graph.nodes.length * 2;
|
|
29
28
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -224,7 +223,9 @@ function superbubblesFromGraph(graph, span) {
|
|
|
224
223
|
(j) => j !== i && !covers[j] && members[j].length > members[i].length && members[i].every((v) => holders.get(v).includes(j))
|
|
225
224
|
);
|
|
226
225
|
const placed = (f) => span !== void 0 || onReference(nodes[f.source >> 1], nodes[f.sink >> 1]);
|
|
227
|
-
const outermost = found.filter(
|
|
226
|
+
const outermost = found.filter(
|
|
227
|
+
(f, i) => !covers[i] && placed(f) && !nested(f, i)
|
|
228
|
+
);
|
|
228
229
|
const byId = new Map(nodes.map((n) => [n.id, n]));
|
|
229
230
|
const walkIndex = walkIndexOf(graph);
|
|
230
231
|
return outermost.map((f) => {
|
|
@@ -267,7 +268,6 @@ function graphBubbles(graph, span) {
|
|
|
267
268
|
}
|
|
268
269
|
|
|
269
270
|
export {
|
|
270
|
-
MAX_SUPERBUBBLES,
|
|
271
271
|
superbubblesFromGraph,
|
|
272
272
|
graphBubbles
|
|
273
273
|
};
|