jbrowse-plugin-mafviewer 1.0.8 → 1.1.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.
- package/README.md +54 -20
- package/dist/{TaffyAdapter/TaffyAdapter.d.ts → BgzipTaffyAdapter/BgzipTaffyAdapter.d.ts} +11 -7
- package/dist/BgzipTaffyAdapter/BgzipTaffyAdapter.js +204 -0
- package/dist/BgzipTaffyAdapter/BgzipTaffyAdapter.js.map +1 -0
- package/dist/{TaffyAdapter → BgzipTaffyAdapter}/configSchema.d.ts +14 -1
- package/dist/{TaffyAdapter → BgzipTaffyAdapter}/configSchema.js +21 -6
- package/dist/BgzipTaffyAdapter/configSchema.js.map +1 -0
- package/dist/BgzipTaffyAdapter/index.d.ts +2 -0
- package/dist/BgzipTaffyAdapter/index.js +11 -0
- package/dist/BgzipTaffyAdapter/index.js.map +1 -0
- package/dist/BgzipTaffyAdapter/rowInstructions.d.ts +35 -0
- package/dist/BgzipTaffyAdapter/rowInstructions.js +55 -0
- package/dist/BgzipTaffyAdapter/rowInstructions.js.map +1 -0
- package/dist/BgzipTaffyAdapter/types.d.ts +13 -0
- package/dist/BgzipTaffyAdapter/types.js +2 -0
- package/dist/BgzipTaffyAdapter/types.js.map +1 -0
- package/dist/BgzipTaffyAdapter/virtualOffset.d.ts +8 -0
- package/dist/BgzipTaffyAdapter/virtualOffset.js +23 -0
- package/dist/BgzipTaffyAdapter/virtualOffset.js.map +1 -0
- package/dist/BigMafAdapter/BigMafAdapter.js +1 -1
- package/dist/BigMafAdapter/BigMafAdapter.js.map +1 -1
- package/dist/BigMafAdapter/configSchema.d.ts +11 -0
- package/dist/BigMafAdapter/configSchema.js +11 -0
- package/dist/BigMafAdapter/configSchema.js.map +1 -1
- package/dist/BigMafAdapter/index.js +1 -1
- package/dist/BigMafAdapter/index.js.map +1 -1
- package/dist/LinearMafDisplay/components/ColorLegend.js +10 -6
- package/dist/LinearMafDisplay/components/ColorLegend.js.map +1 -1
- package/dist/LinearMafDisplay/components/ReactComponent.js +39 -4
- package/dist/LinearMafDisplay/components/ReactComponent.js.map +1 -1
- package/dist/LinearMafDisplay/components/SetRowHeight.js +7 -7
- package/dist/LinearMafDisplay/components/SetRowHeight.js.map +1 -1
- package/dist/LinearMafDisplay/components/SvgWrapper.d.ts +8 -0
- package/dist/LinearMafDisplay/components/SvgWrapper.js +21 -0
- package/dist/LinearMafDisplay/components/SvgWrapper.js.map +1 -0
- package/dist/LinearMafDisplay/components/Tree.d.ts +5 -0
- package/dist/LinearMafDisplay/components/Tree.js +22 -0
- package/dist/LinearMafDisplay/components/Tree.js.map +1 -0
- package/dist/LinearMafDisplay/components/YScaleBars.d.ts +0 -1
- package/dist/LinearMafDisplay/components/YScaleBars.js +6 -27
- package/dist/LinearMafDisplay/components/YScaleBars.js.map +1 -1
- package/dist/LinearMafDisplay/components/util.d.ts +1 -0
- package/dist/LinearMafDisplay/components/util.js +8 -0
- package/dist/LinearMafDisplay/components/util.js.map +1 -0
- package/dist/LinearMafDisplay/index.js +1 -1
- package/dist/LinearMafDisplay/index.js.map +1 -1
- package/dist/LinearMafDisplay/renderSvg.js +1 -0
- package/dist/LinearMafDisplay/renderSvg.js.map +1 -1
- package/dist/LinearMafDisplay/stateModel.d.ts +76 -14
- package/dist/LinearMafDisplay/stateModel.js +118 -18
- package/dist/LinearMafDisplay/stateModel.js.map +1 -1
- package/dist/LinearMafDisplay/types.d.ts +17 -0
- package/dist/LinearMafDisplay/types.js +16 -0
- package/dist/LinearMafDisplay/types.js.map +1 -0
- package/dist/LinearMafRenderer/LinearMafRenderer.d.ts +3 -3
- package/dist/LinearMafRenderer/LinearMafRenderer.js +11 -9
- package/dist/LinearMafRenderer/LinearMafRenderer.js.map +1 -1
- package/dist/LinearMafRenderer/components/ReactComponent.js +1 -1
- package/dist/LinearMafRenderer/components/ReactComponent.js.map +1 -1
- package/dist/LinearMafRenderer/index.js +1 -1
- package/dist/LinearMafRenderer/index.js.map +1 -1
- package/dist/MafAddTrackWorkflow/AddTrackWorkflow.js +42 -25
- package/dist/MafAddTrackWorkflow/AddTrackWorkflow.js.map +1 -1
- package/dist/MafRPC/index.d.ts +16 -0
- package/dist/MafRPC/index.js +19 -0
- package/dist/MafRPC/index.js.map +1 -0
- package/dist/MafTabixAdapter/MafTabixAdapter.d.ts +8 -0
- package/dist/MafTabixAdapter/MafTabixAdapter.js +18 -19
- package/dist/MafTabixAdapter/MafTabixAdapter.js.map +1 -1
- package/dist/MafTabixAdapter/configSchema.d.ts +17 -0
- package/dist/MafTabixAdapter/configSchema.js +17 -1
- package/dist/MafTabixAdapter/configSchema.js.map +1 -1
- package/dist/MafTabixAdapter/index.js +1 -1
- package/dist/MafTabixAdapter/index.js.map +1 -1
- package/dist/MafTrack/index.js.map +1 -1
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/jbrowse-plugin-mafviewer.umd.production.min.js +65 -4
- package/dist/jbrowse-plugin-mafviewer.umd.production.min.js.map +4 -4
- package/dist/parseNewick.d.ts +60 -0
- package/dist/parseNewick.js +95 -0
- package/dist/parseNewick.js.map +1 -0
- package/dist/util.d.ts +9 -0
- package/dist/util.js +9 -0
- package/dist/util.js.map +1 -0
- package/package.json +18 -5
- package/src/BgzipTaffyAdapter/BgzipTaffyAdapter.ts +235 -0
- package/src/{TaffyAdapter → BgzipTaffyAdapter}/configSchema.ts +21 -6
- package/src/{TaffyAdapter → BgzipTaffyAdapter}/index.ts +5 -4
- package/src/BgzipTaffyAdapter/rowInstructions.ts +91 -0
- package/src/BgzipTaffyAdapter/types.ts +16 -0
- package/src/BgzipTaffyAdapter/virtualOffset.ts +29 -0
- package/src/BigMafAdapter/BigMafAdapter.ts +11 -11
- package/src/BigMafAdapter/configSchema.ts +11 -0
- package/src/BigMafAdapter/index.ts +2 -1
- package/src/LinearMafDisplay/components/ColorLegend.tsx +36 -25
- package/src/LinearMafDisplay/components/ReactComponent.tsx +68 -3
- package/src/LinearMafDisplay/components/SetRowHeight.tsx +6 -5
- package/src/LinearMafDisplay/components/SvgWrapper.tsx +39 -0
- package/src/LinearMafDisplay/components/Tree.tsx +33 -0
- package/src/LinearMafDisplay/components/YScaleBars.tsx +8 -43
- package/src/LinearMafDisplay/components/util.ts +7 -0
- package/src/LinearMafDisplay/index.ts +2 -1
- package/src/LinearMafDisplay/renderSvg.tsx +2 -1
- package/src/LinearMafDisplay/stateModel.ts +139 -18
- package/src/LinearMafDisplay/types.ts +41 -0
- package/src/LinearMafRenderer/LinearMafRenderer.ts +13 -10
- package/src/LinearMafRenderer/components/ReactComponent.tsx +2 -1
- package/src/LinearMafRenderer/index.ts +2 -1
- package/src/MafAddTrackWorkflow/AddTrackWorkflow.tsx +109 -65
- package/src/MafRPC/index.ts +39 -0
- package/src/MafTabixAdapter/MafTabixAdapter.ts +31 -25
- package/src/MafTabixAdapter/configSchema.ts +17 -1
- package/src/MafTabixAdapter/index.ts +2 -1
- package/src/MafTrack/index.ts +1 -0
- package/src/index.ts +6 -4
- package/src/parseNewick.ts +94 -0
- package/src/util.ts +11 -0
- package/LICENSE +0 -201
- package/dist/TaffyAdapter/TaffyAdapter.js +0 -89
- package/dist/TaffyAdapter/TaffyAdapter.js.map +0 -1
- package/dist/TaffyAdapter/configSchema.js.map +0 -1
- package/dist/TaffyAdapter/index.d.ts +0 -2
- package/dist/TaffyAdapter/index.js +0 -11
- package/dist/TaffyAdapter/index.js.map +0 -1
- package/src/TaffyAdapter/TaffyAdapter.ts +0 -112
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import PluginManager from '@jbrowse/core/PluginManager'
|
|
2
2
|
import {
|
|
3
3
|
AnyConfigurationModel,
|
|
4
4
|
AnyConfigurationSchemaType,
|
|
@@ -6,12 +6,26 @@ import {
|
|
|
6
6
|
getConf,
|
|
7
7
|
} from '@jbrowse/core/configuration'
|
|
8
8
|
import { getEnv, getSession } from '@jbrowse/core/util'
|
|
9
|
-
import
|
|
9
|
+
import { getRpcSessionId } from '@jbrowse/core/util/tracks'
|
|
10
10
|
import { ExportSvgDisplayOptions } from '@jbrowse/plugin-linear-genome-view'
|
|
11
|
+
import { ascending } from 'd3-array'
|
|
12
|
+
import { type HierarchyNode, cluster, hierarchy } from 'd3-hierarchy'
|
|
13
|
+
import { autorun } from 'mobx'
|
|
14
|
+
import { Instance, addDisposer, isAlive, types } from 'mobx-state-tree'
|
|
15
|
+
|
|
11
16
|
import SetRowHeightDialog from './components/SetRowHeight'
|
|
17
|
+
import {
|
|
18
|
+
NodeWithIds,
|
|
19
|
+
NodeWithIdsAndLength,
|
|
20
|
+
maxLength,
|
|
21
|
+
setBrLength,
|
|
22
|
+
} from './types'
|
|
23
|
+
import { normalize } from '../util'
|
|
12
24
|
|
|
13
|
-
|
|
14
|
-
|
|
25
|
+
interface Sample {
|
|
26
|
+
id: string
|
|
27
|
+
label: string
|
|
28
|
+
color?: string
|
|
15
29
|
}
|
|
16
30
|
|
|
17
31
|
/**
|
|
@@ -56,6 +70,16 @@ export default function stateModelFactory(
|
|
|
56
70
|
* #property
|
|
57
71
|
*/
|
|
58
72
|
mismatchRendering: true,
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* #property
|
|
76
|
+
*/
|
|
77
|
+
showBranchLen: false,
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* #property
|
|
81
|
+
*/
|
|
82
|
+
treeAreaWidth: 80,
|
|
59
83
|
}),
|
|
60
84
|
)
|
|
61
85
|
.volatile(() => ({
|
|
@@ -63,6 +87,14 @@ export default function stateModelFactory(
|
|
|
63
87
|
* #volatile
|
|
64
88
|
*/
|
|
65
89
|
prefersOffset: true,
|
|
90
|
+
/**
|
|
91
|
+
* #volatile
|
|
92
|
+
*/
|
|
93
|
+
volatileSamples: [] as Sample[],
|
|
94
|
+
/**
|
|
95
|
+
* #volatile
|
|
96
|
+
*/
|
|
97
|
+
tree: undefined as any,
|
|
66
98
|
}))
|
|
67
99
|
.actions(self => ({
|
|
68
100
|
/**
|
|
@@ -89,26 +121,22 @@ export default function stateModelFactory(
|
|
|
89
121
|
setMismatchRendering(f: boolean) {
|
|
90
122
|
self.mismatchRendering = f
|
|
91
123
|
},
|
|
92
|
-
}))
|
|
93
|
-
.views(self => ({
|
|
94
124
|
/**
|
|
95
|
-
* #
|
|
125
|
+
* #action
|
|
96
126
|
*/
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
| { id: string; label: string; color?: string }[]
|
|
101
|
-
return isStrs(r)
|
|
102
|
-
? r.map(elt => ({ id: elt, label: elt, color: undefined }))
|
|
103
|
-
: r
|
|
127
|
+
setSamples({ samples, tree }: { samples: Sample[]; tree: unknown }) {
|
|
128
|
+
self.volatileSamples = samples
|
|
129
|
+
self.tree = tree
|
|
104
130
|
},
|
|
105
|
-
|
|
131
|
+
}))
|
|
132
|
+
.views(self => ({
|
|
106
133
|
/**
|
|
107
134
|
* #getter
|
|
108
135
|
*/
|
|
109
136
|
get rendererTypeName() {
|
|
110
137
|
return 'LinearMafRenderer'
|
|
111
138
|
},
|
|
139
|
+
|
|
112
140
|
/**
|
|
113
141
|
* #getter
|
|
114
142
|
*/
|
|
@@ -125,14 +153,77 @@ export default function stateModelFactory(
|
|
|
125
153
|
)
|
|
126
154
|
},
|
|
127
155
|
}))
|
|
156
|
+
|
|
157
|
+
.views(self => ({
|
|
158
|
+
/**
|
|
159
|
+
* #getter
|
|
160
|
+
*/
|
|
161
|
+
get root() {
|
|
162
|
+
return self.tree
|
|
163
|
+
? hierarchy(self.tree, d => d.children)
|
|
164
|
+
// todo: investigate whether needed, typescript says children always true
|
|
165
|
+
.sum(d => (d.children ? 0 : 1))
|
|
166
|
+
.sort((a, b) => ascending(a.data.length || 1, b.data.length || 1))
|
|
167
|
+
: undefined
|
|
168
|
+
},
|
|
169
|
+
}))
|
|
170
|
+
.views(self => ({
|
|
171
|
+
/**
|
|
172
|
+
* #getter
|
|
173
|
+
* generates a new tree that is clustered with x,y positions
|
|
174
|
+
*/
|
|
175
|
+
get hierarchy(): HierarchyNode<NodeWithIdsAndLength> | undefined {
|
|
176
|
+
const r = self.root
|
|
177
|
+
if (r) {
|
|
178
|
+
const width = self.treeAreaWidth
|
|
179
|
+
const clust = cluster<NodeWithIds>()
|
|
180
|
+
.size([this.totalHeight, width])
|
|
181
|
+
.separation(() => 1)
|
|
182
|
+
clust(r)
|
|
183
|
+
setBrLength(r, (r.data.length = 0), width / maxLength(r))
|
|
184
|
+
return r as HierarchyNode<NodeWithIdsAndLength>
|
|
185
|
+
} else {
|
|
186
|
+
return undefined
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
/**
|
|
190
|
+
* #getter
|
|
191
|
+
*/
|
|
192
|
+
get samples() {
|
|
193
|
+
return this.rowNames ? normalize(this.rowNames) : self.volatileSamples
|
|
194
|
+
},
|
|
195
|
+
/**
|
|
196
|
+
* #getter
|
|
197
|
+
*/
|
|
198
|
+
get totalHeight() {
|
|
199
|
+
return this.samples.length * self.rowHeight
|
|
200
|
+
},
|
|
201
|
+
/**
|
|
202
|
+
* #getter
|
|
203
|
+
*/
|
|
204
|
+
get leaves() {
|
|
205
|
+
return self.root?.leaves()
|
|
206
|
+
},
|
|
207
|
+
/**
|
|
208
|
+
* #getter
|
|
209
|
+
*/
|
|
210
|
+
get rowNames(): string[] | undefined {
|
|
211
|
+
return this.leaves?.map(n => n.data.name)
|
|
212
|
+
},
|
|
213
|
+
}))
|
|
128
214
|
.views(self => {
|
|
129
215
|
const {
|
|
130
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
131
216
|
trackMenuItems: superTrackMenuItems,
|
|
132
|
-
|
|
217
|
+
|
|
133
218
|
renderProps: superRenderProps,
|
|
134
219
|
} = self
|
|
135
220
|
return {
|
|
221
|
+
/**
|
|
222
|
+
* #getter
|
|
223
|
+
*/
|
|
224
|
+
get treeWidth() {
|
|
225
|
+
return self.hierarchy ? self.treeAreaWidth : 0
|
|
226
|
+
},
|
|
136
227
|
/**
|
|
137
228
|
* #method
|
|
138
229
|
*/
|
|
@@ -193,8 +284,38 @@ export default function stateModelFactory(
|
|
|
193
284
|
},
|
|
194
285
|
}
|
|
195
286
|
})
|
|
287
|
+
.actions(self => ({
|
|
288
|
+
afterCreate() {
|
|
289
|
+
addDisposer(
|
|
290
|
+
self,
|
|
291
|
+
autorun(async () => {
|
|
292
|
+
try {
|
|
293
|
+
const { rpcManager } = getSession(self)
|
|
294
|
+
const sessionId = getRpcSessionId(self)
|
|
295
|
+
|
|
296
|
+
const results = (await rpcManager.call(
|
|
297
|
+
sessionId,
|
|
298
|
+
'MafGetSamples',
|
|
299
|
+
{
|
|
300
|
+
sessionId,
|
|
301
|
+
adapterConfig: self.adapterConfig,
|
|
302
|
+
statusCallback: (message: string) => {
|
|
303
|
+
if (isAlive(self)) {
|
|
304
|
+
self.setMessage(message)
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
)) as any
|
|
309
|
+
self.setSamples(results)
|
|
310
|
+
} catch (e) {
|
|
311
|
+
console.error(e)
|
|
312
|
+
getSession(self).notifyError(`${e}`, e)
|
|
313
|
+
}
|
|
314
|
+
}),
|
|
315
|
+
)
|
|
316
|
+
},
|
|
317
|
+
}))
|
|
196
318
|
.actions(self => {
|
|
197
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
198
319
|
const { renderSvg: superRenderSvg } = self
|
|
199
320
|
return {
|
|
200
321
|
/**
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { max } from 'd3-array'
|
|
2
|
+
|
|
3
|
+
import type { HierarchyNode } from 'd3-hierarchy'
|
|
4
|
+
|
|
5
|
+
export interface NodeWithIds {
|
|
6
|
+
id: string
|
|
7
|
+
name: string
|
|
8
|
+
children: NodeWithIds[]
|
|
9
|
+
length?: number
|
|
10
|
+
noTree?: boolean
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface NodeWithIdsAndLength {
|
|
14
|
+
id: string
|
|
15
|
+
name: string
|
|
16
|
+
children: NodeWithIdsAndLength[]
|
|
17
|
+
noTree?: boolean
|
|
18
|
+
length: number
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// basically same as maxLength from https://observablehq.com/@d3/tree-of-life
|
|
22
|
+
export function maxLength(d: HierarchyNode<NodeWithIds>): number {
|
|
23
|
+
return (
|
|
24
|
+
(d.data.length || 0) + (d.children ? max(d.children, maxLength) || 0 : 0)
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
// basically same as setRadius from https://observablehq.com/@d3/tree-of-life
|
|
28
|
+
export function setBrLength(
|
|
29
|
+
d: HierarchyNode<NodeWithIds>,
|
|
30
|
+
y0: number,
|
|
31
|
+
k: number,
|
|
32
|
+
) {
|
|
33
|
+
// @ts-expect-error
|
|
34
|
+
d.len = (y0 += Math.max(d.data.length || 0, 0)) * k
|
|
35
|
+
|
|
36
|
+
if (d.children) {
|
|
37
|
+
d.children.forEach(d => {
|
|
38
|
+
setBrLength(d, y0, k)
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
featureSpanPx,
|
|
8
8
|
renderToAbstractCanvas,
|
|
9
9
|
} from '@jbrowse/core/util'
|
|
10
|
+
|
|
10
11
|
import { getColorBaseMap, getContrastBaseMap } from './util'
|
|
11
12
|
|
|
12
13
|
interface Sample {
|
|
@@ -39,7 +40,7 @@ function makeImageData({
|
|
|
39
40
|
rowProportion,
|
|
40
41
|
features,
|
|
41
42
|
} = renderArgs
|
|
42
|
-
const
|
|
43
|
+
const region = regions[0]!
|
|
43
44
|
const h = rowHeight * rowProportion
|
|
44
45
|
const theme = createJBrowseTheme(configTheme)
|
|
45
46
|
const colorForBase = getColorBaseMap(theme)
|
|
@@ -64,7 +65,7 @@ function makeImageData({
|
|
|
64
65
|
|
|
65
66
|
const row = sampleToRowMap.get(sample)
|
|
66
67
|
if (row === undefined) {
|
|
67
|
-
|
|
68
|
+
continue
|
|
68
69
|
}
|
|
69
70
|
|
|
70
71
|
const t = rowHeight * row
|
|
@@ -107,7 +108,7 @@ function makeImageData({
|
|
|
107
108
|
if (seq[i] !== '-') {
|
|
108
109
|
if (c !== '-') {
|
|
109
110
|
const l = leftPx + scale * o
|
|
110
|
-
if (seq[i] !== c) {
|
|
111
|
+
if (seq[i] !== c && c !== ' ') {
|
|
111
112
|
ctx.fillStyle = mismatchRendering
|
|
112
113
|
? // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
113
114
|
(colorForBase[c as keyof typeof colorForBase] ?? 'black')
|
|
@@ -132,10 +133,12 @@ function makeImageData({
|
|
|
132
133
|
if (seq[i] !== '-') {
|
|
133
134
|
const l = leftPx + scale * o
|
|
134
135
|
const offset = (scale - charSizeW) / 2 + 1
|
|
135
|
-
const c = alignment[i]
|
|
136
|
+
const c = alignment[i]!
|
|
136
137
|
if ((showAllLetters || seq[i] !== c) && c !== '-') {
|
|
137
|
-
ctx.fillStyle =
|
|
138
|
-
|
|
138
|
+
ctx.fillStyle = mismatchRendering
|
|
139
|
+
? (contrastForBase[c] ?? 'white')
|
|
140
|
+
: 'black'
|
|
141
|
+
ctx.fillText(origAlignment[i] || '', l + offset, hp2 + t + 3)
|
|
139
142
|
}
|
|
140
143
|
o++
|
|
141
144
|
}
|
|
@@ -156,7 +159,7 @@ function makeImageData({
|
|
|
156
159
|
const alignment = origAlignment.toLowerCase()
|
|
157
160
|
const row = sampleToRowMap.get(sample)
|
|
158
161
|
if (row === undefined) {
|
|
159
|
-
|
|
162
|
+
continue
|
|
160
163
|
}
|
|
161
164
|
|
|
162
165
|
const t = rowHeight * row
|
|
@@ -166,7 +169,7 @@ function makeImageData({
|
|
|
166
169
|
for (let i = 0, o = 0; i < alignment.length; i++) {
|
|
167
170
|
let ins = ''
|
|
168
171
|
while (seq[i] === '-') {
|
|
169
|
-
if (alignment[i] !== '-') {
|
|
172
|
+
if (alignment[i] !== '-' && alignment[i] !== ' ') {
|
|
170
173
|
ins += alignment[i]
|
|
171
174
|
}
|
|
172
175
|
i++
|
|
@@ -197,8 +200,8 @@ export default class LinearMafRenderer extends FeatureRendererType {
|
|
|
197
200
|
}
|
|
198
201
|
async render(renderProps: RenderArgs) {
|
|
199
202
|
const { regions, bpPerPx, samples, rowHeight } = renderProps
|
|
200
|
-
const
|
|
201
|
-
const height = samples.length * rowHeight + 100
|
|
203
|
+
const region = regions[0]!
|
|
204
|
+
const height = samples.length * (rowHeight + 1) + 100
|
|
202
205
|
const width = (region.end - region.start) / bpPerPx
|
|
203
206
|
const features = await this.getFeatures(renderProps)
|
|
204
207
|
const res = await renderToAbstractCanvas(
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import PluginManager from '@jbrowse/core/PluginManager'
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
import LinearMafRenderer from './LinearMafRenderer'
|
|
4
4
|
import ReactComponent from './components/ReactComponent'
|
|
5
|
+
import configSchema from './configSchema'
|
|
5
6
|
|
|
6
7
|
export default function LinearMafRendererF(pluginManager: PluginManager) {
|
|
7
8
|
pluginManager.addRendererType(
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
import React, { useState } from 'react'
|
|
2
|
+
|
|
3
|
+
import { ErrorMessage, FileSelector } from '@jbrowse/core/ui'
|
|
4
|
+
import {
|
|
5
|
+
FileLocation,
|
|
6
|
+
getSession,
|
|
7
|
+
isSessionModelWithWidgets,
|
|
8
|
+
isSessionWithAddTracks,
|
|
9
|
+
} from '@jbrowse/core/util'
|
|
10
|
+
import { AddTrackModel } from '@jbrowse/plugin-data-management'
|
|
2
11
|
import {
|
|
3
12
|
Button,
|
|
4
13
|
FormControl,
|
|
@@ -9,16 +18,8 @@ import {
|
|
|
9
18
|
RadioGroup,
|
|
10
19
|
TextField,
|
|
11
20
|
} 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
21
|
import { getRoot } from 'mobx-state-tree'
|
|
22
|
+
import { makeStyles } from 'tss-react/mui'
|
|
22
23
|
|
|
23
24
|
const useStyles = makeStyles()(theme => ({
|
|
24
25
|
textbox: {
|
|
@@ -35,15 +36,24 @@ const useStyles = makeStyles()(theme => ({
|
|
|
35
36
|
},
|
|
36
37
|
}))
|
|
37
38
|
|
|
39
|
+
type AdapterTypeOptions =
|
|
40
|
+
| 'BigMafAdapter'
|
|
41
|
+
| 'MafTabixAdapter'
|
|
42
|
+
| 'BgzipTaffyAdapter'
|
|
43
|
+
type IndexTypeOptions = 'TBI' | 'CSI'
|
|
44
|
+
|
|
38
45
|
export default function MultiMAFWidget({ model }: { model: AddTrackModel }) {
|
|
39
46
|
const { classes } = useStyles()
|
|
40
47
|
const [samples, setSamples] = useState('')
|
|
41
48
|
const [loc, setLoc] = useState<FileLocation>()
|
|
42
49
|
const [indexLoc, setIndexLoc] = useState<FileLocation>()
|
|
50
|
+
const [nhLoc, setNhLoc] = useState<FileLocation>()
|
|
43
51
|
const [error, setError] = useState<unknown>()
|
|
44
52
|
const [trackName, setTrackName] = useState('MAF track')
|
|
45
|
-
const [fileTypeChoice, setFileTypeChoice] =
|
|
46
|
-
|
|
53
|
+
const [fileTypeChoice, setFileTypeChoice] =
|
|
54
|
+
useState<AdapterTypeOptions>('BigMafAdapter')
|
|
55
|
+
const [indexTypeChoice, setIndexTypeChoice] =
|
|
56
|
+
useState<IndexTypeOptions>('TBI')
|
|
47
57
|
|
|
48
58
|
const rootModel = getRoot<any>(model)
|
|
49
59
|
return (
|
|
@@ -55,21 +65,19 @@ export default function MultiMAFWidget({ model }: { model: AddTrackModel }) {
|
|
|
55
65
|
<RadioGroup
|
|
56
66
|
value={fileTypeChoice}
|
|
57
67
|
onChange={event => {
|
|
58
|
-
setFileTypeChoice(event.target.value)
|
|
68
|
+
setFileTypeChoice(event.target.value as AdapterTypeOptions)
|
|
59
69
|
}}
|
|
60
70
|
>
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
label="mafTabix"
|
|
72
|
-
/>
|
|
71
|
+
{['BigMafAdapter', 'MafTabixAdapter', 'BgzipTaffyAdapter'].map(
|
|
72
|
+
r => (
|
|
73
|
+
<FormControlLabel
|
|
74
|
+
value={r}
|
|
75
|
+
control={<Radio />}
|
|
76
|
+
checked={fileTypeChoice === r}
|
|
77
|
+
label={r}
|
|
78
|
+
/>
|
|
79
|
+
),
|
|
80
|
+
)}
|
|
73
81
|
</RadioGroup>
|
|
74
82
|
</FormControl>
|
|
75
83
|
{fileTypeChoice === 'BigMafAdapter' ? (
|
|
@@ -81,62 +89,88 @@ export default function MultiMAFWidget({ model }: { model: AddTrackModel }) {
|
|
|
81
89
|
setLoc(arg)
|
|
82
90
|
}}
|
|
83
91
|
/>
|
|
84
|
-
) : (
|
|
92
|
+
) : fileTypeChoice === 'MafTabixAdapter' ? (
|
|
85
93
|
<>
|
|
86
94
|
<FormControl>
|
|
87
95
|
<FormLabel>Index type</FormLabel>
|
|
88
96
|
<RadioGroup
|
|
89
97
|
value={fileTypeChoice}
|
|
90
98
|
onChange={event => {
|
|
91
|
-
setIndexTypeChoice(event.target.value)
|
|
99
|
+
setIndexTypeChoice(event.target.value as IndexTypeOptions)
|
|
92
100
|
}}
|
|
93
101
|
>
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
control={<Radio />}
|
|
103
|
-
checked={indexTypeChoice === 'CSI'}
|
|
104
|
-
label="CSI"
|
|
105
|
-
/>
|
|
102
|
+
{['TBI', 'CSI'].map(r => (
|
|
103
|
+
<FormControlLabel
|
|
104
|
+
value={r}
|
|
105
|
+
control={<Radio />}
|
|
106
|
+
checked={fileTypeChoice === r}
|
|
107
|
+
label={r}
|
|
108
|
+
/>
|
|
109
|
+
))}
|
|
106
110
|
</RadioGroup>
|
|
107
111
|
</FormControl>
|
|
108
112
|
<FileSelector
|
|
109
113
|
location={loc}
|
|
110
114
|
name="Path to MAF tabix"
|
|
115
|
+
rootModel={rootModel}
|
|
111
116
|
setLocation={arg => {
|
|
112
117
|
setLoc(arg)
|
|
113
118
|
}}
|
|
114
|
-
rootModel={rootModel}
|
|
115
119
|
/>
|
|
116
120
|
<FileSelector
|
|
117
121
|
location={indexLoc}
|
|
118
122
|
name="Path to MAF tabix index"
|
|
123
|
+
rootModel={rootModel}
|
|
119
124
|
setLocation={arg => {
|
|
120
125
|
setIndexLoc(arg)
|
|
121
126
|
}}
|
|
127
|
+
/>
|
|
128
|
+
</>
|
|
129
|
+
) : (
|
|
130
|
+
<>
|
|
131
|
+
<FileSelector
|
|
132
|
+
location={loc}
|
|
133
|
+
name="Path to TAF.gz (Bgzipped TAF)"
|
|
134
|
+
rootModel={rootModel}
|
|
135
|
+
setLocation={arg => {
|
|
136
|
+
setLoc(arg)
|
|
137
|
+
}}
|
|
138
|
+
/>
|
|
139
|
+
<FileSelector
|
|
140
|
+
location={indexLoc}
|
|
141
|
+
name="Path to TAF.gz.tai (TAF index)"
|
|
122
142
|
rootModel={rootModel}
|
|
143
|
+
setLocation={arg => {
|
|
144
|
+
setIndexLoc(arg)
|
|
145
|
+
}}
|
|
123
146
|
/>
|
|
124
147
|
</>
|
|
125
148
|
)}
|
|
126
149
|
</Paper>
|
|
127
|
-
<
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
150
|
+
<div>
|
|
151
|
+
<FileSelector
|
|
152
|
+
location={nhLoc}
|
|
153
|
+
name="Path to newick tree (.nh)"
|
|
154
|
+
rootModel={rootModel}
|
|
155
|
+
setLocation={arg => {
|
|
156
|
+
setNhLoc(arg)
|
|
157
|
+
}}
|
|
158
|
+
/>
|
|
159
|
+
<TextField
|
|
160
|
+
multiline
|
|
161
|
+
rows={10}
|
|
162
|
+
value={samples}
|
|
163
|
+
onChange={event => {
|
|
164
|
+
setSamples(event.target.value)
|
|
165
|
+
}}
|
|
166
|
+
helperText="Sample names (optional if .nh supplied, required if not)"
|
|
167
|
+
placeholder={
|
|
168
|
+
'Enter sample names from the MAF file, one per line, or JSON formatted array of samples'
|
|
169
|
+
}
|
|
170
|
+
variant="outlined"
|
|
171
|
+
fullWidth
|
|
172
|
+
/>
|
|
173
|
+
</div>
|
|
140
174
|
|
|
141
175
|
<TextField
|
|
142
176
|
value={trackName}
|
|
@@ -172,19 +206,29 @@ export default function MultiMAFWidget({ model }: { model: AddTrackModel }) {
|
|
|
172
206
|
adapter:
|
|
173
207
|
fileTypeChoice === 'BigMafAdapter'
|
|
174
208
|
? {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
209
|
+
type: fileTypeChoice,
|
|
210
|
+
bigBedLocation: loc,
|
|
211
|
+
samples: sampleNames,
|
|
212
|
+
nhLocation: nhLoc,
|
|
213
|
+
}
|
|
214
|
+
: fileTypeChoice === 'MafTabixAdapter'
|
|
215
|
+
? {
|
|
216
|
+
type: fileTypeChoice,
|
|
217
|
+
bedGzLocation: loc,
|
|
218
|
+
nhLocation: nhLoc,
|
|
219
|
+
index: {
|
|
220
|
+
indexType: indexTypeChoice,
|
|
221
|
+
location: indexLoc,
|
|
222
|
+
},
|
|
223
|
+
samples: sampleNames,
|
|
224
|
+
}
|
|
225
|
+
: {
|
|
226
|
+
type: fileTypeChoice,
|
|
227
|
+
tafGzLocation: loc,
|
|
228
|
+
taiLocation: indexLoc,
|
|
229
|
+
nhLocation: nhLoc,
|
|
230
|
+
samples: sampleNames,
|
|
231
|
+
},
|
|
188
232
|
})
|
|
189
233
|
|
|
190
234
|
model.view?.showTrack(trackId)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { getAdapter } from '@jbrowse/core/data_adapters/dataAdapterCache'
|
|
2
|
+
import RpcMethodTypeWithFiltersAndRenameRegions from '@jbrowse/core/pluggableElementTypes/RpcMethodTypeWithFiltersAndRenameRegions'
|
|
3
|
+
|
|
4
|
+
import type PluginManager from '@jbrowse/core/PluginManager'
|
|
5
|
+
import type { AnyConfigurationModel } from '@jbrowse/core/configuration'
|
|
6
|
+
import type { Region } from '@jbrowse/core/util'
|
|
7
|
+
|
|
8
|
+
export class MafGetSamples extends RpcMethodTypeWithFiltersAndRenameRegions {
|
|
9
|
+
name = 'MafGetSamples'
|
|
10
|
+
|
|
11
|
+
async execute(
|
|
12
|
+
args: {
|
|
13
|
+
adapterConfig: AnyConfigurationModel
|
|
14
|
+
stopToken?: string
|
|
15
|
+
sessionId: string
|
|
16
|
+
headers?: Record<string, string>
|
|
17
|
+
regions: Region[]
|
|
18
|
+
bpPerPx: number
|
|
19
|
+
},
|
|
20
|
+
rpcDriverClassName: string,
|
|
21
|
+
) {
|
|
22
|
+
const pm = this.pluginManager
|
|
23
|
+
const deserializedArgs = await this.deserializeArguments(
|
|
24
|
+
args,
|
|
25
|
+
rpcDriverClassName,
|
|
26
|
+
)
|
|
27
|
+
const { regions, adapterConfig, sessionId } = deserializedArgs
|
|
28
|
+
const { dataAdapter } = await getAdapter(pm, sessionId, adapterConfig)
|
|
29
|
+
|
|
30
|
+
// @ts-expect-error
|
|
31
|
+
return dataAdapter.getSamples(regions, deserializedArgs)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default function MafRPCF(pluginManager: PluginManager) {
|
|
36
|
+
pluginManager.addRpcMethod(() => {
|
|
37
|
+
return new MafGetSamples(pluginManager)
|
|
38
|
+
})
|
|
39
|
+
}
|