jbrowse-plugin-msaview 2.6.2 → 2.6.4
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/dist/AddHighlightModel/MsaToGenomeHighlight.js +8 -9
- package/dist/LaunchMsaViewExtensionPoint/index.js +12 -5
- package/dist/MsaViewPanel/afterCreateAutoruns.d.ts +0 -2
- package/dist/MsaViewPanel/afterCreateAutoruns.js +8 -81
- package/dist/MsaViewPanel/model.d.ts +3 -28
- package/dist/MsaViewPanel/model.js +5 -103
- package/dist/MsaViewPanel/structureConnection.d.ts +0 -18
- package/dist/MsaViewPanel/types.d.ts +1 -4
- package/dist/jbrowse-plugin-msaview.umd.production.min.js +26 -26
- package/dist/jbrowse-plugin-msaview.umd.production.min.js.map +4 -4
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/src/AddHighlightModel/MsaToGenomeHighlight.tsx +8 -9
- package/src/LaunchMsaViewExtensionPoint/index.ts +12 -5
- package/src/MsaViewPanel/afterCreateAutoruns.ts +8 -109
- package/src/MsaViewPanel/model.ts +4 -135
- package/src/MsaViewPanel/structureConnection.ts +0 -17
- package/src/MsaViewPanel/types.ts +14 -9
- package/src/version.ts +1 -1
- package/dist/MsaViewPanel/components/ConnectStructureDialog.d.ts +0 -7
- package/dist/MsaViewPanel/components/ConnectStructureDialog.js +0 -60
- package/dist/MsaViewPanel/pairwiseAlignment.d.ts +0 -20
- package/dist/MsaViewPanel/pairwiseAlignment.js +0 -138
- package/dist/MsaViewPanel/pairwiseAlignment.test.d.ts +0 -1
- package/dist/MsaViewPanel/pairwiseAlignment.test.js +0 -111
- package/src/MsaViewPanel/components/ConnectStructureDialog.tsx +0 -154
- package/src/MsaViewPanel/pairwiseAlignment.test.ts +0 -140
- package/src/MsaViewPanel/pairwiseAlignment.ts +0 -182
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "2.6.
|
|
1
|
+
export declare const version = "2.6.4";
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '2.6.
|
|
1
|
+
export const version = '2.6.4';
|
package/package.json
CHANGED
|
@@ -5,7 +5,6 @@ import { observer } from 'mobx-react'
|
|
|
5
5
|
|
|
6
6
|
import { hasHoverPosition, useStyles } from './util'
|
|
7
7
|
import { isMsaView } from '../MsaViewPanel/model'
|
|
8
|
-
import { getCanonicalRefName } from '../MsaViewPanel/util'
|
|
9
8
|
|
|
10
9
|
import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
|
|
11
10
|
|
|
@@ -38,19 +37,19 @@ const MsaToGenomeHighlightRenderer = observer(function ({
|
|
|
38
37
|
highlights: { refName: string; start: number; end: number }[]
|
|
39
38
|
}) {
|
|
40
39
|
const { classes } = useStyles()
|
|
41
|
-
const { assemblyManager } = getSession(model)
|
|
42
40
|
const { offsetPx } = model
|
|
43
41
|
|
|
44
42
|
return (
|
|
45
43
|
<>
|
|
46
44
|
{highlights.map((r, idx) => {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const
|
|
45
|
+
// Use the highlight's own refName, which is already in the connected
|
|
46
|
+
// view's coordinate space (it comes from the connectedFeature the
|
|
47
|
+
// launcher set on this LGV). Do NOT canonicalize: bpToPx matches
|
|
48
|
+
// displayed regions by exact refName with no alias resolution, so
|
|
49
|
+
// rewriting e.g. "chr17" to the assembly-canonical "17" misses a view
|
|
50
|
+
// whose regions are "chr17". (GenomeMouseoverHighlight does the same.)
|
|
51
|
+
const s = model.bpToPx({ refName: r.refName, coord: r.start })
|
|
52
|
+
const e = model.bpToPx({ refName: r.refName, coord: r.end })
|
|
54
53
|
if (s && e) {
|
|
55
54
|
const width = Math.max(Math.abs(e.offsetPx - s.offsetPx), 4)
|
|
56
55
|
const left = Math.min(s.offsetPx, e.offsetPx) - offsetPx
|
|
@@ -46,18 +46,25 @@ export default function LaunchMsaViewExtensionPointF(
|
|
|
46
46
|
)
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
//
|
|
50
|
-
//
|
|
49
|
+
// inline data and the tree URL are native react-msaview snapshot props, set
|
|
50
|
+
// directly. Only sources needing launch-time resolution go through `init`:
|
|
51
|
+
// msaUrl (AlphaFold sniff) and the name-indexed bgzip block (no native loader).
|
|
51
52
|
session.addView('MsaView', {
|
|
52
53
|
type: 'MsaView',
|
|
53
54
|
...rest,
|
|
55
|
+
data,
|
|
56
|
+
...(treeFileLocation
|
|
57
|
+
? {
|
|
58
|
+
treeFilehandle: {
|
|
59
|
+
...treeFileLocation,
|
|
60
|
+
locationType: 'UriLocation',
|
|
61
|
+
},
|
|
62
|
+
}
|
|
63
|
+
: {}),
|
|
54
64
|
init: {
|
|
55
|
-
msaData: data?.msa,
|
|
56
|
-
treeData: data?.tree,
|
|
57
65
|
msaUrl: msaFileLocation?.uri,
|
|
58
66
|
msaIndexedLocation,
|
|
59
67
|
msaName,
|
|
60
|
-
treeUrl: treeFileLocation?.uri,
|
|
61
68
|
querySeqName,
|
|
62
69
|
},
|
|
63
70
|
})
|
|
@@ -10,10 +10,7 @@ import {
|
|
|
10
10
|
retrieveMsaData,
|
|
11
11
|
storeMsaData,
|
|
12
12
|
} from './msaDataStore'
|
|
13
|
-
import {
|
|
14
|
-
gappedToUngappedPosition,
|
|
15
|
-
getProteinViews,
|
|
16
|
-
} from './structureConnection'
|
|
13
|
+
import { getProteinViews } from './structureConnection'
|
|
17
14
|
import { getUniprotIdFromAlphaFoldUrl } from './util'
|
|
18
15
|
|
|
19
16
|
import type { JBrowsePluginMsaViewModel } from './model'
|
|
@@ -128,22 +125,15 @@ export function autoLoadProteinDomains(self: JBrowsePluginMsaViewModel) {
|
|
|
128
125
|
}
|
|
129
126
|
}
|
|
130
127
|
|
|
131
|
-
// Resolve the declarative `init` launch contract once
|
|
132
|
-
//
|
|
133
|
-
//
|
|
134
|
-
//
|
|
128
|
+
// Resolve the declarative `init` launch contract once, then clear it. msaUrl is
|
|
129
|
+
// handed to react-msaview's native filehandle loader (openLocation + progress +
|
|
130
|
+
// abort + CORS-proxy) and sniffed for an AlphaFold uniprotId; the bgzip
|
|
131
|
+
// name-indexed block is the one source with no native loader, so it's fetched
|
|
132
|
+
// here. Inline data and tree URLs arrive as native snapshot props, not via init.
|
|
135
133
|
export function processInit(self: JBrowsePluginMsaViewModel) {
|
|
136
134
|
const { init } = self
|
|
137
135
|
if (init) {
|
|
138
|
-
const {
|
|
139
|
-
msaData,
|
|
140
|
-
msaUrl,
|
|
141
|
-
msaIndexedLocation,
|
|
142
|
-
msaName,
|
|
143
|
-
treeData,
|
|
144
|
-
treeUrl,
|
|
145
|
-
querySeqName,
|
|
146
|
-
} = init
|
|
136
|
+
const { msaUrl, msaIndexedLocation, msaName, querySeqName } = init
|
|
147
137
|
void (async () => {
|
|
148
138
|
try {
|
|
149
139
|
self.setError(undefined)
|
|
@@ -159,9 +149,7 @@ export function processInit(self: JBrowsePluginMsaViewModel) {
|
|
|
159
149
|
self.setQuerySeqName(querySeqName)
|
|
160
150
|
}
|
|
161
151
|
|
|
162
|
-
if (
|
|
163
|
-
self.setMSA(msaData)
|
|
164
|
-
} else if (msaUrl) {
|
|
152
|
+
if (msaUrl) {
|
|
165
153
|
self.setMSAFilehandle({ uri: msaUrl, locationType: 'UriLocation' })
|
|
166
154
|
} else if (msaIndexedLocation && msaName) {
|
|
167
155
|
const fasta = await fetchIndexedMsa({
|
|
@@ -177,12 +165,6 @@ export function processInit(self: JBrowsePluginMsaViewModel) {
|
|
|
177
165
|
}
|
|
178
166
|
}
|
|
179
167
|
|
|
180
|
-
if (treeData) {
|
|
181
|
-
self.setTree(treeData)
|
|
182
|
-
} else if (treeUrl) {
|
|
183
|
-
self.setTreeFilehandle({ uri: treeUrl, locationType: 'UriLocation' })
|
|
184
|
-
}
|
|
185
|
-
|
|
186
168
|
self.setInit(undefined)
|
|
187
169
|
} catch (e) {
|
|
188
170
|
self.setError(e)
|
|
@@ -213,89 +195,6 @@ export function syncGenomeHoverToMsaColumn(self: JBrowsePluginMsaViewModel) {
|
|
|
213
195
|
}
|
|
214
196
|
}
|
|
215
197
|
|
|
216
|
-
export function highlightConnectedStructures(self: JBrowsePluginMsaViewModel) {
|
|
217
|
-
const { mouseCol, connectedProteinViews } = self
|
|
218
|
-
if (connectedProteinViews.length === 0) {
|
|
219
|
-
return
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
for (const conn of connectedProteinViews) {
|
|
223
|
-
const structure = conn.proteinView.structures[conn.structureIdx]
|
|
224
|
-
if (!structure) {
|
|
225
|
-
continue
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
if (mouseCol === undefined) {
|
|
229
|
-
structure.clearHighlightFromExternal?.()
|
|
230
|
-
continue
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
const seq = self.getSequenceByRowName(conn.msaRowName)
|
|
234
|
-
if (!seq) {
|
|
235
|
-
continue
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
const msaUngapped = gappedToUngappedPosition(seq, mouseCol)
|
|
239
|
-
if (msaUngapped === undefined) {
|
|
240
|
-
structure.clearHighlightFromExternal?.()
|
|
241
|
-
continue
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
const structurePos = conn.msaToStructure[msaUngapped]
|
|
245
|
-
if (structurePos === undefined) {
|
|
246
|
-
structure.clearHighlightFromExternal?.()
|
|
247
|
-
} else {
|
|
248
|
-
structure.highlightFromExternal?.(structurePos)
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
export function autoConnectStructures(self: JBrowsePluginMsaViewModel) {
|
|
254
|
-
const { connectedViewId, uniprotId, rows, connectedStructures } = self
|
|
255
|
-
|
|
256
|
-
if (!uniprotId || rows.length === 0) {
|
|
257
|
-
return
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
for (const view of getProteinViews(getSession(self).views)) {
|
|
261
|
-
for (
|
|
262
|
-
let structureIdx = 0;
|
|
263
|
-
structureIdx < view.structures.length;
|
|
264
|
-
structureIdx++
|
|
265
|
-
) {
|
|
266
|
-
const structure = view.structures[structureIdx]
|
|
267
|
-
if (!structure) {
|
|
268
|
-
continue
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
if (structure.connectedViewId !== connectedViewId) {
|
|
272
|
-
continue
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
if (structure.uniprotId !== uniprotId) {
|
|
276
|
-
continue
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
const alreadyConnected = connectedStructures.some(
|
|
280
|
-
c => c.proteinViewId === view.id && c.structureIdx === structureIdx,
|
|
281
|
-
)
|
|
282
|
-
if (alreadyConnected) {
|
|
283
|
-
continue
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
if (!structure.structureSequences?.[0]) {
|
|
287
|
-
continue
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
try {
|
|
291
|
-
self.connectToStructure(view.id, structureIdx)
|
|
292
|
-
} catch (e) {
|
|
293
|
-
console.error('Failed to auto-connect to ProteinView:', e)
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
198
|
/**
|
|
300
199
|
* Mirror a connected 3D protein view's hovered residue onto the MSA's
|
|
301
200
|
* highlighted columns. Returns the autorun body and keeps a flag tracking
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { lazy } from 'react'
|
|
2
|
-
|
|
3
1
|
import { BaseViewModel } from '@jbrowse/core/pluggableElementTypes'
|
|
4
2
|
import { getSession } from '@jbrowse/core/util'
|
|
5
3
|
import { addDisposer, types } from '@jbrowse/mobx-state-tree'
|
|
@@ -12,9 +10,7 @@ import { MSAModelF } from 'react-msaview'
|
|
|
12
10
|
export type { MSAFormat } from 'msa-parsers'
|
|
13
11
|
|
|
14
12
|
import {
|
|
15
|
-
autoConnectStructures,
|
|
16
13
|
autoLoadProteinDomains,
|
|
17
|
-
highlightConnectedStructures,
|
|
18
14
|
launchBlastIfNeeded,
|
|
19
15
|
loadStoredData,
|
|
20
16
|
observeProteinHighlights,
|
|
@@ -24,11 +20,7 @@ import {
|
|
|
24
20
|
syncGenomeHoverToMsaColumn,
|
|
25
21
|
} from './afterCreateAutoruns'
|
|
26
22
|
import { msaCoordToGenomeCoord } from './msaCoordToGenomeCoord'
|
|
27
|
-
import { buildAlignmentMaps, runPairwiseAlignment } from './pairwiseAlignment'
|
|
28
|
-
import { getProteinViews } from './structureConnection'
|
|
29
|
-
import { getCanonicalRefName } from './util'
|
|
30
23
|
|
|
31
|
-
import type { ProteinView, StructureConnection } from './structureConnection'
|
|
32
24
|
import type { MafRegion, MsaViewInitState } from './types'
|
|
33
25
|
import type {
|
|
34
26
|
BlastDatabase,
|
|
@@ -39,10 +31,6 @@ import type { Feature } from '@jbrowse/core/util'
|
|
|
39
31
|
import type { Instance } from '@jbrowse/mobx-state-tree'
|
|
40
32
|
import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
|
|
41
33
|
|
|
42
|
-
const ConnectStructureDialog = lazy(
|
|
43
|
-
() => import('./components/ConnectStructureDialog'),
|
|
44
|
-
)
|
|
45
|
-
|
|
46
34
|
type LGV = LinearGenomeViewModel
|
|
47
35
|
|
|
48
36
|
type MaybeLGV = LGV | undefined
|
|
@@ -106,11 +94,6 @@ export default function stateModelFactory() {
|
|
|
106
94
|
*/
|
|
107
95
|
init: types.frozen<MsaViewInitState | undefined>(),
|
|
108
96
|
|
|
109
|
-
/**
|
|
110
|
-
* #property
|
|
111
|
-
*/
|
|
112
|
-
connectedStructures: types.array(types.frozen<StructureConnection>()),
|
|
113
|
-
|
|
114
97
|
/**
|
|
115
98
|
* #property
|
|
116
99
|
*/
|
|
@@ -194,24 +177,6 @@ export default function stateModelFactory() {
|
|
|
194
177
|
const { views } = getSession(self)
|
|
195
178
|
return views.find(f => f.id === self.connectedViewId) as MaybeLGV
|
|
196
179
|
},
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* #getter
|
|
200
|
-
*/
|
|
201
|
-
get connectedProteinViews() {
|
|
202
|
-
const proteinViews = getProteinViews(getSession(self).views)
|
|
203
|
-
const result: (StructureConnection & { proteinView: ProteinView })[] =
|
|
204
|
-
[]
|
|
205
|
-
for (const conn of self.connectedStructures) {
|
|
206
|
-
const proteinView = proteinViews.find(
|
|
207
|
-
v => v.id === conn.proteinViewId,
|
|
208
|
-
)
|
|
209
|
-
if (proteinView) {
|
|
210
|
-
result.push({ ...conn, proteinView })
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
return result
|
|
214
|
-
},
|
|
215
180
|
}))
|
|
216
181
|
|
|
217
182
|
.views(self => ({
|
|
@@ -315,94 +280,22 @@ export default function stateModelFactory() {
|
|
|
315
280
|
*/
|
|
316
281
|
handleMsaClick(coord: number) {
|
|
317
282
|
const { connectedView, zoomToBaseLevel } = self
|
|
318
|
-
const { assemblyManager } = getSession(self)
|
|
319
283
|
const r2 = msaCoordToGenomeCoord({ model: self, coord })
|
|
320
284
|
|
|
321
285
|
if (!r2 || !connectedView) {
|
|
322
286
|
return
|
|
323
287
|
}
|
|
324
288
|
|
|
289
|
+
// Use the genome coord's own refName for both nav paths — it matches the
|
|
290
|
+
// connected view's displayed regions. Canonicalizing (e.g. "chr17"->"17")
|
|
291
|
+
// can miss a view whose regions are an alias (same as the bpToPx path).
|
|
325
292
|
if (zoomToBaseLevel) {
|
|
326
293
|
connectedView.navTo(r2)
|
|
327
294
|
} else {
|
|
328
|
-
|
|
329
|
-
assemblyManager,
|
|
330
|
-
assemblyNames: connectedView.assemblyNames,
|
|
331
|
-
refName: r2.refName,
|
|
332
|
-
})
|
|
333
|
-
connectedView.centerAt(r2.start, r)
|
|
295
|
+
connectedView.centerAt(r2.start, r2.refName)
|
|
334
296
|
}
|
|
335
297
|
},
|
|
336
298
|
|
|
337
|
-
/**
|
|
338
|
-
* #action
|
|
339
|
-
*/
|
|
340
|
-
connectToStructure(
|
|
341
|
-
proteinViewId: string,
|
|
342
|
-
structureIdx: number,
|
|
343
|
-
msaRowName?: string,
|
|
344
|
-
) {
|
|
345
|
-
const rowName = msaRowName ?? self.querySeqName
|
|
346
|
-
const msaSequence = self.getSequenceByRowName(rowName)
|
|
347
|
-
if (!msaSequence) {
|
|
348
|
-
throw new Error(`MSA row "${rowName}" not found`)
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
const ungappedMsaSequence = msaSequence.replaceAll('-', '')
|
|
352
|
-
|
|
353
|
-
const proteinView = getProteinViews(getSession(self).views).find(
|
|
354
|
-
v => v.id === proteinViewId,
|
|
355
|
-
)
|
|
356
|
-
if (!proteinView) {
|
|
357
|
-
throw new Error(`ProteinView "${proteinViewId}" not found`)
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
const structure = proteinView.structures[structureIdx]
|
|
361
|
-
if (!structure) {
|
|
362
|
-
throw new Error(`Structure at index ${structureIdx} not found`)
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
const structureSequence = structure.structureSequences?.[0]
|
|
366
|
-
if (!structureSequence) {
|
|
367
|
-
throw new Error('Structure sequence not available')
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
const alignment = runPairwiseAlignment(
|
|
371
|
-
ungappedMsaSequence,
|
|
372
|
-
structureSequence,
|
|
373
|
-
)
|
|
374
|
-
const { seq1ToSeq2 } = buildAlignmentMaps(alignment)
|
|
375
|
-
|
|
376
|
-
const connection: StructureConnection = {
|
|
377
|
-
proteinViewId,
|
|
378
|
-
structureIdx,
|
|
379
|
-
msaRowName: rowName,
|
|
380
|
-
msaToStructure: Object.fromEntries(seq1ToSeq2),
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
self.connectedStructures.push(connection)
|
|
384
|
-
},
|
|
385
|
-
|
|
386
|
-
/**
|
|
387
|
-
* #action
|
|
388
|
-
*/
|
|
389
|
-
disconnectFromStructure(proteinViewId: string, structureIdx: number) {
|
|
390
|
-
const idx = self.connectedStructures.findIndex(
|
|
391
|
-
c =>
|
|
392
|
-
c.proteinViewId === proteinViewId &&
|
|
393
|
-
c.structureIdx === structureIdx,
|
|
394
|
-
)
|
|
395
|
-
if (idx !== -1) {
|
|
396
|
-
self.connectedStructures.splice(idx, 1)
|
|
397
|
-
}
|
|
398
|
-
},
|
|
399
|
-
|
|
400
|
-
/**
|
|
401
|
-
* #action
|
|
402
|
-
*/
|
|
403
|
-
disconnectAllStructures() {
|
|
404
|
-
self.connectedStructures.clear()
|
|
405
|
-
},
|
|
406
299
|
}))
|
|
407
300
|
.actions(self => {
|
|
408
301
|
const superSetMouseClickPos = self.setMouseClickPos.bind(self)
|
|
@@ -434,28 +327,6 @@ export default function stateModelFactory() {
|
|
|
434
327
|
self.setZoomToBaseLevel(!self.zoomToBaseLevel)
|
|
435
328
|
},
|
|
436
329
|
},
|
|
437
|
-
{
|
|
438
|
-
label: 'Connect to protein structure...',
|
|
439
|
-
onClick: () => {
|
|
440
|
-
getSession(self).queueDialog(handleClose => [
|
|
441
|
-
ConnectStructureDialog,
|
|
442
|
-
{
|
|
443
|
-
model: self,
|
|
444
|
-
handleClose,
|
|
445
|
-
},
|
|
446
|
-
])
|
|
447
|
-
},
|
|
448
|
-
},
|
|
449
|
-
...(self.connectedStructures.length > 0
|
|
450
|
-
? [
|
|
451
|
-
{
|
|
452
|
-
label: 'Disconnect from protein structures',
|
|
453
|
-
onClick: () => {
|
|
454
|
-
self.disconnectAllStructures()
|
|
455
|
-
},
|
|
456
|
-
},
|
|
457
|
-
]
|
|
458
|
-
: []),
|
|
459
330
|
]
|
|
460
331
|
},
|
|
461
332
|
}))
|
|
@@ -468,8 +339,6 @@ export default function stateModelFactory() {
|
|
|
468
339
|
storeDataToIndexedDB,
|
|
469
340
|
launchBlastIfNeeded,
|
|
470
341
|
processInit,
|
|
471
|
-
highlightConnectedStructures,
|
|
472
|
-
autoConnectStructures,
|
|
473
342
|
autoLoadProteinDomains,
|
|
474
343
|
]) {
|
|
475
344
|
addDisposer(
|
|
@@ -4,9 +4,6 @@ export interface ProteinViewStructure {
|
|
|
4
4
|
uniprotId?: string
|
|
5
5
|
structureSequences?: string[]
|
|
6
6
|
hoverGenomeHighlights?: { start: number; end: number }[]
|
|
7
|
-
hoverPosition?: { structureSeqPos?: number }
|
|
8
|
-
clearHighlightFromExternal?: () => void
|
|
9
|
-
highlightFromExternal?: (pos: number) => void
|
|
10
7
|
}
|
|
11
8
|
|
|
12
9
|
export interface ProteinView {
|
|
@@ -28,20 +25,6 @@ export function getProteinViews(views: { type: string }[]): ProteinView[] {
|
|
|
28
25
|
return (views as unknown[]).filter(isProteinView)
|
|
29
26
|
}
|
|
30
27
|
|
|
31
|
-
/**
|
|
32
|
-
* Represents a connection between the MSA view and a protein structure
|
|
33
|
-
*/
|
|
34
|
-
export interface StructureConnection {
|
|
35
|
-
/** ID of the ProteinView containing the structure */
|
|
36
|
-
proteinViewId: string
|
|
37
|
-
/** Index of the structure within the ProteinView's structures array */
|
|
38
|
-
structureIdx: number
|
|
39
|
-
/** Name of the MSA row that corresponds to this structure */
|
|
40
|
-
msaRowName: string
|
|
41
|
-
/** Map from MSA ungapped position to structure sequence position */
|
|
42
|
-
msaToStructure: Record<number, number>
|
|
43
|
-
}
|
|
44
|
-
|
|
45
28
|
/**
|
|
46
29
|
* Helper to convert gapped MSA column to ungapped position for a specific row
|
|
47
30
|
*/
|
|
@@ -1,19 +1,24 @@
|
|
|
1
|
-
// Declarative launch contract, resolved once by processInit
|
|
2
|
-
//
|
|
3
|
-
//
|
|
1
|
+
// Declarative launch contract, resolved once by processInit, then cleared. Only
|
|
2
|
+
// sources that need launch-time resolution belong here. Inline data and tree URLs
|
|
3
|
+
// do NOT: they are native react-msaview snapshot props (`data`, `treeFilehandle`)
|
|
4
|
+
// applied directly from the addView snapshot, no resolution required.
|
|
5
|
+
//
|
|
6
|
+
// Cross-repo contract: jbrowse-plugin-protein3d builds an MsaView snapshot directly
|
|
7
|
+
// with `init: { msaUrl }`, so these keys must stay stable.
|
|
4
8
|
export interface MsaViewInitState {
|
|
5
|
-
|
|
9
|
+
// resolved here (not as a native msaFilehandle) so the AlphaFold-URL → uniprotId
|
|
10
|
+
// sniff runs once at launch; querySeqName is coupled to it (AlphaFold files name
|
|
11
|
+
// the query row 'query'), which is why it rides along in init rather than being a
|
|
12
|
+
// plain top-level prop.
|
|
6
13
|
msaUrl?: string
|
|
14
|
+
querySeqName?: string
|
|
7
15
|
// a single bgzip `.fa.gz` of per-transcript FASTA blocks; its `.gzi` and name
|
|
8
16
|
// index `.idx` (name<TAB>offset<TAB>length) are found by suffix. `msaName`
|
|
9
17
|
// selects one transcript's block by name (a random read), so one genome-scale
|
|
10
|
-
// alignment serves any gene without per-gene files or coordinates.
|
|
11
|
-
// react-msaview's gene-explorer.
|
|
18
|
+
// alignment serves any gene without per-gene files or coordinates. This is the
|
|
19
|
+
// one alignment source with no native loader. See react-msaview's gene-explorer.
|
|
12
20
|
msaIndexedLocation?: { uri: string }
|
|
13
21
|
msaName?: string
|
|
14
|
-
treeData?: string
|
|
15
|
-
treeUrl?: string
|
|
16
|
-
querySeqName?: string
|
|
17
22
|
}
|
|
18
23
|
|
|
19
24
|
export interface MafRegion {
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '2.6.
|
|
1
|
+
export const version = '2.6.4'
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import type { JBrowsePluginMsaViewModel } from '../model';
|
|
3
|
-
declare const ConnectStructureDialog: ({ model, handleClose, }: {
|
|
4
|
-
model: JBrowsePluginMsaViewModel;
|
|
5
|
-
handleClose: () => void;
|
|
6
|
-
}) => React.JSX.Element;
|
|
7
|
-
export default ConnectStructureDialog;
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import { Dialog, ErrorMessage } from '@jbrowse/core/ui';
|
|
3
|
-
import { getSession } from '@jbrowse/core/util';
|
|
4
|
-
import { Button, DialogActions, DialogContent, FormControl, InputLabel, MenuItem, Select, Typography, } from '@mui/material';
|
|
5
|
-
import { observer } from 'mobx-react';
|
|
6
|
-
import { makeStyles } from 'tss-react/mui';
|
|
7
|
-
import { getProteinViews } from '../structureConnection';
|
|
8
|
-
const useStyles = makeStyles()(theme => ({
|
|
9
|
-
formControl: {
|
|
10
|
-
marginBottom: theme.spacing(2),
|
|
11
|
-
},
|
|
12
|
-
}));
|
|
13
|
-
const ConnectStructureDialog = observer(function ConnectStructureDialog({ model, handleClose, }) {
|
|
14
|
-
const { classes } = useStyles();
|
|
15
|
-
const session = getSession(model);
|
|
16
|
-
const [selectedViewId, setSelectedViewId] = useState('');
|
|
17
|
-
const [selectedStructureIdx, setSelectedStructureIdx] = useState(0);
|
|
18
|
-
const [selectedMsaRow, setSelectedMsaRow] = useState(model.querySeqName);
|
|
19
|
-
const [error, setError] = useState();
|
|
20
|
-
const proteinViews = getProteinViews(session.views);
|
|
21
|
-
const selectedView = proteinViews.find(v => v.id === selectedViewId);
|
|
22
|
-
const structures = selectedView?.structures ?? [];
|
|
23
|
-
const msaRowNames = model.rows.map(r => r[0]);
|
|
24
|
-
const handleConnect = () => {
|
|
25
|
-
if (!selectedViewId) {
|
|
26
|
-
setError('Please select a protein view');
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
try {
|
|
30
|
-
model.connectToStructure(selectedViewId, selectedStructureIdx, selectedMsaRow);
|
|
31
|
-
handleClose();
|
|
32
|
-
}
|
|
33
|
-
catch (e) {
|
|
34
|
-
setError(e instanceof Error ? e.message : String(e));
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
return (React.createElement(Dialog, { maxWidth: "sm", title: "Connect to Protein Structure", open: true, onClose: handleClose },
|
|
38
|
-
React.createElement(DialogContent, null, proteinViews.length === 0 ? (React.createElement(Typography, { color: "textSecondary" }, "No protein views are currently open. Please open a protein structure view first.")) : (React.createElement(React.Fragment, null,
|
|
39
|
-
React.createElement(FormControl, { fullWidth: true, className: classes.formControl },
|
|
40
|
-
React.createElement(InputLabel, null, "Protein View"),
|
|
41
|
-
React.createElement(Select, { value: selectedViewId, label: "Protein View", onChange: e => {
|
|
42
|
-
setSelectedViewId(e.target.value);
|
|
43
|
-
setSelectedStructureIdx(0);
|
|
44
|
-
} }, proteinViews.map(view => (React.createElement(MenuItem, { key: view.id, value: view.id }, view.displayName ?? `ProteinView ${view.id}`))))),
|
|
45
|
-
structures.length > 1 ? (React.createElement(FormControl, { fullWidth: true, className: classes.formControl },
|
|
46
|
-
React.createElement(InputLabel, null, "Structure"),
|
|
47
|
-
React.createElement(Select, { value: selectedStructureIdx, label: "Structure", onChange: e => {
|
|
48
|
-
setSelectedStructureIdx(e.target.value);
|
|
49
|
-
} }, structures.map((structure, idx) => (React.createElement(MenuItem, { key: idx, value: idx }, structure.url ?? `Structure ${idx + 1}`)))))) : null,
|
|
50
|
-
React.createElement(FormControl, { fullWidth: true, className: classes.formControl },
|
|
51
|
-
React.createElement(InputLabel, null, "MSA Row"),
|
|
52
|
-
React.createElement(Select, { value: selectedMsaRow, label: "MSA Row", onChange: e => {
|
|
53
|
-
setSelectedMsaRow(e.target.value);
|
|
54
|
-
} }, msaRowNames.map(name => (React.createElement(MenuItem, { key: name, value: name }, name))))),
|
|
55
|
-
error ? React.createElement(ErrorMessage, { error: error }) : null))),
|
|
56
|
-
React.createElement(DialogActions, null,
|
|
57
|
-
React.createElement(Button, { onClick: handleClose }, "Cancel"),
|
|
58
|
-
React.createElement(Button, { onClick: handleConnect, variant: "contained", disabled: proteinViews.length === 0 || !selectedViewId }, "Connect"))));
|
|
59
|
-
});
|
|
60
|
-
export default ConnectStructureDialog;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
interface AlignmentResult {
|
|
2
|
-
alignedSeq1: string;
|
|
3
|
-
alignedSeq2: string;
|
|
4
|
-
score: number;
|
|
5
|
-
}
|
|
6
|
-
export interface AlignmentRow {
|
|
7
|
-
id: string;
|
|
8
|
-
seq: string;
|
|
9
|
-
}
|
|
10
|
-
export interface PairwiseAlignment {
|
|
11
|
-
consensus: string;
|
|
12
|
-
alns: readonly [AlignmentRow, AlignmentRow];
|
|
13
|
-
}
|
|
14
|
-
export declare function needlemanWunsch(seq1: string, seq2: string, gapOpen?: number, gapExtend?: number): AlignmentResult;
|
|
15
|
-
export declare function runPairwiseAlignment(seq1: string, seq2: string): PairwiseAlignment;
|
|
16
|
-
export declare function buildAlignmentMaps(pairwiseAlignment: PairwiseAlignment): {
|
|
17
|
-
seq1ToSeq2: Map<number, number>;
|
|
18
|
-
seq2ToSeq1: Map<number, number>;
|
|
19
|
-
};
|
|
20
|
-
export {};
|