@jbrowse/bandage-core 6.0.1 → 6.0.3
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 +23 -7
- package/dist/alleleProjection/projectAlleles.js +10 -0
- package/dist/anchoredNodes.js +24 -0
- package/dist/bubbleSpreads.js +11 -0
- package/dist/bubbles/bubbleHalos.js +11 -0
- package/dist/bubbles/bubbleLine.js +14 -0
- package/dist/bubbles/bubblesFromGraph.js +10 -0
- package/dist/bubbles/classifyBubble.js +15 -0
- package/dist/bubbles/popBubble.js +9 -0
- package/dist/chunks/chunk-2CVHXFK7.js +530 -0
- package/dist/chunks/chunk-3S3YVOJ7.js +69 -0
- package/dist/chunks/chunk-47DYCZOK.js +115 -0
- package/dist/chunks/chunk-4EMPBO7S.js +117 -0
- package/dist/chunks/chunk-4S47XRYA.js +149 -0
- package/dist/chunks/chunk-5XQDMQXU.js +431 -0
- package/dist/chunks/chunk-6JEWNXCQ.js +90 -0
- package/dist/chunks/chunk-6SBUFFTB.js +97 -0
- package/dist/chunks/chunk-6SXMCK6I.js +476 -0
- package/dist/chunks/chunk-72N5DJHZ.js +155 -0
- package/dist/chunks/chunk-73RSLGZT.js +73 -0
- package/dist/chunks/chunk-7XHHVYG7.js +13 -0
- package/dist/chunks/chunk-AB35TJST.js +67 -0
- package/dist/chunks/chunk-BPLIXMH7.js +52 -0
- package/dist/chunks/chunk-BUBZ32IC.js +101 -0
- package/dist/chunks/chunk-BXEPA4KS.js +179 -0
- package/dist/chunks/chunk-C44YRP5F.js +85 -0
- package/dist/chunks/chunk-CDLPYR5O.js +135 -0
- package/dist/chunks/chunk-CJ2EE4AF.js +40 -0
- package/dist/chunks/chunk-CPMHA4W5.js +6 -0
- package/dist/chunks/chunk-CR7EGAFE.js +241 -0
- package/dist/chunks/chunk-CS3E4ETM.js +202 -0
- package/dist/chunks/chunk-CTSBC2O6.js +90 -0
- package/dist/chunks/chunk-D3M7SBKL.js +210 -0
- package/dist/chunks/chunk-DKOB2OPC.js +177 -0
- package/dist/chunks/chunk-EJ5OZTCK.js +52 -0
- package/dist/chunks/chunk-EK4HGYO7.js +174 -0
- package/dist/chunks/chunk-EPZORFTI.js +23 -0
- package/dist/chunks/chunk-ES2N6V56.js +83 -0
- package/dist/chunks/chunk-EZPBJPK6.js +54 -0
- package/dist/chunks/chunk-FYQWPEEY.js +65 -0
- package/dist/chunks/chunk-GGQRADFS.js +170 -0
- package/dist/chunks/chunk-GOY6REMT.js +43 -0
- package/dist/chunks/chunk-GQ2AOHU4.js +112 -0
- package/dist/chunks/chunk-HNQPEMYE.js +297 -0
- package/dist/chunks/chunk-IGVV37VI.js +60 -0
- package/dist/chunks/chunk-IO2PCPZI.js +218 -0
- package/dist/chunks/chunk-ISEI2FH3.js +108 -0
- package/dist/chunks/chunk-JKJWSY4V.js +32 -0
- package/dist/chunks/chunk-KQFOCDFY.js +73 -0
- package/dist/chunks/chunk-L3O7AWLI.js +52 -0
- package/dist/chunks/chunk-LLJUG2H7.js +6 -0
- package/dist/chunks/chunk-LOEA5IHZ.js +71 -0
- package/dist/chunks/chunk-LTUWJKHD.js +112 -0
- package/dist/chunks/chunk-MFKORG3F.js +44 -0
- package/dist/chunks/chunk-MI35EUIE.js +76 -0
- package/dist/chunks/chunk-MNUSQCLG.js +29 -0
- package/dist/chunks/chunk-MQJUG2D2.js +53 -0
- package/dist/chunks/chunk-MREQ7GIA.js +181 -0
- package/dist/chunks/chunk-N62KBLFC.js +326 -0
- package/dist/chunks/chunk-NNODIW4U.js +26 -0
- package/dist/chunks/chunk-PBENCR5L.js +60 -0
- package/dist/chunks/chunk-PCZ4PTYC.js +726 -0
- package/dist/chunks/chunk-PUG7LXDF.js +70 -0
- package/dist/chunks/chunk-QYBZZI5H.js +0 -0
- package/dist/chunks/chunk-R6ZUK4Y3.js +232 -0
- package/dist/chunks/chunk-RAKOB6IV.js +169 -0
- package/dist/chunks/chunk-ROF2R3RF.js +205 -0
- package/dist/chunks/chunk-RVS2QCOX.js +135 -0
- package/dist/chunks/chunk-ST2IBUAN.js +119 -0
- package/dist/chunks/chunk-SZNZ2T6D.js +198 -0
- package/dist/chunks/chunk-T43W7NKK.js +122 -0
- package/dist/chunks/chunk-TAMCZHLW.js +190 -0
- package/dist/chunks/chunk-TDQLINVI.js +16 -0
- package/dist/chunks/chunk-TEDQJPMI.js +131 -0
- package/dist/chunks/chunk-TZFWUT2C.js +66 -0
- package/dist/chunks/chunk-UVBGRJQX.js +50 -0
- package/dist/chunks/chunk-VHW7FDHU.js +42 -0
- package/dist/chunks/chunk-VZQ4FKLR.js +38 -0
- package/dist/chunks/chunk-WFX3MAKA.js +102 -0
- package/dist/chunks/chunk-WOO7QYKB.js +121 -0
- package/dist/chunks/chunk-WSIFAZU7.js +132 -0
- package/dist/chunks/chunk-X5L37W4J.js +82 -0
- package/dist/chunks/chunk-Y3IOTZJA.js +61 -0
- package/dist/chunks/chunk-YMSSF2RK.js +257 -0
- package/dist/cli/figure.js +84 -17
- package/dist/colorSchemes.js +10 -0
- package/dist/deletionEdges.js +13 -0
- package/dist/el.js +8 -0
- package/dist/facetGrid.js +16 -0
- package/dist/figure.js +51 -0
- package/dist/gaf/parseGaf.js +12 -0
- package/dist/gbzCut.js +19 -0
- package/dist/gbzJoin.js +6 -0
- package/dist/gbzWindow.js +28 -0
- package/dist/genes/exonOutline.js +11 -0
- package/dist/genes/geneFiles.js +14 -0
- package/dist/genes/genePins.js +10 -0
- package/dist/gfa/gfaConverter.js +11 -0
- package/dist/gfa-core/gfaParser.js +8 -0
- package/dist/gfa-core/index.js +9 -0
- package/dist/graphLabels.js +24 -0
- package/dist/index.js +262 -1407
- package/dist/labelLayout.js +24 -0
- package/dist/layout/anchoredLayout.js +11 -0
- package/dist/layout/deletionRoutes.js +10 -0
- package/dist/layout/drawnScale.js +22 -0
- package/dist/layout/mergeRuns.js +15 -0
- package/dist/layout/orderedLayout.js +12 -0
- package/dist/layout/orientToReference.js +7 -0
- package/dist/layout/placeOffReference.js +9 -0
- package/dist/layout/referenceSeeds.js +11 -0
- package/dist/layout/rowSpacing.js +6 -0
- package/dist/layout/sampleRowLayout.js +11 -0
- package/dist/layout/trimToWindow.js +99 -0
- package/dist/layout/tubeMapLayout.js +28 -0
- package/dist/layout/walkRowDraw.js +65 -0
- package/dist/layout/walkRowLayout.js +13 -0
- package/dist/layout/walkRows.js +11 -0
- package/dist/layout/walkStrip.js +40 -0
- package/dist/layoutModes.js +35 -0
- package/dist/loadBandage.js +6 -0
- package/dist/nodeWidths.js +18 -0
- package/dist/overlayLabels.js +18 -0
- package/dist/pansn.js +18 -0
- package/dist/pathAnchoring.js +18 -0
- package/dist/pathColors.js +31 -0
- package/dist/pipeline.js +40 -0
- package/dist/reference.js +24 -0
- package/dist/referenceRampCss.js +29 -0
- package/dist/referenceSpan.js +11 -0
- package/dist/referenceStrip.js +35 -0
- package/dist/renderer/Canvas2DRenderer.js +9 -0
- package/dist/renderer/GeometryBuilder.js +42 -0
- package/dist/renderer/colorBits.js +8 -0
- package/dist/renderer/recordingCanvas.js +44 -0
- package/dist/renderer/svgCanvas.js +6 -0
- package/dist/renderer/types.js +0 -0
- package/dist/tubeMap/axis.js +25 -0
- package/dist/tubeMap/coarsen.js +361 -0
- package/dist/tubeMap/connectors.js +13 -0
- package/dist/tubeMap/deviations.js +85 -0
- package/dist/tubeMap/draw.js +15 -0
- package/dist/tubeMap/frame.js +9 -0
- package/dist/tubeMap/genes.js +20 -0
- package/dist/tubeMap/mismatches.js +6 -0
- package/dist/tubeMap/nodeColors.js +21 -0
- package/dist/tubeMap/reads.js +17 -0
- package/dist/tubeMap/warp.js +8 -0
- package/dist/types/version.d.ts +1 -1
- package/dist/types.js +0 -0
- package/dist/util/SpatialIndex.js +13 -0
- package/dist/util/edgeCurves.js +10 -0
- package/dist/util/geometry.js +39 -0
- package/dist/util/hitDetection.js +20 -0
- package/dist/util/wheelZoom.js +6 -0
- package/dist/version.js +6 -0
- package/dist/viewport.js +33 -0
- package/dist/walkEncoding.js +39 -0
- package/dist/walkHighlight.js +26 -0
- package/dist/walkKey.js +17 -0
- package/package.json +38 -5
- package/dist/chunks/chunk-EXSFRX2F.js +0 -7400
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildNeighbors
|
|
3
|
+
} from "./chunk-ES2N6V56.js";
|
|
4
|
+
import {
|
|
5
|
+
REFERENCE_RANK,
|
|
6
|
+
isAnchored
|
|
7
|
+
} from "./chunk-FYQWPEEY.js";
|
|
8
|
+
|
|
9
|
+
// src/alleleProjection/projectAlleles.ts
|
|
10
|
+
function parsePanSN(refName) {
|
|
11
|
+
const parts = refName.split("#");
|
|
12
|
+
const haplotype = parts.length >= 2 ? Number(parts[1]) : Number.NaN;
|
|
13
|
+
return {
|
|
14
|
+
sample: parts[0] ?? refName,
|
|
15
|
+
haplotype: Number.isFinite(haplotype) ? haplotype : void 0
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function collectRun(seed, byId, adj, claimed) {
|
|
19
|
+
const members = [];
|
|
20
|
+
const anchors = [];
|
|
21
|
+
const queue = [seed];
|
|
22
|
+
claimed.add(seed);
|
|
23
|
+
while (queue.length > 0) {
|
|
24
|
+
const id = queue.pop();
|
|
25
|
+
const node = byId.get(id);
|
|
26
|
+
if (node) {
|
|
27
|
+
members.push(node);
|
|
28
|
+
for (const neighborId of adj.get(id) ?? []) {
|
|
29
|
+
const neighbor = byId.get(neighborId);
|
|
30
|
+
if (neighbor) {
|
|
31
|
+
if (neighbor.stable.rank === REFERENCE_RANK) {
|
|
32
|
+
anchors.push(neighbor);
|
|
33
|
+
} else if (!claimed.has(neighborId)) {
|
|
34
|
+
claimed.add(neighborId);
|
|
35
|
+
queue.push(neighborId);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return { members, anchors };
|
|
42
|
+
}
|
|
43
|
+
function anchorSpan(anchors) {
|
|
44
|
+
const refNames = new Set(anchors.map((a) => a.stable.refName));
|
|
45
|
+
if (refNames.size !== 1 || anchors.length < 2) {
|
|
46
|
+
return void 0;
|
|
47
|
+
}
|
|
48
|
+
const sorted = [...anchors].sort((a, b) => a.stable.start - b.stable.start);
|
|
49
|
+
const first = sorted[0];
|
|
50
|
+
const last = sorted.at(-1);
|
|
51
|
+
const start = first.stable.start + first.length;
|
|
52
|
+
const end = last.stable.start;
|
|
53
|
+
return end >= start ? { start, end, entry: first } : void 0;
|
|
54
|
+
}
|
|
55
|
+
function runDistances(members, entry, adj) {
|
|
56
|
+
const byId = new Map(members.map((m) => [m.id, m]));
|
|
57
|
+
const dist = /* @__PURE__ */ new Map();
|
|
58
|
+
const queue = [];
|
|
59
|
+
for (const neighborId of adj.get(entry.id) ?? []) {
|
|
60
|
+
if (byId.has(neighborId)) {
|
|
61
|
+
dist.set(neighborId, 0);
|
|
62
|
+
queue.push(neighborId);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (queue.length === 0) {
|
|
66
|
+
for (const member of members) {
|
|
67
|
+
dist.set(member.id, 0);
|
|
68
|
+
queue.push(member.id);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
for (const id of queue) {
|
|
72
|
+
const reach = dist.get(id) + byId.get(id).length;
|
|
73
|
+
for (const neighborId of adj.get(id) ?? []) {
|
|
74
|
+
if (byId.has(neighborId)) {
|
|
75
|
+
const known = dist.get(neighborId);
|
|
76
|
+
if (known === void 0 || reach < known) {
|
|
77
|
+
dist.set(neighborId, reach);
|
|
78
|
+
queue.push(neighborId);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return dist;
|
|
84
|
+
}
|
|
85
|
+
function runOffsets(members, entry, adj) {
|
|
86
|
+
const dist = runDistances(members, entry, adj);
|
|
87
|
+
const ordered = [...members].sort((a, b) => dist.get(a.id) - dist.get(b.id));
|
|
88
|
+
const rank = new Map(ordered.map((m, i) => [m.id, i]));
|
|
89
|
+
const byId = new Map(members.map((m) => [m.id, m]));
|
|
90
|
+
const offsets = /* @__PURE__ */ new Map();
|
|
91
|
+
for (const [i, member] of ordered.entries()) {
|
|
92
|
+
let offset = 0;
|
|
93
|
+
for (const neighborId of adj.get(member.id) ?? []) {
|
|
94
|
+
const neighbor = byId.get(neighborId);
|
|
95
|
+
if (neighbor && rank.get(neighborId) < i) {
|
|
96
|
+
offset = Math.max(offset, offsets.get(neighborId) + neighbor.length);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
offsets.set(member.id, offset);
|
|
100
|
+
}
|
|
101
|
+
return { offsets, ordered };
|
|
102
|
+
}
|
|
103
|
+
function projectAlleles(graph) {
|
|
104
|
+
const byId = new Map(
|
|
105
|
+
graph.nodes.filter(isAnchored).map((n) => [n.id, n])
|
|
106
|
+
);
|
|
107
|
+
const adj = buildNeighbors(graph);
|
|
108
|
+
const claimed = /* @__PURE__ */ new Set();
|
|
109
|
+
const alleles = [];
|
|
110
|
+
for (const node of byId.values()) {
|
|
111
|
+
if (node.stable.rank !== REFERENCE_RANK && !claimed.has(node.id)) {
|
|
112
|
+
const { members, anchors } = collectRun(node.id, byId, adj, claimed);
|
|
113
|
+
const span = anchorSpan(anchors);
|
|
114
|
+
if (span) {
|
|
115
|
+
const { offsets, ordered } = runOffsets(members, span.entry, adj);
|
|
116
|
+
alleles.push({
|
|
117
|
+
start: span.start,
|
|
118
|
+
refSpan: span.end - span.start,
|
|
119
|
+
nodeIds: ordered.map((m) => m.id),
|
|
120
|
+
nodeOffsets: ordered.map((m) => offsets.get(m.id)),
|
|
121
|
+
pathLength: ordered.reduce(
|
|
122
|
+
(max, m) => Math.max(max, offsets.get(m.id) + m.length),
|
|
123
|
+
0
|
|
124
|
+
)
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return alleles.sort((a, b) => a.start - b.start);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export {
|
|
133
|
+
parsePanSN,
|
|
134
|
+
projectAlleles
|
|
135
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import {
|
|
2
|
+
panSNSample
|
|
3
|
+
} from "./chunk-BPLIXMH7.js";
|
|
4
|
+
import {
|
|
5
|
+
REFERENCE_RANK
|
|
6
|
+
} from "./chunk-FYQWPEEY.js";
|
|
7
|
+
|
|
8
|
+
// src/pathAnchoring.ts
|
|
9
|
+
var RANGE_SUFFIX = /:(\d+)-\d+$/;
|
|
10
|
+
function pathOrigin(pathName) {
|
|
11
|
+
const match = RANGE_SUFFIX.exec(pathName);
|
|
12
|
+
return match ? { name: pathName.slice(0, match.index), start: +match[1] } : { name: pathName, start: 0 };
|
|
13
|
+
}
|
|
14
|
+
function surveyPaths(paths, lengthOf) {
|
|
15
|
+
const anchorPaths = [];
|
|
16
|
+
const pathVisits = /* @__PURE__ */ new Map();
|
|
17
|
+
for (const path of paths) {
|
|
18
|
+
const sample = panSNSample(path.name);
|
|
19
|
+
let pos = path.start;
|
|
20
|
+
for (const step of path.steps) {
|
|
21
|
+
const visit = {
|
|
22
|
+
path: path.name,
|
|
23
|
+
sample,
|
|
24
|
+
start: pos,
|
|
25
|
+
strand: step.strand
|
|
26
|
+
};
|
|
27
|
+
const existing = pathVisits.get(step.id);
|
|
28
|
+
if (existing) {
|
|
29
|
+
existing.push(visit);
|
|
30
|
+
} else {
|
|
31
|
+
pathVisits.set(step.id, [visit]);
|
|
32
|
+
}
|
|
33
|
+
pos += lengthOf(step.id);
|
|
34
|
+
}
|
|
35
|
+
anchorPaths.push({
|
|
36
|
+
name: path.name,
|
|
37
|
+
sample,
|
|
38
|
+
start: path.start,
|
|
39
|
+
length: pos - path.start
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return { anchorPaths, pathVisits };
|
|
43
|
+
}
|
|
44
|
+
function chooseReferencePath(anchorPaths, preferred) {
|
|
45
|
+
const named = anchorPaths.find(
|
|
46
|
+
(p) => p.sample === preferred || p.name === preferred
|
|
47
|
+
);
|
|
48
|
+
return named ?? anchorPaths[0];
|
|
49
|
+
}
|
|
50
|
+
var OFF_REFERENCE_RANK = 1;
|
|
51
|
+
function anchorNode(node, visits, reference) {
|
|
52
|
+
let anchored = node;
|
|
53
|
+
if (visits && visits.length > 0) {
|
|
54
|
+
const anchor = visits.find((v) => v.path === reference) ?? visits[0];
|
|
55
|
+
anchored = {
|
|
56
|
+
...node,
|
|
57
|
+
stable: {
|
|
58
|
+
refName: anchor.path,
|
|
59
|
+
start: anchor.start,
|
|
60
|
+
rank: anchor.path === reference ? REFERENCE_RANK : OFF_REFERENCE_RANK,
|
|
61
|
+
strand: anchor.strand
|
|
62
|
+
},
|
|
63
|
+
samples: [...new Set(visits.map((v) => v.sample))].sort()
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return anchored;
|
|
67
|
+
}
|
|
68
|
+
function anchorFromPaths(graph, preferred) {
|
|
69
|
+
const { anchorPaths, pathVisits } = graph;
|
|
70
|
+
const reference = anchorPaths && pathVisits ? chooseReferencePath(anchorPaths, preferred) : void 0;
|
|
71
|
+
return reference && pathVisits ? {
|
|
72
|
+
...graph,
|
|
73
|
+
nodes: graph.nodes.map(
|
|
74
|
+
(node) => anchorNode(node, pathVisits.get(node.name), reference.name)
|
|
75
|
+
),
|
|
76
|
+
anchoredBy: "paths",
|
|
77
|
+
referencePath: reference.name
|
|
78
|
+
} : graph;
|
|
79
|
+
}
|
|
80
|
+
function anchorGraph(graph, preferred) {
|
|
81
|
+
return graph.anchoredBy === "tags" ? graph : anchorFromPaths(graph, preferred);
|
|
82
|
+
}
|
|
83
|
+
function trimOrigins(graph, kept) {
|
|
84
|
+
if (!graph.anchorPaths) {
|
|
85
|
+
return void 0;
|
|
86
|
+
}
|
|
87
|
+
const lengthOf = new Map(graph.nodes.map((n) => [n.id, n.length]));
|
|
88
|
+
const bp = (ids, end = ids.length) => {
|
|
89
|
+
let sum = 0;
|
|
90
|
+
for (let i = 0; i < end; i++) {
|
|
91
|
+
sum += lengthOf.get(ids[i]) ?? 0;
|
|
92
|
+
}
|
|
93
|
+
return sum;
|
|
94
|
+
};
|
|
95
|
+
const byOrigin = /* @__PURE__ */ new Map();
|
|
96
|
+
for (const path of graph.paths ?? []) {
|
|
97
|
+
const origin = pathOrigin(path.name).name;
|
|
98
|
+
byOrigin.set(origin, [...byOrigin.get(origin) ?? [], path]);
|
|
99
|
+
}
|
|
100
|
+
return graph.anchorPaths.map((o) => {
|
|
101
|
+
const pieces = byOrigin.get(o.name);
|
|
102
|
+
const path = pieces?.length === 1 ? pieces[0] : void 0;
|
|
103
|
+
const stretch = path && kept.get(path.name);
|
|
104
|
+
return path && stretch ? {
|
|
105
|
+
...o,
|
|
106
|
+
start: o.start + bp(path.nodeIds, stretch.first),
|
|
107
|
+
length: bp(stretch.nodeIds)
|
|
108
|
+
} : o;
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export {
|
|
113
|
+
pathOrigin,
|
|
114
|
+
surveyPaths,
|
|
115
|
+
chooseReferencePath,
|
|
116
|
+
anchorFromPaths,
|
|
117
|
+
anchorGraph,
|
|
118
|
+
trimOrigins
|
|
119
|
+
};
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import {
|
|
2
|
+
pathOrigin
|
|
3
|
+
} from "./chunk-ST2IBUAN.js";
|
|
4
|
+
import {
|
|
5
|
+
panSNContig,
|
|
6
|
+
panSNSample
|
|
7
|
+
} from "./chunk-BPLIXMH7.js";
|
|
8
|
+
|
|
9
|
+
// src/layout/walkRows.ts
|
|
10
|
+
function sampleOf(path) {
|
|
11
|
+
return path.sample ?? panSNSample(path.name);
|
|
12
|
+
}
|
|
13
|
+
function labelOf(path) {
|
|
14
|
+
return path.haplotype !== void 0 && path.sample !== void 0 ? `${path.sample}#${path.haplotype}` : sampleOf(path);
|
|
15
|
+
}
|
|
16
|
+
function stepsOf(pieces, lengthOf) {
|
|
17
|
+
const steps = [];
|
|
18
|
+
let end;
|
|
19
|
+
for (const piece of pieces) {
|
|
20
|
+
if (end !== void 0 && piece.start !== void 0 && piece.start > end) {
|
|
21
|
+
steps.push(piece.start - end);
|
|
22
|
+
}
|
|
23
|
+
steps.push(...piece.nodeIds);
|
|
24
|
+
const bp = piece.nodeIds.reduce(
|
|
25
|
+
(sum, id) => sum + (lengthOf.get(id) ?? 0),
|
|
26
|
+
0
|
|
27
|
+
);
|
|
28
|
+
end = piece.start === void 0 ? void 0 : piece.start + bp;
|
|
29
|
+
}
|
|
30
|
+
return steps;
|
|
31
|
+
}
|
|
32
|
+
function stepSpans(pieces, lengthOf) {
|
|
33
|
+
const spans = [];
|
|
34
|
+
let end;
|
|
35
|
+
for (const piece of pieces) {
|
|
36
|
+
if (piece.start === void 0 || end !== void 0 && piece.start < end) {
|
|
37
|
+
return void 0;
|
|
38
|
+
}
|
|
39
|
+
if (end !== void 0 && piece.start > end) {
|
|
40
|
+
spans.push({ start: end, end: piece.start });
|
|
41
|
+
}
|
|
42
|
+
let pos = piece.start;
|
|
43
|
+
for (const id of piece.nodeIds) {
|
|
44
|
+
const len = lengthOf.get(id) ?? 0;
|
|
45
|
+
spans.push({ start: pos, end: pos + len });
|
|
46
|
+
pos += len;
|
|
47
|
+
}
|
|
48
|
+
end = pos;
|
|
49
|
+
}
|
|
50
|
+
return spans;
|
|
51
|
+
}
|
|
52
|
+
function sliceBetween(steps, span, region, flanked = true) {
|
|
53
|
+
if (!region || !flanked) {
|
|
54
|
+
return { ids: steps, complete: true, from: -1, to: -1 };
|
|
55
|
+
}
|
|
56
|
+
let i0 = -1;
|
|
57
|
+
let i1 = -1;
|
|
58
|
+
let bestEnd = -Infinity;
|
|
59
|
+
let bestStart = Infinity;
|
|
60
|
+
steps.forEach((id, i) => {
|
|
61
|
+
const s = typeof id === "string" ? span.get(id) : void 0;
|
|
62
|
+
if (s) {
|
|
63
|
+
if (s.end <= region.start && s.end > bestEnd) {
|
|
64
|
+
bestEnd = s.end;
|
|
65
|
+
i0 = i;
|
|
66
|
+
}
|
|
67
|
+
if (s.start >= region.end && s.start < bestStart) {
|
|
68
|
+
bestStart = s.start;
|
|
69
|
+
i1 = i;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
if (i0 < 0 || i1 < 0) {
|
|
74
|
+
return { ids: steps, complete: false, from: -1, to: -1 };
|
|
75
|
+
}
|
|
76
|
+
const ids = steps.slice(Math.min(i0, i1) + 1, Math.max(i0, i1));
|
|
77
|
+
return {
|
|
78
|
+
ids: i0 < i1 ? ids : ids.reverse(),
|
|
79
|
+
complete: true,
|
|
80
|
+
from: i0,
|
|
81
|
+
to: i1
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function filterSamples(rows, samples) {
|
|
85
|
+
return samples ? rows.filter((r) => samples.includes(r.sample)).sort(
|
|
86
|
+
(a, b) => samples.indexOf(a.sample) - samples.indexOf(b.sample) || a.label.localeCompare(b.label)
|
|
87
|
+
) : rows;
|
|
88
|
+
}
|
|
89
|
+
function walkRows(graph, region, unit) {
|
|
90
|
+
const paths = graph.paths ?? [];
|
|
91
|
+
const isReference = (p) => pathOrigin(p.name).name === graph.referencePath;
|
|
92
|
+
const referencePieces = paths.some(isReference) ? paths.filter(isReference).sort((a, b) => (a.start ?? 0) - (b.start ?? 0)) : paths.slice(0, 1);
|
|
93
|
+
const first = referencePieces[0];
|
|
94
|
+
const others = paths.filter((p) => !referencePieces.includes(p));
|
|
95
|
+
if (!first || others.length === 0) {
|
|
96
|
+
return void 0;
|
|
97
|
+
}
|
|
98
|
+
const walks = /* @__PURE__ */ new Map();
|
|
99
|
+
for (const path of others) {
|
|
100
|
+
walks.set(path.name, [...walks.get(path.name) ?? [], path]);
|
|
101
|
+
}
|
|
102
|
+
const lengthOf = new Map(graph.nodes.map((n) => [n.id, n.length]));
|
|
103
|
+
const referenceStart = first.start ?? 0;
|
|
104
|
+
const cut = region && region.end > region.start ? region : void 0;
|
|
105
|
+
const span = /* @__PURE__ */ new Map();
|
|
106
|
+
for (const piece of referencePieces) {
|
|
107
|
+
let pos = piece.start ?? 0;
|
|
108
|
+
for (const id of piece.nodeIds) {
|
|
109
|
+
const len = lengthOf.get(id) ?? 0;
|
|
110
|
+
if (!span.has(id)) {
|
|
111
|
+
span.set(id, { start: pos, end: pos + len });
|
|
112
|
+
}
|
|
113
|
+
pos += len;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const flanked = cut === void 0 || [...span.values()].some((s) => s.end <= cut.start) && [...span.values()].some((s) => s.start >= cut.end);
|
|
117
|
+
const rowOf = (pieces) => {
|
|
118
|
+
const path = pieces[0];
|
|
119
|
+
const ordered = [...pieces].sort((a, b) => (a.start ?? 0) - (b.start ?? 0));
|
|
120
|
+
const { ids, complete, from, to } = sliceBetween(
|
|
121
|
+
stepsOf(ordered, lengthOf),
|
|
122
|
+
span,
|
|
123
|
+
cut,
|
|
124
|
+
flanked
|
|
125
|
+
);
|
|
126
|
+
const spans = stepSpans(ordered, lengthOf);
|
|
127
|
+
const contig = path.contig ?? panSNContig(pathOrigin(path.name).name);
|
|
128
|
+
const axis = !spans?.length ? void 0 : from < 0 ? { contig, start: spans[0].start, reversed: false } : from < to ? { contig, start: spans[from].end, reversed: false } : { contig, start: spans[from].start, reversed: true };
|
|
129
|
+
const runs = [];
|
|
130
|
+
let bp = 0;
|
|
131
|
+
let offReferenceBp = 0;
|
|
132
|
+
let gapBp = 0;
|
|
133
|
+
let step = 0;
|
|
134
|
+
for (const id of ids) {
|
|
135
|
+
if (typeof id === "number") {
|
|
136
|
+
runs.push({ start: bp, bp: id, onReference: false, gap: true });
|
|
137
|
+
bp += id;
|
|
138
|
+
gapBp += id;
|
|
139
|
+
step = 0;
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
const len = lengthOf.get(id) ?? 0;
|
|
143
|
+
const s = span.get(id);
|
|
144
|
+
const last = runs.at(-1);
|
|
145
|
+
const at = last?.referenceStart;
|
|
146
|
+
const forward = s && at !== void 0 && step >= 0 && at + last.bp === s.start;
|
|
147
|
+
const backward = s && at !== void 0 && step <= 0 && s.end === at;
|
|
148
|
+
if (!s && last && !last.onReference && !last.gap) {
|
|
149
|
+
last.bp += len;
|
|
150
|
+
} else if (forward || backward) {
|
|
151
|
+
last.bp += len;
|
|
152
|
+
if (!forward) {
|
|
153
|
+
last.referenceStart = s.start;
|
|
154
|
+
last.reversed = true;
|
|
155
|
+
}
|
|
156
|
+
step = forward ? 1 : -1;
|
|
157
|
+
} else {
|
|
158
|
+
runs.push({
|
|
159
|
+
start: bp,
|
|
160
|
+
bp: len,
|
|
161
|
+
onReference: s !== void 0,
|
|
162
|
+
referenceStart: s?.start
|
|
163
|
+
});
|
|
164
|
+
step = 0;
|
|
165
|
+
}
|
|
166
|
+
bp += len;
|
|
167
|
+
if (!s) {
|
|
168
|
+
offReferenceBp += len;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
name: path.name,
|
|
173
|
+
label: labelOf(path),
|
|
174
|
+
sample: sampleOf(path),
|
|
175
|
+
haplotype: path.haplotype,
|
|
176
|
+
bp,
|
|
177
|
+
offReferenceBp,
|
|
178
|
+
gapBp,
|
|
179
|
+
complete,
|
|
180
|
+
runs,
|
|
181
|
+
axis
|
|
182
|
+
};
|
|
183
|
+
};
|
|
184
|
+
const origin = cut ? cut.start : referenceStart;
|
|
185
|
+
return {
|
|
186
|
+
origin,
|
|
187
|
+
unit,
|
|
188
|
+
reference: rowOf(referencePieces),
|
|
189
|
+
rows: [...walks.values()].map(rowOf).sort(
|
|
190
|
+
(a, b) => Number(b.complete) - Number(a.complete) || b.bp - a.bp || a.label.localeCompare(b.label)
|
|
191
|
+
)
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export {
|
|
196
|
+
filterSamples,
|
|
197
|
+
walkRows
|
|
198
|
+
};
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import {
|
|
2
|
+
hasTubeMapPaths,
|
|
3
|
+
tubeMapLayout,
|
|
4
|
+
tubeMapReferenceLayout
|
|
5
|
+
} from "./chunk-R6ZUK4Y3.js";
|
|
6
|
+
import {
|
|
7
|
+
sampleRowLayout
|
|
8
|
+
} from "./chunk-LOEA5IHZ.js";
|
|
9
|
+
import {
|
|
10
|
+
anchoredLayout
|
|
11
|
+
} from "./chunk-L3O7AWLI.js";
|
|
12
|
+
import {
|
|
13
|
+
orderedLayout
|
|
14
|
+
} from "./chunk-HNQPEMYE.js";
|
|
15
|
+
import {
|
|
16
|
+
walkRowLayout
|
|
17
|
+
} from "./chunk-EZPBJPK6.js";
|
|
18
|
+
import {
|
|
19
|
+
isBackbone,
|
|
20
|
+
isOffReference
|
|
21
|
+
} from "./chunk-FYQWPEEY.js";
|
|
22
|
+
|
|
23
|
+
// src/layoutModes.ts
|
|
24
|
+
var FORCE_LAYOUT_LABEL = "Force-directed layout";
|
|
25
|
+
var hasBackbone = (graph) => graph.nodes.some(isBackbone);
|
|
26
|
+
var hasWalks = (graph) => hasBackbone(graph) && (graph.paths?.length ?? 0) > 1;
|
|
27
|
+
var hasTubeMapBackbone = (graph) => hasBackbone(graph) && hasTubeMapPaths(graph);
|
|
28
|
+
var hasAlleles = (graph) => hasBackbone(graph) && graph.nodes.some(isOffReference);
|
|
29
|
+
var LAYOUT_MODES = [
|
|
30
|
+
{
|
|
31
|
+
value: "auto",
|
|
32
|
+
label: "Anchored",
|
|
33
|
+
description: "x is reference bp, one row per stable rank. Needs rGFA tags or a reference path.",
|
|
34
|
+
run: anchoredLayout,
|
|
35
|
+
cutMargins: true,
|
|
36
|
+
wholeWalks: false,
|
|
37
|
+
available: hasBackbone,
|
|
38
|
+
drawsLocally: hasBackbone,
|
|
39
|
+
drawsNodes: true
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
value: "samplerows",
|
|
43
|
+
label: "Sample rows",
|
|
44
|
+
description: "x is reference bp, one row per contributing assembly. Needs rGFA tags or a reference path.",
|
|
45
|
+
run: sampleRowLayout,
|
|
46
|
+
cutMargins: true,
|
|
47
|
+
wholeWalks: false,
|
|
48
|
+
available: hasAlleles,
|
|
49
|
+
drawsLocally: hasAlleles,
|
|
50
|
+
drawsNodes: true
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
value: "walkrows",
|
|
54
|
+
label: "Walk rows",
|
|
55
|
+
description: "x is each walk's own bp: one bar per haplotype, blue on the reference's path and purple off it, so a repeat expansion reads as bar length, and each bar boxes its haplotype's own genes where the session has them. Needs W or P lines.",
|
|
56
|
+
run: walkRowLayout,
|
|
57
|
+
cutMargins: false,
|
|
58
|
+
wholeWalks: true,
|
|
59
|
+
available: hasWalks,
|
|
60
|
+
drawsLocally: hasWalks,
|
|
61
|
+
drawsNodes: false
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
value: "ordered",
|
|
65
|
+
label: "Ordered",
|
|
66
|
+
description: "x is reference order, not bp: every node gets room, bubbles read as lenses. Needs rGFA tags or a reference path.",
|
|
67
|
+
run: orderedLayout,
|
|
68
|
+
cutMargins: false,
|
|
69
|
+
wholeWalks: false,
|
|
70
|
+
available: hasBackbone,
|
|
71
|
+
drawsLocally: hasBackbone,
|
|
72
|
+
drawsNodes: true
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
value: "tubemap",
|
|
76
|
+
label: "Tube map",
|
|
77
|
+
description: "sequenceTubeMap: every path a coloured tube through boxed nodes, columns in node order and node widths log-scaled. Needs P or W lines.",
|
|
78
|
+
run: tubeMapLayout,
|
|
79
|
+
cutMargins: false,
|
|
80
|
+
wholeWalks: false,
|
|
81
|
+
available: hasTubeMapPaths,
|
|
82
|
+
drawsLocally: hasTubeMapPaths,
|
|
83
|
+
drawsNodes: false
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
value: "tubemapref",
|
|
87
|
+
label: "Tube map on reference",
|
|
88
|
+
description: "The tube map with each column at the reference bp it covers, so the tubes line up with the tracks around them. Needs P or W lines and a reference path.",
|
|
89
|
+
run: tubeMapReferenceLayout,
|
|
90
|
+
cutMargins: true,
|
|
91
|
+
wholeWalks: false,
|
|
92
|
+
available: hasTubeMapBackbone,
|
|
93
|
+
drawsLocally: hasTubeMapBackbone,
|
|
94
|
+
drawsNodes: false
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
value: "force",
|
|
98
|
+
label: FORCE_LAYOUT_LABEL,
|
|
99
|
+
description: "OGDF FMMM, via the external Bandage engine.",
|
|
100
|
+
run: () => void 0,
|
|
101
|
+
cutMargins: false,
|
|
102
|
+
wholeWalks: false,
|
|
103
|
+
available: () => true,
|
|
104
|
+
drawsLocally: () => false,
|
|
105
|
+
drawsNodes: true
|
|
106
|
+
}
|
|
107
|
+
];
|
|
108
|
+
var LAYOUT_MODE_VALUES = LAYOUT_MODES.map((m) => m.value);
|
|
109
|
+
function modeUsesLayoutEngine(value, graph) {
|
|
110
|
+
return !layoutModeByValue(value).drawsLocally(graph);
|
|
111
|
+
}
|
|
112
|
+
function layoutModeByValue(value) {
|
|
113
|
+
return LAYOUT_MODES.find((m) => m.value === value) ?? LAYOUT_MODES[0];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export {
|
|
117
|
+
FORCE_LAYOUT_LABEL,
|
|
118
|
+
LAYOUT_MODES,
|
|
119
|
+
LAYOUT_MODE_VALUES,
|
|
120
|
+
modeUsesLayoutEngine,
|
|
121
|
+
layoutModeByValue
|
|
122
|
+
};
|