@jbrowse/plugin-alignments 1.5.1 → 1.5.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 (54) hide show
  1. package/dist/AlignmentsFeatureDetail/index.d.ts +7 -4
  2. package/dist/AlignmentsTrack/index.d.ts +2 -0
  3. package/dist/BamAdapter/index.d.ts +2 -4
  4. package/dist/CramAdapter/index.d.ts +1 -4
  5. package/dist/HtsgetBamAdapter/HtsgetBamAdapter.d.ts +2 -1
  6. package/dist/HtsgetBamAdapter/index.d.ts +2 -4
  7. package/dist/LinearAlignmentsDisplay/index.d.ts +2 -3
  8. package/dist/LinearPileupDisplay/index.d.ts +2 -2
  9. package/dist/LinearPileupDisplay/model.d.ts +1 -2
  10. package/dist/LinearSNPCoverageDisplay/components/Tooltip.d.ts +1 -1
  11. package/dist/LinearSNPCoverageDisplay/index.d.ts +2 -2
  12. package/dist/LinearSNPCoverageDisplay/models/model.d.ts +1 -0
  13. package/dist/PileupRenderer/PileupRenderer.d.ts +20 -7
  14. package/dist/PileupRenderer/index.d.ts +2 -3
  15. package/dist/SNPCoverageAdapter/SNPCoverageAdapter.d.ts +38 -26
  16. package/dist/SNPCoverageAdapter/index.d.ts +1 -5
  17. package/dist/SNPCoverageRenderer/index.d.ts +3 -3
  18. package/dist/plugin-alignments.cjs.development.js +3750 -3644
  19. package/dist/plugin-alignments.cjs.development.js.map +1 -1
  20. package/dist/plugin-alignments.cjs.production.min.js +1 -1
  21. package/dist/plugin-alignments.cjs.production.min.js.map +1 -1
  22. package/dist/plugin-alignments.esm.js +3753 -3647
  23. package/dist/plugin-alignments.esm.js.map +1 -1
  24. package/package.json +4 -4
  25. package/src/AlignmentsFeatureDetail/{index.js → index.ts} +19 -3
  26. package/src/AlignmentsTrack/index.ts +36 -0
  27. package/src/BamAdapter/BamSlightlyLazyFeature.ts +9 -19
  28. package/src/BamAdapter/MismatchParser.test.ts +20 -0
  29. package/src/BamAdapter/MismatchParser.ts +6 -5
  30. package/src/BamAdapter/index.ts +11 -5
  31. package/src/CramAdapter/index.ts +11 -4
  32. package/src/HtsgetBamAdapter/HtsgetBamAdapter.ts +2 -2
  33. package/src/HtsgetBamAdapter/index.ts +18 -5
  34. package/src/LinearAlignmentsDisplay/index.ts +20 -3
  35. package/src/LinearAlignmentsDisplay/models/configSchema.test.js +8 -68
  36. package/src/LinearPileupDisplay/configSchema.test.js +2 -13
  37. package/src/LinearPileupDisplay/index.ts +19 -2
  38. package/src/LinearPileupDisplay/model.ts +15 -20
  39. package/src/LinearSNPCoverageDisplay/components/Tooltip.tsx +17 -12
  40. package/src/LinearSNPCoverageDisplay/index.ts +19 -2
  41. package/src/LinearSNPCoverageDisplay/models/configSchema.test.js +2 -13
  42. package/src/LinearSNPCoverageDisplay/models/model.ts +21 -0
  43. package/src/PileupRenderer/PileupRenderer.tsx +154 -128
  44. package/src/PileupRenderer/configSchema.ts +2 -2
  45. package/src/PileupRenderer/index.ts +16 -3
  46. package/src/SNPCoverageAdapter/SNPCoverageAdapter.ts +95 -25
  47. package/src/SNPCoverageAdapter/index.ts +17 -5
  48. package/src/SNPCoverageRenderer/SNPCoverageRenderer.ts +60 -13
  49. package/src/SNPCoverageRenderer/configSchema.js +5 -0
  50. package/src/SNPCoverageRenderer/index.ts +24 -0
  51. package/src/index.ts +39 -204
  52. package/src/SNPCoverageAdapter/SNPCoverageAdapter.test.ts +0 -275
  53. package/src/SNPCoverageAdapter/__snapshots__/SNPCoverageAdapter.test.ts.snap +0 -579
  54. package/src/SNPCoverageRenderer/index.js +0 -11
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/plugin-alignments",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
4
4
  "description": "JBrowse 2 alignments adapters, tracks, etc.",
5
5
  "keywords": [
6
6
  "jbrowse",
@@ -35,14 +35,14 @@
35
35
  "useSrc": "node ../../scripts/useSrc.js"
36
36
  },
37
37
  "dependencies": {
38
- "@gmod/bam": "^1.1.8",
38
+ "@gmod/bam": "^1.1.9",
39
39
  "@gmod/cram": "^1.5.9",
40
40
  "@material-ui/icons": "^4.9.1",
41
41
  "abortable-promise-cache": "^1.1.3",
42
42
  "color": "^3.1.2",
43
43
  "copy-to-clipboard": "^3.3.1",
44
44
  "fast-deep-equal": "^3.1.3",
45
- "generic-filehandle": "^2.2.0",
45
+ "generic-filehandle": "^2.2.2",
46
46
  "json-stable-stringify": "^1.0.1",
47
47
  "react-d3-axis": "^0.1.2"
48
48
  },
@@ -61,5 +61,5 @@
61
61
  "publishConfig": {
62
62
  "access": "public"
63
63
  },
64
- "gitHead": "284e408c72a3d4d7a0d603197501a8fc8f68c4bc"
64
+ "gitHead": "94fdfbc34787ab8f12a87e00038da74b247b42fa"
65
65
  }
@@ -1,10 +1,13 @@
1
+ import { lazy } from 'react'
2
+ import PluginManager from '@jbrowse/core/PluginManager'
1
3
  import { ConfigurationSchema } from '@jbrowse/core/configuration'
2
4
  import { ElementId } from '@jbrowse/core/util/types/mst'
3
5
  import { types } from 'mobx-state-tree'
6
+ import WidgetType from '@jbrowse/core/pluggableElementTypes/WidgetType'
4
7
 
5
8
  const configSchema = ConfigurationSchema('AlignmentsFeatureWidget', {})
6
9
 
7
- export default function stateModelFactory(pluginManager) {
10
+ export function stateModelFactory(pluginManager: PluginManager) {
8
11
  return types
9
12
  .model('AlignmentsFeatureWidget', {
10
13
  id: ElementId,
@@ -15,7 +18,7 @@ export default function stateModelFactory(pluginManager) {
15
18
  ),
16
19
  })
17
20
  .actions(self => ({
18
- setFeatureData(data) {
21
+ setFeatureData(data: unknown) {
19
22
  self.featureData = data
20
23
  },
21
24
  clearFeatureData() {
@@ -24,4 +27,17 @@ export default function stateModelFactory(pluginManager) {
24
27
  }))
25
28
  }
26
29
 
27
- export { configSchema, stateModelFactory }
30
+ export default function register(pluginManager: PluginManager) {
31
+ pluginManager.addWidgetType(
32
+ () =>
33
+ new WidgetType({
34
+ name: 'AlignmentsFeatureWidget',
35
+ heading: 'Feature details',
36
+ configSchema,
37
+ stateModel: stateModelFactory(pluginManager),
38
+ ReactComponent: lazy(() => import('./AlignmentsFeatureDetail')),
39
+ }),
40
+ )
41
+ }
42
+
43
+ export { configSchema }
@@ -0,0 +1,36 @@
1
+ import PluginManager from '@jbrowse/core/PluginManager'
2
+ import TrackType from '@jbrowse/core/pluggableElementTypes/TrackType'
3
+ import { ConfigurationSchema } from '@jbrowse/core/configuration'
4
+ import {
5
+ createBaseTrackConfig,
6
+ createBaseTrackModel,
7
+ } from '@jbrowse/core/pluggableElementTypes/models'
8
+ function configSchemaFactory(pluginManager: PluginManager) {
9
+ return ConfigurationSchema(
10
+ 'AlignmentsTrack',
11
+ {},
12
+ { baseConfiguration: createBaseTrackConfig(pluginManager) },
13
+ )
14
+ }
15
+ export default function register(pluginManager: PluginManager) {
16
+ pluginManager.addTrackType(() => {
17
+ const configSchema = configSchemaFactory(pluginManager)
18
+ const track = new TrackType({
19
+ name: 'AlignmentsTrack',
20
+ configSchema,
21
+ stateModel: createBaseTrackModel(
22
+ pluginManager,
23
+ 'AlignmentsTrack',
24
+ configSchema,
25
+ ),
26
+ })
27
+ const linearAlignmentsDisplay = pluginManager.getDisplayType(
28
+ 'LinearAlignmentsDisplay',
29
+ )
30
+ // Add LinearAlignmentsDisplay here so that it has priority over the other
31
+ // linear displays (defaults to order the displays are added, but we have
32
+ // to add the Pileup and SNPCoverage displays first).
33
+ track.addDisplayType(linearAlignmentsDisplay)
34
+ return track
35
+ })
36
+ }
@@ -153,16 +153,12 @@ export default class BamSlightlyLazyFeature implements Feature {
153
153
  }
154
154
 
155
155
  toJSON(): SimpleFeatureSerialized {
156
- const tags = Object.fromEntries(
157
- this.tags()
158
- .map(t => {
159
- return [t, this.get(t)]
160
- })
161
- .filter(elt => elt[1] !== undefined),
162
- )
163
-
164
156
  return {
165
- ...tags,
157
+ ...Object.fromEntries(
158
+ this.tags()
159
+ .map(t => [t, this.get(t)])
160
+ .filter(elt => elt[1] !== undefined),
161
+ ),
166
162
  uniqueId: this.id(),
167
163
  }
168
164
  }
@@ -201,24 +197,18 @@ export default class BamSlightlyLazyFeature implements Feature {
201
197
 
202
198
  // parse the CIGAR tag if it has one
203
199
  const cigarString = this.get(cigarAttributeName)
200
+ const seq = this.get('seq')
201
+ const qual = this.qualRaw()
204
202
  if (cigarString) {
205
203
  cigarOps = parseCigar(cigarString)
206
- mismatches = mismatches.concat(
207
- cigarToMismatches(cigarOps, this.get('seq'), this.qualRaw()),
208
- )
204
+ mismatches = mismatches.concat(cigarToMismatches(cigarOps, seq, qual))
209
205
  }
210
206
 
211
207
  // now let's look for CRAM or MD mismatches
212
208
  const mdString = this.get(mdAttributeName)
213
209
  if (mdString) {
214
210
  mismatches = mismatches.concat(
215
- mdToMismatches(
216
- mdString,
217
- cigarOps,
218
- mismatches,
219
- this.get('seq'),
220
- this.qualRaw(),
221
- ),
211
+ mdToMismatches(mdString, cigarOps, mismatches, seq, qual),
222
212
  )
223
213
  }
224
214
 
@@ -498,3 +498,23 @@ test('getModificationPositions', () => {
498
498
  )
499
499
  expect(positions[0]).toEqual({ type: 'm', positions: [6, 17, 20, 31, 34] })
500
500
  })
501
+
502
+ // ? means "modification status of the skipped bases provided."
503
+ test('getModificationPositions with unknown (?)', () => {
504
+ const positions = getModificationPositions(
505
+ 'C+m?,2,2,1,4,1',
506
+ 'AGCTCTCCAGAGTCGNACGCCATYCGCGCGCCACCA',
507
+ 1,
508
+ )
509
+ expect(positions[0]).toEqual({ type: 'm', positions: [6, 17, 20, 31, 34] })
510
+ })
511
+
512
+ // . means "modification status of the skipped bases is low probability"
513
+ test('getModificationPositions with unknown (.)', () => {
514
+ const positions = getModificationPositions(
515
+ 'C+m.,2,2,1,4,1',
516
+ 'AGCTCTCCAGAGTCGNACGCCATYCGCGCGCCACCA',
517
+ 1,
518
+ )
519
+ expect(positions[0]).toEqual({ type: 'm', positions: [6, 17, 20, 31, 34] })
520
+ })
@@ -153,15 +153,16 @@ export function mdToMismatches(
153
153
  const md = mdstring.match(/(\d+|\^[a-z]+|[a-z])/gi) || []
154
154
  for (let i = 0; i < md.length; i++) {
155
155
  const token = md[i]
156
- if (token.match(/^\d/)) {
157
- curr.start += parseInt(token, 10)
158
- } else if (token.match(/^\^/)) {
156
+ const num = +token
157
+ if (!Number.isNaN(num)) {
158
+ curr.start += num
159
+ } else if (token.startsWith('^')) {
159
160
  curr.length = token.length - 1
160
161
  curr.base = '*'
161
162
  curr.type = 'deletion'
162
163
  curr.seq = token.substring(1)
163
164
  nextRecord()
164
- } else if (token.match(/^[a-z]/i)) {
165
+ } else {
165
166
  // mismatch
166
167
  for (let j = 0; j < token.length; j += 1) {
167
168
  curr.length = 1
@@ -328,7 +329,7 @@ export function getModificationPositions(
328
329
  const [basemod, ...skips] = mod.split(',')
329
330
 
330
331
  // regexes based on parse_mm.pl from hts-specs
331
- const matches = basemod.match(/([A-Z])([-+])([^,]+)/)
332
+ const matches = basemod.match(/([A-Z])([-+])([^,.?]+)([.?])?/)
332
333
  if (!matches) {
333
334
  throw new Error('bad format for MM tag')
334
335
  }
@@ -1,8 +1,14 @@
1
+ import PluginManager from '@jbrowse/core/PluginManager'
2
+ import AdapterType from '@jbrowse/core/pluggableElementTypes/AdapterType'
1
3
  import configSchema from './configSchema'
2
4
 
3
- export default (/* pluginManager: PluginManager */) => {
4
- return {
5
- configSchema,
6
- getAdapterClass: () => import('./BamAdapter').then(r => r.default),
7
- }
5
+ export default (pluginManager: PluginManager) => {
6
+ pluginManager.addAdapterType(
7
+ () =>
8
+ new AdapterType({
9
+ name: 'BamAdapter',
10
+ configSchema,
11
+ getAdapterClass: () => import('./BamAdapter').then(r => r.default),
12
+ }),
13
+ )
8
14
  }
@@ -1,9 +1,16 @@
1
1
  import PluginManager from '@jbrowse/core/PluginManager'
2
+ import AdapterType from '@jbrowse/core/pluggableElementTypes/AdapterType'
3
+
4
+ // locals
2
5
  import configSchemaF from './configSchema'
3
6
 
4
7
  export default (pluginManager: PluginManager) => {
5
- return {
6
- configSchema: pluginManager.load(configSchemaF),
7
- getAdapterClass: () => import('./CramAdapter').then(r => r.default),
8
- }
8
+ pluginManager.addAdapterType(
9
+ () =>
10
+ new AdapterType({
11
+ name: 'CramAdapter',
12
+ configSchema: pluginManager.load(configSchemaF),
13
+ getAdapterClass: () => import('./CramAdapter').then(r => r.default),
14
+ }),
15
+ )
9
16
  }
@@ -1,4 +1,4 @@
1
- import { HtsgetFile } from '@gmod/bam'
1
+ import { BamFile, HtsgetFile } from '@gmod/bam'
2
2
  import { readConfObject } from '@jbrowse/core/configuration'
3
3
  import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter'
4
4
  import BamAdapter from '../BamAdapter/BamAdapter'
@@ -11,7 +11,7 @@ export default class HtsgetBamAdapter extends BamAdapter {
11
11
  const bam = new HtsgetFile({
12
12
  baseUrl: htsgetBase,
13
13
  trackId: htsgetTrackId,
14
- })
14
+ }) as unknown as BamFile
15
15
 
16
16
  const adapterConfig = readConfObject(this.config, 'sequenceAdapter')
17
17
  if (adapterConfig && this.getSubAdapter) {
@@ -1,8 +1,21 @@
1
1
  import configSchema from './configSchema'
2
+ import PluginManager from '@jbrowse/core/PluginManager'
3
+ import AdapterType from '@jbrowse/core/pluggableElementTypes/AdapterType'
2
4
 
3
- export default (/* pluginManager: PluginManager */) => {
4
- return {
5
- configSchema,
6
- getAdapterClass: () => import('./HtsgetBamAdapter').then(r => r.default),
7
- }
5
+ export default (pluginManager: PluginManager) => {
6
+ pluginManager.addAdapterType(
7
+ () =>
8
+ new AdapterType({
9
+ name: 'HtsgetBamAdapter',
10
+ adapterMetadata: {
11
+ category: null,
12
+ hiddenFromGUI: true,
13
+ displayName: null,
14
+ description: null,
15
+ },
16
+ configSchema,
17
+ getAdapterClass: () =>
18
+ import('./HtsgetBamAdapter').then(r => r.default),
19
+ }),
20
+ )
8
21
  }
@@ -1,3 +1,20 @@
1
- export { default as configSchemaFactory } from './models/configSchema'
2
- export { default as modelFactory } from './models/model'
3
- export { default as ReactComponent } from './components/AlignmentsDisplay'
1
+ import DisplayType from '@jbrowse/core/pluggableElementTypes/DisplayType'
2
+ import PluginManager from '@jbrowse/core/PluginManager'
3
+ // locals
4
+ import configSchemaFactory from './models/configSchema'
5
+ import modelFactory from './models/model'
6
+ import ReactComponent from './components/AlignmentsDisplay'
7
+
8
+ export default function (pluginManager: PluginManager) {
9
+ pluginManager.addDisplayType(() => {
10
+ const configSchema = configSchemaFactory(pluginManager)
11
+ return new DisplayType({
12
+ name: 'LinearAlignmentsDisplay',
13
+ configSchema,
14
+ stateModel: modelFactory(pluginManager, configSchema),
15
+ trackType: 'AlignmentsTrack',
16
+ viewType: 'LinearGenomeView',
17
+ ReactComponent,
18
+ })
19
+ })
20
+ }
@@ -1,4 +1,3 @@
1
- import DisplayType from '@jbrowse/core/pluggableElementTypes/DisplayType'
2
1
  import Plugin from '@jbrowse/core/Plugin'
3
2
  import PluginManager from '@jbrowse/core/PluginManager'
4
3
  import BoxRendererType from '@jbrowse/core/pluggableElementTypes/renderers/BoxRendererType'
@@ -6,24 +5,10 @@ import {
6
5
  svgFeatureRendererConfigSchema,
7
6
  SvgFeatureRendererReactComponent,
8
7
  } from '@jbrowse/plugin-svg'
9
- import { BaseLinearDisplayComponent } from '@jbrowse/plugin-linear-genome-view'
10
- import { LinearWiggleDisplayReactComponent } from '@jbrowse/plugin-wiggle'
11
- import PileupRenderer, {
12
- configSchema as pileupRendererConfigSchema,
13
- ReactComponent as PileupRendererReactComponent,
14
- } from '../../PileupRenderer'
15
- import SNPCoverageRenderer, {
16
- configSchema as snpCoverageRendererConfigSchema,
17
- ReactComponent as SNPCoverageRendererReactComponent,
18
- } from '../../SNPCoverageRenderer'
19
- import {
20
- configSchemaFactory as linearPileupDisplayConfigSchemaFactory,
21
- modelFactory as linearPileupDisplayModelFactory,
22
- } from '../../LinearPileupDisplay'
23
- import {
24
- configSchemaFactory as linearSNPCoverageDisplayConfigSchemaFactory,
25
- modelFactory as linearSNPCoverageDisplayModelFactory,
26
- } from '../../LinearSNPCoverageDisplay'
8
+ import PileupRenderer from '../../PileupRenderer'
9
+ import SNPCoverageRenderer from '../../SNPCoverageRenderer'
10
+ import LinearPileupDisplay from '../../LinearPileupDisplay'
11
+ import LinearSNPCoverageDisplay from '../../LinearSNPCoverageDisplay'
27
12
  import configSchemaFactory from './configSchema'
28
13
 
29
14
  // mock warnings to avoid unnecessary outputs
@@ -37,15 +22,7 @@ afterEach(() => {
37
22
 
38
23
  class AlignmentsPlugin extends Plugin {
39
24
  install(pluginManager) {
40
- pluginManager.addRendererType(
41
- () =>
42
- new PileupRenderer({
43
- name: 'PileupRenderer',
44
- ReactComponent: PileupRendererReactComponent,
45
- configSchema: pileupRendererConfigSchema,
46
- pluginManager,
47
- }),
48
- )
25
+ PileupRenderer(pluginManager)
49
26
 
50
27
  pluginManager.addRendererType(
51
28
  () =>
@@ -57,46 +34,9 @@ class AlignmentsPlugin extends Plugin {
57
34
  }),
58
35
  )
59
36
 
60
- pluginManager.addRendererType(
61
- () =>
62
- new SNPCoverageRenderer({
63
- name: 'SNPCoverageRenderer',
64
- ReactComponent: SNPCoverageRendererReactComponent,
65
- configSchema: snpCoverageRendererConfigSchema,
66
- pluginManager,
67
- }),
68
- )
69
-
70
- pluginManager.addDisplayType(() => {
71
- const configSchema = linearPileupDisplayConfigSchemaFactory(pluginManager)
72
- return new DisplayType({
73
- name: 'LinearPileupDisplay',
74
- configSchema,
75
- stateModel: linearPileupDisplayModelFactory(
76
- pluginManager,
77
- configSchema,
78
- ),
79
- trackType: 'AlignmentsTrack',
80
- viewType: 'LinearGenomeView',
81
- ReactComponent: BaseLinearDisplayComponent,
82
- })
83
- })
84
-
85
- pluginManager.addDisplayType(() => {
86
- const configSchema =
87
- linearSNPCoverageDisplayConfigSchemaFactory(pluginManager)
88
- return new DisplayType({
89
- name: 'LinearSNPCoverageDisplay',
90
- configSchema,
91
- stateModel: linearSNPCoverageDisplayModelFactory(
92
- pluginManager,
93
- configSchema,
94
- ),
95
- trackType: 'AlignmentsTrack',
96
- viewType: 'LinearGenomeView',
97
- ReactComponent: LinearWiggleDisplayReactComponent,
98
- })
99
- })
37
+ SNPCoverageRenderer(pluginManager)
38
+ LinearPileupDisplay(pluginManager)
39
+ LinearSNPCoverageDisplay(pluginManager)
100
40
  }
101
41
  }
102
42
 
@@ -5,10 +5,7 @@ import {
5
5
  svgFeatureRendererConfigSchema,
6
6
  SvgFeatureRendererReactComponent,
7
7
  } from '@jbrowse/plugin-svg'
8
- import PileupRenderer, {
9
- configSchema as pileupRendererConfigSchema,
10
- ReactComponent as PileupRendererReactComponent,
11
- } from '../PileupRenderer'
8
+ import PileupRenderer from '../PileupRenderer'
12
9
  import configSchemaFactory from './configSchema'
13
10
 
14
11
  // mock warnings to avoid unnecessary outputs
@@ -22,15 +19,7 @@ afterEach(() => {
22
19
 
23
20
  class PileupRendererPlugin extends Plugin {
24
21
  install(pluginManager) {
25
- pluginManager.addRendererType(
26
- () =>
27
- new PileupRenderer({
28
- name: 'PileupRenderer',
29
- ReactComponent: PileupRendererReactComponent,
30
- configSchema: pileupRendererConfigSchema,
31
- pluginManager,
32
- }),
33
- )
22
+ PileupRenderer(pluginManager)
34
23
  }
35
24
  }
36
25
 
@@ -1,2 +1,19 @@
1
- export { default as configSchemaFactory } from './configSchema'
2
- export { default as modelFactory } from './model'
1
+ import configSchemaFactory from './configSchema'
2
+ import modelFactory from './model'
3
+ import DisplayType from '@jbrowse/core/pluggableElementTypes/DisplayType'
4
+ import PluginManager from '@jbrowse/core/PluginManager'
5
+ import { BaseLinearDisplayComponent } from '@jbrowse/plugin-linear-genome-view'
6
+
7
+ export default function register(pluginManager: PluginManager) {
8
+ pluginManager.addDisplayType(() => {
9
+ const configSchema = configSchemaFactory(pluginManager)
10
+ return new DisplayType({
11
+ name: 'LinearPileupDisplay',
12
+ configSchema,
13
+ stateModel: modelFactory(configSchema),
14
+ trackType: 'AlignmentsTrack',
15
+ viewType: 'LinearGenomeView',
16
+ ReactComponent: BaseLinearDisplayComponent,
17
+ })
18
+ })
19
+ }
@@ -19,7 +19,6 @@ import {
19
19
  } from '@jbrowse/plugin-linear-genome-view'
20
20
  import { cast, types, addDisposer, getEnv, Instance } from 'mobx-state-tree'
21
21
  import copy from 'copy-to-clipboard'
22
- import PluginManager from '@jbrowse/core/PluginManager'
23
22
  import { Feature } from '@jbrowse/core/util/simpleFeature'
24
23
  import MenuOpenIcon from '@material-ui/icons/MenuOpen'
25
24
  import SortIcon from '@material-ui/icons/Sort'
@@ -49,10 +48,7 @@ const rendererTypes = new Map([
49
48
 
50
49
  type LGV = LinearGenomeViewModel
51
50
 
52
- const stateModelFactory = (
53
- pluginManager: PluginManager,
54
- configSchema: LinearPileupDisplayConfigModel,
55
- ) =>
51
+ const stateModelFactory = (configSchema: LinearPileupDisplayConfigModel) =>
56
52
  types
57
53
  .compose(
58
54
  'LinearPileupDisplay',
@@ -387,21 +383,20 @@ const stateModelFactory = (
387
383
 
388
384
  get filters() {
389
385
  let filters: string[] = []
390
- if (self.filterBy) {
391
- const { flagInclude, flagExclude } = self.filterBy
392
- filters = [
393
- `jexl:((get(feature,'flags')&${flagInclude})==${flagInclude}) && !(get(feature,'flags')&${flagExclude})`,
394
- ]
395
- if (self.filterBy.tagFilter) {
396
- const { tag, value } = self.filterBy.tagFilter
397
- filters.push(
398
- `jexl:"${value}" =='*' ? getTag(feature,"${tag}") != undefined : getTag(feature,"${tag}") == "${value}"`,
399
- )
400
- }
401
- if (self.filterBy.readName) {
402
- const { readName } = self.filterBy
403
- filters.push(`jexl:get(feature,'name') == "${readName}"`)
404
- }
386
+ const { flagInclude, flagExclude, tagFilter, readName } =
387
+ self.filterBy
388
+
389
+ filters = [
390
+ `jexl:((get(feature,'flags')&${flagInclude})==${flagInclude}) && !(get(feature,'flags')&${flagExclude})`,
391
+ ]
392
+ if (tagFilter) {
393
+ const { tag, value } = tagFilter
394
+ filters.push(
395
+ `jexl:"${value}" =='*' ? getTag(feature,"${tag}") != undefined : getTag(feature,"${tag}") == "${value}"`,
396
+ )
397
+ }
398
+ if (readName) {
399
+ filters.push(`jexl:get(feature,'name') == "${readName}"`)
405
400
  }
406
401
  return new SerializableFilterChain({ filters })
407
402
  },
@@ -11,6 +11,15 @@ type Count = {
11
11
  }
12
12
  }
13
13
 
14
+ type SNPInfo = {
15
+ ref: Count
16
+ cov: Count
17
+ lowqual: Count
18
+ noncov: Count
19
+ delskips: Count
20
+ total: number
21
+ }
22
+
14
23
  const en = (n: number) => n.toLocaleString('en-US')
15
24
 
16
25
  const TooltipContents = React.forwardRef(
@@ -22,16 +31,8 @@ const TooltipContents = React.forwardRef(
22
31
  .filter(f => !!f)
23
32
  .join(':')
24
33
 
25
- const info = feature.get('snpinfo') as {
26
- ref: Count
27
- cov: Count
28
- lowqual: Count
29
- noncov: Count
30
- delskips: Count
31
- total: number
32
- }
33
-
34
- const total = info.total
34
+ const info = feature.get('snpinfo') as SNPInfo
35
+ const total = info?.total
35
36
 
36
37
  return (
37
38
  <div ref={ref}>
@@ -61,7 +62,7 @@ const TooltipContents = React.forwardRef(
61
62
  <td>{base.toUpperCase()}</td>
62
63
  <td>{score.total}</td>
63
64
  <td>
64
- {base === 'total'
65
+ {base === 'total' || base === 'skip'
65
66
  ? '---'
66
67
  : `${Math.floor((score.total / total) * 100)}%`}
67
68
  </td>
@@ -91,7 +92,11 @@ const SNPCoverageTooltip = observer(
91
92
  clientMouseCoord: Coord
92
93
  clientRect?: ClientRect
93
94
  }) => {
94
- return <Tooltip TooltipContents={TooltipContents} {...props} />
95
+ const { model } = props
96
+ const { featureUnderMouse: feat } = model
97
+ return feat && feat.get('type') === 'skip' ? null : (
98
+ <Tooltip TooltipContents={TooltipContents} {...props} />
99
+ )
95
100
  },
96
101
  )
97
102
 
@@ -1,2 +1,19 @@
1
- export { default as configSchemaFactory } from './models/configSchema'
2
- export { default as modelFactory } from './models/model'
1
+ import PluginManager from '@jbrowse/core/PluginManager'
2
+ import configSchemaFactory from './models/configSchema'
3
+ import modelFactory from './models/model'
4
+ import { LinearWiggleDisplayReactComponent } from '@jbrowse/plugin-wiggle'
5
+ import DisplayType from '@jbrowse/core/pluggableElementTypes/DisplayType'
6
+
7
+ export default function register(pluginManager: PluginManager) {
8
+ pluginManager.addDisplayType(() => {
9
+ const configSchema = configSchemaFactory(pluginManager)
10
+ return new DisplayType({
11
+ name: 'LinearSNPCoverageDisplay',
12
+ configSchema,
13
+ stateModel: modelFactory(pluginManager, configSchema),
14
+ trackType: 'AlignmentsTrack',
15
+ viewType: 'LinearGenomeView',
16
+ ReactComponent: LinearWiggleDisplayReactComponent,
17
+ })
18
+ })
19
+ }
@@ -1,9 +1,6 @@
1
1
  import Plugin from '@jbrowse/core/Plugin'
2
2
  import PluginManager from '@jbrowse/core/PluginManager'
3
- import SNPCoverageRenderer, {
4
- configSchema as snpCoverageRendererConfigSchema,
5
- ReactComponent as SNPCoverageRendererReactComponent,
6
- } from '../../SNPCoverageRenderer' // change renderer
3
+ import SNPCoverageRenderer from '../../SNPCoverageRenderer' // change renderer
7
4
  import configSchemaFactory from './configSchema'
8
5
 
9
6
  // mock warnings to avoid unnecessary outputs
@@ -17,15 +14,7 @@ afterEach(() => {
17
14
  // change renderer
18
15
  class SNPCoverageRendererPlugin extends Plugin {
19
16
  install(pluginManager) {
20
- pluginManager.addRendererType(
21
- () =>
22
- new SNPCoverageRenderer({
23
- name: 'SNPCoverageRenderer',
24
- ReactComponent: SNPCoverageRendererReactComponent,
25
- configSchema: snpCoverageRendererConfigSchema,
26
- pluginManager,
27
- }),
28
- )
17
+ SNPCoverageRenderer(pluginManager)
29
18
  }
30
19
  }
31
20