react-msaview 3.1.11 → 3.2.0
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/bundle/index.js +32 -31
- package/dist/colorSchemes.d.ts +2 -2
- package/dist/colorSchemes.js +3 -4
- package/dist/colorSchemes.js.map +1 -1
- package/dist/components/Loading.d.ts +1 -1
- package/dist/components/Loading.js +4 -4
- package/dist/components/Loading.js.map +1 -1
- package/dist/components/MSAView.d.ts +1 -1
- package/dist/components/MSAView.js +13 -9
- package/dist/components/MSAView.js.map +1 -1
- package/dist/components/ResizeHandles.d.ts +1 -1
- package/dist/components/ResizeHandles.js +2 -2
- package/dist/components/SequenceTextArea.js +4 -0
- package/dist/components/SequenceTextArea.js.map +1 -1
- package/dist/components/TextTrack.d.ts +1 -1
- package/dist/components/Track.d.ts +1 -1
- package/dist/components/VerticalScrollbar.d.ts +6 -0
- package/dist/components/VerticalScrollbar.js +65 -0
- package/dist/components/VerticalScrollbar.js.map +1 -0
- package/dist/components/dialogs/AddTrackDialog.d.ts +1 -1
- package/dist/components/dialogs/DomainDialog.d.ts +6 -0
- package/dist/components/dialogs/DomainDialog.js +19 -0
- package/dist/components/dialogs/DomainDialog.js.map +1 -0
- package/dist/components/dialogs/ExportSVGDialog.d.ts +1 -1
- package/dist/components/dialogs/FeatureDialog.d.ts +1 -1
- package/dist/components/dialogs/FeatureDialog.js.map +1 -1
- package/dist/components/dialogs/InterProScanDialog.d.ts +4 -4
- package/dist/components/dialogs/InterProScanDialog.js +37 -8
- package/dist/components/dialogs/InterProScanDialog.js.map +1 -1
- package/dist/components/dialogs/MetadataDialog.d.ts +1 -1
- package/dist/components/dialogs/SettingsDialog.d.ts +1 -1
- package/dist/components/dialogs/SettingsDialog.js +10 -1
- package/dist/components/dialogs/SettingsDialog.js.map +1 -1
- package/dist/components/dialogs/TabPanel.d.ts +6 -0
- package/dist/components/dialogs/TabPanel.js +6 -0
- package/dist/components/dialogs/TabPanel.js.map +1 -0
- package/dist/components/dialogs/TracklistDialog.d.ts +1 -1
- package/dist/components/dialogs/UserProvidedDomainsDialog.d.ts +7 -0
- package/dist/components/dialogs/UserProvidedDomainsDialog.js +58 -0
- package/dist/components/dialogs/UserProvidedDomainsDialog.js.map +1 -0
- package/dist/components/header/Header.d.ts +1 -1
- package/dist/components/header/Header.js +8 -5
- package/dist/components/header/Header.js.map +1 -1
- package/dist/components/header/HeaderInfoArea.d.ts +1 -1
- package/dist/components/header/HeaderMenu.d.ts +1 -1
- package/dist/components/header/HeaderMenuExtra.d.ts +1 -1
- package/dist/components/header/HeaderMenuExtra.js +54 -41
- package/dist/components/header/HeaderMenuExtra.js.map +1 -1
- package/dist/components/header/HeaderStatusArea.d.ts +1 -1
- package/dist/components/header/HeaderStatusArea.js +2 -1
- package/dist/components/header/HeaderStatusArea.js.map +1 -1
- package/dist/components/header/MultiAlignmentSelector.d.ts +1 -1
- package/dist/components/header/ZoomControls.js +31 -1
- package/dist/components/header/ZoomControls.js.map +1 -1
- package/dist/components/import/ImportForm.d.ts +1 -1
- package/dist/components/import/ImportForm.js +1 -1
- package/dist/components/import/ImportForm.js.map +1 -1
- package/dist/components/import/ImportFormExamples.d.ts +1 -1
- package/dist/components/import/ImportFormExamples.js +10 -8
- package/dist/components/import/ImportFormExamples.js.map +1 -1
- package/dist/components/import/util.d.ts +2 -2
- package/dist/components/minimap/Minimap.d.ts +1 -1
- package/dist/components/minimap/Minimap.js +14 -15
- package/dist/components/minimap/Minimap.js.map +1 -1
- package/dist/components/minimap/MinimapSVG.d.ts +1 -1
- package/dist/components/minimap/MinimapSVG.js +1 -1
- package/dist/components/minimap/MinimapSVG.js.map +1 -1
- package/dist/components/msa/MSACanvas.d.ts +1 -1
- package/dist/components/msa/MSACanvas.js +3 -3
- package/dist/components/msa/MSACanvas.js.map +1 -1
- package/dist/components/msa/MSACanvasBlock.d.ts +3 -3
- package/dist/components/msa/MSACanvasBlock.js +4 -3
- package/dist/components/msa/MSACanvasBlock.js.map +1 -1
- package/dist/components/msa/MSAMouseoverCanvas.d.ts +2 -2
- package/dist/components/msa/MSAMouseoverCanvas.js +1 -1
- package/dist/components/msa/MSAMouseoverCanvas.js.map +1 -1
- package/dist/components/msa/MSAPanel.d.ts +1 -1
- package/dist/components/msa/renderBoxFeatureCanvasBlock.d.ts +1 -1
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js +2 -3
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js.map +1 -1
- package/dist/components/msa/renderMSABlock.d.ts +2 -2
- package/dist/components/msa/renderMSABlock.js +12 -12
- package/dist/components/msa/renderMSABlock.js.map +1 -1
- package/dist/components/msa/renderMSAMouseover.d.ts +1 -1
- package/dist/components/tree/TreeBranchMenu.d.ts +1 -1
- package/dist/components/tree/TreeCanvas.d.ts +1 -1
- package/dist/components/tree/TreeCanvas.js +13 -12
- package/dist/components/tree/TreeCanvas.js.map +1 -1
- package/dist/components/tree/TreeCanvasBlock.d.ts +1 -1
- package/dist/components/tree/TreeCanvasBlock.js +2 -1
- package/dist/components/tree/TreeCanvasBlock.js.map +1 -1
- package/dist/components/tree/TreeNodeMenu.d.ts +1 -1
- package/dist/components/tree/TreeNodeMenu.js +2 -2
- package/dist/components/tree/TreeNodeMenu.js.map +1 -1
- package/dist/components/tree/TreePanel.d.ts +1 -1
- package/dist/components/tree/TreeRuler.d.ts +1 -1
- package/dist/components/tree/dialogs/TreeNodeInfoDialog.d.ts +1 -1
- package/dist/components/tree/renderTreeCanvas.d.ts +3 -3
- package/dist/components/tree/renderTreeCanvas.js +25 -9
- package/dist/components/tree/renderTreeCanvas.js.map +1 -1
- package/dist/components/util.js +1 -1
- package/dist/components/util.js.map +1 -1
- package/dist/fetchUtils.d.ts +1 -1
- package/dist/fetchUtils.js.map +1 -1
- package/dist/launchInterProScan.d.ts +9 -3
- package/dist/launchInterProScan.js +57 -22
- package/dist/launchInterProScan.js.map +1 -1
- package/dist/model/DataModel.d.ts +5 -1
- package/dist/model/DataModel.js +10 -1
- package/dist/model/DataModel.js.map +1 -1
- package/dist/model/DialogQueue.d.ts +1 -1
- package/dist/model.d.ts +138 -43
- package/dist/model.js +235 -110
- package/dist/model.js.map +1 -1
- package/dist/parseNewick.js +1 -1
- package/dist/parseNewick.js.map +1 -1
- package/dist/parsers/ClustalMSA.d.ts +1 -1
- package/dist/parsers/FastaMSA.d.ts +1 -1
- package/dist/parsers/StockholmMSA.d.ts +1 -1
- package/dist/parsers/StockholmMSA.js.map +1 -1
- package/dist/renderToSvg.d.ts +2 -2
- package/dist/renderToSvg.js +3 -28
- package/dist/renderToSvg.js.map +1 -1
- package/dist/reparseTree.d.ts +1 -1
- package/dist/util.d.ts +2 -2
- package/dist/util.js +0 -2
- package/dist/util.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +5 -2
- package/src/colorSchemes.ts +3 -2
- package/src/components/Checkbox2.tsx +1 -1
- package/src/components/Loading.tsx +11 -5
- package/src/components/MSAView.tsx +27 -18
- package/src/components/ResizeHandles.tsx +3 -3
- package/src/components/SequenceTextArea.tsx +8 -0
- package/src/components/TextTrack.tsx +1 -1
- package/src/components/Track.tsx +1 -1
- package/src/components/VerticalScrollbar.tsx +85 -0
- package/src/components/dialogs/AddTrackDialog.tsx +2 -2
- package/src/components/dialogs/DomainDialog.tsx +38 -0
- package/src/components/dialogs/ExportSVGDialog.tsx +1 -1
- package/src/components/dialogs/FeatureDialog.tsx +3 -3
- package/src/components/dialogs/InterProScanDialog.tsx +49 -11
- package/src/components/dialogs/MetadataDialog.tsx +1 -1
- package/src/components/dialogs/SettingsDialog.tsx +38 -3
- package/src/components/dialogs/TabPanel.tsx +19 -0
- package/src/components/dialogs/TracklistDialog.tsx +1 -1
- package/src/components/dialogs/UserProvidedDomainsDialog.tsx +133 -0
- package/src/components/header/Header.tsx +9 -6
- package/src/components/header/HeaderInfoArea.tsx +1 -1
- package/src/components/header/HeaderMenu.tsx +1 -1
- package/src/components/header/HeaderMenuExtra.tsx +65 -48
- package/src/components/header/HeaderStatusArea.tsx +3 -2
- package/src/components/header/MultiAlignmentSelector.tsx +1 -1
- package/src/components/header/ZoomControls.tsx +34 -0
- package/src/components/import/ImportForm.tsx +3 -3
- package/src/components/import/ImportFormExamples.tsx +19 -17
- package/src/components/import/util.ts +2 -2
- package/src/components/minimap/Minimap.tsx +15 -22
- package/src/components/minimap/MinimapSVG.tsx +2 -2
- package/src/components/msa/MSACanvas.tsx +11 -4
- package/src/components/msa/MSACanvasBlock.tsx +5 -4
- package/src/components/msa/MSAMouseoverCanvas.tsx +2 -6
- package/src/components/msa/MSAPanel.tsx +1 -1
- package/src/components/msa/renderBoxFeatureCanvasBlock.ts +5 -6
- package/src/components/msa/renderMSABlock.ts +37 -17
- package/src/components/msa/renderMSAMouseover.ts +1 -1
- package/src/components/tree/TreeBranchMenu.tsx +1 -1
- package/src/components/tree/TreeCanvas.tsx +15 -16
- package/src/components/tree/TreeCanvasBlock.tsx +3 -2
- package/src/components/tree/TreeNodeMenu.tsx +3 -3
- package/src/components/tree/TreePanel.tsx +1 -1
- package/src/components/tree/TreeRuler.tsx +1 -1
- package/src/components/tree/dialogs/TreeNodeInfoDialog.tsx +1 -1
- package/src/components/tree/renderTreeCanvas.ts +32 -12
- package/src/components/util.ts +1 -1
- package/src/fetchUtils.ts +2 -2
- package/src/launchInterProScan.ts +69 -24
- package/src/model/DataModel.ts +10 -0
- package/src/model/DialogQueue.ts +1 -1
- package/src/model.ts +262 -143
- package/src/parseNewick.ts +1 -1
- package/src/parsers/ClustalMSA.ts +1 -1
- package/src/parsers/FastaMSA.ts +1 -1
- package/src/parsers/StockholmMSA.ts +1 -1
- package/src/renderToSvg.tsx +6 -30
- package/src/reparseTree.ts +1 -1
- package/src/util.ts +2 -4
- package/src/version.ts +1 -1
package/src/model.ts
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
+
import type { Buffer } from 'buffer'
|
|
2
3
|
import { autorun, transaction } from 'mobx'
|
|
3
|
-
import { Instance, cast, types, addDisposer } from 'mobx-state-tree'
|
|
4
|
-
import { hierarchy, cluster, HierarchyNode } from 'd3-hierarchy'
|
|
4
|
+
import { type Instance, cast, types, addDisposer } from 'mobx-state-tree'
|
|
5
|
+
import { hierarchy, cluster, type HierarchyNode } from 'd3-hierarchy'
|
|
5
6
|
import { ascending } from 'd3-array'
|
|
6
7
|
import Stockholm from 'stockholm-js'
|
|
7
8
|
import { saveAs } from 'file-saver'
|
|
8
|
-
import { Theme } from '@mui/material'
|
|
9
|
+
import type { Theme } from '@mui/material'
|
|
10
|
+
import { ungzip } from 'pako'
|
|
9
11
|
|
|
10
12
|
// jbrowse
|
|
11
13
|
import { FileLocation, ElementId } from '@jbrowse/core/util/types/mst'
|
|
12
|
-
import { FileLocation as FileLocationType } from '@jbrowse/core/util/types'
|
|
14
|
+
import type { FileLocation as FileLocationType } from '@jbrowse/core/util/types'
|
|
13
15
|
import { openLocation } from '@jbrowse/core/util/io'
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
sum,
|
|
20
|
-
} from '@jbrowse/core/util'
|
|
16
|
+
import { groupBy, notEmpty, sum } from '@jbrowse/core/util'
|
|
17
|
+
|
|
18
|
+
export function isGzip(buf: Buffer) {
|
|
19
|
+
return buf[0] === 31 && buf[1] === 139 && buf[2] === 8
|
|
20
|
+
}
|
|
21
21
|
|
|
22
22
|
// locals
|
|
23
23
|
import {
|
|
@@ -27,8 +27,8 @@ import {
|
|
|
27
27
|
maxLength,
|
|
28
28
|
setBrLength,
|
|
29
29
|
skipBlanks,
|
|
30
|
-
NodeWithIds,
|
|
31
|
-
NodeWithIdsAndLength,
|
|
30
|
+
type NodeWithIds,
|
|
31
|
+
type NodeWithIdsAndLength,
|
|
32
32
|
len,
|
|
33
33
|
} from './util'
|
|
34
34
|
import { colord } from 'colord'
|
|
@@ -52,11 +52,7 @@ import { DataModelF } from './model/DataModel'
|
|
|
52
52
|
import { DialogQueueSessionMixin } from './model/DialogQueue'
|
|
53
53
|
import { TreeF } from './model/treeModel'
|
|
54
54
|
import { MSAModelF } from './model/msaModel'
|
|
55
|
-
import {
|
|
56
|
-
InterProScanResults,
|
|
57
|
-
launchInterProScan,
|
|
58
|
-
loadInterProScanResults,
|
|
59
|
-
} from './launchInterProScan'
|
|
55
|
+
import type { InterProScanResults } from './launchInterProScan'
|
|
60
56
|
|
|
61
57
|
export interface Accession {
|
|
62
58
|
accession: string
|
|
@@ -102,10 +98,20 @@ function stateModelFactory() {
|
|
|
102
98
|
* id of view, randomly generated if not provided
|
|
103
99
|
*/
|
|
104
100
|
id: ElementId,
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* #property
|
|
104
|
+
*/
|
|
105
|
+
showDomains: false,
|
|
106
|
+
/**
|
|
107
|
+
* #property
|
|
108
|
+
*/
|
|
109
|
+
allowedGappyness: 100,
|
|
105
110
|
/**
|
|
106
111
|
* #property
|
|
107
112
|
*/
|
|
108
|
-
|
|
113
|
+
contrastLettering: true,
|
|
114
|
+
|
|
109
115
|
/**
|
|
110
116
|
* #property
|
|
111
117
|
*/
|
|
@@ -117,6 +123,20 @@ function stateModelFactory() {
|
|
|
117
123
|
*/
|
|
118
124
|
type: types.literal('MsaView'),
|
|
119
125
|
|
|
126
|
+
/**
|
|
127
|
+
* #property
|
|
128
|
+
*/
|
|
129
|
+
drawMsaLetters: true,
|
|
130
|
+
/**
|
|
131
|
+
* #property
|
|
132
|
+
*/
|
|
133
|
+
hideGaps: true,
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* #property
|
|
137
|
+
*/
|
|
138
|
+
drawTreeText: true,
|
|
139
|
+
|
|
120
140
|
/**
|
|
121
141
|
* #property
|
|
122
142
|
* height of the div containing the view, px
|
|
@@ -174,15 +194,17 @@ function stateModelFactory() {
|
|
|
174
194
|
|
|
175
195
|
/**
|
|
176
196
|
* #property
|
|
177
|
-
* array of tree parent nodes that are 'collapsed'
|
|
197
|
+
* array of tree parent nodes that are 'collapsed' (all children are
|
|
198
|
+
* hidden)
|
|
178
199
|
*/
|
|
179
200
|
collapsed: types.array(types.string),
|
|
180
201
|
|
|
181
202
|
/**
|
|
182
203
|
* #property
|
|
183
|
-
* array of tree leaf nodes that are 'collapsed'
|
|
204
|
+
* array of tree leaf nodes that are 'collapsed' (just that leaf node
|
|
205
|
+
* is hidden)
|
|
184
206
|
*/
|
|
185
|
-
|
|
207
|
+
collapsedLeaves: types.array(types.string),
|
|
186
208
|
/**
|
|
187
209
|
* #property
|
|
188
210
|
* focus on particular subtree
|
|
@@ -200,6 +222,7 @@ function stateModelFactory() {
|
|
|
200
222
|
* autorun
|
|
201
223
|
*/
|
|
202
224
|
data: types.optional(DataModelF(), { tree: '', msa: '' }),
|
|
225
|
+
|
|
203
226
|
/**
|
|
204
227
|
* #property
|
|
205
228
|
*/
|
|
@@ -207,6 +230,13 @@ function stateModelFactory() {
|
|
|
207
230
|
}),
|
|
208
231
|
)
|
|
209
232
|
.volatile(() => ({
|
|
233
|
+
/**
|
|
234
|
+
* #volatile
|
|
235
|
+
*/
|
|
236
|
+
headerHeight: 0,
|
|
237
|
+
/**
|
|
238
|
+
* #volatile
|
|
239
|
+
*/
|
|
210
240
|
status: undefined as { msg: string; url?: string } | undefined,
|
|
211
241
|
/**
|
|
212
242
|
* #volatile
|
|
@@ -225,7 +255,7 @@ function stateModelFactory() {
|
|
|
225
255
|
/**
|
|
226
256
|
* #volatile
|
|
227
257
|
*/
|
|
228
|
-
|
|
258
|
+
volatileWidth: undefined as number | undefined,
|
|
229
259
|
/**
|
|
230
260
|
* #volatile
|
|
231
261
|
* resize handle width between tree and msa area, px
|
|
@@ -236,7 +266,7 @@ function stateModelFactory() {
|
|
|
236
266
|
* #volatile
|
|
237
267
|
* size of blocks of content to be drawn, px
|
|
238
268
|
*/
|
|
239
|
-
blockSize:
|
|
269
|
+
blockSize: 500,
|
|
240
270
|
|
|
241
271
|
/**
|
|
242
272
|
* #volatile
|
|
@@ -293,17 +323,29 @@ function stateModelFactory() {
|
|
|
293
323
|
* #volatile
|
|
294
324
|
*
|
|
295
325
|
*/
|
|
296
|
-
|
|
326
|
+
interProAnnotations: undefined as
|
|
297
327
|
| undefined
|
|
298
328
|
| Record<string, InterProScanResults>,
|
|
299
|
-
/**
|
|
300
|
-
* #volatile
|
|
301
|
-
*/
|
|
302
|
-
interProScanJobIds: JSON.parse(
|
|
303
|
-
localStorageGetItem('msaview-interproscanqueries') || '[]',
|
|
304
|
-
) as { jobId: string; date: number }[],
|
|
305
329
|
}))
|
|
306
330
|
.actions(self => ({
|
|
331
|
+
/**
|
|
332
|
+
* #action
|
|
333
|
+
*/
|
|
334
|
+
setHideGaps(arg: boolean) {
|
|
335
|
+
self.hideGaps = arg
|
|
336
|
+
},
|
|
337
|
+
/**
|
|
338
|
+
* #action
|
|
339
|
+
*/
|
|
340
|
+
setAllowedGappyness(arg: number) {
|
|
341
|
+
self.allowedGappyness = arg
|
|
342
|
+
},
|
|
343
|
+
/**
|
|
344
|
+
* #action
|
|
345
|
+
*/
|
|
346
|
+
setContrastLettering(arg: boolean) {
|
|
347
|
+
self.contrastLettering = arg
|
|
348
|
+
},
|
|
307
349
|
/**
|
|
308
350
|
* #action
|
|
309
351
|
*/
|
|
@@ -320,7 +362,7 @@ function stateModelFactory() {
|
|
|
320
362
|
* #action
|
|
321
363
|
*/
|
|
322
364
|
setWidth(arg: number) {
|
|
323
|
-
self.
|
|
365
|
+
self.volatileWidth = arg
|
|
324
366
|
},
|
|
325
367
|
/**
|
|
326
368
|
* #action
|
|
@@ -349,8 +391,8 @@ function stateModelFactory() {
|
|
|
349
391
|
/**
|
|
350
392
|
* #action
|
|
351
393
|
*/
|
|
352
|
-
|
|
353
|
-
self.
|
|
394
|
+
setShowDomains(arg: boolean) {
|
|
395
|
+
self.showDomains = arg
|
|
354
396
|
},
|
|
355
397
|
|
|
356
398
|
/**
|
|
@@ -415,10 +457,10 @@ function stateModelFactory() {
|
|
|
415
457
|
* #action
|
|
416
458
|
*/
|
|
417
459
|
toggleCollapsed2(node: string) {
|
|
418
|
-
if (self.
|
|
419
|
-
self.
|
|
460
|
+
if (self.collapsedLeaves.includes(node)) {
|
|
461
|
+
self.collapsedLeaves.remove(node)
|
|
420
462
|
} else {
|
|
421
|
-
self.
|
|
463
|
+
self.collapsedLeaves.push(node)
|
|
422
464
|
}
|
|
423
465
|
},
|
|
424
466
|
/**
|
|
@@ -471,6 +513,29 @@ function stateModelFactory() {
|
|
|
471
513
|
},
|
|
472
514
|
}))
|
|
473
515
|
|
|
516
|
+
.views(self => ({
|
|
517
|
+
/**
|
|
518
|
+
* #getter
|
|
519
|
+
*/
|
|
520
|
+
get actuallyShowDomains() {
|
|
521
|
+
return self.showDomains && !!self.interProAnnotations
|
|
522
|
+
},
|
|
523
|
+
/**
|
|
524
|
+
* #getter
|
|
525
|
+
*/
|
|
526
|
+
get viewInitialized() {
|
|
527
|
+
return self.volatileWidth !== undefined
|
|
528
|
+
},
|
|
529
|
+
/**
|
|
530
|
+
* #getter
|
|
531
|
+
*/
|
|
532
|
+
get width() {
|
|
533
|
+
if (self.volatileWidth === undefined) {
|
|
534
|
+
throw new Error('not initialized')
|
|
535
|
+
}
|
|
536
|
+
return self.volatileWidth
|
|
537
|
+
},
|
|
538
|
+
}))
|
|
474
539
|
.views(self => ({
|
|
475
540
|
/**
|
|
476
541
|
* #method
|
|
@@ -512,13 +577,13 @@ function stateModelFactory() {
|
|
|
512
577
|
* #getter
|
|
513
578
|
*/
|
|
514
579
|
get noTree() {
|
|
515
|
-
return !!this.
|
|
580
|
+
return !!this.tree.noTree
|
|
516
581
|
},
|
|
517
582
|
/**
|
|
518
583
|
* #getter
|
|
519
584
|
*/
|
|
520
|
-
get
|
|
521
|
-
return !self.
|
|
585
|
+
get noDomains() {
|
|
586
|
+
return !self.interProAnnotations
|
|
522
587
|
},
|
|
523
588
|
/**
|
|
524
589
|
* #getter
|
|
@@ -540,11 +605,11 @@ function stateModelFactory() {
|
|
|
540
605
|
if (text) {
|
|
541
606
|
if (Stockholm.sniff(text)) {
|
|
542
607
|
return new StockholmMSA(text, self.currentAlignment)
|
|
543
|
-
}
|
|
608
|
+
}
|
|
609
|
+
if (text.startsWith('>')) {
|
|
544
610
|
return new FastaMSA(text)
|
|
545
|
-
} else {
|
|
546
|
-
return new ClustalMSA(text)
|
|
547
611
|
}
|
|
612
|
+
return new ClustalMSA(text)
|
|
548
613
|
}
|
|
549
614
|
return null
|
|
550
615
|
},
|
|
@@ -558,7 +623,7 @@ function stateModelFactory() {
|
|
|
558
623
|
/**
|
|
559
624
|
* #getter
|
|
560
625
|
*/
|
|
561
|
-
get
|
|
626
|
+
get tree(): NodeWithIds {
|
|
562
627
|
const ret = self.data.tree
|
|
563
628
|
? generateNodeIds(parseNewick(self.data.tree))
|
|
564
629
|
: this.MSA?.getTree() || {
|
|
@@ -573,7 +638,7 @@ function stateModelFactory() {
|
|
|
573
638
|
* #getter
|
|
574
639
|
*/
|
|
575
640
|
get rowNames(): string[] {
|
|
576
|
-
return this.
|
|
641
|
+
return this.leaves.map(n => n.data.name)
|
|
577
642
|
},
|
|
578
643
|
/**
|
|
579
644
|
* #getter
|
|
@@ -587,7 +652,7 @@ function stateModelFactory() {
|
|
|
587
652
|
* #getter
|
|
588
653
|
*/
|
|
589
654
|
get root() {
|
|
590
|
-
let hier = hierarchy(this.
|
|
655
|
+
let hier = hierarchy(this.tree, d => d.branchset)
|
|
591
656
|
.sum(d => (d.branchset ? 0 : 1))
|
|
592
657
|
.sort((a, b) => ascending(a.data.length || 1, b.data.length || 1))
|
|
593
658
|
|
|
@@ -598,7 +663,7 @@ function stateModelFactory() {
|
|
|
598
663
|
}
|
|
599
664
|
}
|
|
600
665
|
|
|
601
|
-
;[...self.collapsed, ...self.
|
|
666
|
+
;[...self.collapsed, ...self.collapsedLeaves]
|
|
602
667
|
.map(collapsedId => hier.find(node => node.data.id === collapsedId))
|
|
603
668
|
.filter(notEmpty)
|
|
604
669
|
.map(node => collapse(node))
|
|
@@ -624,9 +689,9 @@ function stateModelFactory() {
|
|
|
624
689
|
* #getter
|
|
625
690
|
*/
|
|
626
691
|
get blanks() {
|
|
692
|
+
const { allowedGappyness } = self
|
|
627
693
|
const blanks = []
|
|
628
|
-
const strs = this.
|
|
629
|
-
.leaves()
|
|
694
|
+
const strs = this.leaves
|
|
630
695
|
.map(leaf => this.MSA?.getRow(leaf.data.name))
|
|
631
696
|
.filter((item): item is string => !!item)
|
|
632
697
|
|
|
@@ -637,7 +702,7 @@ function stateModelFactory() {
|
|
|
637
702
|
counter++
|
|
638
703
|
}
|
|
639
704
|
}
|
|
640
|
-
if (counter
|
|
705
|
+
if (counter / strs.length >= allowedGappyness / 100) {
|
|
641
706
|
blanks.push(i)
|
|
642
707
|
}
|
|
643
708
|
}
|
|
@@ -648,8 +713,7 @@ function stateModelFactory() {
|
|
|
648
713
|
*/
|
|
649
714
|
get rows() {
|
|
650
715
|
const MSA = this.MSA
|
|
651
|
-
return this.
|
|
652
|
-
.leaves()
|
|
716
|
+
return this.leaves
|
|
653
717
|
.map(leaf => [leaf.data.name, MSA?.getRow(leaf.data.name)] as const)
|
|
654
718
|
.filter((f): f is [string, string] => !!f[1])
|
|
655
719
|
},
|
|
@@ -693,6 +757,17 @@ function stateModelFactory() {
|
|
|
693
757
|
}
|
|
694
758
|
return r
|
|
695
759
|
},
|
|
760
|
+
|
|
761
|
+
/**
|
|
762
|
+
* #getter
|
|
763
|
+
*/
|
|
764
|
+
get colStatsSums() {
|
|
765
|
+
return Object.fromEntries(
|
|
766
|
+
Object.entries(this.colStats).map(([key, val]) => {
|
|
767
|
+
return [key, sum(Object.values(val))]
|
|
768
|
+
}),
|
|
769
|
+
)
|
|
770
|
+
},
|
|
696
771
|
/**
|
|
697
772
|
* #getter
|
|
698
773
|
* generates a new tree that is clustered with x,y positions
|
|
@@ -713,6 +788,13 @@ function stateModelFactory() {
|
|
|
713
788
|
get totalHeight() {
|
|
714
789
|
return this.root.leaves().length * self.rowHeight
|
|
715
790
|
},
|
|
791
|
+
|
|
792
|
+
/**
|
|
793
|
+
* #getter
|
|
794
|
+
*/
|
|
795
|
+
get leaves() {
|
|
796
|
+
return this.hierarchy.leaves()
|
|
797
|
+
},
|
|
716
798
|
}))
|
|
717
799
|
.views(self => ({
|
|
718
800
|
/**
|
|
@@ -727,7 +809,7 @@ function stateModelFactory() {
|
|
|
727
809
|
/**
|
|
728
810
|
* #getter
|
|
729
811
|
*/
|
|
730
|
-
get
|
|
812
|
+
get dataInitialized() {
|
|
731
813
|
return (self.data.msa || self.data.tree) && !self.error
|
|
732
814
|
},
|
|
733
815
|
/**
|
|
@@ -779,29 +861,78 @@ function stateModelFactory() {
|
|
|
779
861
|
get maxScrollX() {
|
|
780
862
|
return -self.totalWidth + (self.msaAreaWidth - 100)
|
|
781
863
|
},
|
|
864
|
+
/**
|
|
865
|
+
* #getter
|
|
866
|
+
*/
|
|
867
|
+
get showMsaLetters() {
|
|
868
|
+
return self.drawMsaLetters && self.rowHeight >= 5
|
|
869
|
+
},
|
|
870
|
+
/**
|
|
871
|
+
* #getter
|
|
872
|
+
*/
|
|
873
|
+
get showTreeText() {
|
|
874
|
+
return self.drawLabels && self.rowHeight >= 5
|
|
875
|
+
},
|
|
782
876
|
}))
|
|
783
877
|
.actions(self => ({
|
|
784
878
|
/**
|
|
785
879
|
* #action
|
|
786
880
|
*/
|
|
787
|
-
|
|
881
|
+
setDrawMsaLetters(arg: boolean) {
|
|
882
|
+
self.drawMsaLetters = arg
|
|
883
|
+
},
|
|
884
|
+
|
|
885
|
+
/**
|
|
886
|
+
* #action
|
|
887
|
+
*/
|
|
888
|
+
zoomOutHorizontal() {
|
|
889
|
+
self.colWidth = Math.max(1, Math.floor(self.colWidth * 0.75))
|
|
890
|
+
self.scrollX = clamp(self.maxScrollX, self.scrollX, 0)
|
|
891
|
+
},
|
|
892
|
+
/**
|
|
893
|
+
* #action
|
|
894
|
+
*/
|
|
895
|
+
zoomInHorizontal() {
|
|
788
896
|
self.colWidth = Math.ceil(self.colWidth * 1.5)
|
|
789
|
-
self.rowHeight = Math.ceil(self.rowHeight * 1.5)
|
|
790
897
|
self.scrollX = clamp(self.maxScrollX, self.scrollX, 0)
|
|
791
898
|
},
|
|
792
899
|
/**
|
|
793
900
|
* #action
|
|
794
901
|
*/
|
|
795
|
-
|
|
796
|
-
self.
|
|
902
|
+
zoomInVertical() {
|
|
903
|
+
self.rowHeight = Math.ceil(self.rowHeight * 1.5)
|
|
904
|
+
},
|
|
905
|
+
/**
|
|
906
|
+
* #action
|
|
907
|
+
*/
|
|
908
|
+
zoomOutVertical() {
|
|
797
909
|
self.rowHeight = Math.max(1.5, Math.floor(self.rowHeight * 0.75))
|
|
798
|
-
self.scrollX = clamp(self.maxScrollX, self.scrollX, 0)
|
|
799
910
|
},
|
|
800
911
|
/**
|
|
801
912
|
* #action
|
|
802
913
|
*/
|
|
803
|
-
|
|
804
|
-
|
|
914
|
+
zoomIn() {
|
|
915
|
+
transaction(() => {
|
|
916
|
+
self.colWidth = Math.ceil(self.colWidth * 1.5)
|
|
917
|
+
self.rowHeight = Math.ceil(self.rowHeight * 1.5)
|
|
918
|
+
self.scrollX = clamp(self.maxScrollX, self.scrollX, 0)
|
|
919
|
+
})
|
|
920
|
+
},
|
|
921
|
+
/**
|
|
922
|
+
* #action
|
|
923
|
+
*/
|
|
924
|
+
zoomOut() {
|
|
925
|
+
transaction(() => {
|
|
926
|
+
self.colWidth = Math.max(1, Math.floor(self.colWidth * 0.75))
|
|
927
|
+
self.rowHeight = Math.max(1.5, Math.floor(self.rowHeight * 0.75))
|
|
928
|
+
self.scrollX = clamp(self.maxScrollX, self.scrollX, 0)
|
|
929
|
+
})
|
|
930
|
+
},
|
|
931
|
+
/**
|
|
932
|
+
* #action
|
|
933
|
+
*/
|
|
934
|
+
setInterProAnnotations(data: Record<string, InterProScanResults>) {
|
|
935
|
+
self.interProAnnotations = data
|
|
805
936
|
},
|
|
806
937
|
|
|
807
938
|
/**
|
|
@@ -835,15 +966,6 @@ function stateModelFactory() {
|
|
|
835
966
|
self.turnedOffTracks.set(id, true)
|
|
836
967
|
}
|
|
837
968
|
},
|
|
838
|
-
/**
|
|
839
|
-
* #action
|
|
840
|
-
*/
|
|
841
|
-
addInterProScanJobId(arg: string) {
|
|
842
|
-
self.interProScanJobIds = [
|
|
843
|
-
...self.interProScanJobIds,
|
|
844
|
-
{ jobId: arg, date: +Date.now() },
|
|
845
|
-
]
|
|
846
|
-
},
|
|
847
969
|
/**
|
|
848
970
|
* #action
|
|
849
971
|
*/
|
|
@@ -857,9 +979,9 @@ function stateModelFactory() {
|
|
|
857
979
|
*/
|
|
858
980
|
get labelsWidth() {
|
|
859
981
|
let x = 0
|
|
860
|
-
const { rowHeight,
|
|
982
|
+
const { rowHeight, leaves, treeMetadata, fontSize } = self
|
|
861
983
|
if (rowHeight > 5) {
|
|
862
|
-
for (const node of
|
|
984
|
+
for (const node of leaves) {
|
|
863
985
|
x = Math.max(
|
|
864
986
|
measureTextCanvas(
|
|
865
987
|
treeMetadata[node.data.name]?.genome || node.data.name,
|
|
@@ -931,6 +1053,13 @@ function stateModelFactory() {
|
|
|
931
1053
|
return this.tracks.filter(f => !self.turnedOffTracks.has(f.model.id))
|
|
932
1054
|
},
|
|
933
1055
|
|
|
1056
|
+
/**
|
|
1057
|
+
* #getter
|
|
1058
|
+
*/
|
|
1059
|
+
get showHorizontalScrollbar() {
|
|
1060
|
+
return self.msaAreaWidth < self.totalWidth
|
|
1061
|
+
},
|
|
1062
|
+
|
|
934
1063
|
/**
|
|
935
1064
|
* #method
|
|
936
1065
|
* return a row-specific sequence coordinate, skipping gaps, given a global
|
|
@@ -982,6 +1111,17 @@ function stateModelFactory() {
|
|
|
982
1111
|
}))
|
|
983
1112
|
|
|
984
1113
|
.views(self => ({
|
|
1114
|
+
/**
|
|
1115
|
+
* #getter
|
|
1116
|
+
* widget width minus the tree area gives the space for the MSA
|
|
1117
|
+
*/
|
|
1118
|
+
get msaAreaHeight() {
|
|
1119
|
+
return (
|
|
1120
|
+
self.height -
|
|
1121
|
+
(self.showHorizontalScrollbar ? self.minimapHeight : 0) -
|
|
1122
|
+
self.headerHeight
|
|
1123
|
+
)
|
|
1124
|
+
},
|
|
985
1125
|
/**
|
|
986
1126
|
* #getter
|
|
987
1127
|
* total height of track area (px)
|
|
@@ -1001,11 +1141,14 @@ function stateModelFactory() {
|
|
|
1001
1141
|
}
|
|
1002
1142
|
return types
|
|
1003
1143
|
},
|
|
1144
|
+
/**
|
|
1145
|
+
* #getter
|
|
1146
|
+
*/
|
|
1004
1147
|
get tidyAnnotations() {
|
|
1005
1148
|
const ret = []
|
|
1006
|
-
const {
|
|
1007
|
-
if (
|
|
1008
|
-
for (const [id, val] of Object.entries(
|
|
1149
|
+
const { interProAnnotations } = self
|
|
1150
|
+
if (interProAnnotations) {
|
|
1151
|
+
for (const [id, val] of Object.entries(interProAnnotations)) {
|
|
1009
1152
|
for (const { signature, locations } of val.matches) {
|
|
1010
1153
|
const { entry } = signature
|
|
1011
1154
|
if (entry) {
|
|
@@ -1042,6 +1185,23 @@ function stateModelFactory() {
|
|
|
1042
1185
|
},
|
|
1043
1186
|
}))
|
|
1044
1187
|
.views(self => ({
|
|
1188
|
+
/**
|
|
1189
|
+
* #getter
|
|
1190
|
+
*/
|
|
1191
|
+
get showVerticalScrollbar() {
|
|
1192
|
+
return self.msaAreaHeight < self.totalHeight
|
|
1193
|
+
},
|
|
1194
|
+
}))
|
|
1195
|
+
.views(self => ({
|
|
1196
|
+
/**
|
|
1197
|
+
* #getter
|
|
1198
|
+
*/
|
|
1199
|
+
get verticalScrollbarWidth() {
|
|
1200
|
+
return self.showVerticalScrollbar ? 20 : 0
|
|
1201
|
+
},
|
|
1202
|
+
/**
|
|
1203
|
+
* #getter
|
|
1204
|
+
*/
|
|
1045
1205
|
get fillPalette() {
|
|
1046
1206
|
const arr = [...self.tidyTypes.keys()]
|
|
1047
1207
|
let i = 0
|
|
@@ -1053,6 +1213,9 @@ function stateModelFactory() {
|
|
|
1053
1213
|
}
|
|
1054
1214
|
return map
|
|
1055
1215
|
},
|
|
1216
|
+
/**
|
|
1217
|
+
* #getter
|
|
1218
|
+
*/
|
|
1056
1219
|
get strokePalette() {
|
|
1057
1220
|
return Object.fromEntries(
|
|
1058
1221
|
Object.entries(this.fillPalette).map(([key, val]) => [
|
|
@@ -1066,49 +1229,20 @@ function stateModelFactory() {
|
|
|
1066
1229
|
/**
|
|
1067
1230
|
* #action
|
|
1068
1231
|
*/
|
|
1069
|
-
|
|
1070
|
-
self.
|
|
1071
|
-
const ret = await loadInterProScanResults(jobId)
|
|
1072
|
-
self.setStatus()
|
|
1073
|
-
self.setLoadedInterProAnnotations(
|
|
1074
|
-
Object.fromEntries(ret.results.map(r => [r.xref[0].id, r])),
|
|
1075
|
-
)
|
|
1076
|
-
},
|
|
1077
|
-
/**
|
|
1078
|
-
* #action
|
|
1079
|
-
*/
|
|
1080
|
-
async queryInterProScan(programs: string[]) {
|
|
1081
|
-
const { rows } = self
|
|
1082
|
-
if (rows.length > 140) {
|
|
1083
|
-
throw new Error('Too many sequences, please run InterProScan offline')
|
|
1084
|
-
}
|
|
1085
|
-
|
|
1086
|
-
const ret = await launchInterProScan({
|
|
1087
|
-
algorithm: 'interproscan',
|
|
1088
|
-
programs: programs,
|
|
1089
|
-
seq: rows
|
|
1090
|
-
.map(row => `>${row[0]}\n${row[1].replaceAll('-', '')}`)
|
|
1091
|
-
.join('\n'),
|
|
1092
|
-
onProgress: arg => self.setStatus(arg),
|
|
1093
|
-
onJobId: jobId => self.addInterProScanJobId(jobId),
|
|
1094
|
-
})
|
|
1095
|
-
|
|
1096
|
-
self.setLoadedInterProAnnotations(
|
|
1097
|
-
Object.fromEntries(ret.results.map(r => [r.xref[0].id, r])),
|
|
1098
|
-
)
|
|
1232
|
+
setHeaderHeight(arg: number) {
|
|
1233
|
+
self.headerHeight = arg
|
|
1099
1234
|
},
|
|
1100
1235
|
/**
|
|
1101
1236
|
* #action
|
|
1102
1237
|
*/
|
|
1103
1238
|
reset() {
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
})
|
|
1239
|
+
self.setData({ tree: '', msa: '' })
|
|
1240
|
+
self.setError(undefined)
|
|
1241
|
+
self.setScrollY(0)
|
|
1242
|
+
self.setScrollX(0)
|
|
1243
|
+
self.setCurrentAlignment(0)
|
|
1244
|
+
self.setTreeFilehandle(undefined)
|
|
1245
|
+
self.setMSAFilehandle(undefined)
|
|
1112
1246
|
},
|
|
1113
1247
|
/**
|
|
1114
1248
|
* #action
|
|
@@ -1156,25 +1290,7 @@ function stateModelFactory() {
|
|
|
1156
1290
|
}
|
|
1157
1291
|
}),
|
|
1158
1292
|
)
|
|
1159
|
-
|
|
1160
|
-
self,
|
|
1161
|
-
autorun(async () => {
|
|
1162
|
-
// const res = Object.fromEntries(
|
|
1163
|
-
// await Promise.all(
|
|
1164
|
-
// self.annotationTracks.map(async f => {
|
|
1165
|
-
// const d = await jsonfetch(
|
|
1166
|
-
// `https://jbrowse.org/demos/interproscan/json/${encodeURIComponent(f)}`,
|
|
1167
|
-
// )
|
|
1168
|
-
// return [
|
|
1169
|
-
// decodeURIComponent(f).replace('.json', ''),
|
|
1170
|
-
// d.result.results[0],
|
|
1171
|
-
// ] as const
|
|
1172
|
-
// }),
|
|
1173
|
-
// ),
|
|
1174
|
-
// )
|
|
1175
|
-
// self.setLoadedInterProAnnotations(res)
|
|
1176
|
-
}),
|
|
1177
|
-
)
|
|
1293
|
+
|
|
1178
1294
|
// autorun opens treeFilehandle
|
|
1179
1295
|
addDisposer(
|
|
1180
1296
|
self,
|
|
@@ -1225,9 +1341,11 @@ function stateModelFactory() {
|
|
|
1225
1341
|
if (msaFilehandle) {
|
|
1226
1342
|
try {
|
|
1227
1343
|
self.setLoadingMSA(true)
|
|
1228
|
-
const res = await openLocation(msaFilehandle).readFile(
|
|
1344
|
+
const res = await openLocation(msaFilehandle).readFile()
|
|
1345
|
+
const buf = isGzip(res) ? ungzip(res) : res
|
|
1346
|
+
const txt = new TextDecoder('utf8').decode(buf)
|
|
1229
1347
|
transaction(() => {
|
|
1230
|
-
self.setMSA(
|
|
1348
|
+
self.setMSA(txt)
|
|
1231
1349
|
if (msaFilehandle.locationType === 'BlobLocation') {
|
|
1232
1350
|
// clear filehandle after loading if from a local file
|
|
1233
1351
|
self.setMSAFilehandle(undefined)
|
|
@@ -1243,6 +1361,17 @@ function stateModelFactory() {
|
|
|
1243
1361
|
}),
|
|
1244
1362
|
)
|
|
1245
1363
|
|
|
1364
|
+
addDisposer(
|
|
1365
|
+
self,
|
|
1366
|
+
autorun(() => {
|
|
1367
|
+
// force colStats not to go stale,
|
|
1368
|
+
// xref solution https://github.com/mobxjs/mobx/issues/266#issuecomment-222007278
|
|
1369
|
+
// xref problem https://github.com/GMOD/react-msaview/issues/75
|
|
1370
|
+
self.colStats
|
|
1371
|
+
self.colStatsSums
|
|
1372
|
+
self.columns
|
|
1373
|
+
}),
|
|
1374
|
+
)
|
|
1246
1375
|
// autorun synchronizes treeWidth with treeAreaWidth
|
|
1247
1376
|
addDisposer(
|
|
1248
1377
|
self,
|
|
@@ -1257,16 +1386,6 @@ function stateModelFactory() {
|
|
|
1257
1386
|
}
|
|
1258
1387
|
}),
|
|
1259
1388
|
)
|
|
1260
|
-
|
|
1261
|
-
addDisposer(
|
|
1262
|
-
self,
|
|
1263
|
-
autorun(() => {
|
|
1264
|
-
localStorageSetItem(
|
|
1265
|
-
'msaview-interproscanqueries',
|
|
1266
|
-
JSON.stringify(self.interProScanJobIds),
|
|
1267
|
-
)
|
|
1268
|
-
}),
|
|
1269
|
-
)
|
|
1270
1389
|
},
|
|
1271
1390
|
}))
|
|
1272
1391
|
.postProcessSnapshot(result => {
|