jbrowse-plugin-mafviewer 1.0.1

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 (31) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +8 -0
  3. package/dist/jbrowse-plugin-mafviewer.umd.development.js +1310 -0
  4. package/dist/jbrowse-plugin-mafviewer.umd.development.js.map +1 -0
  5. package/dist/jbrowse-plugin-mafviewer.umd.production.min.js +2 -0
  6. package/dist/jbrowse-plugin-mafviewer.umd.production.min.js.map +1 -0
  7. package/package.json +90 -0
  8. package/src/BigMafAdapter/BigMafAdapter.ts +120 -0
  9. package/src/BigMafAdapter/configSchema.ts +33 -0
  10. package/src/BigMafAdapter/index.ts +15 -0
  11. package/src/LinearMafDisplay/components/ColorLegend.tsx +59 -0
  12. package/src/LinearMafDisplay/components/ReactComponent.tsx +23 -0
  13. package/src/LinearMafDisplay/components/RectBg.tsx +14 -0
  14. package/src/LinearMafDisplay/components/YScaleBars.tsx +63 -0
  15. package/src/LinearMafDisplay/configSchema.ts +23 -0
  16. package/src/LinearMafDisplay/index.ts +21 -0
  17. package/src/LinearMafDisplay/renderSvg.tsx +26 -0
  18. package/src/LinearMafDisplay/stateModel.ts +111 -0
  19. package/src/LinearMafRenderer/LinearMafRenderer.ts +172 -0
  20. package/src/LinearMafRenderer/components/ReactComponent.tsx +9 -0
  21. package/src/LinearMafRenderer/configSchema.ts +19 -0
  22. package/src/LinearMafRenderer/index.ts +16 -0
  23. package/src/MafAddTrackWorkflow/AddTrackWorkflow.tsx +166 -0
  24. package/src/MafAddTrackWorkflow/index.ts +17 -0
  25. package/src/MafTabixAdapter/MafTabixAdapter.ts +104 -0
  26. package/src/MafTabixAdapter/configSchema.ts +45 -0
  27. package/src/MafTabixAdapter/index.ts +15 -0
  28. package/src/MafTrack/configSchema.ts +20 -0
  29. package/src/MafTrack/index.ts +18 -0
  30. package/src/declare.d.ts +1 -0
  31. package/src/index.ts +26 -0
@@ -0,0 +1,19 @@
1
+ import { ConfigurationSchema } from '@jbrowse/core/configuration'
2
+
3
+ /**
4
+ * #config LinearMafRenderer
5
+ */
6
+ function x() {} // eslint-disable-line @typescript-eslint/no-unused-vars
7
+
8
+ const configSchema = ConfigurationSchema(
9
+ 'LinearMafRenderer',
10
+ {},
11
+ {
12
+ /**
13
+ * #baseConfiguration
14
+ */
15
+ explicitlyTyped: true,
16
+ },
17
+ )
18
+
19
+ export default configSchema
@@ -0,0 +1,16 @@
1
+ import PluginManager from '@jbrowse/core/PluginManager'
2
+ import configSchema from './configSchema'
3
+ import LinearMafRenderer from './LinearMafRenderer'
4
+ import ReactComponent from './components/ReactComponent'
5
+
6
+ export default function LinearMafRendererF(pluginManager: PluginManager) {
7
+ pluginManager.addRendererType(
8
+ () =>
9
+ new LinearMafRenderer({
10
+ name: 'LinearMafRenderer',
11
+ ReactComponent,
12
+ configSchema,
13
+ pluginManager,
14
+ }),
15
+ )
16
+ }
@@ -0,0 +1,166 @@
1
+ import React, { useState } from 'react'
2
+ import {
3
+ Button,
4
+ FormControl,
5
+ FormControlLabel,
6
+ FormLabel,
7
+ Paper,
8
+ Radio,
9
+ RadioGroup,
10
+ TextField,
11
+ } from '@mui/material'
12
+ import { makeStyles } from 'tss-react/mui'
13
+ import {
14
+ FileLocation,
15
+ getSession,
16
+ isSessionModelWithWidgets,
17
+ isSessionWithAddTracks,
18
+ } from '@jbrowse/core/util'
19
+ import { AddTrackModel } from '@jbrowse/plugin-data-management'
20
+ import { ErrorMessage, FileSelector } from '@jbrowse/core/ui'
21
+ import { getRoot } from 'mobx-state-tree'
22
+
23
+ const useStyles = makeStyles()(theme => ({
24
+ textbox: {
25
+ width: '100%',
26
+ },
27
+ paper: {
28
+ margin: theme.spacing(),
29
+ padding: theme.spacing(),
30
+ },
31
+ submit: {
32
+ marginTop: 25,
33
+ marginBottom: 100,
34
+ display: 'block',
35
+ },
36
+ }))
37
+
38
+ export default function MultiMAFWidget({ model }: { model: AddTrackModel }) {
39
+ const { classes } = useStyles()
40
+ const [samples, setSamples] = useState('')
41
+ const [loc, setLoc] = useState<FileLocation>()
42
+ const [indexLoc, setIndexLoc] = useState<FileLocation>()
43
+ const [error, setError] = useState<unknown>()
44
+ const [trackName, setTrackName] = useState('MAF track')
45
+ const [choice, setChoice] = useState('BigMafAdapter')
46
+ const rootModel = getRoot<any>(model)
47
+ return (
48
+ <Paper className={classes.paper}>
49
+ <Paper>
50
+ {error ? <ErrorMessage error={error} /> : null}
51
+ <FormControl>
52
+ <FormLabel>File type</FormLabel>
53
+ <RadioGroup
54
+ value={choice}
55
+ onChange={event => setChoice(event.target.value)}
56
+ >
57
+ <FormControlLabel
58
+ value="BigMafAdapter"
59
+ control={<Radio />}
60
+ checked={choice === 'BigMafAdapter'}
61
+ label="bigMaf"
62
+ />
63
+ <FormControlLabel
64
+ value="MafTabixAdapter"
65
+ control={<Radio />}
66
+ checked={choice === 'MafTabixAdapter'}
67
+ label="mafTabix"
68
+ />
69
+ </RadioGroup>
70
+ </FormControl>
71
+ {choice === 'BigMafAdapter' ? (
72
+ <FileSelector
73
+ location={loc}
74
+ name="Path to bigMaf"
75
+ setLocation={arg => setLoc(arg)}
76
+ rootModel={rootModel}
77
+ />
78
+ ) : (
79
+ <>
80
+ <FileSelector
81
+ location={loc}
82
+ name="Path to MAF tabix"
83
+ setLocation={arg => setLoc(arg)}
84
+ rootModel={rootModel}
85
+ />
86
+ <FileSelector
87
+ location={indexLoc}
88
+ name="Path to MAF tabix index"
89
+ setLocation={arg => setIndexLoc(arg)}
90
+ rootModel={rootModel}
91
+ />
92
+ </>
93
+ )}
94
+ </Paper>
95
+ <TextField
96
+ multiline
97
+ rows={10}
98
+ value={samples}
99
+ onChange={event => setSamples(event.target.value)}
100
+ placeholder={
101
+ 'Enter sample names from the MAF file, one per line, or JSON formatted array of samples'
102
+ }
103
+ variant="outlined"
104
+ fullWidth
105
+ />
106
+
107
+ <TextField
108
+ value={trackName}
109
+ onChange={event => setTrackName(event.target.value)}
110
+ helperText="Track name"
111
+ />
112
+ <Button
113
+ variant="contained"
114
+ className={classes.submit}
115
+ onClick={() => {
116
+ try {
117
+ const session = getSession(model)
118
+ let sampleNames = [] as string[]
119
+ try {
120
+ sampleNames = JSON.parse(samples)
121
+ } catch (e) {
122
+ sampleNames = samples.split(/\n|\r\n|\r/)
123
+ }
124
+
125
+ const trackId = [
126
+ `${trackName.toLowerCase().replaceAll(' ', '_')}-${Date.now()}`,
127
+ `${session.adminMode ? '' : '-sessionTrack'}`,
128
+ ].join('')
129
+
130
+ if (isSessionWithAddTracks(session)) {
131
+ session.addTrackConf({
132
+ trackId,
133
+ type: 'MafTrack',
134
+ name: trackName,
135
+ assemblyNames: [model.assembly],
136
+ adapter:
137
+ choice === 'BigMafAdapter'
138
+ ? {
139
+ type: choice,
140
+ bigBedLocation: loc,
141
+ samples: sampleNames,
142
+ }
143
+ : {
144
+ type: choice,
145
+ bedGzLocation: loc,
146
+ index: { location: indexLoc },
147
+ samples: sampleNames,
148
+ },
149
+ })
150
+
151
+ model.view?.showTrack(trackId)
152
+ }
153
+ model.clearData()
154
+ if (isSessionModelWithWidgets(session)) {
155
+ session.hideWidget(model)
156
+ }
157
+ } catch (e) {
158
+ setError(e)
159
+ }
160
+ }}
161
+ >
162
+ Submit
163
+ </Button>
164
+ </Paper>
165
+ )
166
+ }
@@ -0,0 +1,17 @@
1
+ import PluginManager from '@jbrowse/core/PluginManager'
2
+ import { AddTrackWorkflowType } from '@jbrowse/core/pluggableElementTypes'
3
+ import { types } from 'mobx-state-tree'
4
+
5
+ // locals
6
+ import MultiMAFWidget from './AddTrackWorkflow'
7
+
8
+ export default function MafAddTrackWorkflowF(pluginManager: PluginManager) {
9
+ pluginManager.addAddTrackWorkflowType(
10
+ () =>
11
+ new AddTrackWorkflowType({
12
+ name: 'MAF track',
13
+ ReactComponent: MultiMAFWidget,
14
+ stateModel: types.model({}),
15
+ }),
16
+ )
17
+ }
@@ -0,0 +1,104 @@
1
+ import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter'
2
+ import { getSnapshot } from 'mobx-state-tree'
3
+ import { Feature, Region, SimpleFeature } from '@jbrowse/core/util'
4
+ import { ObservableCreate } from '@jbrowse/core/util/rxjs'
5
+ import { firstValueFrom, toArray } from 'rxjs'
6
+
7
+ interface OrganismRecord {
8
+ chr: string
9
+ start: number
10
+ srcSize: number
11
+ strand: number
12
+ unknown: number
13
+ data: string
14
+ }
15
+ export default class BigMafAdapter extends BaseFeatureDataAdapter {
16
+ public setupP?: Promise<{ adapter: BaseFeatureDataAdapter }>
17
+
18
+ async setup() {
19
+ const config = this.config
20
+ if (!this.getSubAdapter) {
21
+ throw new Error('no getSubAdapter available')
22
+ }
23
+ const adapter = await this.getSubAdapter({
24
+ ...getSnapshot(config),
25
+ type: 'BedTabixAdapter',
26
+ })
27
+ return {
28
+ adapter: adapter.dataAdapter as BaseFeatureDataAdapter,
29
+ }
30
+ }
31
+ async setupPre() {
32
+ if (!this.setupP) {
33
+ this.setupP = this.setup().catch(e => {
34
+ this.setupP = undefined
35
+ throw e
36
+ })
37
+ }
38
+ return this.setupP
39
+ }
40
+
41
+ async getRefNames() {
42
+ const { adapter } = await this.setup()
43
+ return adapter.getRefNames()
44
+ }
45
+
46
+ getFeatures(query: Region) {
47
+ return ObservableCreate<Feature>(async observer => {
48
+ const { adapter } = await this.setup()
49
+ const features = await firstValueFrom(
50
+ adapter.getFeatures(query).pipe(toArray()),
51
+ )
52
+ for (const feature of features) {
53
+ const data = (feature.get('field5') as string).split(',')
54
+ const alignments = {} as Record<string, OrganismRecord>
55
+ const main = data[0]
56
+ const aln = main.split(':')[5]
57
+ const alns = data.map(elt => elt.split(':')[5])
58
+ const alns2 = data.map(() => '')
59
+ // remove extraneous data in other alignments
60
+ // reason being: cannot represent missing data in main species that are in others)
61
+ for (let i = 0, o = 0; i < aln.length; i++, o++) {
62
+ if (aln[i] !== '-') {
63
+ for (let j = 0; j < data.length; j++) {
64
+ alns2[j] += alns[j][i]
65
+ }
66
+ }
67
+ }
68
+ for (let j = 0; j < data.length; j++) {
69
+ const elt = data[j]
70
+
71
+ const ad = elt.split(':')
72
+ const org = ad[0].split('.')[0]
73
+ const chr = ad[0].split('.')[1]
74
+
75
+ alignments[org] = {
76
+ chr: chr,
77
+ start: +ad[1],
78
+ srcSize: +ad[2],
79
+ strand: ad[3] === '-' ? -1 : 1,
80
+ unknown: +ad[4],
81
+ data: alns2[j],
82
+ }
83
+ }
84
+
85
+ observer.next(
86
+ new SimpleFeature({
87
+ id: feature.id(),
88
+ data: {
89
+ start: feature.get('start'),
90
+ end: feature.get('end'),
91
+ refName: feature.get('refName'),
92
+ name: feature.get('name'),
93
+ score: feature.get('score'),
94
+ alignments: alignments,
95
+ seq: alns2[0],
96
+ },
97
+ }),
98
+ )
99
+ }
100
+ observer.complete()
101
+ })
102
+ }
103
+ freeResources(): void {}
104
+ }
@@ -0,0 +1,45 @@
1
+ import { ConfigurationSchema } from '@jbrowse/core/configuration'
2
+
3
+ /**
4
+ * #config MafTabixAdapter
5
+ * used to configure MafTabix adapter
6
+ */
7
+ function x() {} // eslint-disable-line @typescript-eslint/no-unused-vars
8
+
9
+ const configSchema = ConfigurationSchema(
10
+ 'MafTabixAdapter',
11
+ {
12
+ /**
13
+ * #slot
14
+ */
15
+ samples: {
16
+ type: 'stringArray',
17
+ defaultValue: [],
18
+ },
19
+ /**
20
+ * #slot
21
+ */
22
+ bedGzLocation: {
23
+ type: 'fileLocation',
24
+ defaultValue: {
25
+ uri: '/path/to/my.bed.gz.tbi',
26
+ locationType: 'UriLocation',
27
+ },
28
+ },
29
+ index: ConfigurationSchema('Index', {
30
+ location: {
31
+ type: 'fileLocation',
32
+ defaultValue: {
33
+ uri: '/path/to/my.bed.gz.tbi',
34
+ },
35
+ },
36
+ indexType: {
37
+ type: 'string',
38
+ defaultValue: 'TBI',
39
+ },
40
+ }),
41
+ },
42
+ { explicitlyTyped: true },
43
+ )
44
+
45
+ export default configSchema
@@ -0,0 +1,15 @@
1
+ import PluginManager from '@jbrowse/core/PluginManager'
2
+ import { AdapterType } from '@jbrowse/core/pluggableElementTypes'
3
+ import configSchema from './configSchema'
4
+ import MafTabixAdapter from './MafTabixAdapter'
5
+
6
+ export default function MafTabixAdapterF(pluginManager: PluginManager) {
7
+ return pluginManager.addAdapterType(
8
+ () =>
9
+ new AdapterType({
10
+ name: 'MafTabixAdapter',
11
+ AdapterClass: MafTabixAdapter,
12
+ configSchema,
13
+ }),
14
+ )
15
+ }
@@ -0,0 +1,20 @@
1
+ import PluginManager from '@jbrowse/core/PluginManager'
2
+ import { ConfigurationSchema } from '@jbrowse/core/configuration'
3
+ import { createBaseTrackConfig } from '@jbrowse/core/pluggableElementTypes'
4
+
5
+ export default function configSchemaF(pluginManager: PluginManager) {
6
+ return ConfigurationSchema(
7
+ 'MafTrack',
8
+ {},
9
+ {
10
+ /**
11
+ * #baseConfiguration
12
+ */
13
+ baseConfiguration: createBaseTrackConfig(pluginManager),
14
+ /**
15
+ * #identifier
16
+ */
17
+ explicitIdentifier: 'trackId',
18
+ },
19
+ )
20
+ }
@@ -0,0 +1,18 @@
1
+ import PluginManager from '@jbrowse/core/PluginManager'
2
+ import {
3
+ TrackType,
4
+ createBaseTrackModel,
5
+ } from '@jbrowse/core/pluggableElementTypes'
6
+ import configSchemaF from './configSchema'
7
+
8
+ export default function MafTrackF(pluginManager: PluginManager) {
9
+ return pluginManager.addTrackType(() => {
10
+ const configSchema = configSchemaF(pluginManager)
11
+ return new TrackType({
12
+ name: 'MafTrack',
13
+ configSchema,
14
+ displayName: 'MAF track',
15
+ stateModel: createBaseTrackModel(pluginManager, 'MafTrack', configSchema),
16
+ })
17
+ })
18
+ }
@@ -0,0 +1 @@
1
+ declare module '*.json'
package/src/index.ts ADDED
@@ -0,0 +1,26 @@
1
+ import Plugin from '@jbrowse/core/Plugin'
2
+ import PluginManager from '@jbrowse/core/PluginManager'
3
+
4
+ import { version } from '../package.json'
5
+ import BigMafAdapterF from './BigMafAdapter'
6
+ import MafTrackF from './MafTrack'
7
+ import LinearMafDisplayF from './LinearMafDisplay'
8
+ import LinearMafRendererF from './LinearMafRenderer'
9
+ import MafTabixAdapterF from './MafTabixAdapter'
10
+ import MafAddTrackWorkflowF from './MafAddTrackWorkflow'
11
+
12
+ export default class MafViewerPlugin extends Plugin {
13
+ name = 'MafViewerPlugin'
14
+ version = version
15
+
16
+ install(pluginManager: PluginManager) {
17
+ BigMafAdapterF(pluginManager)
18
+ MafTrackF(pluginManager)
19
+ LinearMafDisplayF(pluginManager)
20
+ LinearMafRendererF(pluginManager)
21
+ MafTabixAdapterF(pluginManager)
22
+ MafAddTrackWorkflowF(pluginManager)
23
+ }
24
+
25
+ configure(pluginManager: PluginManager) {}
26
+ }