@jbrowse/bandage-core 9.9.2 → 10.0.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 +3 -0
- package/dist/bubbles/popBubble.js +3 -2
- package/dist/bubbles/superbubbles.js +5 -4
- package/dist/chunks/{chunk-YAN2ZPNV.js → chunk-33T67FPZ.js} +1 -1
- package/dist/chunks/{chunk-TOVOJNT7.js → chunk-3APK25GI.js} +1 -1
- package/dist/chunks/{chunk-A6PSWTLX.js → chunk-4QTNXTGW.js} +1 -1
- package/dist/chunks/{chunk-ROQGMTFB.js → chunk-BEWLQADP.js} +6 -6
- package/dist/chunks/{chunk-BQ33OOLC.js → chunk-CDPYXHVR.js} +1 -1
- package/dist/chunks/{chunk-YS7VA5SI.js → chunk-DCJC32QW.js} +1 -1
- package/dist/chunks/{chunk-YGN4KL7W.js → chunk-E5UEYZWK.js} +1 -1
- package/dist/chunks/{chunk-IGJCTPFB.js → chunk-EMUUNWRU.js} +52 -43
- package/dist/chunks/{chunk-PIN7ZMTZ.js → chunk-EU6FBTQF.js} +4 -4
- package/dist/chunks/{chunk-WVBYR6Y7.js → chunk-FG762CCP.js} +3 -8
- package/dist/chunks/{chunk-73RSLGZT.js → chunk-FLFBYSJO.js} +1 -1
- package/dist/chunks/{chunk-IJRNMO4D.js → chunk-ICXMWYOA.js} +5 -5
- package/dist/chunks/{chunk-HOZI3FBG.js → chunk-IM4SJUPO.js} +12 -22
- package/dist/chunks/{chunk-6PYZYBBF.js → chunk-KAN2WTG5.js} +1 -1
- package/dist/chunks/{chunk-RK3MF4FD.js → chunk-KJYSOHVN.js} +1 -1
- package/dist/chunks/{chunk-F4BKWWLS.js → chunk-NP356MC2.js} +4 -4
- package/dist/chunks/{chunk-KJEMKHVB.js → chunk-OEPCRURR.js} +1 -1
- package/dist/chunks/{chunk-ZBLKAWSD.js → chunk-OOLNLCIO.js} +1 -1
- package/dist/chunks/chunk-OPPVSPEF.js +57 -0
- package/dist/chunks/{chunk-OA7RIMZ2.js → chunk-PSMKPSO4.js} +89 -22
- package/dist/chunks/chunk-Q6IOQP4J.js +292 -0
- package/dist/chunks/{chunk-LTUWJKHD.js → chunk-Q7LYHGGQ.js} +114 -6
- package/dist/chunks/{chunk-EE37PVQY.js → chunk-QIVPRZ4H.js} +12 -7
- package/dist/chunks/{chunk-J7YKQ5YW.js → chunk-QXAB2FLJ.js} +1 -1
- package/dist/chunks/chunk-RAEABQNW.js +227 -0
- package/dist/chunks/{chunk-EDASNMLY.js → chunk-REE4GUDM.js} +4 -4
- package/dist/chunks/{chunk-IZ3W5IU2.js → chunk-RJXPPYA7.js} +36 -36
- package/dist/chunks/{chunk-F5BYHLIN.js → chunk-VOWI544A.js} +1 -1
- package/dist/chunks/{chunk-P6O4RSOQ.js → chunk-VZNKA3K2.js} +5 -5
- package/dist/chunks/{chunk-FPTI3WAV.js → chunk-W4GZCVUK.js} +18 -13
- package/dist/chunks/{chunk-MECWJY2R.js → chunk-WI7ZHJ27.js} +5 -5
- package/dist/cli/figure.js +50 -48
- package/dist/cli/fold.js +8 -6
- package/dist/figure.js +31 -29
- package/dist/figureData.js +63 -0
- package/dist/figureSettings.js +9 -7
- package/dist/gbzCut.js +3 -2
- package/dist/gbzWindow.js +6 -1
- package/dist/gfa/gfaConverter.js +3 -2
- package/dist/gfa/graphTables.js +2 -1
- package/dist/index.js +173 -156
- package/dist/layout/forceCache.js +9 -7
- package/dist/layout/smoothChains.js +6 -0
- package/dist/layout/trimToWindow.js +17 -23
- package/dist/layout/tubeMapLayout.js +5 -4
- package/dist/layout/walkRowDraw.js +10 -9
- package/dist/layout/walkRowLayout.js +4 -3
- package/dist/layout/walkRows.js +3 -2
- package/dist/layout/walkStrip.js +11 -10
- package/dist/layoutModes.js +11 -10
- package/dist/pathAnchoring.js +2 -1
- package/dist/pathColors.js +4 -3
- package/dist/pathVisits.js +8 -0
- package/dist/pipeline.js +8 -6
- package/dist/referenceRampCss.js +8 -7
- package/dist/referenceStrip.js +8 -7
- package/dist/renderer/GeometryBuilder.js +7 -6
- package/dist/tubeMap/bundle.js +6 -5
- package/dist/tubeMap/coarsen.js +17 -15
- package/dist/tubeMap/draw.js +4 -3
- package/dist/tubeMap/nodeColors.js +8 -7
- package/dist/types/figureData.d.ts +146 -0
- package/dist/types/gbzWindow.d.ts +15 -1
- package/dist/types/gfa/gfaConverter.d.ts +1 -1
- package/dist/types/index.d.ts +4 -1
- package/dist/types/layout/deletionRoutes.d.ts +1 -1
- package/dist/types/layout/smoothChains.d.ts +2 -0
- package/dist/types/pathAnchoring.d.ts +3 -2
- package/dist/types/pathVisits.d.ts +64 -0
- package/dist/types/types.d.ts +2 -1
- package/dist/types/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/viewport.js +9 -7
- package/dist/walkEncoding.js +8 -7
- package/dist/walkHighlight.js +9 -8
- package/package.json +1 -1
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PathVisits
|
|
3
|
+
} from "./chunk-RAEABQNW.js";
|
|
1
4
|
import {
|
|
2
5
|
panSNSample
|
|
3
6
|
} from "./chunk-BPLIXMH7.js";
|
|
@@ -7,6 +10,32 @@ function walkFields(panSN) {
|
|
|
7
10
|
const [sample = "", haplotype = "", ...contig] = panSN.split("#");
|
|
8
11
|
return { sample, haplotype, contig: contig.join("#") };
|
|
9
12
|
}
|
|
13
|
+
function namesByList(lists, names, listCount, pathNames) {
|
|
14
|
+
const starts = new Int32Array(listCount + 1);
|
|
15
|
+
for (const list of lists) {
|
|
16
|
+
starts[list + 1]++;
|
|
17
|
+
}
|
|
18
|
+
for (let i = 0; i < listCount; i++) {
|
|
19
|
+
starts[i + 1] += starts[i];
|
|
20
|
+
}
|
|
21
|
+
const fill = starts.slice(0, listCount);
|
|
22
|
+
const grouped = new Int32Array(lists.length);
|
|
23
|
+
lists.forEach((list, i) => {
|
|
24
|
+
grouped[fill[list]++] = names[i];
|
|
25
|
+
});
|
|
26
|
+
const listed = new Int32Array(pathNames.length).fill(-1);
|
|
27
|
+
return Array.from({ length: listCount }, (_, list) => {
|
|
28
|
+
const out = [];
|
|
29
|
+
for (let i = starts[list]; i < starts[list + 1]; i++) {
|
|
30
|
+
const k = grouped[i];
|
|
31
|
+
if (listed[k] !== list) {
|
|
32
|
+
listed[k] = list;
|
|
33
|
+
out.push(pathNames[k]);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return out;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
10
39
|
function graphFromTables({ nodes: n, links: l, walks: w }, name = "Imported GFA") {
|
|
11
40
|
const count = n.names.length;
|
|
12
41
|
const declared = n.lengths.length;
|
|
@@ -95,27 +124,54 @@ function graphFromTables({ nodes: n, links: l, walks: w }, name = "Imported GFA"
|
|
|
95
124
|
}
|
|
96
125
|
edgeLists.push(list);
|
|
97
126
|
}
|
|
127
|
+
const adjacency = new Int32Array(count + 1);
|
|
128
|
+
for (let a = 0; a < count; a++) {
|
|
129
|
+
adjacency[a + 1] = adjacency[a] + (neighbours[a]?.length ?? 0) / 2;
|
|
130
|
+
}
|
|
131
|
+
const adjacentNode = new Int32Array(adjacency[count]);
|
|
132
|
+
const adjacentList = new Int32Array(adjacency[count]);
|
|
133
|
+
neighbours.forEach((near, a) => {
|
|
134
|
+
for (let j = 0; j < near.length; j += 2) {
|
|
135
|
+
adjacentNode[adjacency[a] + j / 2] = near[j];
|
|
136
|
+
adjacentList[adjacency[a] + j / 2] = near[j + 1];
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
const listOf = (a, b) => {
|
|
140
|
+
for (let j = adjacency[a]; j < adjacency[a + 1]; j++) {
|
|
141
|
+
if (adjacentNode[j] === b) {
|
|
142
|
+
return adjacentList[j];
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return -1;
|
|
146
|
+
};
|
|
98
147
|
const nameIndex = /* @__PURE__ */ new Map();
|
|
99
148
|
const pathNames = [];
|
|
100
|
-
const
|
|
149
|
+
const crossedList = new Int32Array(w.offsets[w.names.length] ?? 0);
|
|
150
|
+
const crossedName = new Int32Array(crossedList.length);
|
|
151
|
+
let crossings = 0;
|
|
101
152
|
const lastWalk = new Int32Array(lists).fill(-1);
|
|
102
153
|
const paths = [];
|
|
103
154
|
const anchorPaths = [];
|
|
104
|
-
const
|
|
105
|
-
const
|
|
155
|
+
const totalSteps = w.offsets[w.names.length] ?? 0;
|
|
156
|
+
const visitPath = new Int32Array(totalSteps);
|
|
157
|
+
const visitStart = new Float64Array(totalSteps);
|
|
158
|
+
const visitReversed = new Uint8Array(totalSteps);
|
|
159
|
+
const fill = new Int32Array(count).fill(-1);
|
|
106
160
|
const visitOrder = [];
|
|
161
|
+
const blocks = [0];
|
|
162
|
+
const pathSamples = [];
|
|
107
163
|
for (const p of drawnWalks) {
|
|
108
164
|
const { sample, haplotype, contig } = walkFields(w.names[p]);
|
|
109
165
|
const pathName = `${sample}#${+haplotype}#${contig}`;
|
|
110
166
|
let named = nameIndex.get(pathName);
|
|
111
|
-
const repeat = named !== void 0;
|
|
112
167
|
if (named === void 0) {
|
|
113
168
|
named = pathNames.length;
|
|
114
169
|
nameIndex.set(pathName, named);
|
|
115
170
|
pathNames.push(pathName);
|
|
171
|
+
pathSamples.push(panSNSample(pathName));
|
|
116
172
|
}
|
|
117
173
|
const start = w.starts[p];
|
|
118
|
-
const visitSample =
|
|
174
|
+
const visitSample = pathSamples[named];
|
|
119
175
|
const first = w.offsets[p];
|
|
120
176
|
const nodeIds = new Array(w.offsets[p + 1] - first);
|
|
121
177
|
let pos = start;
|
|
@@ -123,25 +179,22 @@ function graphFromTables({ nodes: n, links: l, walks: w }, name = "Imported GFA"
|
|
|
123
179
|
for (let s = first; s < w.offsets[p + 1]; s++) {
|
|
124
180
|
const node = w.steps[s];
|
|
125
181
|
nodeIds[s - first] = ids[node];
|
|
126
|
-
if (
|
|
127
|
-
|
|
182
|
+
if (fill[node] === -1) {
|
|
183
|
+
fill[node] = blocks.at(-1);
|
|
184
|
+
blocks.push(fill[node] + traversals[node]);
|
|
128
185
|
visitOrder.push(node);
|
|
129
186
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
strand: w.reversed[s] ? "-" : "+"
|
|
135
|
-
};
|
|
187
|
+
const at = fill[node]++;
|
|
188
|
+
visitPath[at] = named;
|
|
189
|
+
visitStart[at] = pos;
|
|
190
|
+
visitReversed[at] = w.reversed[s];
|
|
136
191
|
pos += node < declared ? n.lengths[node] : 0;
|
|
137
192
|
if (prev >= 0) {
|
|
138
|
-
const list =
|
|
139
|
-
if (list
|
|
193
|
+
const list = listOf(prev, node);
|
|
194
|
+
if (list >= 0 && lastWalk[list] !== p) {
|
|
140
195
|
lastWalk[list] = p;
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
names.push(named);
|
|
144
|
-
}
|
|
196
|
+
crossedList[crossings] = list;
|
|
197
|
+
crossedName[crossings++] = named;
|
|
145
198
|
}
|
|
146
199
|
}
|
|
147
200
|
prev = node;
|
|
@@ -161,10 +214,16 @@ function graphFromTables({ nodes: n, links: l, walks: w }, name = "Imported GFA"
|
|
|
161
214
|
length: pos - start
|
|
162
215
|
});
|
|
163
216
|
}
|
|
217
|
+
const listNames = namesByList(
|
|
218
|
+
crossedList.subarray(0, crossings),
|
|
219
|
+
crossedName,
|
|
220
|
+
lists,
|
|
221
|
+
pathNames
|
|
222
|
+
);
|
|
164
223
|
edges.forEach((edge, i) => {
|
|
165
|
-
const names =
|
|
224
|
+
const names = listNames[edgeLists[i]];
|
|
166
225
|
if (names.length > 0) {
|
|
167
|
-
edge.pathIds = names
|
|
226
|
+
edge.pathIds = names;
|
|
168
227
|
}
|
|
169
228
|
});
|
|
170
229
|
const walked = drawnWalks.length > 0;
|
|
@@ -174,7 +233,15 @@ function graphFromTables({ nodes: n, links: l, walks: w }, name = "Imported GFA"
|
|
|
174
233
|
edges,
|
|
175
234
|
paths: walked ? paths : void 0,
|
|
176
235
|
anchorPaths: walked ? anchorPaths : void 0,
|
|
177
|
-
pathVisits: walked ? new
|
|
236
|
+
pathVisits: walked ? new PathVisits({
|
|
237
|
+
segments: visitOrder.map((node) => n.names[node]),
|
|
238
|
+
offsets: Int32Array.from(blocks),
|
|
239
|
+
path: visitPath.subarray(0, blocks.at(-1)),
|
|
240
|
+
start: visitStart.subarray(0, blocks.at(-1)),
|
|
241
|
+
reversed: visitReversed.subarray(0, blocks.at(-1)),
|
|
242
|
+
paths: pathNames,
|
|
243
|
+
samples: pathSamples
|
|
244
|
+
}) : void 0,
|
|
178
245
|
anchoredBy: nodes.some((node) => node.stable) ? "tags" : void 0
|
|
179
246
|
};
|
|
180
247
|
}
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import {
|
|
2
|
+
layoutEngine
|
|
3
|
+
} from "./chunk-VK6XMP6B.js";
|
|
4
|
+
import {
|
|
5
|
+
layoutModeByValue
|
|
6
|
+
} from "./chunk-ICXMWYOA.js";
|
|
7
|
+
import {
|
|
8
|
+
parseRegion
|
|
9
|
+
} from "./chunk-FLFBYSJO.js";
|
|
10
|
+
import {
|
|
11
|
+
layoutGeometryInputs
|
|
12
|
+
} from "./chunk-LOCJN3BZ.js";
|
|
13
|
+
import {
|
|
14
|
+
version
|
|
15
|
+
} from "./chunk-CDPYXHVR.js";
|
|
16
|
+
import {
|
|
17
|
+
axisScaleOf
|
|
18
|
+
} from "./chunk-OOLNLCIO.js";
|
|
19
|
+
import {
|
|
20
|
+
facetLifts,
|
|
21
|
+
walkLift
|
|
22
|
+
} from "./chunk-QIVPRZ4H.js";
|
|
23
|
+
import {
|
|
24
|
+
walkKey
|
|
25
|
+
} from "./chunk-2LQ5BWT7.js";
|
|
26
|
+
import {
|
|
27
|
+
buildGeometry,
|
|
28
|
+
computeReferenceRamp
|
|
29
|
+
} from "./chunk-NP356MC2.js";
|
|
30
|
+
import {
|
|
31
|
+
abgrAlpha,
|
|
32
|
+
abgrBlue,
|
|
33
|
+
abgrGreen,
|
|
34
|
+
abgrRed
|
|
35
|
+
} from "./chunk-G2FD7S3C.js";
|
|
36
|
+
import {
|
|
37
|
+
pathLegend,
|
|
38
|
+
walkLabelsOf
|
|
39
|
+
} from "./chunk-REE4GUDM.js";
|
|
40
|
+
import {
|
|
41
|
+
drawingBounds,
|
|
42
|
+
engineSettingsOf,
|
|
43
|
+
fitTransform,
|
|
44
|
+
forceLayout,
|
|
45
|
+
loadGraph
|
|
46
|
+
} from "./chunk-W4GZCVUK.js";
|
|
47
|
+
import {
|
|
48
|
+
referenceLabel
|
|
49
|
+
} from "./chunk-RAKOB6IV.js";
|
|
50
|
+
import {
|
|
51
|
+
resolveColorScheme
|
|
52
|
+
} from "./chunk-JKJWSY4V.js";
|
|
53
|
+
import {
|
|
54
|
+
deletionDrawing,
|
|
55
|
+
deletionEdges
|
|
56
|
+
} from "./chunk-N6FECAXP.js";
|
|
57
|
+
import {
|
|
58
|
+
isBackbone
|
|
59
|
+
} from "./chunk-FYQWPEEY.js";
|
|
60
|
+
import {
|
|
61
|
+
facetCells,
|
|
62
|
+
facetSettingOf
|
|
63
|
+
} from "./chunk-XV4P5KEQ.js";
|
|
64
|
+
|
|
65
|
+
// src/figureData.ts
|
|
66
|
+
function columns(keys) {
|
|
67
|
+
const out = Object.fromEntries(
|
|
68
|
+
keys.map((k) => [k, []])
|
|
69
|
+
);
|
|
70
|
+
return {
|
|
71
|
+
out,
|
|
72
|
+
push(row) {
|
|
73
|
+
for (const k of keys) {
|
|
74
|
+
out[k].push(row[k]);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
var hex = (v) => v.toString(16).padStart(2, "0");
|
|
80
|
+
var cssHex = (c) => `#${hex(abgrRed(c))}${hex(abgrGreen(c))}${hex(abgrBlue(c))}`;
|
|
81
|
+
var alphaOf = (c) => abgrAlpha(c) / 255;
|
|
82
|
+
function figureData(graph, layout, o = {}) {
|
|
83
|
+
if (layout.tubeMap) {
|
|
84
|
+
throw new Error("figure data has no tables for a tube map yet");
|
|
85
|
+
}
|
|
86
|
+
const width = o.width ?? 1200;
|
|
87
|
+
const height = o.height ?? 800;
|
|
88
|
+
const region = o.region;
|
|
89
|
+
const pixelRows = layout.pixelRows ?? false;
|
|
90
|
+
const bounds = drawingBounds(layout, {
|
|
91
|
+
region: o.fitToDrawing ? void 0 : region
|
|
92
|
+
});
|
|
93
|
+
const fit = fitTransform(bounds, width, height, pixelRows);
|
|
94
|
+
if (!fit) {
|
|
95
|
+
throw new Error("the layout drew nothing to fit");
|
|
96
|
+
}
|
|
97
|
+
const axis = axisScaleOf(fit.scale, pixelRows);
|
|
98
|
+
const nodeById = new Map(graph.nodes.map((node) => [node.id, node]));
|
|
99
|
+
const colorScheme = resolveColorScheme(o.colorScheme ?? "auto", graph);
|
|
100
|
+
const rampDomain = o.colorDomain ?? region;
|
|
101
|
+
const referenceRamp = colorScheme === "reference-position" ? computeReferenceRamp(graph, rampDomain) : void 0;
|
|
102
|
+
const drawnDeletions = deletionDrawing(
|
|
103
|
+
graph,
|
|
104
|
+
deletionEdges(graph),
|
|
105
|
+
o.showDeletionEdges
|
|
106
|
+
);
|
|
107
|
+
const layers = o.walks ?? [];
|
|
108
|
+
const walkRamp = layers.some((l) => l.color?.field === "reference") ? referenceRamp ?? computeReferenceRamp(graph, rampDomain) : void 0;
|
|
109
|
+
const lift = layers.length > 0 ? walkLift(graph, layers, walkRamp) : void 0;
|
|
110
|
+
const facet = facetSettingOf(o.facet);
|
|
111
|
+
const facetted = facet.field && lift && lift.walks.length > 1 ? facetLifts(graph, lift, layers, walkRamp) : void 0;
|
|
112
|
+
const labels = walkLabelsOf(
|
|
113
|
+
graph.paths?.length ? pathLegend(graph.paths) : []
|
|
114
|
+
);
|
|
115
|
+
const labelOf = (name) => labels.get(name) ?? name;
|
|
116
|
+
const referenceName = o.referenceName ?? referenceLabel(graph, region);
|
|
117
|
+
const reference = lift?.referenceDomain && {
|
|
118
|
+
...lift.referenceDomain,
|
|
119
|
+
name: referenceName
|
|
120
|
+
};
|
|
121
|
+
const panels = [];
|
|
122
|
+
if (facetted) {
|
|
123
|
+
const place = facetCells(
|
|
124
|
+
facetted.map((p) => p.walks[0].name),
|
|
125
|
+
facet.field || "walk",
|
|
126
|
+
facet.domain
|
|
127
|
+
);
|
|
128
|
+
const ordered = facetted.map((panel, i) => ({ panel, cell: place.cells[i] })).sort((a, b) => a.cell - b.cell);
|
|
129
|
+
for (const { panel } of ordered) {
|
|
130
|
+
const walk = panel.walks[0];
|
|
131
|
+
const key = walkKey(walk, reference);
|
|
132
|
+
panels.push({
|
|
133
|
+
highlight: panel,
|
|
134
|
+
name: labelOf(walk.name),
|
|
135
|
+
key: key.delta + key.outside + key.reversed,
|
|
136
|
+
range: key.scale ?? ""
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
panels.push({ highlight: lift, name: "", key: "", range: "" });
|
|
141
|
+
}
|
|
142
|
+
const nodes = columns([
|
|
143
|
+
"panel",
|
|
144
|
+
"node",
|
|
145
|
+
"stroke",
|
|
146
|
+
"x",
|
|
147
|
+
"y",
|
|
148
|
+
"color",
|
|
149
|
+
"alpha",
|
|
150
|
+
"width"
|
|
151
|
+
]);
|
|
152
|
+
const edges = columns([
|
|
153
|
+
"panel",
|
|
154
|
+
"edge",
|
|
155
|
+
"curve",
|
|
156
|
+
"x0",
|
|
157
|
+
"y0",
|
|
158
|
+
"cx0",
|
|
159
|
+
"cy0",
|
|
160
|
+
"cx1",
|
|
161
|
+
"cy1",
|
|
162
|
+
"x1",
|
|
163
|
+
"y1",
|
|
164
|
+
"color",
|
|
165
|
+
"alpha",
|
|
166
|
+
"width",
|
|
167
|
+
"deletion"
|
|
168
|
+
]);
|
|
169
|
+
const arrows = columns([
|
|
170
|
+
"panel",
|
|
171
|
+
"edge",
|
|
172
|
+
"x",
|
|
173
|
+
"y",
|
|
174
|
+
"angle",
|
|
175
|
+
"length",
|
|
176
|
+
"halfWidth",
|
|
177
|
+
"color",
|
|
178
|
+
"alpha"
|
|
179
|
+
]);
|
|
180
|
+
for (const { highlight, name: panel } of panels) {
|
|
181
|
+
const batch = buildGeometry({
|
|
182
|
+
...layoutGeometryInputs(layout, drawnDeletions),
|
|
183
|
+
graph,
|
|
184
|
+
nodeById,
|
|
185
|
+
colorScheme,
|
|
186
|
+
contigThickness: o.contigThickness ?? 6,
|
|
187
|
+
connectorThickness: o.connectorThickness ?? 2,
|
|
188
|
+
drawPaths: false,
|
|
189
|
+
nodeWidth: o.nodeWidth ?? "depth",
|
|
190
|
+
linearLayout: o.linearLayout,
|
|
191
|
+
highlight,
|
|
192
|
+
axis,
|
|
193
|
+
referenceRamp
|
|
194
|
+
});
|
|
195
|
+
for (const [node, run] of batch.nodeStrokeRuns) {
|
|
196
|
+
for (let i = run.start; i < run.start + run.count; i++) {
|
|
197
|
+
const s = batch.nodeStrokes[i];
|
|
198
|
+
for (const p of s.points) {
|
|
199
|
+
nodes.push({
|
|
200
|
+
panel,
|
|
201
|
+
node,
|
|
202
|
+
stroke: i,
|
|
203
|
+
x: p.x,
|
|
204
|
+
y: p.y,
|
|
205
|
+
color: cssHex(s.color),
|
|
206
|
+
alpha: alphaOf(s.color),
|
|
207
|
+
width: s.thickness * 2
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
for (const [edge, run] of batch.edgeCurveRuns) {
|
|
213
|
+
for (let i = run.start; i < run.start + run.count; i++) {
|
|
214
|
+
const b = batch.edgeCurves[i];
|
|
215
|
+
for (const c of b.curves) {
|
|
216
|
+
edges.push({
|
|
217
|
+
panel,
|
|
218
|
+
edge,
|
|
219
|
+
curve: i,
|
|
220
|
+
...c,
|
|
221
|
+
color: cssHex(b.color),
|
|
222
|
+
alpha: alphaOf(b.color),
|
|
223
|
+
width: b.thickness * 2,
|
|
224
|
+
deletion: drawnDeletions.bypassed.has(edge)
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
for (const [edge, run] of batch.arrowRuns) {
|
|
230
|
+
for (let i = run.start; i < run.start + run.count; i++) {
|
|
231
|
+
const a = batch.arrows[i];
|
|
232
|
+
arrows.push({
|
|
233
|
+
panel,
|
|
234
|
+
edge,
|
|
235
|
+
x: a.x,
|
|
236
|
+
y: a.y,
|
|
237
|
+
angle: a.angle,
|
|
238
|
+
length: a.length,
|
|
239
|
+
halfWidth: a.halfWidth,
|
|
240
|
+
color: cssHex(a.color),
|
|
241
|
+
alpha: alphaOf(a.color)
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return {
|
|
247
|
+
meta: {
|
|
248
|
+
generator: `@jbrowse/bandage-core@${version}`,
|
|
249
|
+
width,
|
|
250
|
+
scaleX: axis.scaleX,
|
|
251
|
+
scaleY: axis.scaleY,
|
|
252
|
+
pixelRows,
|
|
253
|
+
referenceAxis: layout.referenceAxis ?? false,
|
|
254
|
+
colorScheme,
|
|
255
|
+
referenceName: referenceName ?? null
|
|
256
|
+
},
|
|
257
|
+
panels: {
|
|
258
|
+
panel: panels.map((p) => p.name),
|
|
259
|
+
key: panels.map((p) => p.key),
|
|
260
|
+
range: panels.map((p) => p.range)
|
|
261
|
+
},
|
|
262
|
+
nodes: nodes.out,
|
|
263
|
+
edges: edges.out,
|
|
264
|
+
arrows: arrows.out,
|
|
265
|
+
nodeInfo: {
|
|
266
|
+
node: graph.nodes.map((n) => n.id),
|
|
267
|
+
name: graph.nodes.map((n) => n.name),
|
|
268
|
+
length: graph.nodes.map((n) => n.length),
|
|
269
|
+
depth: graph.nodes.map((n) => n.depth),
|
|
270
|
+
backbone: graph.nodes.map((n) => isBackbone(n))
|
|
271
|
+
},
|
|
272
|
+
rowLabels: {
|
|
273
|
+
label: (layout.rowLabels ?? []).map((r) => r.label),
|
|
274
|
+
y: (layout.rowLabels ?? []).map((r) => r.y)
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
async function gfaFigureData(text, name, spec = {}) {
|
|
279
|
+
const region = spec.region ? parseRegion(spec.region) : void 0;
|
|
280
|
+
const graph = loadGraph(text, name, { referencePath: spec.referencePath });
|
|
281
|
+
const layout = layoutModeByValue(spec.layout ?? "force").run(graph, region) ?? (await forceLayout(graph, engineSettingsOf(spec), layoutEngine)).result;
|
|
282
|
+
return figureData(graph, layout, {
|
|
283
|
+
...spec,
|
|
284
|
+
region,
|
|
285
|
+
walks: spec.walks?.map((w) => typeof w === "string" ? { walk: w } : w)
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export {
|
|
290
|
+
figureData,
|
|
291
|
+
gfaFigureData
|
|
292
|
+
};
|
|
@@ -4,12 +4,16 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
wellKnownSample
|
|
6
6
|
} from "./chunk-RAKOB6IV.js";
|
|
7
|
+
import {
|
|
8
|
+
gfaTables
|
|
9
|
+
} from "./chunk-G45YY72K.js";
|
|
7
10
|
import {
|
|
8
11
|
panSNMatchesPrefix,
|
|
9
12
|
panSNSample
|
|
10
13
|
} from "./chunk-BPLIXMH7.js";
|
|
11
14
|
|
|
12
15
|
// src/gbzWindow.ts
|
|
16
|
+
import { isReverse, nodeId } from "@gmod/gbz-base";
|
|
13
17
|
var NoReferenceSampleError = class extends Error {
|
|
14
18
|
constructor(anchor, referenceSamples) {
|
|
15
19
|
super(
|
|
@@ -82,13 +86,12 @@ var GBZ_CUT_DEFAULTS = {
|
|
|
82
86
|
snarls: "contained",
|
|
83
87
|
limit: 1e5
|
|
84
88
|
};
|
|
85
|
-
async function
|
|
86
|
-
|
|
87
|
-
return "";
|
|
88
|
-
}
|
|
89
|
-
const subgraphs = await db.getSubgraphs({ ...opts, path: query, start, end, haplotypes: "all" }).catch((error) => {
|
|
89
|
+
async function windowCuts(db, query, start, end, opts) {
|
|
90
|
+
return db.getSubgraphs({ ...opts, path: query, start, end, haplotypes: "all" }).catch((error) => {
|
|
90
91
|
throw nodeLimitError(error, opts.limit, end - start) ?? error;
|
|
91
92
|
});
|
|
93
|
+
}
|
|
94
|
+
async function joinedGFA(db, subgraphs) {
|
|
92
95
|
const paths = await db.paths();
|
|
93
96
|
return joinCuts(
|
|
94
97
|
await Promise.all(subgraphs.map((subgraph) => subgraph.toGFA())),
|
|
@@ -97,6 +100,109 @@ async function cutWindowGFA(db, query, start, end, opts) {
|
|
|
97
100
|
)
|
|
98
101
|
);
|
|
99
102
|
}
|
|
103
|
+
async function cutWindowGFA(db, query, start, end, opts) {
|
|
104
|
+
return query ? joinedGFA(db, await windowCuts(db, query, start, end, opts)) : "";
|
|
105
|
+
}
|
|
106
|
+
async function cutWindowTables(db, query, start, end, opts) {
|
|
107
|
+
if (!query) {
|
|
108
|
+
return "";
|
|
109
|
+
}
|
|
110
|
+
const subgraphs = await windowCuts(db, query, start, end, opts);
|
|
111
|
+
if (subgraphs.length === 1) {
|
|
112
|
+
return compactTables(subgraphs[0].toCompactSubgraph());
|
|
113
|
+
}
|
|
114
|
+
const text = await joinedGFA(db, subgraphs);
|
|
115
|
+
return text && gfaTables(text) || text;
|
|
116
|
+
}
|
|
117
|
+
function segmentIndex(ids, names) {
|
|
118
|
+
let low = Infinity;
|
|
119
|
+
let high = -Infinity;
|
|
120
|
+
for (const id of ids) {
|
|
121
|
+
low = Math.min(low, id);
|
|
122
|
+
high = Math.max(high, id);
|
|
123
|
+
}
|
|
124
|
+
const span = high - low + 1;
|
|
125
|
+
const table = ids.length > 0 && span <= 16 * ids.length ? new Int32Array(span).fill(-1) : void 0;
|
|
126
|
+
const extra = /* @__PURE__ */ new Map();
|
|
127
|
+
ids.forEach((id, i) => {
|
|
128
|
+
if (table) {
|
|
129
|
+
table[id - low] = i;
|
|
130
|
+
} else {
|
|
131
|
+
extra.set(id, i);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
return (handle) => {
|
|
135
|
+
const id = nodeId(handle);
|
|
136
|
+
const tabled = table !== void 0 && id >= low && id <= high;
|
|
137
|
+
const i = tabled ? table[id - low] : extra.get(id) ?? -1;
|
|
138
|
+
if (i >= 0) {
|
|
139
|
+
return i;
|
|
140
|
+
}
|
|
141
|
+
if (tabled) {
|
|
142
|
+
table[id - low] = names.length;
|
|
143
|
+
} else {
|
|
144
|
+
extra.set(id, names.length);
|
|
145
|
+
}
|
|
146
|
+
names.push(String(id));
|
|
147
|
+
return names.length - 1;
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
var WALK_NAME = /^(.*)\[(\d+)-(\d+)\]$/;
|
|
151
|
+
function compactTables(cut) {
|
|
152
|
+
const names = Array.from(cut.nodeIds, String);
|
|
153
|
+
const indexOf = segmentIndex(cut.nodeIds, names);
|
|
154
|
+
const declared = cut.nodeIds.length;
|
|
155
|
+
const linkCount = cut.edges.length / 2;
|
|
156
|
+
const from = new Int32Array(linkCount);
|
|
157
|
+
const to = new Int32Array(linkCount);
|
|
158
|
+
const strands = new Uint8Array(linkCount);
|
|
159
|
+
for (let k = 0; k < linkCount; k++) {
|
|
160
|
+
const a = cut.edges[2 * k];
|
|
161
|
+
const b = cut.edges[2 * k + 1];
|
|
162
|
+
from[k] = indexOf(a);
|
|
163
|
+
to[k] = indexOf(b);
|
|
164
|
+
strands[k] = (isReverse(a) ? 1 : 0) | (isReverse(b) ? 2 : 0);
|
|
165
|
+
}
|
|
166
|
+
const walks = cut.paths.filter((path) => path.steps.length > 0);
|
|
167
|
+
const offsets = new Int32Array(walks.length + 1);
|
|
168
|
+
walks.forEach((walk, p) => {
|
|
169
|
+
offsets[p + 1] = offsets[p] + walk.steps.length;
|
|
170
|
+
});
|
|
171
|
+
const steps = new Int32Array(offsets[walks.length]);
|
|
172
|
+
const reversed = new Uint8Array(steps.length);
|
|
173
|
+
const starts = new Float64Array(walks.length);
|
|
174
|
+
const ends = new Float64Array(walks.length);
|
|
175
|
+
const walkNames = walks.map((walk, p) => {
|
|
176
|
+
const named = WALK_NAME.exec(walk.name);
|
|
177
|
+
starts[p] = named ? +named[2] : 0;
|
|
178
|
+
ends[p] = named ? +named[3] : -1;
|
|
179
|
+
let at = offsets[p];
|
|
180
|
+
for (const handle of walk.steps) {
|
|
181
|
+
steps[at] = indexOf(handle);
|
|
182
|
+
reversed[at++] = isReverse(handle) ? 1 : 0;
|
|
183
|
+
}
|
|
184
|
+
return named ? named[1] : walk.name;
|
|
185
|
+
});
|
|
186
|
+
return {
|
|
187
|
+
nodes: {
|
|
188
|
+
names,
|
|
189
|
+
lengths: Int32Array.from(cut.nodeSequences, (s) => s.length),
|
|
190
|
+
refs: new Int32Array(declared).fill(-1),
|
|
191
|
+
starts: new Float64Array(declared),
|
|
192
|
+
ranks: new Int32Array(declared),
|
|
193
|
+
refNames: []
|
|
194
|
+
},
|
|
195
|
+
links: { from, to, strands },
|
|
196
|
+
walks: {
|
|
197
|
+
names: walkNames,
|
|
198
|
+
starts,
|
|
199
|
+
ends,
|
|
200
|
+
offsets,
|
|
201
|
+
steps,
|
|
202
|
+
reversed
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
}
|
|
100
206
|
|
|
101
207
|
export {
|
|
102
208
|
NoReferenceSampleError,
|
|
@@ -108,5 +214,7 @@ export {
|
|
|
108
214
|
referencePathQuery,
|
|
109
215
|
nodeLimitError,
|
|
110
216
|
GBZ_CUT_DEFAULTS,
|
|
111
|
-
cutWindowGFA
|
|
217
|
+
cutWindowGFA,
|
|
218
|
+
cutWindowTables,
|
|
219
|
+
compactTables
|
|
112
220
|
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
encodedColor,
|
|
3
3
|
resolveEncoding
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-VOWI544A.js";
|
|
5
5
|
import {
|
|
6
6
|
pathOrigin
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-EMUUNWRU.js";
|
|
8
8
|
import {
|
|
9
9
|
panSNContig
|
|
10
10
|
} from "./chunk-BPLIXMH7.js";
|
|
@@ -90,14 +90,19 @@ function reversedNodes(graph, walk) {
|
|
|
90
90
|
if (!referencePath || walk.reference) {
|
|
91
91
|
return { reversed, bp };
|
|
92
92
|
}
|
|
93
|
-
const
|
|
93
|
+
const visits = graph.pathVisits;
|
|
94
|
+
if (!visits) {
|
|
95
|
+
return { reversed, bp };
|
|
96
|
+
}
|
|
97
|
+
const own = visits.pathIndex(pathOrigin(walk.name).name);
|
|
98
|
+
const theirs = visits.pathIndex(referencePath);
|
|
94
99
|
const byId = new Map(graph.nodes.map((n) => [n.id, n]));
|
|
95
100
|
for (const id of walk.progress.keys()) {
|
|
96
101
|
const node = byId.get(id);
|
|
97
|
-
const
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
-
if (
|
|
102
|
+
const slot = node ? visits.slot(node.name) : -1;
|
|
103
|
+
const a = slot < 0 ? -1 : visits.firstBy(slot, own);
|
|
104
|
+
const b = slot < 0 ? -1 : visits.firstBy(slot, theirs);
|
|
105
|
+
if (a >= 0 && b >= 0 && visits.reversed[a] !== visits.reversed[b]) {
|
|
101
106
|
reversed.add(id);
|
|
102
107
|
bp += node.length;
|
|
103
108
|
}
|