@jbrowse/plugin-alignments 1.7.7 → 1.7.10

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.
Files changed (39) hide show
  1. package/dist/AlignmentsFeatureDetail/AlignmentsFeatureDetail.js +13 -3
  2. package/dist/AlignmentsFeatureDetail/index.d.ts +28 -3
  3. package/dist/AlignmentsFeatureDetail/index.js +6 -17
  4. package/dist/BamAdapter/BamAdapter.d.ts +1 -1
  5. package/dist/BamAdapter/BamAdapter.js +3 -3
  6. package/dist/BamAdapter/MismatchParser.d.ts +2 -5
  7. package/dist/BamAdapter/MismatchParser.js +108 -46
  8. package/dist/BamAdapter/MismatchParser.test.js +6 -14
  9. package/dist/CramAdapter/CramAdapter.d.ts +10 -9
  10. package/dist/CramAdapter/CramAdapter.js +6 -6
  11. package/dist/CramAdapter/CramSlightlyLazyFeature.js +35 -30
  12. package/dist/LinearPileupDisplay/model.d.ts +6 -3
  13. package/dist/LinearPileupDisplay/model.js +132 -51
  14. package/dist/LinearSNPCoverageDisplay/components/Tooltip.js +37 -17
  15. package/dist/LinearSNPCoverageDisplay/models/model.d.ts +2 -2
  16. package/dist/LinearSNPCoverageDisplay/models/model.js +1 -1
  17. package/dist/PileupRenderer/PileupLayoutSession.d.ts +3 -0
  18. package/dist/PileupRenderer/PileupLayoutSession.js +3 -1
  19. package/dist/PileupRenderer/PileupRenderer.d.ts +66 -9
  20. package/dist/PileupRenderer/PileupRenderer.js +296 -258
  21. package/dist/PileupRenderer/configSchema.js +2 -2
  22. package/dist/SNPCoverageAdapter/SNPCoverageAdapter.d.ts +6 -6
  23. package/dist/SNPCoverageAdapter/SNPCoverageAdapter.js +95 -96
  24. package/dist/SNPCoverageRenderer/configSchema.d.ts +1 -1
  25. package/package.json +3 -3
  26. package/src/AlignmentsFeatureDetail/AlignmentsFeatureDetail.tsx +14 -3
  27. package/src/AlignmentsFeatureDetail/index.ts +7 -17
  28. package/src/BamAdapter/BamAdapter.ts +3 -3
  29. package/src/BamAdapter/MismatchParser.test.ts +5 -7
  30. package/src/BamAdapter/MismatchParser.ts +72 -59
  31. package/src/CramAdapter/CramAdapter.ts +14 -10
  32. package/src/CramAdapter/CramSlightlyLazyFeature.ts +84 -91
  33. package/src/LinearPileupDisplay/model.ts +76 -24
  34. package/src/LinearSNPCoverageDisplay/components/Tooltip.tsx +41 -20
  35. package/src/LinearSNPCoverageDisplay/models/model.ts +1 -1
  36. package/src/PileupRenderer/PileupLayoutSession.ts +6 -1
  37. package/src/PileupRenderer/PileupRenderer.tsx +413 -225
  38. package/src/PileupRenderer/configSchema.ts +2 -2
  39. package/src/SNPCoverageAdapter/SNPCoverageAdapter.ts +89 -76
@@ -31,8 +31,8 @@ export default ConfigurationSchema(
31
31
  minSubfeatureWidth: {
32
32
  type: 'number',
33
33
  description:
34
- 'the minimum width in px for a pileup mismatch feature. use for increasing mismatch marker widths when zoomed out to e.g. 1px or 0.5px',
35
- defaultValue: 0,
34
+ 'the minimum width in px for a pileup mismatch feature. use for increasing/decreasing mismatch marker widths when zoomed out, e.g. 0 or 1',
35
+ defaultValue: 0.7,
36
36
  },
37
37
  maxHeight: {
38
38
  type: 'integer',
@@ -30,22 +30,16 @@ function isInterbase(type: string) {
30
30
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
31
  function inc(bin: any, strand: number, type: string, field: string) {
32
32
  let thisBin = bin[type][field]
33
- if (!thisBin) {
33
+ if (thisBin === undefined) {
34
34
  thisBin = bin[type][field] = {
35
35
  total: 0,
36
- strands: { '-1': 0, '0': 0, '1': 0 },
36
+ '-1': 0,
37
+ '0': 0,
38
+ '1': 0,
37
39
  }
38
40
  }
39
41
  thisBin.total++
40
- thisBin.strands[strand]++
41
- }
42
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
43
- function dec(bin: any, strand: number, type: string, field: string) {
44
- if (!bin[type][field]) {
45
- bin[type][field] = { total: 0, strands: { '-1': 0, '0': 0, '1': 0 } }
46
- }
47
- bin[type][field].total--
48
- bin[type][field].strands[strand]--
42
+ thisBin[strand]++
49
43
  }
50
44
 
51
45
  export default class SNPCoverageAdapter extends BaseFeatureDataAdapter {
@@ -172,43 +166,56 @@ export default class SNPCoverageAdapter extends BaseFeatureDataAdapter {
172
166
  : undefined
173
167
 
174
168
  const bins = [] as {
169
+ refbase?: string
175
170
  total: number
171
+ all: number
172
+ ref: number
173
+ '-1': 0
174
+ '0': 0
175
+ '1': 0
176
176
  lowqual: BinType
177
177
  cov: BinType
178
178
  delskips: BinType
179
179
  noncov: BinType
180
- ref: BinType
181
180
  }[]
182
181
 
183
182
  for (let i = 0; i < features.length; i++) {
184
183
  const feature = features[i]
185
- const ops = parseCigar(feature.get('CIGAR'))
186
184
  const fstart = feature.get('start')
187
185
  const fend = feature.get('end')
188
- const fstrand = feature.get('strand')
186
+ const fstrand = feature.get('strand') as -1 | 0 | 1
189
187
 
190
- for (let j = fstart; j < fend; j++) {
188
+ for (let j = fstart; j < fend + 1; j++) {
191
189
  const i = j - region.start
192
190
  if (i >= 0 && i < binMax) {
193
- const bin = bins[i] || {
194
- total: 0,
195
- lowqual: {} as BinType,
196
- cov: {} as BinType,
197
- delskips: {} as BinType,
198
- noncov: {} as BinType,
199
- ref: {} as BinType,
191
+ if (bins[i] === undefined) {
192
+ bins[i] = {
193
+ total: 0,
194
+ all: 0,
195
+ ref: 0,
196
+ '-1': 0,
197
+ '0': 0,
198
+ '1': 0,
199
+ lowqual: {} as BinType,
200
+ cov: {} as BinType,
201
+ delskips: {} as BinType,
202
+ noncov: {} as BinType,
203
+ }
200
204
  }
201
205
  if (j !== fend) {
202
- bin.total++
203
- inc(bin, fstrand, 'ref', 'ref')
206
+ bins[i].total++
207
+ bins[i].all++
208
+ bins[i].ref++
209
+ bins[i][fstrand]++
204
210
  }
205
- bins[i] = bin
206
211
  }
207
212
  }
208
213
 
209
214
  if (colorBy?.type === 'modifications') {
210
215
  const seq = feature.get('seq') as string
211
216
  const mm = (getTagAlt(feature, 'MM', 'Mm') as string) || ''
217
+ const ops = parseCigar(feature.get('CIGAR'))
218
+ const fend = feature.get('end')
212
219
 
213
220
  getModificationPositions(mm, seq, fstrand).forEach(
214
221
  ({ type, positions }) => {
@@ -217,7 +224,13 @@ export default class SNPCoverageAdapter extends BaseFeatureDataAdapter {
217
224
  const epos = pos + fstart - region.start
218
225
  if (epos >= 0 && epos < bins.length && pos + fstart < fend) {
219
226
  const bin = bins[epos]
220
- inc(bin, fstrand, 'cov', mod)
227
+ if (bin) {
228
+ inc(bin, fstrand, 'cov', mod)
229
+ } else {
230
+ console.warn(
231
+ 'Undefined position in modifications snpcoverage encountered',
232
+ )
233
+ }
221
234
  }
222
235
  }
223
236
  },
@@ -235,6 +248,7 @@ export default class SNPCoverageAdapter extends BaseFeatureDataAdapter {
235
248
  const seq = feature.get('seq')
236
249
  const mm = getTagAlt(feature, 'MM', 'Mm') || ''
237
250
  const methBins = new Array(region.end - region.start).fill(0)
251
+ const ops = parseCigar(feature.get('CIGAR'))
238
252
 
239
253
  getModificationPositions(mm, seq, fstrand).forEach(
240
254
  ({ type, positions }) => {
@@ -263,13 +277,17 @@ export default class SNPCoverageAdapter extends BaseFeatureDataAdapter {
263
277
  if (methBins[i] || methBins[i + 1]) {
264
278
  inc(bin, fstrand, 'cov', 'meth')
265
279
  inc(bin1, fstrand, 'cov', 'meth')
266
- dec(bin, fstrand, 'ref', 'ref')
267
- dec(bin1, fstrand, 'ref', 'ref')
280
+ bins[i].ref--
281
+ bins[i][fstrand]--
282
+ bins[i + 1].ref--
283
+ bins[i + 1][fstrand]--
268
284
  } else {
269
285
  inc(bin, fstrand, 'cov', 'unmeth')
270
286
  inc(bin1, fstrand, 'cov', 'unmeth')
271
- dec(bin, fstrand, 'ref', 'ref')
272
- dec(bin1, fstrand, 'ref', 'ref')
287
+ bins[i].ref--
288
+ bins[i][fstrand]--
289
+ bins[i + 1].ref--
290
+ bins[i + 1][fstrand]--
273
291
  }
274
292
  }
275
293
  }
@@ -277,56 +295,51 @@ export default class SNPCoverageAdapter extends BaseFeatureDataAdapter {
277
295
  }
278
296
 
279
297
  // normal SNP based coloring
280
- else {
281
- const mismatches = feature.get('mismatches') as Mismatch[] | undefined
282
-
283
- if (mismatches) {
284
- for (let i = 0; i < mismatches.length; i++) {
285
- const mismatch = mismatches[i]
286
- const mstart = fstart + mismatch.start
287
- for (let j = mstart; j < mstart + mismatchLen(mismatch); j++) {
288
- const epos = j - region.start
289
- if (epos >= 0 && epos < bins.length) {
290
- const bin = bins[epos]
291
- const { base, type } = mismatch
292
- const interbase = isInterbase(type)
293
- if (!interbase) {
294
- dec(bin, fstrand, 'ref', 'ref')
295
- } else {
296
- inc(bin, fstrand, 'noncov', type)
297
- }
298
+ const mismatches = (feature.get('mismatches') as Mismatch[]) || []
299
+ const colorSNPs =
300
+ colorBy?.type !== 'modifications' && colorBy?.type !== 'methylation'
301
+
302
+ for (let i = 0; i < mismatches.length; i++) {
303
+ const mismatch = mismatches[i]
304
+ const mstart = fstart + mismatch.start
305
+ const mlen = mismatchLen(mismatch)
306
+ const mend = mstart + mlen
307
+ for (let j = mstart; j < mstart + mlen; j++) {
308
+ const epos = j - region.start
309
+ if (epos >= 0 && epos < bins.length) {
310
+ const bin = bins[epos]
311
+ const { base, type } = mismatch
312
+ const interbase = isInterbase(type)
313
+ if (!interbase) {
314
+ bin.ref--
315
+ bin[fstrand]--
316
+ } else {
317
+ inc(bin, fstrand, 'noncov', type)
318
+ }
298
319
 
299
- if (type === 'deletion' || type === 'skip') {
300
- inc(bin, fstrand, 'delskips', type)
301
- bin.total--
302
- } else if (!interbase) {
303
- inc(bin, fstrand, 'cov', base)
304
- }
305
- }
320
+ if (type === 'deletion' || type === 'skip') {
321
+ inc(bin, fstrand, 'delskips', type)
322
+ bin.total--
323
+ } else if (!interbase && colorSNPs) {
324
+ inc(bin, fstrand, 'cov', base)
325
+ bin.refbase = mismatch.altbase
306
326
  }
307
327
  }
328
+ }
308
329
 
309
- mismatches
310
- .filter(mismatch => mismatch.type === 'skip')
311
- .forEach(mismatch => {
312
- const mstart = feature.get('start') + mismatch.start
313
- const start = mstart
314
- const end = mstart + mismatch.length
315
- const strand = feature.get('strand')
316
- const hash = `${start}_${end}_${strand}`
317
- if (!skipmap[hash]) {
318
- skipmap[hash] = {
319
- feature: feature,
320
- start,
321
- end,
322
- strand,
323
- xs: getTag(feature, 'XS') || getTag(feature, 'TS'),
324
- score: 1,
325
- }
326
- } else {
327
- skipmap[hash].score++
328
- }
329
- })
330
+ if (mismatch.type === 'skip') {
331
+ const hash = `${mstart}_${mend}_${fstrand}`
332
+ if (skipmap[hash] === undefined) {
333
+ skipmap[hash] = {
334
+ feature: feature,
335
+ start: mstart,
336
+ end: mend,
337
+ strand: fstrand,
338
+ xs: getTag(feature, 'XS') || getTag(feature, 'TS'),
339
+ score: 0,
340
+ }
341
+ }
342
+ skipmap[hash].score++
330
343
  }
331
344
  }
332
345
  }