@jbrowse/plugin-alignments 2.2.1 → 2.2.2

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 (64) hide show
  1. package/dist/CramAdapter/CramTestAdapters.js +2 -1
  2. package/dist/CramAdapter/CramTestAdapters.js.map +1 -1
  3. package/dist/LinearPileupDisplay/components/ColorByModifications.d.ts +3 -1
  4. package/dist/LinearPileupDisplay/components/ColorByModifications.js +7 -22
  5. package/dist/LinearPileupDisplay/components/ColorByModifications.js.map +1 -1
  6. package/dist/LinearPileupDisplay/components/ColorByTag.js +2 -22
  7. package/dist/LinearPileupDisplay/components/ColorByTag.js.map +1 -1
  8. package/dist/LinearPileupDisplay/components/FilterByTag.js +2 -15
  9. package/dist/LinearPileupDisplay/components/FilterByTag.js.map +1 -1
  10. package/dist/LinearPileupDisplay/components/SetFeatureHeight.js +2 -19
  11. package/dist/LinearPileupDisplay/components/SetFeatureHeight.js.map +1 -1
  12. package/dist/LinearPileupDisplay/components/SetMaxHeight.js +2 -18
  13. package/dist/LinearPileupDisplay/components/SetMaxHeight.js.map +1 -1
  14. package/dist/LinearPileupDisplay/components/SortByTag.js +2 -23
  15. package/dist/LinearPileupDisplay/components/SortByTag.js.map +1 -1
  16. package/dist/LinearSNPCoverageDisplay/models/model.d.ts +13 -9
  17. package/dist/LinearSNPCoverageDisplay/models/model.js +8 -6
  18. package/dist/LinearSNPCoverageDisplay/models/model.js.map +1 -1
  19. package/dist/PileupRenderer/configSchema.js +1 -1
  20. package/dist/PileupRenderer/configSchema.js.map +1 -1
  21. package/dist/SNPCoverageAdapter/SNPCoverageAdapter.d.ts +0 -51
  22. package/dist/SNPCoverageAdapter/SNPCoverageAdapter.js +3 -182
  23. package/dist/SNPCoverageAdapter/SNPCoverageAdapter.js.map +1 -1
  24. package/dist/SNPCoverageAdapter/generateCoverageBins.d.ts +53 -0
  25. package/dist/SNPCoverageAdapter/generateCoverageBins.js +185 -0
  26. package/dist/SNPCoverageAdapter/generateCoverageBins.js.map +1 -0
  27. package/esm/CramAdapter/CramTestAdapters.js +2 -1
  28. package/esm/CramAdapter/CramTestAdapters.js.map +1 -1
  29. package/esm/LinearPileupDisplay/components/ColorByModifications.d.ts +3 -1
  30. package/esm/LinearPileupDisplay/components/ColorByModifications.js +8 -23
  31. package/esm/LinearPileupDisplay/components/ColorByModifications.js.map +1 -1
  32. package/esm/LinearPileupDisplay/components/ColorByTag.js +3 -20
  33. package/esm/LinearPileupDisplay/components/ColorByTag.js.map +1 -1
  34. package/esm/LinearPileupDisplay/components/FilterByTag.js +3 -13
  35. package/esm/LinearPileupDisplay/components/FilterByTag.js.map +1 -1
  36. package/esm/LinearPileupDisplay/components/SetFeatureHeight.js +3 -17
  37. package/esm/LinearPileupDisplay/components/SetFeatureHeight.js.map +1 -1
  38. package/esm/LinearPileupDisplay/components/SetMaxHeight.js +3 -16
  39. package/esm/LinearPileupDisplay/components/SetMaxHeight.js.map +1 -1
  40. package/esm/LinearPileupDisplay/components/SortByTag.js +3 -21
  41. package/esm/LinearPileupDisplay/components/SortByTag.js.map +1 -1
  42. package/esm/LinearSNPCoverageDisplay/models/model.d.ts +13 -9
  43. package/esm/LinearSNPCoverageDisplay/models/model.js +9 -7
  44. package/esm/LinearSNPCoverageDisplay/models/model.js.map +1 -1
  45. package/esm/PileupRenderer/configSchema.js +1 -1
  46. package/esm/PileupRenderer/configSchema.js.map +1 -1
  47. package/esm/SNPCoverageAdapter/SNPCoverageAdapter.d.ts +0 -51
  48. package/esm/SNPCoverageAdapter/SNPCoverageAdapter.js +4 -183
  49. package/esm/SNPCoverageAdapter/SNPCoverageAdapter.js.map +1 -1
  50. package/esm/SNPCoverageAdapter/generateCoverageBins.d.ts +53 -0
  51. package/esm/SNPCoverageAdapter/generateCoverageBins.js +182 -0
  52. package/esm/SNPCoverageAdapter/generateCoverageBins.js.map +1 -0
  53. package/package.json +3 -3
  54. package/src/CramAdapter/CramTestAdapters.ts +1 -0
  55. package/src/LinearPileupDisplay/components/ColorByModifications.tsx +5 -34
  56. package/src/LinearPileupDisplay/components/ColorByTag.tsx +2 -29
  57. package/src/LinearPileupDisplay/components/FilterByTag.tsx +2 -22
  58. package/src/LinearPileupDisplay/components/SetFeatureHeight.tsx +2 -22
  59. package/src/LinearPileupDisplay/components/SetMaxHeight.tsx +2 -24
  60. package/src/LinearPileupDisplay/components/SortByTag.tsx +2 -31
  61. package/src/LinearSNPCoverageDisplay/models/model.ts +12 -8
  62. package/src/PileupRenderer/configSchema.ts +1 -1
  63. package/src/SNPCoverageAdapter/SNPCoverageAdapter.ts +5 -249
  64. package/src/SNPCoverageAdapter/generateCoverageBins.ts +245 -0
@@ -2,50 +2,23 @@ import React, { useState } from 'react'
2
2
  import { observer } from 'mobx-react'
3
3
  import {
4
4
  Button,
5
- Dialog,
6
5
  DialogContent,
7
6
  DialogActions,
8
- DialogTitle,
9
- IconButton,
10
7
  TextField,
11
8
  Typography,
12
9
  } from '@mui/material'
13
- import { makeStyles } from 'tss-react/mui'
14
- import CloseIcon from '@mui/icons-material/Close'
15
-
16
- const useStyles = makeStyles()(theme => ({
17
- root: {
18
- width: 300,
19
- },
20
- closeButton: {
21
- position: 'absolute',
22
- right: theme.spacing(1),
23
- top: theme.spacing(1),
24
- color: theme.palette.grey[500],
25
- },
26
- }))
10
+ import { Dialog } from '@jbrowse/core/ui'
27
11
 
28
12
  function ColorByTagDlg(props: {
29
13
  model: { setColorScheme: Function }
30
14
  handleClose: () => void
31
15
  }) {
32
- const { classes } = useStyles()
33
16
  const { model, handleClose } = props
34
17
  const [tag, setTag] = useState('')
35
18
  const validTag = tag.match(/^[A-Za-z][A-Za-z0-9]$/)
36
19
 
37
20
  return (
38
- <Dialog open onClose={handleClose}>
39
- <DialogTitle>
40
- Color by tag
41
- <IconButton
42
- aria-label="close"
43
- className={classes.closeButton}
44
- onClick={handleClose}
45
- >
46
- <CloseIcon />
47
- </IconButton>
48
- </DialogTitle>
21
+ <Dialog open onClose={handleClose} title="Color by tag">
49
22
  <DialogContent style={{ overflowX: 'hidden' }}>
50
23
  <Typography>Enter tag to color by: </Typography>
51
24
  <Typography color="textSecondary">
@@ -2,31 +2,21 @@ import React, { useState } from 'react'
2
2
  import { observer } from 'mobx-react'
3
3
  import {
4
4
  Button,
5
- Dialog,
6
5
  DialogActions,
7
6
  DialogContent,
8
- DialogTitle,
9
- IconButton,
10
7
  Link,
11
8
  Paper,
12
9
  TextField,
13
10
  Typography,
14
11
  } from '@mui/material'
12
+ import { Dialog } from '@jbrowse/core/ui'
15
13
  import { makeStyles } from 'tss-react/mui'
16
14
 
17
- import CloseIcon from '@mui/icons-material/Close'
18
-
19
15
  const useStyles = makeStyles()(theme => ({
20
16
  paper: {
21
17
  padding: theme.spacing(2),
22
18
  margin: theme.spacing(2),
23
19
  },
24
- closeButton: {
25
- position: 'absolute',
26
- right: theme.spacing(1),
27
- top: theme.spacing(1),
28
- color: theme.palette.grey[500],
29
- },
30
20
  field: {
31
21
  margin: theme.spacing(2),
32
22
  },
@@ -105,17 +95,7 @@ function FilterByTagDlg(props: {
105
95
  const site = 'https://broadinstitute.github.io/picard/explain-flags.html'
106
96
 
107
97
  return (
108
- <Dialog open onClose={handleClose}>
109
- <DialogTitle>
110
- Filter options
111
- <IconButton
112
- aria-label="close"
113
- className={classes.closeButton}
114
- onClick={handleClose}
115
- >
116
- <CloseIcon />
117
- </IconButton>
118
- </DialogTitle>
98
+ <Dialog open onClose={handleClose} title="Filter options">
119
99
  <DialogContent>
120
100
  <Typography>
121
101
  Set filter bitmask options. Refer to <Link href={site}>{site}</Link>{' '}
@@ -3,26 +3,13 @@ import { observer } from 'mobx-react'
3
3
  import {
4
4
  Button,
5
5
  Checkbox,
6
- Dialog,
7
6
  DialogActions,
8
7
  DialogContent,
9
- DialogTitle,
10
8
  FormControlLabel,
11
- IconButton,
12
9
  TextField,
13
10
  Typography,
14
11
  } from '@mui/material'
15
- import { makeStyles } from 'tss-react/mui'
16
- import CloseIcon from '@mui/icons-material/Close'
17
-
18
- const useStyles = makeStyles()(theme => ({
19
- closeButton: {
20
- position: 'absolute',
21
- right: theme.spacing(1),
22
- top: theme.spacing(1),
23
- color: theme.palette.grey[500],
24
- },
25
- }))
12
+ import { Dialog } from '@jbrowse/core/ui'
26
13
 
27
14
  function SetFeatureHeightDlg(props: {
28
15
  model: {
@@ -33,7 +20,6 @@ function SetFeatureHeightDlg(props: {
33
20
  }
34
21
  handleClose: () => void
35
22
  }) {
36
- const { classes } = useStyles()
37
23
  const { model, handleClose } = props
38
24
  const { featureHeightSetting, noSpacing: noSpacingSetting } = model
39
25
  const [height, setHeight] = useState(`${featureHeightSetting}`)
@@ -42,13 +28,7 @@ function SetFeatureHeightDlg(props: {
42
28
  const ok = height !== '' && !Number.isNaN(+height)
43
29
 
44
30
  return (
45
- <Dialog open onClose={handleClose}>
46
- <DialogTitle>
47
- Set feature height
48
- <IconButton className={classes.closeButton} onClick={handleClose}>
49
- <CloseIcon />
50
- </IconButton>
51
- </DialogTitle>
31
+ <Dialog open onClose={handleClose} title={'Set feature height'}>
52
32
  <DialogContent>
53
33
  <Typography>
54
34
  Adjust the feature height and whether there is any spacing between
@@ -2,30 +2,18 @@ import React, { useState } from 'react'
2
2
  import { observer } from 'mobx-react'
3
3
  import {
4
4
  Button,
5
- Dialog,
6
5
  DialogActions,
7
6
  DialogContent,
8
- DialogTitle,
9
- IconButton,
10
7
  TextField,
11
8
  Typography,
12
9
  } from '@mui/material'
10
+ import { Dialog } from '@jbrowse/core/ui'
13
11
  import { makeStyles } from 'tss-react/mui'
14
- import CloseIcon from '@mui/icons-material/Close'
15
12
 
16
13
  const useStyles = makeStyles()(theme => ({
17
14
  root: {
18
15
  width: 500,
19
16
  },
20
- closeButton: {
21
- position: 'absolute',
22
- right: theme.spacing(1),
23
- top: theme.spacing(1),
24
- color: theme.palette.grey[500],
25
- },
26
- field: {
27
- margin: theme.spacing(2),
28
- },
29
17
  }))
30
18
 
31
19
  function SetMaxHeightDlg(props: {
@@ -41,17 +29,7 @@ function SetMaxHeightDlg(props: {
41
29
  const [max, setMax] = useState(`${maxHeight}`)
42
30
 
43
31
  return (
44
- <Dialog open onClose={handleClose}>
45
- <DialogTitle>
46
- Filter options
47
- <IconButton
48
- aria-label="close"
49
- className={classes.closeButton}
50
- onClick={handleClose}
51
- >
52
- <CloseIcon />
53
- </IconButton>
54
- </DialogTitle>
32
+ <Dialog open onClose={handleClose} title="Filter options">
55
33
  <DialogContent className={classes.root}>
56
34
  <Typography>
57
35
  Set max height for the track. For example, you can increase this if
@@ -2,51 +2,22 @@ import React, { useState } from 'react'
2
2
  import { observer } from 'mobx-react'
3
3
  import {
4
4
  Button,
5
- Dialog,
6
5
  DialogActions,
7
6
  DialogContent,
8
- DialogTitle,
9
- IconButton,
10
7
  TextField,
11
8
  Typography,
12
9
  } from '@mui/material'
13
- import { makeStyles } from 'tss-react/mui'
14
-
15
- import CloseIcon from '@mui/icons-material/Close'
16
-
17
- const useStyles = makeStyles()(theme => ({
18
- root: {
19
- margin: 0,
20
- padding: theme.spacing(2),
21
- },
22
- closeButton: {
23
- position: 'absolute',
24
- right: theme.spacing(1),
25
- top: theme.spacing(1),
26
- color: theme.palette.grey[500],
27
- },
28
- }))
10
+ import { Dialog } from '@jbrowse/core/ui'
29
11
 
30
12
  function SortByTagDlg(props: {
31
13
  model: { setSortedBy: Function }
32
14
  handleClose: () => void
33
15
  }) {
34
- const { classes } = useStyles()
35
16
  const { model, handleClose } = props
36
17
  const [tag, setTag] = useState('')
37
18
  const validTag = tag.match(/^[A-Za-z][A-Za-z0-9]$/)
38
19
  return (
39
- <Dialog open onClose={handleClose}>
40
- <DialogTitle>
41
- Sort by tag
42
- <IconButton
43
- aria-label="close"
44
- className={classes.closeButton}
45
- onClick={handleClose}
46
- >
47
- <CloseIcon />
48
- </IconButton>
49
- </DialogTitle>
20
+ <Dialog open onClose={handleClose} title="Sort by tag">
50
21
  <DialogContent>
51
22
  <Typography>Set the tag to sort by</Typography>
52
23
  <Typography color="textSecondary">
@@ -1,5 +1,9 @@
1
1
  import { addDisposer, types, cast, getEnv, getSnapshot } from 'mobx-state-tree'
2
- import { observable, autorun } from 'mobx'
2
+ import clone from 'clone'
3
+ import { autorun } from 'mobx'
4
+
5
+ // jbrowse
6
+ import PluginManager from '@jbrowse/core/PluginManager'
3
7
  import {
4
8
  getConf,
5
9
  readConfObject,
@@ -8,7 +12,6 @@ import {
8
12
  } from '@jbrowse/core/configuration'
9
13
  import { linearWiggleDisplayModelFactory } from '@jbrowse/plugin-wiggle'
10
14
  import { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
11
- import PluginManager from '@jbrowse/core/PluginManager'
12
15
  import { getContainingView } from '@jbrowse/core/util'
13
16
 
14
17
  // locals
@@ -75,7 +78,7 @@ function stateModelFactory(
75
78
  }),
76
79
  )
77
80
  .volatile(() => ({
78
- modificationTagMap: observable.map({}),
81
+ modificationTagMap: undefined as Record<string, string> | undefined,
79
82
  }))
80
83
  .actions(self => ({
81
84
  /**
@@ -109,12 +112,14 @@ function stateModelFactory(
109
112
  const colorPalette = ['red', 'blue', 'green', 'orange', 'purple']
110
113
  let i = 0
111
114
 
115
+ const newMap = clone(self.modificationTagMap) || {}
112
116
  uniqueModifications.forEach(value => {
113
- if (!self.modificationTagMap.has(value)) {
117
+ if (!newMap[value]) {
114
118
  const newColor = colorPalette[i++]
115
- self.modificationTagMap.set(value, newColor)
119
+ newMap[value] = newColor
116
120
  }
117
121
  })
122
+ self.modificationTagMap = newMap
118
123
  },
119
124
  }))
120
125
  .views(self => {
@@ -170,8 +175,7 @@ function stateModelFactory(
170
175
  */
171
176
  get modificationsReady() {
172
177
  return self.colorBy?.type === 'modifications'
173
- ? Object.keys(JSON.parse(JSON.stringify(self.modificationTagMap)))
174
- .length > 0
178
+ ? self.modificationTagMap !== undefined
175
179
  : true
176
180
  },
177
181
 
@@ -184,7 +188,7 @@ function stateModelFactory(
184
188
  return {
185
189
  ...superProps,
186
190
  notReady: superProps.notReady || !this.modificationsReady,
187
- modificationTagMap: Object.fromEntries(modificationTagMap.toJSON()),
191
+ modificationTagMap: modificationTagMap,
188
192
 
189
193
  // must use getSnapshot because otherwise changes to e.g. just the
190
194
  // colorBy.type are not read
@@ -28,7 +28,7 @@ const PileupRenderer = ConfigurationSchema(
28
28
  model: types.enumeration('orientationType', ['fr', 'rf', 'ff']),
29
29
  defaultValue: 'fr',
30
30
  description:
31
- 'read sequencer orienation. fr is normal "reads pointing at each other ---> <--- while some other sequencers can use other options',
31
+ 'read sequencer orientation. fr is normal "reads pointing at each other ---> <--- while some other sequencers can use other options',
32
32
  },
33
33
  /**
34
34
  * #slot
@@ -6,46 +6,13 @@ import { AugmentedRegion as Region } from '@jbrowse/core/util/types'
6
6
  import SimpleFeature, { Feature } from '@jbrowse/core/util/simpleFeature'
7
7
  import { ObservableCreate } from '@jbrowse/core/util/rxjs'
8
8
  import { toArray } from 'rxjs/operators'
9
- import {
10
- getTag,
11
- getTagAlt,
12
- fetchSequence,
13
- shouldFetchReferenceSequence,
14
- } from '../util'
15
- import {
16
- parseCigar,
17
- getNextRefPos,
18
- getModificationPositions,
19
- Mismatch,
20
- } from '../BamAdapter/MismatchParser'
21
-
22
- function mismatchLen(mismatch: Mismatch) {
23
- return !isInterbase(mismatch.type) ? mismatch.length : 1
24
- }
25
-
26
- function isInterbase(type: string) {
27
- return type === 'softclip' || type === 'hardclip' || type === 'insertion'
28
- }
29
-
30
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
- function inc(bin: any, strand: number, type: string, field: string) {
32
- let thisBin = bin[type][field]
33
- if (thisBin === undefined) {
34
- thisBin = bin[type][field] = {
35
- total: 0,
36
- '-1': 0,
37
- '0': 0,
38
- '1': 0,
39
- }
40
- }
41
- thisBin.total++
42
- thisBin[strand]++
43
- }
9
+ import generateCoverageBins from './generateCoverageBins'
10
+ import { fetchSequence } from '../util'
44
11
 
45
12
  export default class SNPCoverageAdapter extends BaseFeatureDataAdapter {
46
13
  protected async configure() {
47
14
  const subadapterConfig = this.getConf('subadapter')
48
- const sequenceConf = this.getConf(['subadapter', 'sequenceAdapter'])
15
+ const sequenceConf = subadapterConfig.sequenceAdapter
49
16
  const dataAdapter = await this.getSubAdapter?.(subadapterConfig)
50
17
 
51
18
  const sequenceAdapter = sequenceConf
@@ -81,10 +48,11 @@ export default class SNPCoverageAdapter extends BaseFeatureDataAdapter {
81
48
  .pipe(toArray())
82
49
  .toPromise()
83
50
 
84
- const { bins, skipmap } = await this.generateCoverageBins(
51
+ const { bins, skipmap } = await generateCoverageBins(
85
52
  feats,
86
53
  region,
87
54
  opts,
55
+ arg => this.fetchSequence(arg),
88
56
  )
89
57
 
90
58
  bins.forEach((bin, index) => {
@@ -135,218 +103,6 @@ export default class SNPCoverageAdapter extends BaseFeatureDataAdapter {
135
103
  }
136
104
 
137
105
  freeResources(/* { region } */): void {}
138
-
139
- async generateCoverageBins(
140
- features: Feature[],
141
- region: Region,
142
- opts: { bpPerPx?: number; colorBy?: { type: string; tag?: string } },
143
- ) {
144
- const { colorBy } = opts
145
- const binMax = Math.ceil(region.end - region.start)
146
-
147
- const skipmap = {} as {
148
- [key: string]: {
149
- score: number
150
- feature: unknown
151
- start: number
152
- end: number
153
- strand: number
154
- xs: string
155
- }
156
- }
157
-
158
- // bins contain:
159
- // - cov feature if they contribute to coverage
160
- // - noncov are insertions/clip features that don't contribute to coverage
161
- // - delskips deletions or introns that don't contribute to coverage
162
- type BinType = { total: number; strands: { [key: string]: number } }
163
-
164
- const regionSeq =
165
- features.length && shouldFetchReferenceSequence(opts.colorBy?.type)
166
- ? await this.fetchSequence(region)
167
- : undefined
168
-
169
- const bins = [] as {
170
- refbase?: string
171
- total: number
172
- all: number
173
- ref: number
174
- '-1': 0
175
- '0': 0
176
- '1': 0
177
- lowqual: BinType
178
- cov: BinType
179
- delskips: BinType
180
- noncov: BinType
181
- }[]
182
-
183
- for (let i = 0; i < features.length; i++) {
184
- const feature = features[i]
185
- const fstart = feature.get('start')
186
- const fend = feature.get('end')
187
- const fstrand = feature.get('strand') as -1 | 0 | 1
188
-
189
- for (let j = fstart; j < fend + 1; j++) {
190
- const i = j - region.start
191
- if (i >= 0 && i < binMax) {
192
- if (bins[i] === undefined) {
193
- bins[i] = {
194
- total: 0,
195
- all: 0,
196
- ref: 0,
197
- '-1': 0,
198
- '0': 0,
199
- '1': 0,
200
- lowqual: {} as BinType,
201
- cov: {} as BinType,
202
- delskips: {} as BinType,
203
- noncov: {} as BinType,
204
- }
205
- }
206
- if (j !== fend) {
207
- bins[i].total++
208
- bins[i].all++
209
- bins[i].ref++
210
- bins[i][fstrand]++
211
- }
212
- }
213
- }
214
-
215
- if (colorBy?.type === 'modifications') {
216
- const seq = feature.get('seq') as string
217
- const mm = (getTagAlt(feature, 'MM', 'Mm') as string) || ''
218
- const ops = parseCigar(feature.get('CIGAR'))
219
- const fend = feature.get('end')
220
-
221
- getModificationPositions(mm, seq, fstrand).forEach(
222
- ({ type, positions }) => {
223
- const mod = `mod_${type}`
224
- for (const pos of getNextRefPos(ops, positions)) {
225
- const epos = pos + fstart - region.start
226
- if (epos >= 0 && epos < bins.length && pos + fstart < fend) {
227
- const bin = bins[epos]
228
- if (bin) {
229
- inc(bin, fstrand, 'cov', mod)
230
- } else {
231
- console.warn(
232
- 'Undefined position in modifications snpcoverage encountered',
233
- )
234
- }
235
- }
236
- }
237
- },
238
- )
239
- }
240
-
241
- // methylation based coloring takes into account both reference
242
- // sequence CpG detection and reads
243
- else if (colorBy?.type === 'methylation') {
244
- if (!regionSeq) {
245
- throw new Error(
246
- 'no region sequence detected, need sequenceAdapter configuration',
247
- )
248
- }
249
- const seq = feature.get('seq')
250
- const mm = getTagAlt(feature, 'MM', 'Mm') || ''
251
- const methBins = new Array(region.end - region.start).fill(0)
252
- const ops = parseCigar(feature.get('CIGAR'))
253
-
254
- getModificationPositions(mm, seq, fstrand).forEach(
255
- ({ type, positions }) => {
256
- // we are processing methylation
257
- if (type === 'm') {
258
- for (const pos of getNextRefPos(ops, positions)) {
259
- const epos = pos + fstart - region.start
260
- if (epos >= 0 && epos < methBins.length) {
261
- methBins[epos] = 1
262
- }
263
- }
264
- }
265
- },
266
- )
267
-
268
- for (let j = fstart; j < fend; j++) {
269
- const i = j - region.start
270
- if (i >= 0 && i < bins.length - 1) {
271
- const l1 = regionSeq[i].toLowerCase()
272
- const l2 = regionSeq[i + 1].toLowerCase()
273
- const bin = bins[i]
274
- const bin1 = bins[i + 1]
275
-
276
- // color
277
- if (l1 === 'c' && l2 === 'g') {
278
- if (methBins[i] || methBins[i + 1]) {
279
- inc(bin, fstrand, 'cov', 'meth')
280
- inc(bin1, fstrand, 'cov', 'meth')
281
- bins[i].ref--
282
- bins[i][fstrand]--
283
- bins[i + 1].ref--
284
- bins[i + 1][fstrand]--
285
- } else {
286
- inc(bin, fstrand, 'cov', 'unmeth')
287
- inc(bin1, fstrand, 'cov', 'unmeth')
288
- bins[i].ref--
289
- bins[i][fstrand]--
290
- bins[i + 1].ref--
291
- bins[i + 1][fstrand]--
292
- }
293
- }
294
- }
295
- }
296
- }
297
-
298
- // normal SNP based coloring
299
- const mismatches = (feature.get('mismatches') as Mismatch[]) || []
300
- const colorSNPs =
301
- colorBy?.type !== 'modifications' && colorBy?.type !== 'methylation'
302
-
303
- for (let i = 0; i < mismatches.length; i++) {
304
- const mismatch = mismatches[i]
305
- const mstart = fstart + mismatch.start
306
- const mlen = mismatchLen(mismatch)
307
- const mend = mstart + mlen
308
- for (let j = mstart; j < mstart + mlen; j++) {
309
- const epos = j - region.start
310
- if (epos >= 0 && epos < bins.length) {
311
- const bin = bins[epos]
312
- const { base, type } = mismatch
313
- const interbase = isInterbase(type)
314
- if (!interbase) {
315
- bin.ref--
316
- bin[fstrand]--
317
- } else {
318
- inc(bin, fstrand, 'noncov', type)
319
- }
320
-
321
- if (type === 'deletion' || type === 'skip') {
322
- inc(bin, fstrand, 'delskips', type)
323
- bin.total--
324
- } else if (!interbase && colorSNPs) {
325
- inc(bin, fstrand, 'cov', base)
326
- bin.refbase = mismatch.altbase
327
- }
328
- }
329
- }
330
-
331
- if (mismatch.type === 'skip') {
332
- const hash = `${mstart}_${mend}_${fstrand}`
333
- if (skipmap[hash] === undefined) {
334
- skipmap[hash] = {
335
- feature: feature,
336
- start: mstart,
337
- end: mend,
338
- strand: fstrand,
339
- xs: getTag(feature, 'XS') || getTag(feature, 'TS'),
340
- score: 0,
341
- }
342
- }
343
- skipmap[hash].score++
344
- }
345
- }
346
- }
347
-
348
- return { bins, skipmap }
349
- }
350
106
  }
351
107
 
352
108
  const { capabilities } = SNPCoverageAdapter