@jbrowse/plugin-alignments 2.1.7 → 2.2.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/AlignmentsTrack/index.d.ts +1 -1
- package/dist/AlignmentsTrack/index.js +16 -6
- package/dist/AlignmentsTrack/index.js.map +1 -1
- package/dist/BamAdapter/BamAdapter.d.ts +6 -2
- package/dist/BamAdapter/BamAdapter.js +35 -31
- package/dist/BamAdapter/BamAdapter.js.map +1 -1
- package/dist/BamAdapter/configSchema.d.ts +2 -2
- package/dist/BamAdapter/configSchema.js +27 -2
- package/dist/BamAdapter/configSchema.js.map +1 -1
- package/dist/CramAdapter/CramAdapter.d.ts +13 -7
- package/dist/CramAdapter/CramAdapter.js +56 -61
- package/dist/CramAdapter/CramAdapter.js.map +1 -1
- package/dist/CramAdapter/CramSlightlyLazyFeature.d.ts +14 -13
- package/dist/CramAdapter/CramSlightlyLazyFeature.js +28 -22
- package/dist/CramAdapter/CramSlightlyLazyFeature.js.map +1 -1
- package/dist/CramAdapter/configSchema.d.ts +2 -3
- package/dist/CramAdapter/configSchema.js +44 -22
- package/dist/CramAdapter/configSchema.js.map +1 -1
- package/dist/CramAdapter/index.js +1 -1
- package/dist/CramAdapter/index.js.map +1 -1
- package/dist/HtsgetBamAdapter/HtsgetBamAdapter.d.ts +5 -2
- package/dist/HtsgetBamAdapter/HtsgetBamAdapter.js +15 -20
- package/dist/HtsgetBamAdapter/HtsgetBamAdapter.js.map +1 -1
- package/dist/HtsgetBamAdapter/configSchema.d.ts +2 -2
- package/dist/HtsgetBamAdapter/configSchema.js +20 -3
- package/dist/HtsgetBamAdapter/configSchema.js.map +1 -1
- package/dist/LinearAlignmentsDisplay/models/configSchema.d.ts +1 -1
- package/dist/LinearAlignmentsDisplay/models/configSchema.js +23 -6
- package/dist/LinearAlignmentsDisplay/models/configSchema.js.map +1 -1
- package/dist/LinearAlignmentsDisplay/models/model.d.ts +72 -5
- package/dist/LinearAlignmentsDisplay/models/model.js +95 -2
- package/dist/LinearAlignmentsDisplay/models/model.js.map +1 -1
- package/dist/LinearPileupDisplay/configSchema.js +20 -3
- package/dist/LinearPileupDisplay/configSchema.js.map +1 -1
- package/dist/LinearPileupDisplay/model.d.ts +87 -3
- package/dist/LinearPileupDisplay/model.js +616 -503
- package/dist/LinearPileupDisplay/model.js.map +1 -1
- package/dist/LinearSNPCoverageDisplay/models/configSchema.js +33 -4
- package/dist/LinearSNPCoverageDisplay/models/configSchema.js.map +1 -1
- package/dist/LinearSNPCoverageDisplay/models/model.d.ts +86 -3
- package/dist/LinearSNPCoverageDisplay/models/model.js +240 -159
- package/dist/LinearSNPCoverageDisplay/models/model.js.map +1 -1
- package/dist/PileupRenderer/PileupRenderer.d.ts +1 -1
- package/dist/PileupRenderer/PileupRenderer.js +5 -6
- package/dist/PileupRenderer/PileupRenderer.js.map +1 -1
- package/dist/PileupRenderer/configSchema.d.ts +2 -2
- package/dist/PileupRenderer/configSchema.js +37 -2
- package/dist/PileupRenderer/configSchema.js.map +1 -1
- package/dist/SNPCoverageAdapter/configSchema.d.ts +2 -2
- package/dist/SNPCoverageAdapter/configSchema.js +11 -3
- package/dist/SNPCoverageAdapter/configSchema.js.map +1 -1
- package/dist/SNPCoverageRenderer/configSchema.d.ts +2 -2
- package/dist/SNPCoverageRenderer/configSchema.js +21 -1
- package/dist/SNPCoverageRenderer/configSchema.js.map +1 -1
- package/dist/SNPCoverageRenderer/index.d.ts +0 -1
- package/dist/SNPCoverageRenderer/index.js +1 -4
- package/dist/SNPCoverageRenderer/index.js.map +1 -1
- package/esm/AlignmentsTrack/index.d.ts +1 -1
- package/esm/AlignmentsTrack/index.js +16 -6
- package/esm/AlignmentsTrack/index.js.map +1 -1
- package/esm/BamAdapter/BamAdapter.d.ts +6 -2
- package/esm/BamAdapter/BamAdapter.js +35 -31
- package/esm/BamAdapter/BamAdapter.js.map +1 -1
- package/esm/BamAdapter/configSchema.d.ts +2 -2
- package/esm/BamAdapter/configSchema.js +27 -2
- package/esm/BamAdapter/configSchema.js.map +1 -1
- package/esm/CramAdapter/CramAdapter.d.ts +13 -7
- package/esm/CramAdapter/CramAdapter.js +56 -61
- package/esm/CramAdapter/CramAdapter.js.map +1 -1
- package/esm/CramAdapter/CramSlightlyLazyFeature.d.ts +14 -13
- package/esm/CramAdapter/CramSlightlyLazyFeature.js +28 -22
- package/esm/CramAdapter/CramSlightlyLazyFeature.js.map +1 -1
- package/esm/CramAdapter/configSchema.d.ts +2 -3
- package/esm/CramAdapter/configSchema.js +44 -22
- package/esm/CramAdapter/configSchema.js.map +1 -1
- package/esm/CramAdapter/index.js +2 -2
- package/esm/CramAdapter/index.js.map +1 -1
- package/esm/HtsgetBamAdapter/HtsgetBamAdapter.d.ts +5 -2
- package/esm/HtsgetBamAdapter/HtsgetBamAdapter.js +15 -20
- package/esm/HtsgetBamAdapter/HtsgetBamAdapter.js.map +1 -1
- package/esm/HtsgetBamAdapter/configSchema.d.ts +2 -2
- package/esm/HtsgetBamAdapter/configSchema.js +20 -3
- package/esm/HtsgetBamAdapter/configSchema.js.map +1 -1
- package/esm/LinearAlignmentsDisplay/models/configSchema.d.ts +1 -1
- package/esm/LinearAlignmentsDisplay/models/configSchema.js +23 -6
- package/esm/LinearAlignmentsDisplay/models/configSchema.js.map +1 -1
- package/esm/LinearAlignmentsDisplay/models/model.d.ts +72 -5
- package/esm/LinearAlignmentsDisplay/models/model.js +95 -2
- package/esm/LinearAlignmentsDisplay/models/model.js.map +1 -1
- package/esm/LinearPileupDisplay/configSchema.js +20 -3
- package/esm/LinearPileupDisplay/configSchema.js.map +1 -1
- package/esm/LinearPileupDisplay/model.d.ts +87 -3
- package/esm/LinearPileupDisplay/model.js +616 -503
- package/esm/LinearPileupDisplay/model.js.map +1 -1
- package/esm/LinearSNPCoverageDisplay/models/configSchema.js +33 -4
- package/esm/LinearSNPCoverageDisplay/models/configSchema.js.map +1 -1
- package/esm/LinearSNPCoverageDisplay/models/model.d.ts +86 -3
- package/esm/LinearSNPCoverageDisplay/models/model.js +240 -159
- package/esm/LinearSNPCoverageDisplay/models/model.js.map +1 -1
- package/esm/PileupRenderer/PileupRenderer.d.ts +1 -1
- package/esm/PileupRenderer/PileupRenderer.js +5 -6
- package/esm/PileupRenderer/PileupRenderer.js.map +1 -1
- package/esm/PileupRenderer/configSchema.d.ts +2 -2
- package/esm/PileupRenderer/configSchema.js +37 -2
- package/esm/PileupRenderer/configSchema.js.map +1 -1
- package/esm/SNPCoverageAdapter/configSchema.d.ts +2 -2
- package/esm/SNPCoverageAdapter/configSchema.js +11 -3
- package/esm/SNPCoverageAdapter/configSchema.js.map +1 -1
- package/esm/SNPCoverageRenderer/configSchema.d.ts +2 -2
- package/esm/SNPCoverageRenderer/configSchema.js +21 -1
- package/esm/SNPCoverageRenderer/configSchema.js.map +1 -1
- package/esm/SNPCoverageRenderer/index.d.ts +0 -1
- package/esm/SNPCoverageRenderer/index.js +1 -3
- package/esm/SNPCoverageRenderer/index.js.map +1 -1
- package/package.json +3 -3
- package/src/AlignmentsFeatureDetail/__snapshots__/index.test.js.snap +54 -54
- package/src/AlignmentsTrack/index.ts +18 -12
- package/src/BamAdapter/BamAdapter.ts +39 -39
- package/src/BamAdapter/configSchema.ts +57 -29
- package/src/CramAdapter/CramAdapter.test.ts +1 -2
- package/src/CramAdapter/CramAdapter.ts +83 -84
- package/src/CramAdapter/CramSlightlyLazyFeature.ts +34 -25
- package/src/CramAdapter/configSchema.ts +55 -30
- package/src/CramAdapter/index.ts +2 -2
- package/src/HtsgetBamAdapter/HtsgetBamAdapter.ts +14 -21
- package/src/HtsgetBamAdapter/configSchema.ts +36 -19
- package/src/LinearAlignmentsDisplay/models/configSchema.ts +23 -10
- package/src/LinearAlignmentsDisplay/models/model.tsx +99 -4
- package/src/LinearPileupDisplay/configSchema.ts +23 -5
- package/src/LinearPileupDisplay/model.ts +120 -4
- package/src/LinearSNPCoverageDisplay/models/configSchema.ts +36 -9
- package/src/LinearSNPCoverageDisplay/models/model.ts +83 -4
- package/src/PileupRenderer/PileupRenderer.tsx +5 -9
- package/src/PileupRenderer/configSchema.ts +39 -2
- package/src/SNPCoverageAdapter/configSchema.ts +18 -10
- package/src/SNPCoverageRenderer/configSchema.ts +23 -1
- package/src/SNPCoverageRenderer/index.ts +1 -8
- package/src/declare.d.ts +0 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { CraiIndex, IndexedCramFile } from '@gmod/cram'
|
|
1
|
+
import { CraiIndex, IndexedCramFile, CramRecord } from '@gmod/cram'
|
|
2
2
|
import {
|
|
3
3
|
BaseFeatureDataAdapter,
|
|
4
4
|
BaseOptions,
|
|
5
|
+
BaseSequenceAdapter,
|
|
5
6
|
} from '@jbrowse/core/data_adapters/BaseAdapter'
|
|
6
7
|
import { checkAbortSignal, Region, Feature } from '@jbrowse/core/util'
|
|
7
8
|
import { openLocation } from '@jbrowse/core/util/io'
|
|
@@ -9,15 +10,10 @@ import { ObservableCreate } from '@jbrowse/core/util/rxjs'
|
|
|
9
10
|
import { toArray } from 'rxjs/operators'
|
|
10
11
|
import CramSlightlyLazyFeature from './CramSlightlyLazyFeature'
|
|
11
12
|
|
|
12
|
-
interface HeaderLine {
|
|
13
|
-
tag: string
|
|
14
|
-
value: any // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
15
|
-
data: HeaderLine[]
|
|
16
|
-
}
|
|
17
13
|
interface Header {
|
|
18
14
|
idToName?: string[]
|
|
19
15
|
nameToId?: Record<string, number>
|
|
20
|
-
readGroups?:
|
|
16
|
+
readGroups?: (string | undefined)[]
|
|
21
17
|
}
|
|
22
18
|
|
|
23
19
|
interface FilterBy {
|
|
@@ -32,8 +28,13 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
|
|
|
32
28
|
|
|
33
29
|
private setupP?: Promise<{
|
|
34
30
|
samHeader: Header
|
|
35
|
-
cram:
|
|
36
|
-
sequenceAdapter:
|
|
31
|
+
cram: IndexedCramFile
|
|
32
|
+
sequenceAdapter: BaseSequenceAdapter
|
|
33
|
+
}>
|
|
34
|
+
|
|
35
|
+
private configureP?: Promise<{
|
|
36
|
+
cram: IndexedCramFile
|
|
37
|
+
sequenceAdapter: BaseSequenceAdapter
|
|
37
38
|
}>
|
|
38
39
|
|
|
39
40
|
// maps a refname to an id
|
|
@@ -42,7 +43,7 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
|
|
|
42
43
|
// maps a seqId to original refname, passed specially to render args, to a seqid
|
|
43
44
|
private seqIdToOriginalRefName: string[] = []
|
|
44
45
|
|
|
45
|
-
public async
|
|
46
|
+
public async configurePre() {
|
|
46
47
|
const cramLocation = this.getConf('cramLocation')
|
|
47
48
|
const craiLocation = this.getConf('craiLocation')
|
|
48
49
|
if (!cramLocation) {
|
|
@@ -51,48 +52,55 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
|
|
|
51
52
|
if (!craiLocation) {
|
|
52
53
|
throw new Error('missing craiLocation argument')
|
|
53
54
|
}
|
|
55
|
+
const pm = this.pluginManager
|
|
54
56
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
filehandle: openLocation(craiLocation, this.pluginManager),
|
|
60
|
-
}),
|
|
61
|
-
seqFetch: this.seqFetch.bind(this),
|
|
57
|
+
const cram = new IndexedCramFile({
|
|
58
|
+
cramFilehandle: openLocation(cramLocation, pm),
|
|
59
|
+
index: new CraiIndex({ filehandle: openLocation(craiLocation, pm) }),
|
|
60
|
+
seqFetch: (...args) => this.seqFetch(...args),
|
|
62
61
|
checkSequenceMD5: false,
|
|
63
62
|
fetchSizeLimit: 200_000_000, // just make this a large size to avoid hitting it
|
|
64
63
|
})
|
|
65
|
-
// instantiate the sequence adapter
|
|
66
|
-
const sequenceAdapterType = this.getConf(['sequenceAdapter', 'type'])
|
|
67
64
|
|
|
68
65
|
if (!this.getSubAdapter) {
|
|
69
66
|
throw new Error('Error getting subadapter')
|
|
70
67
|
}
|
|
71
68
|
|
|
72
69
|
const seqConf = this.getConf('sequenceAdapter')
|
|
73
|
-
const
|
|
70
|
+
const subadapter = await this.getSubAdapter(seqConf)
|
|
74
71
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
)
|
|
72
|
+
return {
|
|
73
|
+
cram,
|
|
74
|
+
sequenceAdapter: subadapter.dataAdapter as BaseSequenceAdapter,
|
|
79
75
|
}
|
|
76
|
+
}
|
|
80
77
|
|
|
81
|
-
|
|
78
|
+
public async configure() {
|
|
79
|
+
if (!this.configureP) {
|
|
80
|
+
this.configureP = this.configurePre().catch(e => {
|
|
81
|
+
this.configureP = undefined
|
|
82
|
+
throw e
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
return this.configureP
|
|
82
86
|
}
|
|
83
87
|
|
|
84
88
|
async getHeader(opts?: BaseOptions) {
|
|
85
89
|
const { cram } = await this.configure()
|
|
86
|
-
return cram.cram.getHeaderText(
|
|
90
|
+
return cram.cram.getHeaderText()
|
|
87
91
|
}
|
|
88
92
|
|
|
89
|
-
private async seqFetch(
|
|
93
|
+
private async seqFetch(
|
|
94
|
+
seqId: number,
|
|
95
|
+
start: number,
|
|
96
|
+
end: number,
|
|
97
|
+
): Promise<string> {
|
|
90
98
|
start -= 1 // convert from 1-based closed to interbase
|
|
91
99
|
|
|
92
100
|
const { sequenceAdapter } = await this.configure()
|
|
93
101
|
const refName = this.refIdToOriginalName(seqId) || this.refIdToName(seqId)
|
|
94
102
|
if (!refName) {
|
|
95
|
-
|
|
103
|
+
throw new Error('unknown')
|
|
96
104
|
}
|
|
97
105
|
|
|
98
106
|
const seqChunks = await sequenceAdapter
|
|
@@ -132,10 +140,10 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
|
|
|
132
140
|
|
|
133
141
|
private async setupPre(opts?: BaseOptions) {
|
|
134
142
|
const { statusCallback = () => {} } = opts || {}
|
|
135
|
-
const
|
|
143
|
+
const conf = await this.configure()
|
|
136
144
|
statusCallback('Downloading index')
|
|
137
|
-
const { cram } =
|
|
138
|
-
const samHeader
|
|
145
|
+
const { cram } = conf
|
|
146
|
+
const samHeader = await cram.cram.getSamHeader()
|
|
139
147
|
|
|
140
148
|
// use the @SQ lines in the header to figure out the
|
|
141
149
|
// mapping between ref ID numbers and names
|
|
@@ -161,7 +169,7 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
|
|
|
161
169
|
const data = { idToName, nameToId, readGroups }
|
|
162
170
|
statusCallback('')
|
|
163
171
|
this.samHeader = data
|
|
164
|
-
return { samHeader: data, ...
|
|
172
|
+
return { samHeader: data, ...conf }
|
|
165
173
|
}
|
|
166
174
|
|
|
167
175
|
private async setup(opts?: BaseOptions) {
|
|
@@ -197,13 +205,7 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
|
|
|
197
205
|
// use info from the SAM header if possible, but fall back to using
|
|
198
206
|
// the ref seq order from when the browser's refseqs were loaded
|
|
199
207
|
refIdToName(refId: number) {
|
|
200
|
-
|
|
201
|
-
return this.samHeader.idToName[refId]
|
|
202
|
-
}
|
|
203
|
-
if (this.seqIdToRefName) {
|
|
204
|
-
return this.seqIdToRefName[refId]
|
|
205
|
-
}
|
|
206
|
-
return undefined
|
|
208
|
+
return this.samHeader.idToName?.[refId] || this.seqIdToRefName?.[refId]
|
|
207
209
|
}
|
|
208
210
|
|
|
209
211
|
refIdToOriginalName(refId: number) {
|
|
@@ -220,53 +222,48 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
|
|
|
220
222
|
const { refName, start, end, originalRefName } = region
|
|
221
223
|
|
|
222
224
|
return ObservableCreate<Feature>(async observer => {
|
|
223
|
-
const { cram
|
|
224
|
-
|
|
225
|
-
if (!this.seqIdToRefName) {
|
|
226
|
-
this.seqIdToRefName = await sequenceAdapter.getRefNames(opts)
|
|
227
|
-
}
|
|
225
|
+
const { cram } = await this.setup(opts)
|
|
226
|
+
|
|
228
227
|
const refId = this.refNameToId(refName)
|
|
229
|
-
if (refId
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
228
|
+
if (refId === undefined) {
|
|
229
|
+
console.warn('Unknown refName', refName)
|
|
230
|
+
observer.complete()
|
|
231
|
+
return
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (originalRefName) {
|
|
235
|
+
this.seqIdToOriginalRefName[refId] = originalRefName
|
|
236
|
+
}
|
|
237
|
+
statusCallback('Downloading alignments')
|
|
238
|
+
const records = await cram.getRecordsForRange(refId, start, end)
|
|
239
|
+
checkAbortSignal(signal)
|
|
240
|
+
const {
|
|
241
|
+
flagInclude = 0,
|
|
242
|
+
flagExclude = 0,
|
|
243
|
+
tagFilter,
|
|
244
|
+
readName,
|
|
245
|
+
} = filterBy || {}
|
|
246
|
+
|
|
247
|
+
let filtered = records.filter(record => {
|
|
248
|
+
const flags = record.flags
|
|
249
|
+
return (flags & flagInclude) === flagInclude && !(flags & flagExclude)
|
|
250
|
+
})
|
|
247
251
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
})
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
if (readName) {
|
|
257
|
-
filtered = filtered.filter(
|
|
258
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
259
|
-
(record: any) => record.readName === readName,
|
|
260
|
-
)
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
264
|
-
filtered.forEach((record: any) => {
|
|
265
|
-
observer.next(this.cramRecordToFeature(record))
|
|
252
|
+
if (tagFilter) {
|
|
253
|
+
filtered = filtered.filter(record => {
|
|
254
|
+
// @ts-ignore
|
|
255
|
+
const val = record[tagFilter.tag]
|
|
256
|
+
return val === '*' ? val !== undefined : val === tagFilter.value
|
|
266
257
|
})
|
|
267
|
-
} else {
|
|
268
|
-
console.warn('Unknown refName', refName)
|
|
269
258
|
}
|
|
259
|
+
|
|
260
|
+
if (readName) {
|
|
261
|
+
filtered = filtered.filter(record => record.readName === readName)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
filtered.forEach(record => {
|
|
265
|
+
observer.next(this.cramRecordToFeature(record))
|
|
266
|
+
})
|
|
270
267
|
statusCallback('')
|
|
271
268
|
observer.complete()
|
|
272
269
|
}, signal)
|
|
@@ -274,7 +271,7 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
|
|
|
274
271
|
|
|
275
272
|
freeResources(/* { region } */): void {}
|
|
276
273
|
|
|
277
|
-
cramRecordToFeature(record:
|
|
274
|
+
cramRecordToFeature(record: CramRecord) {
|
|
278
275
|
return new CramSlightlyLazyFeature(record, this)
|
|
279
276
|
}
|
|
280
277
|
|
|
@@ -299,7 +296,9 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
|
|
|
299
296
|
regions.map(region => {
|
|
300
297
|
const { refName, start, end } = region
|
|
301
298
|
const chrId = this.refNameToId(refName)
|
|
302
|
-
return
|
|
299
|
+
return chrId !== undefined
|
|
300
|
+
? cram.index.getEntriesForRange(chrId, start, end)
|
|
301
|
+
: [{ sliceBytes: 0 }]
|
|
303
302
|
}),
|
|
304
303
|
)
|
|
305
304
|
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
Feature,
|
|
4
4
|
SimpleFeatureSerialized,
|
|
5
5
|
} from '@jbrowse/core/util/simpleFeature'
|
|
6
|
-
|
|
6
|
+
import { CramRecord } from '@gmod/cram'
|
|
7
7
|
import CramAdapter from './CramAdapter'
|
|
8
8
|
|
|
9
9
|
export interface Mismatch {
|
|
@@ -20,8 +20,8 @@ export interface Mismatch {
|
|
|
20
20
|
export default class CramSlightlyLazyFeature implements Feature {
|
|
21
21
|
// uses parameter properties to automatically create fields on the class
|
|
22
22
|
// https://www.typescriptlang.org/docs/handbook/classes.html#parameter-properties
|
|
23
|
-
|
|
24
|
-
constructor(private record:
|
|
23
|
+
|
|
24
|
+
constructor(private record: CramRecord, private _store: CramAdapter) {}
|
|
25
25
|
|
|
26
26
|
_get_name() {
|
|
27
27
|
return this.record.readName
|
|
@@ -32,7 +32,7 @@ export default class CramSlightlyLazyFeature implements Feature {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
_get_end() {
|
|
35
|
-
return this.record.alignmentStart + this.record.lengthOnRef - 1
|
|
35
|
+
return this.record.alignmentStart + (this.record.lengthOnRef ?? 1) - 1
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
_get_cram_read_features() {
|
|
@@ -123,6 +123,9 @@ export default class CramSlightlyLazyFeature implements Feature {
|
|
|
123
123
|
let cigar = ''
|
|
124
124
|
let op = 'M'
|
|
125
125
|
let oplen = 0
|
|
126
|
+
if (!this.record._refRegion) {
|
|
127
|
+
return ''
|
|
128
|
+
}
|
|
126
129
|
|
|
127
130
|
// not sure I should access these, but...
|
|
128
131
|
const ref = this.record._refRegion.seq
|
|
@@ -130,6 +133,7 @@ export default class CramSlightlyLazyFeature implements Feature {
|
|
|
130
133
|
let last_pos = this.record.alignmentStart
|
|
131
134
|
let sublen = 0
|
|
132
135
|
if (typeof this.record.readFeatures !== 'undefined') {
|
|
136
|
+
let insLen = 0
|
|
133
137
|
// @ts-ignore
|
|
134
138
|
for (let i = 0; i < this.record.readFeatures.length; i++) {
|
|
135
139
|
const { code, refPos, sub, data } = this.record.readFeatures[i]
|
|
@@ -145,6 +149,10 @@ export default class CramSlightlyLazyFeature implements Feature {
|
|
|
145
149
|
op = 'M'
|
|
146
150
|
oplen += sublen
|
|
147
151
|
}
|
|
152
|
+
if (insLen > 0 && code !== 'i') {
|
|
153
|
+
cigar += `${insLen}I`
|
|
154
|
+
insLen = 0
|
|
155
|
+
}
|
|
148
156
|
|
|
149
157
|
if (code === 'b') {
|
|
150
158
|
// An array of bases stored verbatim
|
|
@@ -181,11 +189,11 @@ export default class CramSlightlyLazyFeature implements Feature {
|
|
|
181
189
|
oplen = 0
|
|
182
190
|
} else if (code === 'i') {
|
|
183
191
|
// Single base insertion
|
|
184
|
-
seq += data
|
|
192
|
+
// seq += data
|
|
185
193
|
if (oplen) {
|
|
186
194
|
cigar += oplen + op
|
|
187
195
|
}
|
|
188
|
-
|
|
196
|
+
insLen++
|
|
189
197
|
oplen = 0
|
|
190
198
|
} else if (code === 'P') {
|
|
191
199
|
// Padding
|
|
@@ -280,19 +288,12 @@ export default class CramSlightlyLazyFeature implements Feature {
|
|
|
280
288
|
}
|
|
281
289
|
|
|
282
290
|
toJSON(): SimpleFeatureSerialized {
|
|
283
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
284
|
-
const tags: Record<string, any> = {}
|
|
285
|
-
this.tags().forEach((t: string) => {
|
|
286
|
-
const val = this.get(t)
|
|
287
|
-
if (val !== undefined) {
|
|
288
|
-
tags[t] = val
|
|
289
|
-
}
|
|
290
|
-
})
|
|
291
|
-
|
|
292
291
|
return {
|
|
293
|
-
...
|
|
294
|
-
|
|
295
|
-
|
|
292
|
+
...Object.fromEntries(
|
|
293
|
+
this.tags()
|
|
294
|
+
.map(t => [t, this.get(t)])
|
|
295
|
+
.filter(elt => elt[1] !== undefined),
|
|
296
|
+
),
|
|
296
297
|
uniqueId: this.id(),
|
|
297
298
|
}
|
|
298
299
|
}
|
|
@@ -306,10 +307,23 @@ export default class CramSlightlyLazyFeature implements Feature {
|
|
|
306
307
|
const start = this.get('start')
|
|
307
308
|
const mismatches: Mismatch[] = new Array(readFeatures.length)
|
|
308
309
|
let j = 0
|
|
310
|
+
let insLen = 0
|
|
311
|
+
|
|
312
|
+
let refPos = 0
|
|
309
313
|
for (let i = 0; i < readFeatures.length; i++) {
|
|
310
314
|
const f = readFeatures[i]
|
|
311
315
|
const { code, pos, data, sub, ref } = f
|
|
312
|
-
|
|
316
|
+
if (insLen > 0 && code !== 'i') {
|
|
317
|
+
mismatches[j++] = {
|
|
318
|
+
start: refPos,
|
|
319
|
+
type: 'insertion',
|
|
320
|
+
base: `${insLen}`,
|
|
321
|
+
length: 0,
|
|
322
|
+
}
|
|
323
|
+
insLen = 0
|
|
324
|
+
}
|
|
325
|
+
refPos = f.refPos - 1 - start
|
|
326
|
+
|
|
313
327
|
if (code === 'X') {
|
|
314
328
|
// substitution
|
|
315
329
|
mismatches[j++] = {
|
|
@@ -375,12 +389,7 @@ export default class CramSlightlyLazyFeature implements Feature {
|
|
|
375
389
|
} else if (code === 'i') {
|
|
376
390
|
// single-base insertion
|
|
377
391
|
// insertion
|
|
378
|
-
|
|
379
|
-
start: refPos,
|
|
380
|
-
type: 'insertion',
|
|
381
|
-
base: data,
|
|
382
|
-
length: 1,
|
|
383
|
-
}
|
|
392
|
+
insLen++
|
|
384
393
|
} else if (code === 'Q') {
|
|
385
394
|
// single quality value
|
|
386
395
|
}
|
|
@@ -1,33 +1,58 @@
|
|
|
1
|
-
import PluginManager from '@jbrowse/core/PluginManager'
|
|
2
1
|
import { ConfigurationSchema } from '@jbrowse/core/configuration'
|
|
3
|
-
import { types } from 'mobx-state-tree'
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
3
|
+
/**
|
|
4
|
+
* #config CramAdapter
|
|
5
|
+
* used to configure CRAM adapter
|
|
6
|
+
*/
|
|
7
|
+
function x() {} // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
8
|
+
|
|
9
|
+
const configSchema = ConfigurationSchema(
|
|
10
|
+
'CramAdapter',
|
|
11
|
+
{
|
|
12
|
+
/**
|
|
13
|
+
* #slot fetchSizeLimit
|
|
14
|
+
*/
|
|
15
|
+
fetchSizeLimit: {
|
|
16
|
+
type: 'number',
|
|
17
|
+
description:
|
|
18
|
+
'used to determine when to display a warning to the user that too much data will be fetched',
|
|
19
|
+
defaultValue: 3_000_000,
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* #slot cramLocation
|
|
24
|
+
*/
|
|
25
|
+
cramLocation: {
|
|
26
|
+
type: 'fileLocation',
|
|
27
|
+
defaultValue: {
|
|
28
|
+
uri: '/path/to/my.cram',
|
|
29
|
+
locationType: 'UriLocation',
|
|
29
30
|
},
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* #slot craiLocation
|
|
35
|
+
*/
|
|
36
|
+
craiLocation: {
|
|
37
|
+
type: 'fileLocation',
|
|
38
|
+
defaultValue: {
|
|
39
|
+
uri: '/path/to/my.cram.crai',
|
|
40
|
+
locationType: 'UriLocation',
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* #slot sequenceAdapter
|
|
46
|
+
* generally refers to the reference genome assembly's sequence adapter
|
|
47
|
+
* currently needs to be manually added
|
|
48
|
+
*/
|
|
49
|
+
sequenceAdapter: {
|
|
50
|
+
type: 'frozen',
|
|
51
|
+
description:
|
|
52
|
+
'sequence data adapter, used to calculate SNPs when BAM reads lacking MD tags',
|
|
53
|
+
defaultValue: null,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
{ explicitlyTyped: true },
|
|
57
|
+
)
|
|
58
|
+
export default configSchema
|
package/src/CramAdapter/index.ts
CHANGED
|
@@ -2,14 +2,14 @@ import PluginManager from '@jbrowse/core/PluginManager'
|
|
|
2
2
|
import AdapterType from '@jbrowse/core/pluggableElementTypes/AdapterType'
|
|
3
3
|
|
|
4
4
|
// locals
|
|
5
|
-
import
|
|
5
|
+
import configSchema from './configSchema'
|
|
6
6
|
|
|
7
7
|
export default (pluginManager: PluginManager) => {
|
|
8
8
|
pluginManager.addAdapterType(
|
|
9
9
|
() =>
|
|
10
10
|
new AdapterType({
|
|
11
11
|
name: 'CramAdapter',
|
|
12
|
-
configSchema
|
|
12
|
+
configSchema,
|
|
13
13
|
getAdapterClass: () => import('./CramAdapter').then(r => r.default),
|
|
14
14
|
}),
|
|
15
15
|
)
|
|
@@ -1,31 +1,24 @@
|
|
|
1
1
|
import { BamFile, HtsgetFile } from '@gmod/bam'
|
|
2
|
-
import { readConfObject } from '@jbrowse/core/configuration'
|
|
3
2
|
import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter'
|
|
4
3
|
import BamAdapter from '../BamAdapter/BamAdapter'
|
|
5
4
|
|
|
6
5
|
export default class HtsgetBamAdapter extends BamAdapter {
|
|
7
|
-
protected async
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}) as unknown as BamFile
|
|
6
|
+
protected async configurePre() {
|
|
7
|
+
const htsgetBase = this.getConf('htsgetBase')
|
|
8
|
+
const htsgetTrackId = this.getConf('htsgetTrackId')
|
|
9
|
+
const bam = new HtsgetFile({
|
|
10
|
+
baseUrl: htsgetBase,
|
|
11
|
+
trackId: htsgetTrackId,
|
|
12
|
+
}) as unknown as BamFile
|
|
15
13
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
sequenceAdapter: dataAdapter as BaseFeatureDataAdapter,
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
)
|
|
14
|
+
const adapterConfig = this.getConf('sequenceAdapter')
|
|
15
|
+
if (adapterConfig && this.getSubAdapter) {
|
|
16
|
+
const adapter = await this.getSubAdapter(adapterConfig)
|
|
17
|
+
return {
|
|
18
|
+
bam,
|
|
19
|
+
sequenceAdapter: adapter.dataAdapter as BaseFeatureDataAdapter,
|
|
26
20
|
}
|
|
27
|
-
this.configured = Promise.resolve({ bam })
|
|
28
21
|
}
|
|
29
|
-
return
|
|
22
|
+
return { bam }
|
|
30
23
|
}
|
|
31
24
|
}
|
|
@@ -1,23 +1,40 @@
|
|
|
1
1
|
import { ConfigurationSchema } from '@jbrowse/core/configuration'
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* #config HtsgetBamAdapter
|
|
4
|
+
* Used to fetch data from Htsget endpoints in BAM format, using the gmod/bam library
|
|
5
|
+
*/
|
|
6
|
+
function x() {} // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
3
7
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
defaultValue: '',
|
|
15
|
-
},
|
|
16
|
-
sequenceAdapter: {
|
|
17
|
-
type: 'frozen',
|
|
18
|
-
defaultValue: null,
|
|
19
|
-
},
|
|
8
|
+
const HtsgetBamAdapter = ConfigurationSchema(
|
|
9
|
+
'HtsgetBamAdapter',
|
|
10
|
+
{
|
|
11
|
+
/**
|
|
12
|
+
* #slot
|
|
13
|
+
*/
|
|
14
|
+
htsgetBase: {
|
|
15
|
+
type: 'string',
|
|
16
|
+
description: 'the base URL to fetch from',
|
|
17
|
+
defaultValue: '',
|
|
20
18
|
},
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
/**
|
|
20
|
+
* #slot
|
|
21
|
+
*/
|
|
22
|
+
htsgetTrackId: {
|
|
23
|
+
type: 'string',
|
|
24
|
+
description: 'the trackId, which is appended to the base URL',
|
|
25
|
+
defaultValue: '',
|
|
26
|
+
},
|
|
27
|
+
/**
|
|
28
|
+
* #slot
|
|
29
|
+
*/
|
|
30
|
+
sequenceAdapter: {
|
|
31
|
+
type: 'frozen',
|
|
32
|
+
description:
|
|
33
|
+
'sequence data adapter, used to calculate SNPs when BAM reads lacking MD tags',
|
|
34
|
+
defaultValue: null,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
{ explicitlyTyped: true },
|
|
23
38
|
)
|
|
39
|
+
|
|
40
|
+
export default HtsgetBamAdapter
|
|
@@ -2,21 +2,34 @@ import { ConfigurationSchema } from '@jbrowse/core/configuration'
|
|
|
2
2
|
import { baseLinearDisplayConfigSchema } from '@jbrowse/plugin-linear-genome-view'
|
|
3
3
|
import PluginManager from '@jbrowse/core/PluginManager'
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
).configSchema
|
|
5
|
+
/**
|
|
6
|
+
* #config LinearAlignmentsDisplay
|
|
7
|
+
* has a "pileup" sub-display, where you can see individual reads and a
|
|
8
|
+
* quantitative "snpcoverage" sub-display track showing SNP frequencies
|
|
9
|
+
*/
|
|
10
|
+
function x() {} // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
12
11
|
|
|
12
|
+
const configModelFactory = (pm: PluginManager) => {
|
|
13
13
|
return ConfigurationSchema(
|
|
14
14
|
'LinearAlignmentsDisplay',
|
|
15
15
|
{
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
/**
|
|
17
|
+
* #slot
|
|
18
|
+
*/
|
|
19
|
+
pileupDisplay: pm.getDisplayType('LinearPileupDisplay').configSchema,
|
|
20
|
+
/**
|
|
21
|
+
* #slot
|
|
22
|
+
*/
|
|
23
|
+
snpCoverageDisplay: pm.getDisplayType('LinearSNPCoverageDisplay')
|
|
24
|
+
.configSchema,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
/**
|
|
28
|
+
* #baseConfiguration
|
|
29
|
+
*/
|
|
30
|
+
baseConfiguration: baseLinearDisplayConfigSchema,
|
|
31
|
+
explicitlyTyped: true,
|
|
18
32
|
},
|
|
19
|
-
{ baseConfiguration: baseLinearDisplayConfigSchema, explicitlyTyped: true },
|
|
20
33
|
)
|
|
21
34
|
}
|
|
22
35
|
|