@jbrowse/bandage-core 9.0.0 → 9.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/dist/bubbles/bubbleHalos.js +9 -5
- package/dist/bubbles/bubbleLine.js +3 -1
- package/dist/bubbles/bubblesFromGraph.js +8 -4
- package/dist/bubbles/classifyBubble.js +2 -2
- package/dist/bubbles/superbubbles.js +21 -0
- package/dist/chunks/{chunk-ISEI2FH3.js → chunk-2AWUWGAD.js} +10 -4
- package/dist/chunks/{chunk-YOYLCLIG.js → chunk-2ZT7ZF7A.js} +6 -2
- package/dist/chunks/{chunk-TLQ7F2ZT.js → chunk-3TGUKQWQ.js} +4 -4
- package/dist/chunks/{chunk-LLP3FXPM.js → chunk-75HR3756.js} +24 -7
- package/dist/chunks/chunk-FUVI4WQP.js +273 -0
- package/dist/chunks/{chunk-MFKORG3F.js → chunk-FX4RDMDN.js} +5 -1
- package/dist/chunks/{chunk-4S47XRYA.js → chunk-GOZYKNQ2.js} +16 -11
- package/dist/chunks/{chunk-TL4B342F.js → chunk-MXDQGA7A.js} +1 -1
- package/dist/chunks/{chunk-SKKYLBRA.js → chunk-RRZMMYBG.js} +1 -1
- package/dist/chunks/{chunk-AMS3MAFP.js → chunk-UID3QBWH.js} +1 -1
- package/dist/chunks/{chunk-2WNBVB55.js → chunk-WBCOREDZ.js} +121 -74
- package/dist/chunks/{chunk-WOO7QYKB.js → chunk-XKWD2RY3.js} +8 -2
- package/dist/chunks/{chunk-6VBDMZBZ.js → chunk-XLCTQHBE.js} +1 -1
- package/dist/cli/figure.js +6 -6
- package/dist/figure.js +6 -6
- package/dist/figureSettings.js +3 -3
- package/dist/index.js +34 -24
- package/dist/layout/forceCache.js +3 -3
- package/dist/pipeline.js +2 -2
- package/dist/renderer/Canvas2DRenderer.js +1 -1
- package/dist/renderer/recordingCanvas.js +12 -1
- package/dist/tubeMap/connectors.js +3 -1
- package/dist/tubeMap/draw.js +3 -1
- package/dist/types/bubbles/bubbleHalos.d.ts +2 -0
- package/dist/types/bubbles/bubbleLine.d.ts +3 -0
- package/dist/types/bubbles/bubblesFromGraph.d.ts +12 -2
- package/dist/types/bubbles/superbubbles.d.ts +5 -0
- package/dist/types/index.d.ts +3 -2
- package/dist/types/renderer/Canvas2DRenderer.d.ts +6 -3
- package/dist/types/tubeMap/connectors.d.ts +1 -0
- package/dist/types/tubeMap/draw.d.ts +1 -0
- package/dist/types/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/viewport.js +3 -3
- package/package.json +1 -1
- package/dist/chunks/{chunk-5OIVTEF7.js → chunk-OOXIMURX.js} +3 -3
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
WHOLE_FRACTION,
|
|
3
|
+
bubbleHalos,
|
|
4
|
+
coversGraph
|
|
5
|
+
} from "../chunks/chunk-2AWUWGAD.js";
|
|
6
|
+
import "../chunks/chunk-XKWD2RY3.js";
|
|
7
|
+
import "../chunks/chunk-FX4RDMDN.js";
|
|
6
8
|
import "../chunks/chunk-2CVHXFK7.js";
|
|
7
9
|
import "../chunks/chunk-CPMHA4W5.js";
|
|
8
10
|
import "../chunks/chunk-FYQWPEEY.js";
|
|
9
11
|
export {
|
|
10
|
-
|
|
12
|
+
WHOLE_FRACTION,
|
|
13
|
+
bubbleHalos,
|
|
14
|
+
coversGraph
|
|
11
15
|
};
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SATURATED_PATH_COUNT,
|
|
3
3
|
bubbleDescription,
|
|
4
|
+
bubbleKey,
|
|
4
5
|
bubbleLabel,
|
|
5
6
|
parseBubbleLine,
|
|
6
7
|
sameBubble
|
|
7
|
-
} from "../chunks/chunk-
|
|
8
|
+
} from "../chunks/chunk-FX4RDMDN.js";
|
|
8
9
|
export {
|
|
9
10
|
SATURATED_PATH_COUNT,
|
|
10
11
|
bubbleDescription,
|
|
12
|
+
bubbleKey,
|
|
11
13
|
bubbleLabel,
|
|
12
14
|
parseBubbleLine,
|
|
13
15
|
sameBubble
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
|
-
bubblesFromGraph
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
bubblesFromGraph,
|
|
3
|
+
walkIndexOf,
|
|
4
|
+
walkRoutes
|
|
5
|
+
} from "../chunks/chunk-GOZYKNQ2.js";
|
|
6
|
+
import "../chunks/chunk-FX4RDMDN.js";
|
|
5
7
|
import "../chunks/chunk-HNQPEMYE.js";
|
|
6
8
|
import "../chunks/chunk-CPMHA4W5.js";
|
|
7
9
|
import "../chunks/chunk-FYQWPEEY.js";
|
|
8
10
|
export {
|
|
9
|
-
bubblesFromGraph
|
|
11
|
+
bubblesFromGraph,
|
|
12
|
+
walkIndexOf,
|
|
13
|
+
walkRoutes
|
|
10
14
|
};
|
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
bubbleSegmentIds,
|
|
5
5
|
classifyBubble,
|
|
6
6
|
formatBp
|
|
7
|
-
} from "../chunks/chunk-
|
|
8
|
-
import "../chunks/chunk-
|
|
7
|
+
} from "../chunks/chunk-XKWD2RY3.js";
|
|
8
|
+
import "../chunks/chunk-FX4RDMDN.js";
|
|
9
9
|
export {
|
|
10
10
|
BUBBLE_KIND_COLORS,
|
|
11
11
|
BUBBLE_KIND_NAMES,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MAX_SUPERBUBBLES,
|
|
3
|
+
graphBubbles,
|
|
4
|
+
superbubblesFromGraph
|
|
5
|
+
} from "../chunks/chunk-FUVI4WQP.js";
|
|
6
|
+
import "../chunks/chunk-VHW7FDHU.js";
|
|
7
|
+
import "../chunks/chunk-2AWUWGAD.js";
|
|
8
|
+
import "../chunks/chunk-GOZYKNQ2.js";
|
|
9
|
+
import "../chunks/chunk-XKWD2RY3.js";
|
|
10
|
+
import "../chunks/chunk-FX4RDMDN.js";
|
|
11
|
+
import "../chunks/chunk-HNQPEMYE.js";
|
|
12
|
+
import "../chunks/chunk-ST2IBUAN.js";
|
|
13
|
+
import "../chunks/chunk-BPLIXMH7.js";
|
|
14
|
+
import "../chunks/chunk-2CVHXFK7.js";
|
|
15
|
+
import "../chunks/chunk-CPMHA4W5.js";
|
|
16
|
+
import "../chunks/chunk-FYQWPEEY.js";
|
|
17
|
+
export {
|
|
18
|
+
MAX_SUPERBUBBLES,
|
|
19
|
+
graphBubbles,
|
|
20
|
+
superbubblesFromGraph
|
|
21
|
+
};
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
bubbleSegmentIds,
|
|
3
3
|
classifyBubble,
|
|
4
4
|
formatBp
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-XKWD2RY3.js";
|
|
6
6
|
import {
|
|
7
7
|
svgPath
|
|
8
8
|
} from "./chunk-2CVHXFK7.js";
|
|
@@ -12,6 +12,9 @@ import {
|
|
|
12
12
|
|
|
13
13
|
// src/bubbles/bubbleHalos.ts
|
|
14
14
|
var WHOLE_FRACTION = 0.9;
|
|
15
|
+
function coversGraph(members, nodes) {
|
|
16
|
+
return members + 2 >= nodes || members >= WHOLE_FRACTION * nodes;
|
|
17
|
+
}
|
|
15
18
|
var NAMED_WALKS = 2;
|
|
16
19
|
var MIN_CHIPPED_BP = 1e3;
|
|
17
20
|
function bubbleHalos(graph, bubbles, positions, walkLabel = (name) => name, repeats = []) {
|
|
@@ -24,13 +27,14 @@ function bubbleHalos(graph, bubbles, positions, walkLabel = (name) => name, repe
|
|
|
24
27
|
let minY = Infinity;
|
|
25
28
|
const nodeIds = [];
|
|
26
29
|
const ends = [];
|
|
27
|
-
|
|
30
|
+
const names = bubbleSegmentIds(bubble);
|
|
31
|
+
for (const [i, name] of names.entries()) {
|
|
28
32
|
const node = byName.get(name);
|
|
29
33
|
const line = node && positions[node.id];
|
|
30
34
|
if (!node || !line?.length) {
|
|
31
35
|
continue;
|
|
32
36
|
}
|
|
33
|
-
if (isBackbone(node) && (node.stable.start < bubble.start || node.stable.start >= bubble.end)) {
|
|
37
|
+
if (bubble.key ? i === 0 || i === names.length - 1 : isBackbone(node) && (node.stable.start < bubble.start || node.stable.start >= bubble.end)) {
|
|
34
38
|
ends.push(line[Math.floor(line.length / 2)]);
|
|
35
39
|
continue;
|
|
36
40
|
}
|
|
@@ -90,7 +94,7 @@ function bubbleHalos(graph, bubbles, positions, walkLabel = (name) => name, repe
|
|
|
90
94
|
labelAt,
|
|
91
95
|
members: nodeIds.length,
|
|
92
96
|
nodeIds,
|
|
93
|
-
whole: nodeIds.length
|
|
97
|
+
whole: coversGraph(nodeIds.length, graph.nodes.length),
|
|
94
98
|
routes
|
|
95
99
|
});
|
|
96
100
|
}
|
|
@@ -104,5 +108,7 @@ function routeText(route, walkLabel) {
|
|
|
104
108
|
}
|
|
105
109
|
|
|
106
110
|
export {
|
|
111
|
+
WHOLE_FRACTION,
|
|
112
|
+
coversGraph,
|
|
107
113
|
bubbleHalos
|
|
108
114
|
};
|
|
@@ -69,7 +69,10 @@ function drawTubeMapConnectors(ctx, connectors, bottom, {
|
|
|
69
69
|
ctx.strokeStyle = `rgba(${ink},0.35)`;
|
|
70
70
|
ctx.lineWidth = 0.5;
|
|
71
71
|
ctx.stroke();
|
|
72
|
-
|
|
72
|
+
drawLitConnector(ctx, connectors, bottom, highlightNode);
|
|
73
|
+
}
|
|
74
|
+
function drawLitConnector(ctx, connectors, bottom, node) {
|
|
75
|
+
const lit = bottom > 0 && node ? connectors.find((c) => c.node === node) : void 0;
|
|
73
76
|
if (lit) {
|
|
74
77
|
ctx.beginPath();
|
|
75
78
|
band(ctx, lit, bottom);
|
|
@@ -86,5 +89,6 @@ function drawTubeMapConnectors(ctx, connectors, bottom, {
|
|
|
86
89
|
export {
|
|
87
90
|
tubeMapConnectors,
|
|
88
91
|
connectorAt,
|
|
89
|
-
drawTubeMapConnectors
|
|
92
|
+
drawTubeMapConnectors,
|
|
93
|
+
drawLitConnector
|
|
90
94
|
};
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
} from "./chunk-MIW3HYPE.js";
|
|
17
17
|
import {
|
|
18
18
|
Canvas2DRenderer
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-WBCOREDZ.js";
|
|
20
20
|
import {
|
|
21
21
|
EXON_COLOR,
|
|
22
22
|
exonOutlineTree,
|
|
@@ -42,10 +42,10 @@ import {
|
|
|
42
42
|
} from "./chunk-HBEKUQO4.js";
|
|
43
43
|
import {
|
|
44
44
|
version
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-UID3QBWH.js";
|
|
46
46
|
import {
|
|
47
47
|
axisScaleOf
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-MXDQGA7A.js";
|
|
49
49
|
import {
|
|
50
50
|
walkRowLabels,
|
|
51
51
|
walkRowsExtent
|
|
@@ -91,7 +91,7 @@ import {
|
|
|
91
91
|
FIT_PADDING,
|
|
92
92
|
drawingBounds,
|
|
93
93
|
fitTransform
|
|
94
|
-
} from "./chunk-
|
|
94
|
+
} from "./chunk-OOXIMURX.js";
|
|
95
95
|
import {
|
|
96
96
|
deletionDrawing,
|
|
97
97
|
deletionEdges
|
|
@@ -192,24 +192,40 @@ function drawTubeMap(ctx, picture, frame) {
|
|
|
192
192
|
}
|
|
193
193
|
const stroke = frame.darkMode ? "#d0d0d0" : "#000000";
|
|
194
194
|
const fill = frame.darkMode ? "rgba(40,40,40,0.4)" : "rgba(255,255,255,0.4)";
|
|
195
|
-
ctx.lineWidth =
|
|
195
|
+
ctx.lineWidth = outlineWidth(frame);
|
|
196
196
|
for (const node of picture.nodes) {
|
|
197
|
-
if (visible(node)) {
|
|
198
|
-
const lit = node.name === frame.highlightNode;
|
|
197
|
+
if (visible(node) && node.name !== frame.highlightNode) {
|
|
199
198
|
ctx.beginPath();
|
|
200
199
|
trace(ctx, node.commands, x, y);
|
|
201
|
-
const tint =
|
|
202
|
-
ctx.fillStyle =
|
|
203
|
-
ctx.strokeStyle =
|
|
200
|
+
const tint = frame.nodeColors?.get(node.name);
|
|
201
|
+
ctx.fillStyle = tint ?? fill;
|
|
202
|
+
ctx.strokeStyle = stroke;
|
|
204
203
|
ctx.globalAlpha = tint ? NODE_TINT_ALPHA : 1;
|
|
205
204
|
ctx.fill();
|
|
206
|
-
ctx.globalAlpha =
|
|
205
|
+
ctx.globalAlpha = outlineAlpha(x(node.x1) - x(node.x0));
|
|
207
206
|
ctx.stroke();
|
|
208
207
|
ctx.globalAlpha = 1;
|
|
209
208
|
}
|
|
210
209
|
}
|
|
210
|
+
drawTubeMapHighlight(ctx, picture, frame);
|
|
211
211
|
drawMismatches(ctx, picture.mismatches, frame);
|
|
212
212
|
}
|
|
213
|
+
function outlineWidth(frame) {
|
|
214
|
+
return 2 * Math.max(0.25, Math.min(1, frame.yScale));
|
|
215
|
+
}
|
|
216
|
+
function drawTubeMapHighlight(ctx, picture, frame) {
|
|
217
|
+
const node = frame.highlightNode ? picture.nodes.find((n) => n.name === frame.highlightNode) : void 0;
|
|
218
|
+
if (node) {
|
|
219
|
+
ctx.beginPath();
|
|
220
|
+
trace(ctx, node.commands, frame.x, frame.y);
|
|
221
|
+
ctx.globalAlpha = 1;
|
|
222
|
+
ctx.lineWidth = outlineWidth(frame);
|
|
223
|
+
ctx.fillStyle = "rgba(255,192,203,0.5)";
|
|
224
|
+
ctx.strokeStyle = "#ff0000";
|
|
225
|
+
ctx.fill();
|
|
226
|
+
ctx.stroke();
|
|
227
|
+
}
|
|
228
|
+
}
|
|
213
229
|
var MISMATCH_FONT_PX = 12;
|
|
214
230
|
var MIN_MISMATCH_FONT_PX = 6;
|
|
215
231
|
function mismatchesLegible(yScale) {
|
|
@@ -273,6 +289,7 @@ export {
|
|
|
273
289
|
trackColors,
|
|
274
290
|
tubeMapPicture,
|
|
275
291
|
drawTubeMap,
|
|
292
|
+
drawTubeMapHighlight,
|
|
276
293
|
mismatchesLegible,
|
|
277
294
|
mismatchOnScreen,
|
|
278
295
|
tubeMapTrackAt,
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import {
|
|
2
|
+
bubbleSubgraph
|
|
3
|
+
} from "./chunk-VHW7FDHU.js";
|
|
4
|
+
import {
|
|
5
|
+
coversGraph
|
|
6
|
+
} from "./chunk-2AWUWGAD.js";
|
|
7
|
+
import {
|
|
8
|
+
bubblesFromGraph,
|
|
9
|
+
walkIndexOf,
|
|
10
|
+
walkRoutes
|
|
11
|
+
} from "./chunk-GOZYKNQ2.js";
|
|
12
|
+
import {
|
|
13
|
+
bubbleSegmentIds
|
|
14
|
+
} from "./chunk-XKWD2RY3.js";
|
|
15
|
+
import {
|
|
16
|
+
SATURATED_PATH_COUNT
|
|
17
|
+
} from "./chunk-FX4RDMDN.js";
|
|
18
|
+
import {
|
|
19
|
+
strandSides
|
|
20
|
+
} from "./chunk-2CVHXFK7.js";
|
|
21
|
+
import {
|
|
22
|
+
isBackbone
|
|
23
|
+
} from "./chunk-FYQWPEEY.js";
|
|
24
|
+
|
|
25
|
+
// src/bubbles/superbubbles.ts
|
|
26
|
+
var MAX_SUPERBUBBLES = 50;
|
|
27
|
+
function slotGraph(graph, index) {
|
|
28
|
+
const slots = graph.nodes.length * 2;
|
|
29
|
+
const seen = /* @__PURE__ */ new Set();
|
|
30
|
+
const pairs = [];
|
|
31
|
+
const degree = new Int32Array(slots);
|
|
32
|
+
for (const e of graph.edges) {
|
|
33
|
+
const a = index.get(e.from);
|
|
34
|
+
const b = index.get(e.to);
|
|
35
|
+
if (a === void 0 || b === void 0) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const sides = strandSides(e);
|
|
39
|
+
const ka = a * 2 + (sides.from === "end" ? 1 : 0);
|
|
40
|
+
const kb = b * 2 + (sides.to === "end" ? 1 : 0);
|
|
41
|
+
const id = Math.min(ka, kb) * slots + Math.max(ka, kb);
|
|
42
|
+
if (seen.has(id)) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
seen.add(id);
|
|
46
|
+
pairs.push(ka, kb);
|
|
47
|
+
degree[ka]++;
|
|
48
|
+
if (ka !== kb) {
|
|
49
|
+
degree[kb]++;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const offset = new Int32Array(slots + 1);
|
|
53
|
+
for (let k = 0; k < slots; k++) {
|
|
54
|
+
offset[k + 1] = offset[k] + degree[k];
|
|
55
|
+
}
|
|
56
|
+
const next = new Int32Array(offset[slots]);
|
|
57
|
+
const fill = offset.slice(0, slots);
|
|
58
|
+
for (let i = 0; i < pairs.length; i += 2) {
|
|
59
|
+
const ka = pairs[i];
|
|
60
|
+
const kb = pairs[i + 1];
|
|
61
|
+
next[fill[ka]++] = kb;
|
|
62
|
+
if (ka !== kb) {
|
|
63
|
+
next[fill[kb]++] = ka;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return { offset, next };
|
|
67
|
+
}
|
|
68
|
+
function searcher(nodes, offset, next) {
|
|
69
|
+
const visited = new Int32Array(nodes);
|
|
70
|
+
const pending = new Uint8Array(nodes * 2);
|
|
71
|
+
const stack = new Int32Array(nodes * 2);
|
|
72
|
+
const inside = new Int32Array(nodes);
|
|
73
|
+
const touched = [];
|
|
74
|
+
let stamp = 0;
|
|
75
|
+
return (start) => {
|
|
76
|
+
const s = start >> 1;
|
|
77
|
+
stamp++;
|
|
78
|
+
touched.length = 0;
|
|
79
|
+
let open = 0;
|
|
80
|
+
let top = 0;
|
|
81
|
+
let count = 0;
|
|
82
|
+
let found;
|
|
83
|
+
const expect = (k) => {
|
|
84
|
+
if (!pending[k]) {
|
|
85
|
+
pending[k] = 1;
|
|
86
|
+
open++;
|
|
87
|
+
touched.push(k);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
expect(start);
|
|
91
|
+
stack[top++] = start;
|
|
92
|
+
search: while (top > 0) {
|
|
93
|
+
const k = stack[--top];
|
|
94
|
+
const v = k >> 1;
|
|
95
|
+
visited[v] = stamp;
|
|
96
|
+
if (v !== s) {
|
|
97
|
+
inside[count++] = k;
|
|
98
|
+
}
|
|
99
|
+
if (pending[k]) {
|
|
100
|
+
pending[k] = 0;
|
|
101
|
+
open--;
|
|
102
|
+
}
|
|
103
|
+
if (offset[k] === offset[k + 1]) {
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
for (let p = offset[k]; p < offset[k + 1]; p++) {
|
|
107
|
+
const entry = next[p];
|
|
108
|
+
const u = entry >> 1;
|
|
109
|
+
if (u === s) {
|
|
110
|
+
break search;
|
|
111
|
+
}
|
|
112
|
+
expect(entry ^ 1);
|
|
113
|
+
if (visited[u] === stamp) {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
let ready = true;
|
|
117
|
+
for (let q = offset[entry]; q < offset[entry + 1]; q++) {
|
|
118
|
+
if (visited[next[q] >> 1] !== stamp) {
|
|
119
|
+
ready = false;
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (ready) {
|
|
124
|
+
stack[top++] = entry ^ 1;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (top === 1 && open === 1) {
|
|
128
|
+
if (count > 0) {
|
|
129
|
+
found = {
|
|
130
|
+
source: start,
|
|
131
|
+
sink: stack[0],
|
|
132
|
+
inside: inside.slice(0, count)
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
for (const k of touched) {
|
|
139
|
+
pending[k] = 0;
|
|
140
|
+
}
|
|
141
|
+
return found;
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function reversed(f) {
|
|
145
|
+
return {
|
|
146
|
+
source: f.sink ^ 1,
|
|
147
|
+
sink: f.source ^ 1,
|
|
148
|
+
inside: f.inside.map((k) => k ^ 1).reverse()
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
var collator = new Intl.Collator(void 0, { numeric: true });
|
|
152
|
+
function onReference(a, b) {
|
|
153
|
+
return isBackbone(a) && isBackbone(b) && a.stable.refName === b.stable.refName;
|
|
154
|
+
}
|
|
155
|
+
function forward(f, nodes) {
|
|
156
|
+
const a = nodes[f.source >> 1];
|
|
157
|
+
const b = nodes[f.sink >> 1];
|
|
158
|
+
const byRef = onReference(a, b) ? a.stable.start - b.stable.start : 0;
|
|
159
|
+
const bySide = ((f.sink ^ 1) & 1) - (f.source & 1);
|
|
160
|
+
return (byRef || bySide || collator.compare(a.name, b.name)) < 0;
|
|
161
|
+
}
|
|
162
|
+
function nodesOf(f) {
|
|
163
|
+
return [f.source >> 1, ...Array.from(f.inside, (k) => k >> 1), f.sink >> 1];
|
|
164
|
+
}
|
|
165
|
+
function allSuperbubbles(graph) {
|
|
166
|
+
const { nodes } = graph;
|
|
167
|
+
const index = new Map(nodes.map((n, i) => [n.id, i]));
|
|
168
|
+
const { offset, next } = slotGraph(graph, index);
|
|
169
|
+
const find = searcher(nodes.length, offset, next);
|
|
170
|
+
const byEnds = /* @__PURE__ */ new Map();
|
|
171
|
+
for (let k = 0; k < nodes.length * 2; k++) {
|
|
172
|
+
const hit = find(k);
|
|
173
|
+
if (!hit) {
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
const a = hit.source >> 1;
|
|
177
|
+
const b = hit.sink >> 1;
|
|
178
|
+
const id = Math.min(a, b) * nodes.length + Math.max(a, b);
|
|
179
|
+
if (forward(hit, nodes) || !byEnds.has(id)) {
|
|
180
|
+
byEnds.set(id, hit);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
const found = [...byEnds.values()].map(
|
|
184
|
+
(f) => forward(f, nodes) ? f : reversed(f)
|
|
185
|
+
);
|
|
186
|
+
return { found, offset, next };
|
|
187
|
+
}
|
|
188
|
+
function routesThrough(nodes, offset, next, f) {
|
|
189
|
+
const sink = f.sink >> 1;
|
|
190
|
+
const best = /* @__PURE__ */ new Map([
|
|
191
|
+
[f.source >> 1, { min: 0, max: 0, n: 1 }]
|
|
192
|
+
]);
|
|
193
|
+
for (const k of [f.source, ...f.inside]) {
|
|
194
|
+
const cur = best.get(k >> 1);
|
|
195
|
+
if (!cur) {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
for (let p = offset[k]; p < offset[k + 1]; p++) {
|
|
199
|
+
const u = next[p] >> 1;
|
|
200
|
+
const add = u === sink ? 0 : nodes[u].length;
|
|
201
|
+
const prev = best.get(u);
|
|
202
|
+
best.set(u, {
|
|
203
|
+
min: Math.min(prev?.min ?? Infinity, cur.min + add),
|
|
204
|
+
max: Math.max(prev?.max ?? -Infinity, cur.max + add),
|
|
205
|
+
n: Math.min(SATURATED_PATH_COUNT, cur.n + (prev?.n ?? 0))
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return best.get(sink) ?? { min: 0, max: 0, n: 0 };
|
|
210
|
+
}
|
|
211
|
+
function superbubblesFromGraph(graph, span) {
|
|
212
|
+
const { nodes } = graph;
|
|
213
|
+
const { found, offset, next } = allSuperbubbles(graph);
|
|
214
|
+
const covers = found.map((f) => coversGraph(f.inside.length, nodes.length));
|
|
215
|
+
const members = found.map(nodesOf);
|
|
216
|
+
const holders = /* @__PURE__ */ new Map();
|
|
217
|
+
members.forEach((vs, i) => {
|
|
218
|
+
for (const v of vs) {
|
|
219
|
+
;
|
|
220
|
+
(holders.get(v) ?? holders.set(v, []).get(v)).push(i);
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
const nested = (f, i) => holders.get(f.inside[0] >> 1).some(
|
|
224
|
+
(j) => j !== i && !covers[j] && members[j].length > members[i].length && members[i].every((v) => holders.get(v).includes(j))
|
|
225
|
+
);
|
|
226
|
+
const placed = (f) => span !== void 0 || onReference(nodes[f.source >> 1], nodes[f.sink >> 1]);
|
|
227
|
+
const outermost = found.filter((f, i) => !covers[i] && placed(f) && !nested(f, i)).sort((a, b) => b.inside.length - a.inside.length).slice(0, MAX_SUPERBUBBLES);
|
|
228
|
+
const byId = new Map(nodes.map((n) => [n.id, n]));
|
|
229
|
+
const walkIndex = walkIndexOf(graph);
|
|
230
|
+
return outermost.map((f) => {
|
|
231
|
+
const source = nodes[f.source >> 1];
|
|
232
|
+
const sink = nodes[f.sink >> 1];
|
|
233
|
+
const walked = walkIndex && walkRoutes(graph, byId, walkIndex, source.id, sink.id);
|
|
234
|
+
const crossed = walked?.n ? walked : void 0;
|
|
235
|
+
const routes = crossed ?? routesThrough(nodes, offset, next, f);
|
|
236
|
+
const placedOn = onReference(source, sink);
|
|
237
|
+
return {
|
|
238
|
+
refName: placedOn ? source.stable.refName : span.refName,
|
|
239
|
+
start: placedOn ? source.stable.start + source.length : span.start,
|
|
240
|
+
end: placedOn ? sink.stable.start : span.end,
|
|
241
|
+
segmentCount: f.inside.length + 2,
|
|
242
|
+
pathCount: routes.n,
|
|
243
|
+
inversion: false,
|
|
244
|
+
shortestAlleleLength: routes.min,
|
|
245
|
+
longestAlleleLength: routes.max,
|
|
246
|
+
segments: nodesOf(f).map((v) => nodes[v].name).join(","),
|
|
247
|
+
shortestAllele: void 0,
|
|
248
|
+
longestAllele: void 0,
|
|
249
|
+
partial: walked !== void 0 && walked.left > 0,
|
|
250
|
+
routes: crossed?.routes,
|
|
251
|
+
key: `${source.name}>${sink.name}`,
|
|
252
|
+
...placedOn ? {} : { offReference: true }
|
|
253
|
+
};
|
|
254
|
+
}).sort(
|
|
255
|
+
(a, b) => a.start - b.start || a.end - b.end || collator.compare(a.key, b.key)
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
function graphBubbles(graph, span) {
|
|
259
|
+
const n = graph.nodes.length;
|
|
260
|
+
const reach = bubblesFromGraph(graph);
|
|
261
|
+
return reach.length === 0 ? superbubblesFromGraph(graph, span) : reach.flatMap(
|
|
262
|
+
(b) => coversGraph(b.segmentCount - 2, n) ? superbubblesFromGraph(
|
|
263
|
+
b.segmentCount === n ? graph : bubbleSubgraph(graph, bubbleSegmentIds(b)),
|
|
264
|
+
b
|
|
265
|
+
) : [b]
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export {
|
|
270
|
+
MAX_SUPERBUBBLES,
|
|
271
|
+
superbubblesFromGraph,
|
|
272
|
+
graphBubbles
|
|
273
|
+
};
|
|
@@ -19,7 +19,10 @@ function parseBubbleLine(line) {
|
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
21
|
function sameBubble(a, b) {
|
|
22
|
-
return a.refName === b.refName && a.start === b.start && a.end === b.end;
|
|
22
|
+
return a.key !== void 0 || b.key !== void 0 ? a.key === b.key : a.refName === b.refName && a.start === b.start && a.end === b.end;
|
|
23
|
+
}
|
|
24
|
+
function bubbleKey(b) {
|
|
25
|
+
return b.key ?? `${b.refName}:${b.start}-${b.end}`;
|
|
23
26
|
}
|
|
24
27
|
function bubbleLabel(bubble) {
|
|
25
28
|
const { shortestAlleleLength: min, longestAlleleLength: max } = bubble;
|
|
@@ -38,6 +41,7 @@ function bubbleDescription(bubble) {
|
|
|
38
41
|
export {
|
|
39
42
|
parseBubbleLine,
|
|
40
43
|
sameBubble,
|
|
44
|
+
bubbleKey,
|
|
41
45
|
bubbleLabel,
|
|
42
46
|
SATURATED_PATH_COUNT,
|
|
43
47
|
bubbleDescription
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SATURATED_PATH_COUNT
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-FX4RDMDN.js";
|
|
4
4
|
import {
|
|
5
5
|
referenceOrder
|
|
6
6
|
} from "./chunk-HNQPEMYE.js";
|
|
@@ -38,15 +38,7 @@ function bubblesFromGraph(graph) {
|
|
|
38
38
|
const backbone = graph.nodes.filter(isBackbone).sort((a, b) => a.stable.start - b.stable.start);
|
|
39
39
|
const ends = /* @__PURE__ */ new Set([backbone[0].id, backbone.at(-1).id]);
|
|
40
40
|
const boundaries = backbone.map((node) => [node, indexOf.get(node.id)]).filter(([node, i]) => ends.has(node.id) || reach[i] === 0).sort(([a, ia], [b, ib]) => ia - ib || a.stable.start - b.stable.start);
|
|
41
|
-
const walkIndex = graph
|
|
42
|
-
const at = /* @__PURE__ */ new Map();
|
|
43
|
-
p.nodeIds.forEach((id, i) => {
|
|
44
|
-
if (!at.has(id)) {
|
|
45
|
-
at.set(id, i);
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
return at;
|
|
49
|
-
});
|
|
41
|
+
const walkIndex = walkIndexOf(graph);
|
|
50
42
|
const bubbles = [];
|
|
51
43
|
for (let i = 0; i + 1 < boundaries.length; i++) {
|
|
52
44
|
const [start, i0] = boundaries[i];
|
|
@@ -112,6 +104,17 @@ function bubblesFromGraph(graph) {
|
|
|
112
104
|
}
|
|
113
105
|
return bubbles;
|
|
114
106
|
}
|
|
107
|
+
function walkIndexOf(graph) {
|
|
108
|
+
return graph.paths?.map((p) => {
|
|
109
|
+
const at = /* @__PURE__ */ new Map();
|
|
110
|
+
p.nodeIds.forEach((id, i) => {
|
|
111
|
+
if (!at.has(id)) {
|
|
112
|
+
at.set(id, i);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
return at;
|
|
116
|
+
});
|
|
117
|
+
}
|
|
115
118
|
function walkRoutes(graph, byId, walkIndex, startId, endId) {
|
|
116
119
|
const seen = /* @__PURE__ */ new Map();
|
|
117
120
|
let min = Infinity;
|
|
@@ -145,5 +148,7 @@ function walkRoutes(graph, byId, walkIndex, startId, endId) {
|
|
|
145
148
|
}
|
|
146
149
|
|
|
147
150
|
export {
|
|
148
|
-
bubblesFromGraph
|
|
151
|
+
bubblesFromGraph,
|
|
152
|
+
walkIndexOf,
|
|
153
|
+
walkRoutes
|
|
149
154
|
};
|