jbrowse-plugin-mafviewer 1.0.5 → 1.0.8

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 (104) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +17 -2
  3. package/dist/BigMafAdapter/BigMafAdapter.d.ts +17 -0
  4. package/dist/BigMafAdapter/BigMafAdapter.js +92 -0
  5. package/dist/BigMafAdapter/BigMafAdapter.js.map +1 -0
  6. package/dist/BigMafAdapter/configSchema.d.ts +21 -0
  7. package/dist/BigMafAdapter/configSchema.js +28 -0
  8. package/dist/BigMafAdapter/configSchema.js.map +1 -0
  9. package/dist/BigMafAdapter/index.d.ts +2 -0
  10. package/dist/BigMafAdapter/index.js +11 -0
  11. package/dist/BigMafAdapter/index.js.map +1 -0
  12. package/dist/LinearMafDisplay/components/ColorLegend.d.ts +8 -0
  13. package/dist/LinearMafDisplay/components/ColorLegend.js +15 -0
  14. package/dist/LinearMafDisplay/components/ColorLegend.js.map +1 -0
  15. package/dist/LinearMafDisplay/components/ReactComponent.d.ts +6 -0
  16. package/dist/LinearMafDisplay/components/ReactComponent.js +15 -0
  17. package/dist/LinearMafDisplay/components/ReactComponent.js.map +1 -0
  18. package/dist/LinearMafDisplay/components/RectBg.d.ts +9 -0
  19. package/dist/LinearMafDisplay/components/RectBg.js +7 -0
  20. package/dist/LinearMafDisplay/components/RectBg.js.map +1 -0
  21. package/dist/LinearMafDisplay/components/SetRowHeight.d.ts +11 -0
  22. package/dist/LinearMafDisplay/components/SetRowHeight.js +36 -0
  23. package/dist/LinearMafDisplay/components/SetRowHeight.js.map +1 -0
  24. package/dist/LinearMafDisplay/components/YScaleBars.d.ts +9 -0
  25. package/dist/LinearMafDisplay/components/YScaleBars.js +41 -0
  26. package/dist/LinearMafDisplay/components/YScaleBars.js.map +1 -0
  27. package/dist/LinearMafDisplay/configSchema.d.ts +34 -0
  28. package/dist/LinearMafDisplay/configSchema.js +15 -0
  29. package/dist/LinearMafDisplay/configSchema.js.map +1 -0
  30. package/dist/LinearMafDisplay/index.d.ts +2 -0
  31. package/dist/LinearMafDisplay/index.js +20 -0
  32. package/dist/LinearMafDisplay/index.js.map +1 -0
  33. package/dist/LinearMafDisplay/renderSvg.d.ts +4 -0
  34. package/dist/LinearMafDisplay/renderSvg.js +17 -0
  35. package/dist/LinearMafDisplay/renderSvg.js.map +1 -0
  36. package/dist/LinearMafDisplay/stateModel.d.ts +364 -0
  37. package/dist/LinearMafDisplay/stateModel.js +176 -0
  38. package/dist/LinearMafDisplay/stateModel.js.map +1 -0
  39. package/dist/LinearMafRenderer/LinearMafRenderer.d.ts +45 -0
  40. package/dist/LinearMafRenderer/LinearMafRenderer.js +181 -0
  41. package/dist/LinearMafRenderer/LinearMafRenderer.js.map +1 -0
  42. package/dist/LinearMafRenderer/components/ReactComponent.d.ts +6 -0
  43. package/dist/LinearMafRenderer/components/ReactComponent.js +8 -0
  44. package/dist/LinearMafRenderer/components/ReactComponent.js.map +1 -0
  45. package/dist/LinearMafRenderer/configSchema.d.ts +2 -0
  46. package/dist/LinearMafRenderer/configSchema.js +13 -0
  47. package/dist/LinearMafRenderer/configSchema.js.map +1 -0
  48. package/dist/LinearMafRenderer/index.d.ts +2 -0
  49. package/dist/LinearMafRenderer/index.js +12 -0
  50. package/dist/LinearMafRenderer/index.js.map +1 -0
  51. package/dist/LinearMafRenderer/util.d.ts +10 -0
  52. package/dist/LinearMafRenderer/util.js +16 -0
  53. package/dist/LinearMafRenderer/util.js.map +1 -0
  54. package/dist/MafAddTrackWorkflow/AddTrackWorkflow.d.ts +5 -0
  55. package/dist/MafAddTrackWorkflow/AddTrackWorkflow.js +111 -0
  56. package/dist/MafAddTrackWorkflow/AddTrackWorkflow.js.map +1 -0
  57. package/dist/MafAddTrackWorkflow/index.d.ts +2 -0
  58. package/dist/MafAddTrackWorkflow/index.js +12 -0
  59. package/dist/MafAddTrackWorkflow/index.js.map +1 -0
  60. package/dist/MafTabixAdapter/MafTabixAdapter.d.ts +17 -0
  61. package/dist/MafTabixAdapter/MafTabixAdapter.js +96 -0
  62. package/dist/MafTabixAdapter/MafTabixAdapter.js.map +1 -0
  63. package/dist/MafTabixAdapter/configSchema.d.ts +33 -0
  64. package/dist/MafTabixAdapter/configSchema.js +40 -0
  65. package/dist/MafTabixAdapter/configSchema.js.map +1 -0
  66. package/dist/MafTabixAdapter/index.d.ts +2 -0
  67. package/dist/MafTabixAdapter/index.js +11 -0
  68. package/dist/MafTabixAdapter/index.js.map +1 -0
  69. package/dist/MafTrack/configSchema.d.ts +79 -0
  70. package/dist/MafTrack/configSchema.js +15 -0
  71. package/dist/MafTrack/configSchema.js.map +1 -0
  72. package/dist/MafTrack/index.d.ts +2 -0
  73. package/dist/MafTrack/index.js +14 -0
  74. package/dist/MafTrack/index.js.map +1 -0
  75. package/dist/TaffyAdapter/TaffyAdapter.d.ts +16 -0
  76. package/dist/TaffyAdapter/TaffyAdapter.js +89 -0
  77. package/dist/TaffyAdapter/TaffyAdapter.js.map +1 -0
  78. package/dist/TaffyAdapter/configSchema.d.ts +31 -0
  79. package/dist/TaffyAdapter/configSchema.js +38 -0
  80. package/dist/TaffyAdapter/configSchema.js.map +1 -0
  81. package/dist/TaffyAdapter/index.d.ts +2 -0
  82. package/dist/TaffyAdapter/index.js +11 -0
  83. package/dist/TaffyAdapter/index.js.map +1 -0
  84. package/dist/index.d.ts +8 -0
  85. package/dist/index.js +24 -0
  86. package/dist/index.js.map +1 -0
  87. package/dist/jbrowse-plugin-mafviewer.umd.production.min.js +4 -1
  88. package/dist/jbrowse-plugin-mafviewer.umd.production.min.js.map +7 -1
  89. package/package.json +22 -51
  90. package/src/BigMafAdapter/BigMafAdapter.ts +1 -2
  91. package/src/LinearMafDisplay/components/ColorLegend.tsx +2 -2
  92. package/src/LinearMafDisplay/components/SetRowHeight.tsx +9 -3
  93. package/src/LinearMafDisplay/components/YScaleBars.tsx +11 -3
  94. package/src/LinearMafDisplay/stateModel.ts +29 -1
  95. package/src/LinearMafRenderer/LinearMafRenderer.ts +38 -34
  96. package/src/LinearMafRenderer/util.ts +20 -0
  97. package/src/MafAddTrackWorkflow/AddTrackWorkflow.tsx +60 -22
  98. package/src/MafTabixAdapter/MafTabixAdapter.ts +27 -10
  99. package/src/TaffyAdapter/TaffyAdapter.ts +112 -0
  100. package/src/TaffyAdapter/configSchema.ts +44 -0
  101. package/src/TaffyAdapter/index.ts +15 -0
  102. package/src/index.ts +2 -0
  103. package/dist/jbrowse-plugin-mafviewer.umd.development.js +0 -1423
  104. package/dist/jbrowse-plugin-mafviewer.umd.development.js.map +0 -1
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.0.5",
2
+ "version": "1.0.8",
3
3
  "name": "jbrowse-plugin-mafviewer",
4
4
  "keywords": [
5
5
  "jbrowse",
@@ -12,77 +12,48 @@
12
12
  "dist",
13
13
  "src"
14
14
  ],
15
- "config": {
16
- "port": 9000,
17
- "browse": {
18
- "port": 8999
19
- },
20
- "jbrowse": {
21
- "plugin": {
22
- "name": "MafViewer"
23
- }
24
- }
25
- },
26
15
  "scripts": {
27
16
  "clean": "rimraf dist",
28
17
  "start": "node esbuild.mjs",
29
18
  "prebuild": "npm run clean",
30
- "build": "rollup --config --bundleConfigAsCjs",
31
- "lint": "eslint --ext .js,.ts,.jsx,.tsx src/",
19
+ "build": "tsc && NODE_ENV=production node esbuild.mjs",
20
+ "lint": "eslint --report-unused-disable-directives --max-warnings 0",
32
21
  "prepack": "npm run build",
33
22
  "postversion": "git push --follow-tags"
34
23
  },
35
- "jbrowse-plugin": {
36
- "name": "MafViewer"
37
- },
38
24
  "devDependencies": {
39
25
  "@babel/core": "^7.16.5",
40
26
  "@babel/preset-react": "^7.10.4",
41
27
  "@emotion/react": "^11.10.4",
42
28
  "@fal-works/esbuild-plugin-global-externals": "^2.1.2",
43
- "@jbrowse/cli": "^2.6.1",
44
29
  "@jbrowse/core": "^2.6.1",
45
- "@jbrowse/development-tools": "^2.1.1",
46
30
  "@jbrowse/plugin-data-management": "^2.7.1",
47
31
  "@jbrowse/plugin-linear-genome-view": "^2.7.1",
48
- "@mui/material": "^5.10.5",
49
- "@mui/system": "^5.10.5",
50
- "@mui/x-data-grid": "^6.9.2",
51
- "@schemastore/package": "^0.0.10",
52
- "@types/node": "^20.8.7",
53
- "@types/react": "^18.2.31",
54
- "@typescript-eslint/eslint-plugin": "^6.8.0",
55
- "@typescript-eslint/parser": "^6.8.0",
56
- "babel-eslint": "^10.0.0",
32
+ "@mui/material": "^6.2.0",
33
+ "@mui/system": "^6.2.0",
34
+ "@mui/x-data-grid": "^7.2.0",
35
+ "@types/node": "^22.10.2",
36
+ "@types/react": "^19.0.1",
37
+ "@typescript-eslint/eslint-plugin": "^8.18.0",
38
+ "@typescript-eslint/parser": "^8.18.0",
57
39
  "chalk": "^5.3.0",
58
- "cross-env": "^7.0.3",
59
- "cross-var": "^1.1.0",
60
- "cypress": "^13.3.2",
61
- "esbuild": "^0.19.5",
62
- "eslint": "^8.36.0",
63
- "eslint-config-prettier": "^9.0.0",
64
- "eslint-config-react-app": "^7.0.1",
65
- "eslint-plugin-flowtype": "^8.0.3",
66
- "eslint-plugin-import": "^2.22.0",
67
- "eslint-plugin-jsx-a11y": "^6.3.1",
68
- "eslint-plugin-prettier": "^5.0.1",
40
+ "esbuild": "^0.24.0",
41
+ "eslint": "^9.17.0",
69
42
  "eslint-plugin-react": "^7.20.3",
70
- "eslint-plugin-react-hooks": "^4.0.8",
71
- "eslint-plugin-react-refresh": "^0.4.3",
72
- "eslint-plugin-unicorn": "^48.0.1",
43
+ "eslint-plugin-react-hooks": "^5.1.0",
44
+ "eslint-plugin-unicorn": "^56.0.1",
73
45
  "mobx": "^6.0.0",
74
46
  "mobx-react": "^9.0.1",
75
- "mobx-state-tree": "5.2.0",
76
- "prettier": "^3.0.0",
77
- "prop-types": "^15.8.1",
78
- "react": "^18.2.0",
79
- "react-dom": "^18.2.0",
80
- "rimraf": "^5.0.1",
81
- "rollup": "^3.0.0",
47
+ "mobx-state-tree": "5.4.1",
48
+ "prettier": "^3.4.2",
49
+ "pretty-bytes": "^6.1.1",
50
+ "react": "^19.0.0",
51
+ "react-dom": "^19.0.0",
52
+ "rimraf": "^6.0.1",
82
53
  "rxjs": "^7.8.1",
83
54
  "serve": "^14.2.0",
84
- "start-server-and-test": "^2.0.0",
85
55
  "tss-react": "^4.8.6",
86
- "typescript": "^5.1.6"
56
+ "typescript": "^5.1.6",
57
+ "typescript-eslint": "^8.18.0"
87
58
  }
88
59
  }
@@ -29,7 +29,7 @@ export default class BigMafAdapter extends BaseFeatureDataAdapter {
29
29
  }
30
30
  async setupPre() {
31
31
  if (!this.setupP) {
32
- this.setupP = this.setup().catch(e => {
32
+ this.setupP = this.setup().catch((e: unknown) => {
33
33
  this.setupP = undefined
34
34
  throw e
35
35
  })
@@ -73,7 +73,6 @@ export default class BigMafAdapter extends BaseFeatureDataAdapter {
73
73
  }
74
74
  }
75
75
 
76
- // eslint-disable-next-line unicorn/no-for-loop
77
76
  for (let i = 0; i < blocks2.length; i++) {
78
77
  const elt = blocks2[i]
79
78
  const ad = elt.split(/ +/)
@@ -18,7 +18,7 @@ const ColorLegend = observer(function ({
18
18
  const canDisplayLabel = rowHeight >= 10
19
19
  const boxHeight = Math.min(20, rowHeight)
20
20
 
21
- return samples ? (
21
+ return (
22
22
  <>
23
23
  {samples.map((sample, idx) => (
24
24
  <RectBg
@@ -44,7 +44,7 @@ const ColorLegend = observer(function ({
44
44
  ))
45
45
  : null}
46
46
  </>
47
- ) : null
47
+ )
48
48
  })
49
49
 
50
50
  export default ColorLegend
@@ -39,12 +39,16 @@ const SetRowHeightDialog = observer(function (props: {
39
39
  </Typography>
40
40
  <TextField
41
41
  value={rowHeight}
42
- onChange={event => setRowHeight(event.target.value)}
42
+ onChange={event => {
43
+ setRowHeight(event.target.value)
44
+ }}
43
45
  placeholder="Enter row height"
44
46
  />
45
47
  <TextField
46
48
  value={rowProportion}
47
- onChange={event => setRowProportion(event.target.value)}
49
+ onChange={event => {
50
+ setRowProportion(event.target.value)
51
+ }}
48
52
  placeholder="Enter row proportion"
49
53
  />
50
54
  <DialogActions>
@@ -64,7 +68,9 @@ const SetRowHeightDialog = observer(function (props: {
64
68
  <Button
65
69
  variant="contained"
66
70
  color="secondary"
67
- onClick={() => handleClose()}
71
+ onClick={() => {
72
+ handleClose()
73
+ }}
68
74
  >
69
75
  Cancel
70
76
  </Button>
@@ -36,6 +36,14 @@ const Wrapper = observer(function ({
36
36
  }
37
37
  })
38
38
 
39
+ export function max(arr: number[], init = Number.NEGATIVE_INFINITY) {
40
+ let max = init
41
+ for (const entry of arr) {
42
+ max = Math.max(entry, max)
43
+ }
44
+ return max
45
+ }
46
+
39
47
  export const YScaleBars = observer(function (props: {
40
48
  model: LinearMafDisplayModel
41
49
  orientation?: string
@@ -47,10 +55,10 @@ export const YScaleBars = observer(function (props: {
47
55
  const canDisplayLabel = rowHeight >= 10
48
56
  const minWidth = 20
49
57
 
50
- const labelWidth = Math.max(
51
- ...(samples
58
+ const labelWidth = max(
59
+ samples
52
60
  .map(s => measureText(s.label, svgFontSize))
53
- .map(width => (canDisplayLabel ? width : minWidth)) || [0]),
61
+ .map(width => (canDisplayLabel ? width : minWidth)),
54
62
  )
55
63
 
56
64
  return (
@@ -52,9 +52,16 @@ export default function stateModelFactory(
52
52
  * #property
53
53
  */
54
54
  showAllLetters: false,
55
+ /**
56
+ * #property
57
+ */
58
+ mismatchRendering: true,
55
59
  }),
56
60
  )
57
61
  .volatile(() => ({
62
+ /**
63
+ * #volatile
64
+ */
58
65
  prefersOffset: true,
59
66
  }))
60
67
  .actions(self => ({
@@ -76,6 +83,12 @@ export default function stateModelFactory(
76
83
  setShowAllLetters(f: boolean) {
77
84
  self.showAllLetters = f
78
85
  },
86
+ /**
87
+ * #action
88
+ */
89
+ setMismatchRendering(f: boolean) {
90
+ self.mismatchRendering = f
91
+ },
79
92
  }))
80
93
  .views(self => ({
81
94
  /**
@@ -114,7 +127,9 @@ export default function stateModelFactory(
114
127
  }))
115
128
  .views(self => {
116
129
  const {
130
+ // eslint-disable-next-line @typescript-eslint/unbound-method
117
131
  trackMenuItems: superTrackMenuItems,
132
+ // eslint-disable-next-line @typescript-eslint/unbound-method
118
133
  renderProps: superRenderProps,
119
134
  } = self
120
135
  return {
@@ -128,6 +143,7 @@ export default function stateModelFactory(
128
143
  samples,
129
144
  rowHeight,
130
145
  rowProportion,
146
+ mismatchRendering,
131
147
  } = self
132
148
  return {
133
149
  ...superRenderProps(),
@@ -136,6 +152,7 @@ export default function stateModelFactory(
136
152
  rowHeight,
137
153
  rowProportion,
138
154
  showAllLetters,
155
+ mismatchRendering,
139
156
  }
140
157
  },
141
158
  /**
@@ -149,7 +166,10 @@ export default function stateModelFactory(
149
166
  onClick: () => {
150
167
  getSession(self).queueDialog(handleClose => [
151
168
  SetRowHeightDialog,
152
- { model: self, handleClose },
169
+ {
170
+ model: self,
171
+ handleClose,
172
+ },
153
173
  ])
154
174
  },
155
175
  },
@@ -161,6 +181,14 @@ export default function stateModelFactory(
161
181
  self.setShowAllLetters(!self.showAllLetters)
162
182
  },
163
183
  },
184
+ {
185
+ label: 'Draw mismatches as single color',
186
+ type: 'checkbox',
187
+ checked: !self.mismatchRendering,
188
+ onClick: () => {
189
+ self.setMismatchRendering(!self.mismatchRendering)
190
+ },
191
+ },
164
192
  ]
165
193
  },
166
194
  }
@@ -7,33 +7,20 @@ import {
7
7
  featureSpanPx,
8
8
  renderToAbstractCanvas,
9
9
  } from '@jbrowse/core/util'
10
- import { Theme } from '@mui/material'
10
+ import { getColorBaseMap, getContrastBaseMap } from './util'
11
11
 
12
- export function getContrastBaseMap(theme: Theme) {
13
- return Object.fromEntries(
14
- Object.entries(getColorBaseMap(theme)).map(([key, value]) => [
15
- key,
16
- theme.palette.getContrastText(value),
17
- ]),
18
- )
12
+ interface Sample {
13
+ id: string
14
+ color?: string
19
15
  }
20
-
21
16
  interface RenderArgs extends RenderArgsDeserialized {
22
- samples: { id: string; color?: string }[]
17
+ samples: Sample[]
23
18
  rowHeight: number
24
19
  rowProportion: number
25
20
  showAllLetters: boolean
21
+ mismatchRendering: boolean
26
22
  }
27
23
 
28
- export function getColorBaseMap(theme: Theme) {
29
- const { bases } = theme.palette
30
- return {
31
- a: bases.A.main,
32
- c: bases.C.main,
33
- g: bases.G.main,
34
- t: bases.T.main,
35
- }
36
- }
37
24
  function makeImageData({
38
25
  ctx,
39
26
  renderArgs,
@@ -47,6 +34,7 @@ function makeImageData({
47
34
  rowHeight,
48
35
  showAllLetters,
49
36
  theme: configTheme,
37
+ mismatchRendering,
50
38
  samples,
51
39
  rowProportion,
52
40
  features,
@@ -117,23 +105,33 @@ function makeImageData({
117
105
  for (let i = 0, o = 0; i < alignment.length; i++) {
118
106
  const c = alignment[i]
119
107
  if (seq[i] !== '-') {
120
- if ((showAllLetters || seq[i] !== c) && c !== '-') {
108
+ if (c !== '-') {
121
109
  const l = leftPx + scale * o
122
- ctx.fillStyle =
123
- colorForBase[c as keyof typeof colorForBase] ?? 'black'
124
- ctx.fillRect(l, offset + t, scale + f, h)
110
+ if (seq[i] !== c) {
111
+ ctx.fillStyle = mismatchRendering
112
+ ? // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
113
+ (colorForBase[c as keyof typeof colorForBase] ?? 'black')
114
+ : 'orange'
115
+ ctx.fillRect(l, offset + t, scale + f, h)
116
+ } else if (showAllLetters) {
117
+ ctx.fillStyle = mismatchRendering
118
+ ? // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
119
+ (colorForBase[c as keyof typeof colorForBase] ?? 'black')
120
+ : 'lightblue'
121
+ ctx.fillRect(l, offset + t, scale + f, h)
122
+ }
125
123
  }
126
124
  o++
127
125
  }
128
126
  }
129
127
 
130
128
  // font
131
- const charSize = { w: 10 }
132
- if (scale >= charSize.w) {
129
+ const charSizeW = 10
130
+ if (scale >= charSizeW) {
133
131
  for (let i = 0, o = 0; i < alignment.length; i++) {
134
132
  if (seq[i] !== '-') {
135
133
  const l = leftPx + scale * o
136
- const offset = (scale - charSize.w) / 2 + 1
134
+ const offset = (scale - charSizeW) / 2 + 1
137
135
  const c = alignment[i]
138
136
  if ((showAllLetters || seq[i] !== c) && c !== '-') {
139
137
  ctx.fillStyle = contrastForBase[c] ?? 'white'
@@ -203,14 +201,20 @@ export default class LinearMafRenderer extends FeatureRendererType {
203
201
  const height = samples.length * rowHeight + 100
204
202
  const width = (region.end - region.start) / bpPerPx
205
203
  const features = await this.getFeatures(renderProps)
206
- const res = await renderToAbstractCanvas(width, height, renderProps, ctx =>
207
- makeImageData({
208
- ctx,
209
- renderArgs: {
210
- ...renderProps,
211
- features,
212
- },
213
- }),
204
+ const res = await renderToAbstractCanvas(
205
+ width,
206
+ height,
207
+ renderProps,
208
+ ctx => {
209
+ makeImageData({
210
+ ctx,
211
+ renderArgs: {
212
+ ...renderProps,
213
+ features,
214
+ },
215
+ })
216
+ return undefined
217
+ },
214
218
  )
215
219
  const results = await super.render({
216
220
  ...renderProps,
@@ -0,0 +1,20 @@
1
+ import { Theme } from '@mui/material'
2
+
3
+ export function getContrastBaseMap(theme: Theme) {
4
+ return Object.fromEntries(
5
+ Object.entries(getColorBaseMap(theme)).map(([key, value]) => [
6
+ key,
7
+ theme.palette.getContrastText(value),
8
+ ]),
9
+ )
10
+ }
11
+
12
+ export function getColorBaseMap(theme: Theme) {
13
+ const { bases } = theme.palette
14
+ return {
15
+ a: bases.A.main,
16
+ c: bases.C.main,
17
+ g: bases.G.main,
18
+ t: bases.T.main,
19
+ }
20
+ }
@@ -42,8 +42,9 @@ export default function MultiMAFWidget({ model }: { model: AddTrackModel }) {
42
42
  const [indexLoc, setIndexLoc] = useState<FileLocation>()
43
43
  const [error, setError] = useState<unknown>()
44
44
  const [trackName, setTrackName] = useState('MAF track')
45
- const [choice, setChoice] = useState('BigMafAdapter')
46
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
45
+ const [fileTypeChoice, setFileTypeChoice] = useState('BigMafAdapter')
46
+ const [indexTypeChoice, setIndexTypeChoice] = useState('TBI')
47
+
47
48
  const rootModel = getRoot<any>(model)
48
49
  return (
49
50
  <Paper className={classes.paper}>
@@ -52,42 +53,72 @@ export default function MultiMAFWidget({ model }: { model: AddTrackModel }) {
52
53
  <FormControl>
53
54
  <FormLabel>File type</FormLabel>
54
55
  <RadioGroup
55
- value={choice}
56
- onChange={event => setChoice(event.target.value)}
56
+ value={fileTypeChoice}
57
+ onChange={event => {
58
+ setFileTypeChoice(event.target.value)
59
+ }}
57
60
  >
58
61
  <FormControlLabel
59
62
  value="BigMafAdapter"
60
63
  control={<Radio />}
61
- checked={choice === 'BigMafAdapter'}
64
+ checked={fileTypeChoice === 'BigMafAdapter'}
62
65
  label="bigMaf"
63
66
  />
64
67
  <FormControlLabel
65
68
  value="MafTabixAdapter"
66
69
  control={<Radio />}
67
- checked={choice === 'MafTabixAdapter'}
70
+ checked={fileTypeChoice === 'MafTabixAdapter'}
68
71
  label="mafTabix"
69
72
  />
70
73
  </RadioGroup>
71
74
  </FormControl>
72
- {choice === 'BigMafAdapter' ? (
75
+ {fileTypeChoice === 'BigMafAdapter' ? (
73
76
  <FileSelector
74
77
  location={loc}
75
78
  name="Path to bigMaf"
76
- setLocation={arg => setLoc(arg)}
77
79
  rootModel={rootModel}
80
+ setLocation={arg => {
81
+ setLoc(arg)
82
+ }}
78
83
  />
79
84
  ) : (
80
85
  <>
86
+ <FormControl>
87
+ <FormLabel>Index type</FormLabel>
88
+ <RadioGroup
89
+ value={fileTypeChoice}
90
+ onChange={event => {
91
+ setIndexTypeChoice(event.target.value)
92
+ }}
93
+ >
94
+ <FormControlLabel
95
+ value="TBI"
96
+ control={<Radio />}
97
+ checked={indexTypeChoice === 'TBI'}
98
+ label="TBI"
99
+ />
100
+ <FormControlLabel
101
+ value="CSI"
102
+ control={<Radio />}
103
+ checked={indexTypeChoice === 'CSI'}
104
+ label="CSI"
105
+ />
106
+ </RadioGroup>
107
+ </FormControl>
81
108
  <FileSelector
82
109
  location={loc}
83
110
  name="Path to MAF tabix"
84
- setLocation={arg => setLoc(arg)}
111
+ setLocation={arg => {
112
+ setLoc(arg)
113
+ }}
85
114
  rootModel={rootModel}
86
115
  />
87
116
  <FileSelector
88
117
  location={indexLoc}
89
118
  name="Path to MAF tabix index"
90
- setLocation={arg => setIndexLoc(arg)}
119
+ setLocation={arg => {
120
+ setIndexLoc(arg)
121
+ }}
91
122
  rootModel={rootModel}
92
123
  />
93
124
  </>
@@ -97,7 +128,9 @@ export default function MultiMAFWidget({ model }: { model: AddTrackModel }) {
97
128
  multiline
98
129
  rows={10}
99
130
  value={samples}
100
- onChange={event => setSamples(event.target.value)}
131
+ onChange={event => {
132
+ setSamples(event.target.value)
133
+ }}
101
134
  placeholder={
102
135
  'Enter sample names from the MAF file, one per line, or JSON formatted array of samples'
103
136
  }
@@ -107,8 +140,10 @@ export default function MultiMAFWidget({ model }: { model: AddTrackModel }) {
107
140
 
108
141
  <TextField
109
142
  value={trackName}
110
- onChange={event => setTrackName(event.target.value)}
111
143
  helperText="Track name"
144
+ onChange={event => {
145
+ setTrackName(event.target.value)
146
+ }}
112
147
  />
113
148
  <Button
114
149
  variant="contained"
@@ -125,7 +160,7 @@ export default function MultiMAFWidget({ model }: { model: AddTrackModel }) {
125
160
 
126
161
  const trackId = [
127
162
  `${trackName.toLowerCase().replaceAll(' ', '_')}-${Date.now()}`,
128
- `${session.adminMode ? '' : '-sessionTrack'}`,
163
+ session.adminMode ? '' : '-sessionTrack',
129
164
  ].join('')
130
165
 
131
166
  if (isSessionWithAddTracks(session)) {
@@ -135,18 +170,21 @@ export default function MultiMAFWidget({ model }: { model: AddTrackModel }) {
135
170
  name: trackName,
136
171
  assemblyNames: [model.assembly],
137
172
  adapter:
138
- choice === 'BigMafAdapter'
173
+ fileTypeChoice === 'BigMafAdapter'
139
174
  ? {
140
- type: choice,
141
- bigBedLocation: loc,
142
- samples: sampleNames,
143
- }
175
+ type: fileTypeChoice,
176
+ bigBedLocation: loc,
177
+ samples: sampleNames,
178
+ }
144
179
  : {
145
- type: choice,
146
- bedGzLocation: loc,
147
- index: { location: indexLoc },
148
- samples: sampleNames,
180
+ type: fileTypeChoice,
181
+ bedGzLocation: loc,
182
+ index: {
183
+ indexType: indexTypeChoice,
184
+ location: indexLoc,
149
185
  },
186
+ samples: sampleNames,
187
+ },
150
188
  })
151
189
 
152
190
  model.view?.showTrack(trackId)
@@ -12,7 +12,8 @@ interface OrganismRecord {
12
12
  unknown: number
13
13
  data: string
14
14
  }
15
- export default class BigMafAdapter extends BaseFeatureDataAdapter {
15
+
16
+ export default class MafTabixAdapter extends BaseFeatureDataAdapter {
16
17
  public setupP?: Promise<{ adapter: BaseFeatureDataAdapter }>
17
18
 
18
19
  async setup() {
@@ -30,7 +31,7 @@ export default class BigMafAdapter extends BaseFeatureDataAdapter {
30
31
  }
31
32
  async setupPre() {
32
33
  if (!this.setupP) {
33
- this.setupP = this.setup().catch(e => {
34
+ this.setupP = this.setup().catch((e: unknown) => {
34
35
  this.setupP = undefined
35
36
  throw e
36
37
  })
@@ -54,6 +55,13 @@ export default class BigMafAdapter extends BaseFeatureDataAdapter {
54
55
  const features = await firstValueFrom(
55
56
  adapter.getFeatures(query).pipe(toArray()),
56
57
  )
58
+ const samples = this.getConf('samples') as string[] | { id: string }[]
59
+ const sampleStrings =
60
+ typeof samples[0] === 'string'
61
+ ? (samples as string[])
62
+ : (samples as { id: string }[]).map(s => s.id)
63
+ const sampleSet = new Set(sampleStrings)
64
+ let i = 0
57
65
  for (const feature of features) {
58
66
  const data = (feature.get('field5') as string).split(',')
59
67
  const alignments = {} as Record<string, OrganismRecord>
@@ -64,14 +72,23 @@ export default class BigMafAdapter extends BaseFeatureDataAdapter {
64
72
  const idx = ad[0].lastIndexOf('.')
65
73
  const org = ad[0].slice(0, idx)
66
74
  const last = ad[0].slice(idx + 1)
67
-
68
- alignments[org] = {
69
- chr: last,
70
- start: +ad[1],
71
- srcSize: +ad[2],
72
- strand: ad[3] === '-' ? -1 : 1,
73
- unknown: +ad[4],
74
- data: alns[j],
75
+ const s = sampleSet.has(org)
76
+ ? org
77
+ : sampleStrings.find(f => ad[0].startsWith(f))
78
+ if (s) {
79
+ alignments[s] = {
80
+ chr: last,
81
+ start: +ad[1],
82
+ srcSize: +ad[2],
83
+ strand: ad[3] === '-' ? -1 : 1,
84
+ unknown: +ad[4],
85
+ data: alns[j],
86
+ }
87
+ } else if (i < 100) {
88
+ console.error(`line not processed ${ad[0]}`)
89
+ i++
90
+ } else if (i > 100) {
91
+ console.error('too many errors, not printing any more')
75
92
  }
76
93
  }
77
94