@jbrowse/plugin-alignments 1.6.6 → 1.6.9
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/BamAdapter/BamSlightlyLazyFeature.d.ts +1 -10
- package/dist/BamAdapter/MismatchParser.d.ts +3 -5
- package/dist/CramAdapter/CramSlightlyLazyFeature.d.ts +1 -2
- package/dist/LinearSNPCoverageDisplay/models/model.d.ts +2 -2
- package/dist/PileupRenderer/PileupRenderer.d.ts +20 -6
- package/dist/SNPCoverageAdapter/SNPCoverageAdapter.d.ts +3 -11
- package/dist/plugin-alignments.cjs.development.js +591 -552
- package/dist/plugin-alignments.cjs.development.js.map +1 -1
- package/dist/plugin-alignments.cjs.production.min.js +1 -1
- package/dist/plugin-alignments.cjs.production.min.js.map +1 -1
- package/dist/plugin-alignments.esm.js +594 -555
- package/dist/plugin-alignments.esm.js.map +1 -1
- package/dist/util.d.ts +4 -0
- package/package.json +3 -3
- package/src/BamAdapter/BamAdapter.ts +10 -7
- package/src/BamAdapter/BamSlightlyLazyFeature.ts +11 -79
- package/src/BamAdapter/MismatchParser.test.ts +53 -297
- package/src/BamAdapter/MismatchParser.ts +54 -116
- package/src/BamAdapter/configSchema.ts +0 -4
- package/src/CramAdapter/CramSlightlyLazyFeature.ts +3 -10
- package/src/LinearAlignmentsDisplay/models/model.tsx +4 -6
- package/src/LinearPileupDisplay/components/ColorByModifications.tsx +76 -80
- package/src/LinearPileupDisplay/components/ColorByTag.tsx +24 -23
- package/src/LinearPileupDisplay/components/FilterByTag.tsx +73 -68
- package/src/LinearPileupDisplay/components/SetFeatureHeight.tsx +28 -26
- package/src/LinearPileupDisplay/components/SetMaxHeight.tsx +24 -13
- package/src/LinearPileupDisplay/components/SortByTag.tsx +29 -21
- package/src/LinearPileupDisplay/model.ts +6 -0
- package/src/PileupRenderer/PileupRenderer.tsx +178 -57
- package/src/SNPCoverageAdapter/SNPCoverageAdapter.ts +180 -229
- package/src/SNPCoverageRenderer/SNPCoverageRenderer.ts +12 -11
- package/src/util.ts +25 -0
|
@@ -4,12 +4,15 @@ import {
|
|
|
4
4
|
} from '@jbrowse/core/data_adapters/BaseAdapter'
|
|
5
5
|
import { AugmentedRegion as Region } from '@jbrowse/core/util/types'
|
|
6
6
|
import SimpleFeature, { Feature } from '@jbrowse/core/util/simpleFeature'
|
|
7
|
-
import { readConfObject } from '@jbrowse/core/configuration'
|
|
8
7
|
import SerializableFilterChain from '@jbrowse/core/pluggableElementTypes/renderers/util/serializableFilterChain'
|
|
9
8
|
import { ObservableCreate } from '@jbrowse/core/util/rxjs'
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
9
|
+
import { toArray } from 'rxjs/operators'
|
|
10
|
+
import {
|
|
11
|
+
getTag,
|
|
12
|
+
getTagAlt,
|
|
13
|
+
fetchSequence,
|
|
14
|
+
shouldFetchReferenceSequence,
|
|
15
|
+
} from '../util'
|
|
13
16
|
import {
|
|
14
17
|
parseCigar,
|
|
15
18
|
getNextRefPos,
|
|
@@ -48,11 +51,8 @@ function dec(bin: any, strand: number, type: string, field: string) {
|
|
|
48
51
|
|
|
49
52
|
export default class SNPCoverageAdapter extends BaseFeatureDataAdapter {
|
|
50
53
|
protected async configure() {
|
|
51
|
-
const subadapterConfig =
|
|
52
|
-
const sequenceConf =
|
|
53
|
-
'subadapter',
|
|
54
|
-
'sequenceAdapter',
|
|
55
|
-
])
|
|
54
|
+
const subadapterConfig = this.getConf('subadapter')
|
|
55
|
+
const sequenceConf = this.getConf(['subadapter', 'sequenceAdapter'])
|
|
56
56
|
const dataAdapter = await this.getSubAdapter?.(subadapterConfig)
|
|
57
57
|
|
|
58
58
|
const sequenceAdapter = sequenceConf
|
|
@@ -71,18 +71,30 @@ export default class SNPCoverageAdapter extends BaseFeatureDataAdapter {
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
async fetchSequence(region: Region) {
|
|
75
|
+
const { sequenceAdapter } = await this.configure()
|
|
76
|
+
if (!sequenceAdapter) {
|
|
77
|
+
return undefined
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return fetchSequence(region, sequenceAdapter)
|
|
81
|
+
}
|
|
82
|
+
|
|
74
83
|
getFeatures(region: Region, opts: SNPCoverageOptions = {}) {
|
|
75
84
|
return ObservableCreate<Feature>(async observer => {
|
|
76
85
|
const { subadapter } = await this.configure()
|
|
77
|
-
let
|
|
86
|
+
let feats = await subadapter
|
|
87
|
+
.getFeatures(region, opts)
|
|
88
|
+
.pipe(toArray())
|
|
89
|
+
.toPromise()
|
|
78
90
|
|
|
79
91
|
if (opts.filters) {
|
|
80
92
|
const { filters } = opts
|
|
81
|
-
|
|
93
|
+
feats = feats.filter(f => filters.passes(f, opts))
|
|
82
94
|
}
|
|
83
95
|
|
|
84
96
|
const { bins, skipmap } = await this.generateCoverageBins(
|
|
85
|
-
|
|
97
|
+
feats,
|
|
86
98
|
region,
|
|
87
99
|
opts,
|
|
88
100
|
)
|
|
@@ -135,22 +147,12 @@ export default class SNPCoverageAdapter extends BaseFeatureDataAdapter {
|
|
|
135
147
|
|
|
136
148
|
freeResources(/* { region } */): void {}
|
|
137
149
|
|
|
138
|
-
/**
|
|
139
|
-
* Generates coverage bins from features which details
|
|
140
|
-
* the reference, mismatches, strands, and coverage info
|
|
141
|
-
* @param features - Features of region to be passed in
|
|
142
|
-
* @param region - Region
|
|
143
|
-
* @param bpPerPx - base pairs per pixel
|
|
144
|
-
* @returns Array of nested frequency tables
|
|
145
|
-
*/
|
|
146
150
|
async generateCoverageBins(
|
|
147
|
-
features:
|
|
151
|
+
features: Feature[],
|
|
148
152
|
region: Region,
|
|
149
153
|
opts: { bpPerPx?: number; colorBy?: { type: string; tag?: string } },
|
|
150
154
|
) {
|
|
151
155
|
const { colorBy } = opts
|
|
152
|
-
const { sequenceAdapter } = await this.configure()
|
|
153
|
-
const { originalRefName, refName, start, end } = region
|
|
154
156
|
const binMax = Math.ceil(region.end - region.start)
|
|
155
157
|
|
|
156
158
|
const skipmap = {} as {
|
|
@@ -164,227 +166,176 @@ export default class SNPCoverageAdapter extends BaseFeatureDataAdapter {
|
|
|
164
166
|
}
|
|
165
167
|
}
|
|
166
168
|
|
|
167
|
-
// bins contain
|
|
168
|
-
//
|
|
169
|
-
//
|
|
170
|
-
//
|
|
169
|
+
// bins contain:
|
|
170
|
+
// - cov feature if they contribute to coverage
|
|
171
|
+
// - noncov are insertions/clip features that don't contribute to coverage
|
|
172
|
+
// - delskips deletions or introns that don't contribute to coverage
|
|
171
173
|
type BinType = { total: number; strands: { [key: string]: number } }
|
|
172
174
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
175
|
+
const regionSeq =
|
|
176
|
+
features.length && shouldFetchReferenceSequence(opts.colorBy?.type)
|
|
177
|
+
? await this.fetchSequence(region)
|
|
178
|
+
: undefined
|
|
179
|
+
|
|
180
|
+
const bins = [] as {
|
|
181
|
+
total: number
|
|
182
|
+
lowqual: BinType
|
|
183
|
+
cov: BinType
|
|
184
|
+
delskips: BinType
|
|
185
|
+
noncov: BinType
|
|
186
|
+
ref: BinType
|
|
187
|
+
}[]
|
|
188
|
+
|
|
189
|
+
for (let i = 0; i < features.length; i++) {
|
|
190
|
+
const feature = features[i]
|
|
191
|
+
const ops = parseCigar(feature.get('CIGAR'))
|
|
192
|
+
const fstart = feature.get('start')
|
|
193
|
+
const fend = feature.get('end')
|
|
194
|
+
const fstrand = feature.get('strand')
|
|
195
|
+
|
|
196
|
+
for (let j = fstart; j < fend; j++) {
|
|
197
|
+
const i = j - region.start
|
|
198
|
+
if (i >= 0 && i < binMax) {
|
|
199
|
+
const bin = bins[i] || {
|
|
200
|
+
total: 0,
|
|
201
|
+
lowqual: {} as BinType,
|
|
202
|
+
cov: {} as BinType,
|
|
203
|
+
delskips: {} as BinType,
|
|
204
|
+
noncov: {} as BinType,
|
|
205
|
+
ref: {} as BinType,
|
|
206
|
+
}
|
|
207
|
+
if (j !== fend) {
|
|
208
|
+
bin.total++
|
|
209
|
+
inc(bin, fstrand, 'ref', 'ref')
|
|
210
|
+
}
|
|
211
|
+
bins[i] = bin
|
|
212
|
+
}
|
|
213
|
+
}
|
|
188
214
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
const
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
if (i >= 0 && i < binMax) {
|
|
202
|
-
const bin = bins[i] || {
|
|
203
|
-
total: 0,
|
|
204
|
-
lowqual: {} as BinType,
|
|
205
|
-
cov: {} as BinType,
|
|
206
|
-
delskips: {} as BinType,
|
|
207
|
-
noncov: {} as BinType,
|
|
208
|
-
ref: {} as BinType,
|
|
209
|
-
}
|
|
210
|
-
if (j !== fend) {
|
|
211
|
-
bin.total++
|
|
212
|
-
inc(bin, fstrand, 'ref', 'ref')
|
|
213
|
-
}
|
|
214
|
-
bins[i] = bin
|
|
215
|
+
if (colorBy?.type === 'modifications') {
|
|
216
|
+
const seq = feature.get('seq') as string
|
|
217
|
+
const mm = (getTagAlt(feature, 'MM', 'Mm') as string) || ''
|
|
218
|
+
|
|
219
|
+
getModificationPositions(mm, seq, fstrand).forEach(
|
|
220
|
+
({ type, positions }) => {
|
|
221
|
+
const mod = `mod_${type}`
|
|
222
|
+
for (const pos of getNextRefPos(ops, positions)) {
|
|
223
|
+
const epos = pos + fstart - region.start
|
|
224
|
+
if (epos >= 0 && epos < bins.length && pos + fstart < fend) {
|
|
225
|
+
const bin = bins[epos]
|
|
226
|
+
inc(bin, fstrand, 'cov', mod)
|
|
215
227
|
}
|
|
216
228
|
}
|
|
229
|
+
},
|
|
230
|
+
)
|
|
231
|
+
}
|
|
217
232
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
const epos = pos + fstart - region.start
|
|
241
|
-
if (
|
|
242
|
-
epos >= 0 &&
|
|
243
|
-
epos < bins.length &&
|
|
244
|
-
pos + fstart < fend
|
|
245
|
-
) {
|
|
246
|
-
const bin = bins[epos] || {
|
|
247
|
-
total: 0,
|
|
248
|
-
lowqual: {} as BinType,
|
|
249
|
-
cov: {} as BinType,
|
|
250
|
-
delskips: {} as BinType,
|
|
251
|
-
noncov: {} as BinType,
|
|
252
|
-
ref: {} as BinType,
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (probabilities[probIndex] > 0.5) {
|
|
256
|
-
inc(bin, fstrand, 'cov', mod)
|
|
257
|
-
} else {
|
|
258
|
-
inc(bin, fstrand, 'lowqual', mod)
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
probIndex++
|
|
262
|
-
}
|
|
263
|
-
},
|
|
264
|
-
)
|
|
233
|
+
// methylation based coloring takes into account both reference
|
|
234
|
+
// sequence CpG detection and reads
|
|
235
|
+
else if (colorBy?.type === 'methylation') {
|
|
236
|
+
if (!regionSeq) {
|
|
237
|
+
throw new Error(
|
|
238
|
+
'no region sequence detected, need sequenceAdapter configuration',
|
|
239
|
+
)
|
|
240
|
+
}
|
|
241
|
+
const seq = feature.get('seq')
|
|
242
|
+
const mm = getTagAlt(feature, 'MM', 'Mm') || ''
|
|
243
|
+
const methBins = new Array(region.end - region.start).fill(0)
|
|
244
|
+
|
|
245
|
+
getModificationPositions(mm, seq, fstrand).forEach(
|
|
246
|
+
({ type, positions }) => {
|
|
247
|
+
// we are processing methylation
|
|
248
|
+
if (type === 'm') {
|
|
249
|
+
for (const pos of getNextRefPos(ops, positions)) {
|
|
250
|
+
const epos = pos + fstart - region.start
|
|
251
|
+
if (epos >= 0 && epos < methBins.length) {
|
|
252
|
+
methBins[epos] = 1
|
|
253
|
+
}
|
|
254
|
+
}
|
|
265
255
|
}
|
|
256
|
+
},
|
|
257
|
+
)
|
|
266
258
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
(
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
},
|
|
291
|
-
)
|
|
292
|
-
|
|
293
|
-
for (let j = fstart; j < fend; j++) {
|
|
294
|
-
const i = j - region.start
|
|
295
|
-
if (i >= 0 && i < bins.length - 1) {
|
|
296
|
-
const l1 = regionSeq[i].toLowerCase()
|
|
297
|
-
const l2 = regionSeq[i + 1].toLowerCase()
|
|
298
|
-
const bin = bins[i]
|
|
299
|
-
const bin1 = bins[i + 1]
|
|
300
|
-
|
|
301
|
-
// color
|
|
302
|
-
if (l1 === 'c' && l2 === 'g') {
|
|
303
|
-
if (methBins[i] || methBins[i + 1]) {
|
|
304
|
-
inc(bin, fstrand, 'cov', 'meth')
|
|
305
|
-
inc(bin1, fstrand, 'cov', 'meth')
|
|
306
|
-
dec(bin, fstrand, 'ref', 'ref')
|
|
307
|
-
dec(bin1, fstrand, 'ref', 'ref')
|
|
308
|
-
} else {
|
|
309
|
-
inc(bin, fstrand, 'cov', 'unmeth')
|
|
310
|
-
inc(bin1, fstrand, 'cov', 'unmeth')
|
|
311
|
-
dec(bin, fstrand, 'ref', 'ref')
|
|
312
|
-
dec(bin1, fstrand, 'ref', 'ref')
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
259
|
+
for (let j = fstart; j < fend; j++) {
|
|
260
|
+
const i = j - region.start
|
|
261
|
+
if (i >= 0 && i < bins.length - 1) {
|
|
262
|
+
const l1 = regionSeq[i].toLowerCase()
|
|
263
|
+
const l2 = regionSeq[i + 1].toLowerCase()
|
|
264
|
+
const bin = bins[i]
|
|
265
|
+
const bin1 = bins[i + 1]
|
|
266
|
+
|
|
267
|
+
// color
|
|
268
|
+
if (l1 === 'c' && l2 === 'g') {
|
|
269
|
+
if (methBins[i] || methBins[i + 1]) {
|
|
270
|
+
inc(bin, fstrand, 'cov', 'meth')
|
|
271
|
+
inc(bin1, fstrand, 'cov', 'meth')
|
|
272
|
+
dec(bin, fstrand, 'ref', 'ref')
|
|
273
|
+
dec(bin1, fstrand, 'ref', 'ref')
|
|
274
|
+
} else {
|
|
275
|
+
inc(bin, fstrand, 'cov', 'unmeth')
|
|
276
|
+
inc(bin1, fstrand, 'cov', 'unmeth')
|
|
277
|
+
dec(bin, fstrand, 'ref', 'ref')
|
|
278
|
+
dec(bin1, fstrand, 'ref', 'ref')
|
|
316
279
|
}
|
|
317
280
|
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
318
284
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
} else {
|
|
338
|
-
inc(bin, fstrand, 'noncov', type)
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
if (type === 'deletion' || type === 'skip') {
|
|
342
|
-
inc(bin, fstrand, 'delskips', type)
|
|
343
|
-
bin.total--
|
|
344
|
-
} else if (!interbase) {
|
|
345
|
-
inc(bin, fstrand, 'cov', base)
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
}
|
|
285
|
+
// normal SNP based coloring
|
|
286
|
+
else {
|
|
287
|
+
const mismatches = feature.get('mismatches') as Mismatch[] | undefined
|
|
288
|
+
|
|
289
|
+
if (mismatches) {
|
|
290
|
+
for (let i = 0; i < mismatches.length; i++) {
|
|
291
|
+
const mismatch = mismatches[i]
|
|
292
|
+
const mstart = fstart + mismatch.start
|
|
293
|
+
for (let j = mstart; j < mstart + mismatchLen(mismatch); j++) {
|
|
294
|
+
const epos = j - region.start
|
|
295
|
+
if (epos >= 0 && epos < bins.length) {
|
|
296
|
+
const bin = bins[epos]
|
|
297
|
+
const { base, type } = mismatch
|
|
298
|
+
const interbase = isInterbase(type)
|
|
299
|
+
if (!interbase) {
|
|
300
|
+
dec(bin, fstrand, 'ref', 'ref')
|
|
301
|
+
} else {
|
|
302
|
+
inc(bin, fstrand, 'noncov', type)
|
|
349
303
|
}
|
|
350
304
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
.
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
const strand = feature.get('strand')
|
|
358
|
-
const hash = `${start}_${end}_${strand}`
|
|
359
|
-
if (!skipmap[hash]) {
|
|
360
|
-
skipmap[hash] = {
|
|
361
|
-
feature: feature,
|
|
362
|
-
start,
|
|
363
|
-
end,
|
|
364
|
-
strand,
|
|
365
|
-
xs: getTag(feature, 'XS') || getTag(feature, 'TS'),
|
|
366
|
-
score: 1,
|
|
367
|
-
}
|
|
368
|
-
} else {
|
|
369
|
-
skipmap[hash].score++
|
|
370
|
-
}
|
|
371
|
-
})
|
|
305
|
+
if (type === 'deletion' || type === 'skip') {
|
|
306
|
+
inc(bin, fstrand, 'delskips', type)
|
|
307
|
+
bin.total--
|
|
308
|
+
} else if (!interbase) {
|
|
309
|
+
inc(bin, fstrand, 'cov', base)
|
|
310
|
+
}
|
|
372
311
|
}
|
|
373
312
|
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
mismatches
|
|
316
|
+
.filter(mismatch => mismatch.type === 'skip')
|
|
317
|
+
.forEach(mismatch => {
|
|
318
|
+
const mstart = feature.get('start') + mismatch.start
|
|
319
|
+
const start = mstart
|
|
320
|
+
const end = mstart + mismatch.length
|
|
321
|
+
const strand = feature.get('strand')
|
|
322
|
+
const hash = `${start}_${end}_${strand}`
|
|
323
|
+
if (!skipmap[hash]) {
|
|
324
|
+
skipmap[hash] = {
|
|
325
|
+
feature: feature,
|
|
326
|
+
start,
|
|
327
|
+
end,
|
|
328
|
+
strand,
|
|
329
|
+
xs: getTag(feature, 'XS') || getTag(feature, 'TS'),
|
|
330
|
+
score: 1,
|
|
331
|
+
}
|
|
332
|
+
} else {
|
|
333
|
+
skipmap[hash].score++
|
|
334
|
+
}
|
|
335
|
+
})
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
388
339
|
|
|
389
340
|
return { bins, skipmap }
|
|
390
341
|
}
|
|
@@ -71,11 +71,7 @@ export default class SNPCoverageRenderer extends WiggleBaseRenderer {
|
|
|
71
71
|
}
|
|
72
72
|
const opts = { ...scaleOpts, range: [0, height] }
|
|
73
73
|
const viewScale = getScale(opts)
|
|
74
|
-
|
|
75
|
-
...opts,
|
|
76
|
-
range: [0, height],
|
|
77
|
-
scaleType: 'linear',
|
|
78
|
-
})
|
|
74
|
+
|
|
79
75
|
// clipping and insertion indicators, uses a smaller height/2 scale
|
|
80
76
|
const indicatorViewScale = getScale({
|
|
81
77
|
...opts,
|
|
@@ -83,7 +79,6 @@ export default class SNPCoverageRenderer extends WiggleBaseRenderer {
|
|
|
83
79
|
scaleType: 'linear',
|
|
84
80
|
})
|
|
85
81
|
const originY = getOrigin(scaleOpts.scaleType)
|
|
86
|
-
const snpOriginY = getOrigin('linear')
|
|
87
82
|
|
|
88
83
|
const indicatorThreshold = readConfObject(cfg, 'indicatorThreshold')
|
|
89
84
|
const drawInterbaseCounts = readConfObject(cfg, 'drawInterbaseCounts')
|
|
@@ -94,13 +89,10 @@ export default class SNPCoverageRenderer extends WiggleBaseRenderer {
|
|
|
94
89
|
const toY = (n: number) => height - (viewScale(n) || 0) + offset
|
|
95
90
|
const toHeight = (n: number) => toY(originY) - toY(n)
|
|
96
91
|
|
|
97
|
-
// this is always linear scale, even when plotted on top of log scale
|
|
98
|
-
const snpToY = (n: number) => height - (snpViewScale(n) || 0) + offset
|
|
99
92
|
const indicatorToY = (n: number) =>
|
|
100
93
|
height - (indicatorViewScale(n) || 0) + offset
|
|
101
|
-
const snpToHeight = (n: number) => snpToY(snpOriginY) - snpToY(n)
|
|
102
94
|
const indicatorToHeight = (n: number) =>
|
|
103
|
-
indicatorToY(
|
|
95
|
+
indicatorToY(getOrigin('linear')) - indicatorToY(n)
|
|
104
96
|
|
|
105
97
|
const colorForBase: { [key: string]: string } = {
|
|
106
98
|
A: theme.palette.bases.A.main,
|
|
@@ -150,6 +142,7 @@ export default class SNPCoverageRenderer extends WiggleBaseRenderer {
|
|
|
150
142
|
const feature = coverage[i]
|
|
151
143
|
const [leftPx, rightPx] = featureSpanPx(feature, region, bpPerPx)
|
|
152
144
|
|
|
145
|
+
const score = feature.get('score') as number
|
|
153
146
|
const snpinfo = feature.get('snpinfo') as SNPInfo
|
|
154
147
|
const w = Math.max(rightPx - leftPx + 0.3, 1)
|
|
155
148
|
const totalScore = snpinfo.total
|
|
@@ -163,7 +156,15 @@ export default class SNPCoverageRenderer extends WiggleBaseRenderer {
|
|
|
163
156
|
colorForBase[base] ||
|
|
164
157
|
modificationTagMap[base.replace('mod_', '')] ||
|
|
165
158
|
'#888'
|
|
166
|
-
|
|
159
|
+
|
|
160
|
+
const height = toHeight(score)
|
|
161
|
+
const bottom = toY(score) + height
|
|
162
|
+
ctx.fillRect(
|
|
163
|
+
leftPx,
|
|
164
|
+
bottom - ((total + curr) / score) * height,
|
|
165
|
+
w,
|
|
166
|
+
(total / score) * height,
|
|
167
|
+
)
|
|
167
168
|
curr += total
|
|
168
169
|
}
|
|
169
170
|
|
package/src/util.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter'
|
|
2
|
+
import { toArray } from 'rxjs/operators'
|
|
1
3
|
import { Feature } from '@jbrowse/core/util/simpleFeature'
|
|
4
|
+
import { AugmentedRegion } from '@jbrowse/core/util'
|
|
2
5
|
// get tag from BAM or CRAM feature, where CRAM uses feature.get('tags') and
|
|
3
6
|
// BAM does not
|
|
4
7
|
export function getTag(feature: Feature, tag: string) {
|
|
@@ -76,3 +79,25 @@ export function getColorWGBS(strand: number, base: string) {
|
|
|
76
79
|
}
|
|
77
80
|
return '#888'
|
|
78
81
|
}
|
|
82
|
+
|
|
83
|
+
export async function fetchSequence(
|
|
84
|
+
region: AugmentedRegion,
|
|
85
|
+
adapter: BaseFeatureDataAdapter,
|
|
86
|
+
) {
|
|
87
|
+
const { end, originalRefName, refName } = region
|
|
88
|
+
|
|
89
|
+
const feats = await adapter
|
|
90
|
+
.getFeatures({
|
|
91
|
+
...region,
|
|
92
|
+
refName: originalRefName || refName,
|
|
93
|
+
end: end + 1,
|
|
94
|
+
})
|
|
95
|
+
.pipe(toArray())
|
|
96
|
+
.toPromise()
|
|
97
|
+
return feats[0]?.get('seq')
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// has to check underlying C-G (aka CpG) on the reference sequence
|
|
101
|
+
export function shouldFetchReferenceSequence(type?: string) {
|
|
102
|
+
return type === 'methylation'
|
|
103
|
+
}
|