jbrowse-plugin-graphgenomeviewer 7.2.0 → 7.2.1
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/chunks/GbzBaseSyntenyAdapter-FXMGIM7Z.js +2 -0
- package/dist/chunks/{GbzBaseSyntenyAdapter-NB6WBBZH.js.map → GbzBaseSyntenyAdapter-FXMGIM7Z.js.map} +3 -3
- package/dist/chunks/{GraphGenomeView-4O5F5I37.js → GraphGenomeView-WJ3FIDY2.js} +2 -2
- package/dist/chunks/{GraphTrackSettingsDialog-WZEJAF7F.js → GraphTrackSettingsDialog-ZW7ALMDV.js} +2 -2
- package/dist/chunks/{HighlightColorDialog-SRT2FPXP.js → HighlightColorDialog-VBZRUKD5.js} +2 -2
- package/dist/chunks/{LinearGraphDisplay-Z33PVCJL.js → LinearGraphDisplay-SPOPTJEN.js} +2 -2
- package/dist/chunks/MinigraphBubbleAdapter-QCOMFPLL.js +2 -0
- package/dist/chunks/{MinigraphBubbleAdapter-HDLUZ6YF.js.map → MinigraphBubbleAdapter-QCOMFPLL.js.map} +1 -1
- package/dist/chunks/RgfaTabixAdapter-O3NMNRZ2.js +2 -0
- package/dist/chunks/RgfaTabixAdapter-O3NMNRZ2.js.map +7 -0
- package/dist/chunks/WalkTabixSyntenyAdapter-I3PY6HJ2.js +2 -0
- package/dist/chunks/{WalkTabixSyntenyAdapter-WBHOZLAN.js.map → WalkTabixSyntenyAdapter-I3PY6HJ2.js.map} +1 -1
- package/dist/chunks/chunk-2M4XYSLG.js +2 -0
- package/dist/chunks/chunk-2M4XYSLG.js.map +7 -0
- package/dist/chunks/{chunk-JLGPQO5L.js → chunk-2O3YVA2I.js} +2 -2
- package/dist/chunks/{chunk-CWNJR5XB.js → chunk-44CJ2N3N.js} +1 -1
- package/dist/chunks/{chunk-CWNJR5XB.js.map → chunk-44CJ2N3N.js.map} +1 -1
- package/dist/chunks/chunk-6KUHGRHU.js +2 -0
- package/dist/chunks/chunk-6KUHGRHU.js.map +7 -0
- package/dist/chunks/chunk-6MUBJVBG.js +2 -0
- package/dist/chunks/chunk-6MUBJVBG.js.map +7 -0
- package/dist/chunks/{chunk-GUXZESDR.js → chunk-7HWHWPRW.js} +1 -1
- package/dist/chunks/{chunk-GUXZESDR.js.map → chunk-7HWHWPRW.js.map} +1 -1
- package/dist/chunks/chunk-B2EP6FOQ.js +3 -0
- package/dist/chunks/chunk-B2EP6FOQ.js.map +7 -0
- package/dist/chunks/{chunk-44HZPYGC.js → chunk-BXRTG7FU.js} +2 -2
- package/dist/chunks/{chunk-44HZPYGC.js.map → chunk-BXRTG7FU.js.map} +1 -1
- package/dist/chunks/{chunk-HLKZCTQ3.js → chunk-DBPEUVUC.js} +1 -1
- package/dist/chunks/{chunk-HLKZCTQ3.js.map → chunk-DBPEUVUC.js.map} +1 -1
- package/dist/chunks/{chunk-FME624X3.js → chunk-DUR437TH.js} +2 -2
- package/dist/chunks/{chunk-FME624X3.js.map → chunk-DUR437TH.js.map} +1 -1
- package/dist/chunks/{chunk-6WA6WF6A.js → chunk-FIRQAKMX.js} +1 -1
- package/dist/chunks/{chunk-6WA6WF6A.js.map → chunk-FIRQAKMX.js.map} +1 -1
- package/dist/chunks/chunk-JCAZTNYG.js +2 -0
- package/dist/chunks/chunk-JCAZTNYG.js.map +7 -0
- package/dist/chunks/chunk-N74HGPAW.js +3 -0
- package/dist/chunks/chunk-N74HGPAW.js.map +7 -0
- package/dist/chunks/chunk-PEDWEPNK.js +2 -0
- package/dist/chunks/chunk-PEDWEPNK.js.map +7 -0
- package/dist/chunks/chunk-PYQG3JHP.js +3 -0
- package/dist/chunks/chunk-PYQG3JHP.js.map +7 -0
- package/dist/chunks/chunk-RFDSEB2X.js +4 -0
- package/dist/chunks/chunk-RFDSEB2X.js.map +7 -0
- package/dist/chunks/{chunk-O7Y7LYN6.js → chunk-RW775LQN.js} +2 -2
- package/dist/chunks/{chunk-O7Y7LYN6.js.map → chunk-RW775LQN.js.map} +1 -1
- package/dist/chunks/{chunk-N4WBX2OS.js → chunk-VQ77X5QU.js} +2 -2
- package/dist/chunks/{chunk-N4WBX2OS.js.map → chunk-VQ77X5QU.js.map} +1 -1
- package/dist/chunks/{chunk-LXCMWL7B.js → chunk-WUSKVEA6.js} +2 -2
- package/dist/chunks/{chunk-LXCMWL7B.js.map → chunk-WUSKVEA6.js.map} +1 -1
- package/dist/chunks/{chunk-ZNT7TQLN.js → chunk-YKSUKPYY.js} +2 -2
- package/dist/chunks/chunk-YKSUKPYY.js.map +7 -0
- package/dist/chunks/{renderSvg-RRWCAEGF.js → renderSvg-WD6YDV2I.js} +2 -2
- package/dist/jbrowse-plugin-graphgenomeviewer.esm.js +4 -4
- package/dist/jbrowse-plugin-graphgenomeviewer.esm.js.map +4 -4
- package/package.json +3 -3
- package/src/GbzBaseSyntenyAdapter/GbzBaseSyntenyAdapter.test.ts +2 -2
- package/src/GbzBaseSyntenyAdapter/GbzBaseSyntenyAdapter.ts +1 -1
- package/src/GetSubgraph.ts +1 -1
- package/src/GraphGenomeView/genes/genes.test.ts +20 -2
- package/src/GraphGenomeView/legendSections.test.ts +1 -1
- package/src/GraphGenomeView/legendSections.ts +1 -7
- package/src/GraphGenomeView/model.test.ts +1 -2
- package/src/GraphGenomeView/pane/graphViews.ts +24 -35
- package/src/GraphGenomeView/pane/loadActions.ts +4 -3
- package/src/GraphGenomeView/pane/paneBase.ts +1 -1
- package/src/GraphGenomeView/subgraphLoad.test.ts +41 -1
- package/src/GraphGenomeView/walkRowsCut.ts +10 -44
- package/src/RgfaTabixAdapter/RgfaTabixAdapter.test.ts +23 -4
- package/src/RgfaTabixAdapter/RgfaTabixAdapter.ts +2 -3
- package/src/RgfaTabixAdapter/bubbleTier.test.ts +1 -1
- package/src/RgfaTabixAdapter/walkCut.ts +20 -0
- package/src/RgfaTabixAdapter/walkFiles.test.ts +2 -2
- package/src/RgfaTabixAdapter/walkReader.ts +1 -1
- package/src/WalkTabixSyntenyAdapter/WalkTabixSyntenyAdapter.test.ts +1 -1
- package/src/version.ts +1 -1
- package/dist/chunks/GbzBaseSyntenyAdapter-NB6WBBZH.js +0 -2
- package/dist/chunks/MinigraphBubbleAdapter-HDLUZ6YF.js +0 -2
- package/dist/chunks/RgfaTabixAdapter-XZRTWQMZ.js +0 -3
- package/dist/chunks/RgfaTabixAdapter-XZRTWQMZ.js.map +0 -7
- package/dist/chunks/WalkTabixSyntenyAdapter-WBHOZLAN.js +0 -2
- package/dist/chunks/chunk-BWP3XYKD.js +0 -2
- package/dist/chunks/chunk-BWP3XYKD.js.map +0 -7
- package/dist/chunks/chunk-EDSIYH4H.js +0 -2
- package/dist/chunks/chunk-EDSIYH4H.js.map +0 -7
- package/dist/chunks/chunk-III4GT4G.js +0 -2
- package/dist/chunks/chunk-III4GT4G.js.map +0 -7
- package/dist/chunks/chunk-N5GYTUIL.js +0 -3
- package/dist/chunks/chunk-N5GYTUIL.js.map +0 -7
- package/dist/chunks/chunk-PA4HKAUJ.js +0 -2
- package/dist/chunks/chunk-PA4HKAUJ.js.map +0 -7
- package/dist/chunks/chunk-PFAHNHMM.js +0 -2
- package/dist/chunks/chunk-PFAHNHMM.js.map +0 -7
- package/dist/chunks/chunk-UFQTIWSN.js +0 -4
- package/dist/chunks/chunk-UFQTIWSN.js.map +0 -7
- package/dist/chunks/chunk-VDHDEEMF.js +0 -2
- package/dist/chunks/chunk-VDHDEEMF.js.map +0 -7
- package/dist/chunks/chunk-WGVATZLM.js +0 -3
- package/dist/chunks/chunk-WGVATZLM.js.map +0 -7
- package/dist/chunks/chunk-ZNT7TQLN.js.map +0 -7
- package/src/RgfaTabixAdapter/rgfaBed.test.ts +0 -254
- package/src/RgfaTabixAdapter/rgfaBed.ts +0 -314
- package/src/RgfaTabixAdapter/rgfaCut.ts +0 -139
- package/src/RgfaTabixAdapter/walkRowRuns.test.ts +0 -192
- package/src/RgfaTabixAdapter/walkRowRuns.ts +0 -520
- /package/dist/chunks/{GraphGenomeView-4O5F5I37.js.map → GraphGenomeView-WJ3FIDY2.js.map} +0 -0
- /package/dist/chunks/{GraphTrackSettingsDialog-WZEJAF7F.js.map → GraphTrackSettingsDialog-ZW7ALMDV.js.map} +0 -0
- /package/dist/chunks/{HighlightColorDialog-SRT2FPXP.js.map → HighlightColorDialog-VBZRUKD5.js.map} +0 -0
- /package/dist/chunks/{LinearGraphDisplay-Z33PVCJL.js.map → LinearGraphDisplay-SPOPTJEN.js.map} +0 -0
- /package/dist/chunks/{chunk-JLGPQO5L.js.map → chunk-2O3YVA2I.js.map} +0 -0
- /package/dist/chunks/{renderSvg-RRWCAEGF.js.map → renderSvg-WD6YDV2I.js.map} +0 -0
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
addLink,
|
|
3
|
-
anchoredCut,
|
|
4
|
-
closingLinks,
|
|
5
|
-
closingSpans,
|
|
6
|
-
formatSubgraph,
|
|
7
|
-
parseLinkLine,
|
|
8
|
-
parseSegmentRow,
|
|
9
|
-
} from './rgfaBed.ts'
|
|
10
|
-
import { getLines } from '../tabixRange.ts'
|
|
11
|
-
|
|
12
|
-
import type { RgfaLink, RgfaSegment, StableSpan } from './rgfaBed.ts'
|
|
13
|
-
import type { TabixIndexedFile } from '@gmod/tabix'
|
|
14
|
-
|
|
15
|
-
// What a hop follows: alleles, never the backbone. A rank-0 segment reached
|
|
16
|
-
// through a link is flanking backbone, usually outside the window, so querying
|
|
17
|
-
// its links walks the reference away from the region, brings back more backbone,
|
|
18
|
-
// and closes nothing. Every segment that closes a bubble is an allele interior,
|
|
19
|
-
// and an allele interior is rank > 0 in both index formats (rGFA's SR tag, and
|
|
20
|
-
// pggb's rank 0-or-1 against the anchor path). Reached backbone still becomes a
|
|
21
|
-
// node and its edge still draws; it is only not walked through.
|
|
22
|
-
//
|
|
23
|
-
// This is gfabase's rule, arrived at from the other end. `gfabase sub` expands
|
|
24
|
-
// from a seed either to the whole connected component (`--connected`, which its
|
|
25
|
-
// own README calls overkill) or with `--cutpoints 1`, which takes the biconnected
|
|
26
|
-
// component by *stopping at cutpoints*, the segments every end-to-end walk of
|
|
27
|
-
// the chromosome must traverse. In a reference-anchored pangenome the cutpoints
|
|
28
|
-
// are the backbone, and rank is what the index already states about it, so
|
|
29
|
-
// `rank > 0` is that stopping rule without a connectivity index to build. The
|
|
30
|
-
// third tool is the same shape again: `gfatools view -R` maps the region onto its
|
|
31
|
-
// precomputed bubble decomposition and returns whole overlapping bubbles
|
|
32
|
-
// (gfa_query_by_reg), which is complete for the same reason. Bandage's own
|
|
33
|
-
// `--distance` is a node-step radius, but Bandage holds the entire graph in
|
|
34
|
-
// memory, so its scope is a drawing filter rather than a fetch strategy.
|
|
35
|
-
//
|
|
36
|
-
// Measured with this rule: the E. coli paa window converges at one hop (17
|
|
37
|
-
// segments at 1 and at 2), so the cut closes and stays closed. HPRC's amylase
|
|
38
|
-
// window keeps growing (63 at 0, 78 at 1, 92 at 2) because its alleles have
|
|
39
|
-
// alleles, and wall-clock is flat across all three, since a hop's queries go out
|
|
40
|
-
// together and the remote index dominates.
|
|
41
|
-
//
|
|
42
|
-
// The exact version, when a graph ships a bubble index beside its segments:
|
|
43
|
-
// gfatools' bubble rows carry the member segment ids of every bubble, so the
|
|
44
|
-
// bubbles overlapping the region state which segments a complete cut must
|
|
45
|
-
// contain. That turns the hop count into a termination condition rather than a
|
|
46
|
-
// setting, and MinigraphBubbleAdapter already parses those rows.
|
|
47
|
-
function offReference(segments: RgfaSegment[]) {
|
|
48
|
-
return segments.filter(segment => segment.rank > 0)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export interface RgfaFiles {
|
|
52
|
-
segments: TabixIndexedFile
|
|
53
|
-
links: TabixIndexedFile
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
async function linksOver(
|
|
57
|
-
file: TabixIndexedFile,
|
|
58
|
-
span: StableSpan,
|
|
59
|
-
signal?: AbortSignal,
|
|
60
|
-
) {
|
|
61
|
-
const found: RgfaLink[] = []
|
|
62
|
-
await getLines(file, span.refName, span.start, span.end, {
|
|
63
|
-
signal,
|
|
64
|
-
lineCallback: line => {
|
|
65
|
-
found.push(parseLinkLine(line))
|
|
66
|
-
},
|
|
67
|
-
})
|
|
68
|
-
return found
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* The graph around a window of one stable sequence, as GFA text. The window's
|
|
73
|
-
* own segments come from the segment file; the link file supplies the edges
|
|
74
|
-
* incident to them *and* the coordinates of the segments on the other end,
|
|
75
|
-
* which typically sit on a different stable sequence (a rank>0 bubble) and so
|
|
76
|
-
* are not reachable by any coordinate query on this window.
|
|
77
|
-
*
|
|
78
|
-
* `hops` is extra rounds of link-following past the window's own segments and
|
|
79
|
-
* their immediate neighbours, each costing one tabix query per off-reference
|
|
80
|
-
* segment newly reached. After the last round, one more read per stretch of
|
|
81
|
-
* stable sequence the cut holds closes it (closingSpans), so an allele reached
|
|
82
|
-
* from both ends draws whole. The view asks for one hop; a hopless cut stays
|
|
83
|
-
* as cheap as it was. `signal` goes to every one of those queries, so a cut
|
|
84
|
-
* the view has replaced stops.
|
|
85
|
-
*/
|
|
86
|
-
export async function rgfaCut(
|
|
87
|
-
files: RgfaFiles,
|
|
88
|
-
window: StableSpan,
|
|
89
|
-
{ hops = 0, signal }: { hops?: number; signal?: AbortSignal } = {},
|
|
90
|
-
) {
|
|
91
|
-
const segments = new Map<string, RgfaSegment>()
|
|
92
|
-
const links = new Map<string, RgfaLink>()
|
|
93
|
-
const layout = { anchored: false }
|
|
94
|
-
await getLines(files.segments, window.refName, window.start, window.end, {
|
|
95
|
-
signal,
|
|
96
|
-
lineCallback: line => {
|
|
97
|
-
const row = parseSegmentRow(line)
|
|
98
|
-
layout.anchored ||= row.anchored
|
|
99
|
-
segments.set(row.segment.id, row.segment)
|
|
100
|
-
},
|
|
101
|
-
})
|
|
102
|
-
// An anchored index files every allele and every link under the reference
|
|
103
|
-
// interval its bubble hangs from, so one read of each file holds the whole
|
|
104
|
-
// graph under the window and there is nothing to hop to or close.
|
|
105
|
-
if (layout.anchored) {
|
|
106
|
-
const cut = anchoredCut(
|
|
107
|
-
segments,
|
|
108
|
-
await linksOver(files.links, window, signal),
|
|
109
|
-
window,
|
|
110
|
-
)
|
|
111
|
-
return formatSubgraph(cut.segments, cut.links)
|
|
112
|
-
}
|
|
113
|
-
const addLinksOver = async (span: StableSpan) =>
|
|
114
|
-
(await linksOver(files.links, span, signal)).flatMap(link =>
|
|
115
|
-
addLink(segments, links, link),
|
|
116
|
-
)
|
|
117
|
-
let frontier = offReference(await addLinksOver(window))
|
|
118
|
-
for (let hop = 0; hop < hops; hop++) {
|
|
119
|
-
// One hop's queries are independent of each other, so they go out
|
|
120
|
-
// together rather than one round-trip at a time, and the output is sorted
|
|
121
|
-
// at the end regardless of the order they arrive in.
|
|
122
|
-
const reached = await Promise.all(frontier.map(addLinksOver))
|
|
123
|
-
frontier = offReference(reached.flat())
|
|
124
|
-
}
|
|
125
|
-
if (hops > 0) {
|
|
126
|
-
const spans = closingSpans(
|
|
127
|
-
[...segments.values()],
|
|
128
|
-
new Set(frontier.map(segment => segment.id)),
|
|
129
|
-
window,
|
|
130
|
-
)
|
|
131
|
-
const found = await Promise.all(
|
|
132
|
-
spans.map(span => linksOver(files.links, span, signal)),
|
|
133
|
-
)
|
|
134
|
-
for (const link of closingLinks(found.flat(), segments, spans)) {
|
|
135
|
-
addLink(segments, links, link)
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
return formatSubgraph(segments, links)
|
|
139
|
-
}
|
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
import { gfaTables } from '@jbrowse/bandage-core/gfa/gfaTables'
|
|
2
|
-
import { walkRows } from '@jbrowse/bandage-core/layout/walkRows'
|
|
3
|
-
import { loadGraph } from '@jbrowse/bandage-core/pipeline'
|
|
4
|
-
|
|
5
|
-
import { walkRowRuns, walkRowsOf } from './walkRowRuns.ts'
|
|
6
|
-
|
|
7
|
-
import type { GraphTables } from '@jbrowse/bandage-core/gfa/graphTables'
|
|
8
|
-
import type { WalkRow } from '@jbrowse/bandage-core/layout/walkRows'
|
|
9
|
-
|
|
10
|
-
// GRCh38 runs 0..4 over chr1:0-5000, a kb a node, with node 5 (300 bp) an
|
|
11
|
-
// expansion off it. The repeat is node 2, chr1:2000-3000. A has the
|
|
12
|
-
// reference's left flank from 0 and ends inside the repeat, B the same from
|
|
13
|
-
// 1000, and C runs against the reference from its right flank and ends
|
|
14
|
-
// inside too, each off the reference. D's contig ends on the repeat's node
|
|
15
|
-
// and E's on the left flank.
|
|
16
|
-
const tables: GraphTables = {
|
|
17
|
-
nodes: {
|
|
18
|
-
names: ['0', '1', '2', '3', '4', '5'],
|
|
19
|
-
lengths: Int32Array.of(1000, 1000, 1000, 1000, 1000, 300),
|
|
20
|
-
refs: Int32Array.of(0, 0, 0, 0, 0, 1),
|
|
21
|
-
starts: Float64Array.of(0, 1000, 2000, 3000, 4000, 0),
|
|
22
|
-
ranks: Int32Array.of(0, 0, 0, 0, 0, 1),
|
|
23
|
-
refNames: ['chr1', 'alt'],
|
|
24
|
-
},
|
|
25
|
-
links: {
|
|
26
|
-
from: new Int32Array(0),
|
|
27
|
-
to: new Int32Array(0),
|
|
28
|
-
strands: new Uint8Array(0),
|
|
29
|
-
},
|
|
30
|
-
walks: {
|
|
31
|
-
names: ['GRCh38#0#chr1', 'A#1#a', 'B#1#b', 'C#1#c', 'D#1#d', 'E#1#e'],
|
|
32
|
-
starts: Float64Array.of(0, 0, 0, 0, 0, 0),
|
|
33
|
-
ends: Float64Array.of(5000, 3300, 2300, 2300, 3000, 2000),
|
|
34
|
-
offsets: Int32Array.of(0, 5, 9, 12, 15, 18, 20),
|
|
35
|
-
steps: Int32Array.of(
|
|
36
|
-
...[0, 1, 2, 3, 4],
|
|
37
|
-
...[0, 1, 2, 5],
|
|
38
|
-
...[1, 2, 5],
|
|
39
|
-
...[4, 3, 5],
|
|
40
|
-
...[0, 1, 2],
|
|
41
|
-
...[0, 1],
|
|
42
|
-
),
|
|
43
|
-
reversed: Uint8Array.of(
|
|
44
|
-
...[0, 0, 0, 0, 0],
|
|
45
|
-
...[0, 0, 0, 0],
|
|
46
|
-
...[0, 0, 0],
|
|
47
|
-
...[1, 1, 1],
|
|
48
|
-
...[0, 0, 0],
|
|
49
|
-
...[0, 0],
|
|
50
|
-
),
|
|
51
|
-
},
|
|
52
|
-
}
|
|
53
|
-
const repeat = { start: 2000, end: 3000 }
|
|
54
|
-
|
|
55
|
-
test('a walk that ends inside the repeat measures from the flank it enters by', () => {
|
|
56
|
-
const rows = walkRowsOf(walkRowRuns(tables, repeat)!).rows
|
|
57
|
-
const byLabel = Object.fromEntries(rows.map(r => [r.label, r]))
|
|
58
|
-
expect(byLabel['A#1']).toMatchObject({ bp: 1300, complete: false })
|
|
59
|
-
expect(byLabel['B#1']).toMatchObject({ bp: 1300, complete: false })
|
|
60
|
-
expect(byLabel['C#1']).toMatchObject({ bp: 300, complete: false })
|
|
61
|
-
for (const label of ['A#1', 'B#1', 'C#1']) {
|
|
62
|
-
expect(byLabel[label]!.stop).toEqual({ contigEnds: false, shortBp: 0 })
|
|
63
|
-
}
|
|
64
|
-
expect(byLabel['D#1']).toMatchObject({
|
|
65
|
-
bp: 1000,
|
|
66
|
-
complete: false,
|
|
67
|
-
stop: { contigEnds: true, shortBp: 0 },
|
|
68
|
-
})
|
|
69
|
-
expect(byLabel['E#1']).toMatchObject({
|
|
70
|
-
bp: 0,
|
|
71
|
-
complete: false,
|
|
72
|
-
stop: { contigEnds: true, shortBp: 0 },
|
|
73
|
-
})
|
|
74
|
-
expect(byLabel['A#1']!.axis).toEqual({
|
|
75
|
-
contig: 'a',
|
|
76
|
-
start: 2000,
|
|
77
|
-
reversed: false,
|
|
78
|
-
})
|
|
79
|
-
expect(byLabel['C#1']!.axis).toEqual({
|
|
80
|
-
contig: 'c',
|
|
81
|
-
start: 2300,
|
|
82
|
-
reversed: true,
|
|
83
|
-
})
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
test('walkRows measures and stops the same walks', () => {
|
|
87
|
-
for (const region of [repeat, { start: 2500, end: 3000 }]) {
|
|
88
|
-
const fields = ({ label, bp, complete, stop }: WalkRow) => ({
|
|
89
|
-
label,
|
|
90
|
-
bp,
|
|
91
|
-
complete,
|
|
92
|
-
stop,
|
|
93
|
-
})
|
|
94
|
-
const ours = walkRowsOf(walkRowRuns(tables, region)!).rows.map(fields)
|
|
95
|
-
const theirs = walkRows(loadGraph(tables, 'cut'), region)!.rows.map(fields)
|
|
96
|
-
expect(ours).toEqual(theirs)
|
|
97
|
-
}
|
|
98
|
-
const short = walkRowsOf(
|
|
99
|
-
walkRowRuns(tables, { start: 2500, end: 3000 })!,
|
|
100
|
-
).rows.find(r => r.label === 'E#1')!
|
|
101
|
-
expect(short.stop).toEqual({ contigEnds: true, shortBp: 500 })
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
test('walks named without a haplotype field are rows of their own, on their contigs', () => {
|
|
105
|
-
const twoPart: GraphTables = {
|
|
106
|
-
...tables,
|
|
107
|
-
walks: {
|
|
108
|
-
...tables.walks,
|
|
109
|
-
names: ['GRCh38#0#chr1', 'A#a', 'A#b', 'C#1#c', 'D#1#d', 'E#1#e'],
|
|
110
|
-
},
|
|
111
|
-
}
|
|
112
|
-
const rows = walkRowsOf(walkRowRuns(twoPart, repeat)!).rows
|
|
113
|
-
expect(
|
|
114
|
-
rows
|
|
115
|
-
.filter(r => r.sample === 'A')
|
|
116
|
-
.map(({ name, label, haplotype, axis }) => ({
|
|
117
|
-
name,
|
|
118
|
-
label,
|
|
119
|
-
haplotype,
|
|
120
|
-
contig: axis?.contig,
|
|
121
|
-
}))
|
|
122
|
-
.sort((x, y) => x.name.localeCompare(y.name)),
|
|
123
|
-
).toEqual([
|
|
124
|
-
{ name: 'A#a', label: 'A', haplotype: undefined, contig: 'a' },
|
|
125
|
-
{ name: 'A#b', label: 'A', haplotype: undefined, contig: 'b' },
|
|
126
|
-
])
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
test('a reference cut into pieces is one reference row, as walkRows reads it', () => {
|
|
130
|
-
const split: GraphTables = {
|
|
131
|
-
...tables,
|
|
132
|
-
walks: {
|
|
133
|
-
names: ['GRCh38#0#chr1', 'GRCh38#0#chr1', 'A#1#a'],
|
|
134
|
-
starts: Float64Array.of(0, 3000, 0),
|
|
135
|
-
ends: Float64Array.of(2000, 5000, 5000),
|
|
136
|
-
offsets: Int32Array.of(0, 2, 4, 9),
|
|
137
|
-
steps: Int32Array.of(...[0, 1], ...[3, 4], ...[0, 1, 2, 3, 4]),
|
|
138
|
-
reversed: new Uint8Array(9),
|
|
139
|
-
},
|
|
140
|
-
}
|
|
141
|
-
const region = { start: 2200, end: 2800 }
|
|
142
|
-
const fields = ({ label, bp, offReferenceBp, complete }: WalkRow) => ({
|
|
143
|
-
label,
|
|
144
|
-
bp,
|
|
145
|
-
offReferenceBp,
|
|
146
|
-
complete,
|
|
147
|
-
})
|
|
148
|
-
const ours = walkRowsOf(walkRowRuns(split, region)!)
|
|
149
|
-
const graph = loadGraph(split, 'cut')
|
|
150
|
-
const theirs = walkRows({ ...graph, referencePath: 'GRCh38#0#chr1' }, region)!
|
|
151
|
-
expect(ours.rows.map(fields)).toEqual(theirs.rows.map(fields))
|
|
152
|
-
expect(fields(ours.reference)).toEqual(fields(theirs.reference))
|
|
153
|
-
expect(ours.rows.map(r => r.label)).toEqual(['A#1'])
|
|
154
|
-
expect(ours.rows[0]).toMatchObject({ bp: 1000, complete: true })
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
test("a gap's parts cross from the worker with their causes, as walkRows splits them", () => {
|
|
158
|
-
const S = [1, 2, 3, 4, 5, 6, 7].map(id => `S\t${id}\t*\tLN:i:1000`)
|
|
159
|
-
const L = [1, 2, 3, 4, 5, 6].map(id => `L\t${id}\t+\t${id + 1}\t+\t0M`)
|
|
160
|
-
const text = [
|
|
161
|
-
'H\tVN:Z:1.1',
|
|
162
|
-
...S,
|
|
163
|
-
...L,
|
|
164
|
-
'W\tGRCh38\t0\tchr1\t0\t7000\t>1>2>3>4>5>6>7\tws:Z:end\twe:Z:end',
|
|
165
|
-
'W\tA\t1\ta\t0\t3000\t>1>2>3\tws:Z:end\twe:Z:break,bp=600,trimmed=400',
|
|
166
|
-
'W\tA\t1\ta\t4000\t7000\t>5>6>7\tws:Z:break,bp=600\twe:Z:end',
|
|
167
|
-
'W\tB\t1\tb\t0\t3000\t<7<6<5\tws:Z:end\twe:Z:elsewhere,chunk=GRCh38#0#chr1:20316160',
|
|
168
|
-
'W\tB\t1\tb\t4000\t7000\t<3<2<1\tws:Z:break,bp=300\twe:Z:end',
|
|
169
|
-
].join('\n')
|
|
170
|
-
const region = { start: 1000, end: 6000 }
|
|
171
|
-
const gaps = (rows: WalkRow[]) =>
|
|
172
|
-
rows.map(r => [
|
|
173
|
-
r.label,
|
|
174
|
-
r.runs
|
|
175
|
-
.filter(run => run.gap)
|
|
176
|
-
.map(({ bp, cause, chunk }) => ({ bp, cause, chunk })),
|
|
177
|
-
])
|
|
178
|
-
const ours = walkRowsOf(walkRowRuns(gfaTables(text)!, region)!).rows
|
|
179
|
-
const graph = loadGraph(text, 'cut', { referencePath: 'GRCh38#0#chr1' })
|
|
180
|
-
expect(gaps(ours)).toEqual(gaps(walkRows(graph, region)!.rows))
|
|
181
|
-
const chunk = { refName: 'GRCh38#0#chr1', start: 20316160 }
|
|
182
|
-
expect(Object.fromEntries(gaps(ours))).toEqual({
|
|
183
|
-
'A#1': [
|
|
184
|
-
{ bp: 400, cause: undefined, chunk: undefined },
|
|
185
|
-
{ bp: 600, cause: 'missing', chunk: undefined },
|
|
186
|
-
],
|
|
187
|
-
'B#1': [
|
|
188
|
-
{ bp: 300, cause: 'missing', chunk: undefined },
|
|
189
|
-
{ bp: 700, cause: 'elsewhere', chunk },
|
|
190
|
-
],
|
|
191
|
-
})
|
|
192
|
-
})
|