jbrowse-plugin-protein3d 0.0.2 → 0.0.3
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/LaunchProteinView/components/AlphaFoldDBSearch.js +44 -27
- package/dist/LaunchProteinView/components/AlphaFoldDBSearch.js.map +1 -1
- package/dist/LaunchProteinView/components/AlphaFoldDBSearchStatus.d.ts +7 -4
- package/dist/LaunchProteinView/components/AlphaFoldDBSearchStatus.js +30 -11
- package/dist/LaunchProteinView/components/AlphaFoldDBSearchStatus.js.map +1 -1
- package/dist/LaunchProteinView/components/HelpDialog.js +10 -3
- package/dist/LaunchProteinView/components/HelpDialog.js.map +1 -1
- package/dist/LaunchProteinView/components/LaunchProteinViewDialog.js +3 -7
- package/dist/LaunchProteinView/components/LaunchProteinViewDialog.js.map +1 -1
- package/dist/LaunchProteinView/components/MSATable.d.ts +10 -0
- package/dist/LaunchProteinView/components/MSATable.js +53 -0
- package/dist/LaunchProteinView/components/MSATable.js.map +1 -0
- package/dist/LaunchProteinView/components/TranscriptSelector.d.ts +7 -3
- package/dist/LaunchProteinView/components/TranscriptSelector.js +22 -7
- package/dist/LaunchProteinView/components/TranscriptSelector.js.map +1 -1
- package/dist/LaunchProteinView/components/UserProvidedStructure.js +56 -43
- package/dist/LaunchProteinView/components/UserProvidedStructure.js.map +1 -1
- package/dist/LaunchProteinView/components/calculateProteinSequence.js.map +1 -0
- package/dist/LaunchProteinView/components/useIsoformProteinSequences.d.ts +14 -0
- package/dist/LaunchProteinView/{useProteinSequences.js → components/useIsoformProteinSequences.js} +11 -6
- package/dist/LaunchProteinView/components/useIsoformProteinSequences.js.map +1 -0
- package/dist/LaunchProteinView/components/useLocalStructureFileSequence.d.ts +7 -0
- package/dist/LaunchProteinView/components/useLocalStructureFileSequence.js +44 -0
- package/dist/LaunchProteinView/components/useLocalStructureFileSequence.js.map +1 -0
- package/dist/LaunchProteinView/{useMyGeneInfo.d.ts → components/useMyGeneInfoUniprotIdLookup.d.ts} +2 -2
- package/dist/LaunchProteinView/{useMyGeneInfo.js → components/useMyGeneInfoUniprotIdLookup.js} +15 -10
- package/dist/LaunchProteinView/components/useMyGeneInfoUniprotIdLookup.js.map +1 -0
- package/dist/LaunchProteinView/components/useRemoteStructureFileSequence.d.ts +7 -0
- package/dist/LaunchProteinView/components/useRemoteStructureFileSequence.js +42 -0
- package/dist/LaunchProteinView/components/useRemoteStructureFileSequence.js.map +1 -0
- package/dist/LaunchProteinView/{util.d.ts → components/util.d.ts} +0 -10
- package/dist/LaunchProteinView/{util.js → components/util.js} +3 -24
- package/dist/LaunchProteinView/components/util.js.map +1 -0
- package/dist/LaunchProteinView/index.js +1 -1
- package/dist/LaunchProteinView/index.js.map +1 -1
- package/dist/ProteinView/components/Header.js +1 -1
- package/dist/ProteinView/components/Header.js.map +1 -1
- package/dist/ProteinView/components/SplitString.js +1 -1
- package/dist/ProteinView/components/SplitString.js.map +1 -1
- package/dist/ProteinView/model.d.ts +8 -4
- package/dist/ProteinView/model.js +39 -13
- package/dist/ProteinView/model.js.map +1 -1
- package/dist/index.js +0 -9
- package/dist/index.js.map +1 -1
- package/dist/jbrowse-plugin-protein3d.umd.production.min.js +147 -148
- package/dist/jbrowse-plugin-protein3d.umd.production.min.js.map +4 -4
- package/package.json +2 -2
- package/src/LaunchProteinView/components/AlphaFoldDBSearch.tsx +98 -47
- package/src/LaunchProteinView/components/AlphaFoldDBSearchStatus.tsx +65 -25
- package/src/LaunchProteinView/components/HelpDialog.tsx +35 -7
- package/src/LaunchProteinView/components/LaunchProteinViewDialog.tsx +1 -10
- package/src/LaunchProteinView/components/MSATable.tsx +96 -0
- package/src/LaunchProteinView/components/TranscriptSelector.tsx +36 -10
- package/src/LaunchProteinView/components/UserProvidedStructure.tsx +110 -64
- package/src/LaunchProteinView/{useProteinSequences.ts → components/useIsoformProteinSequences.ts} +12 -7
- package/src/LaunchProteinView/components/useLocalStructureFileSequence.ts +53 -0
- package/src/LaunchProteinView/{useMyGeneInfo.ts → components/useMyGeneInfoUniprotIdLookup.ts} +16 -11
- package/src/LaunchProteinView/components/useRemoteStructureFileSequence.ts +44 -0
- package/src/LaunchProteinView/{util.ts → components/util.ts} +3 -35
- package/src/LaunchProteinView/index.ts +1 -1
- package/src/ProteinView/components/Header.tsx +7 -5
- package/src/ProteinView/components/SplitString.tsx +1 -1
- package/src/ProteinView/model.ts +40 -12
- package/src/index.ts +1 -12
- package/dist/LaunchProteinView/calculateProteinSequence.js.map +0 -1
- package/dist/LaunchProteinView/components/PreLoadedStructureMapping.d.ts +0 -8
- package/dist/LaunchProteinView/components/PreLoadedStructureMapping.js +0 -72
- package/dist/LaunchProteinView/components/PreLoadedStructureMapping.js.map +0 -1
- package/dist/LaunchProteinView/components/useCheckAlphaFoldDBExistence.d.ts +0 -7
- package/dist/LaunchProteinView/components/useCheckAlphaFoldDBExistence.js +0 -26
- package/dist/LaunchProteinView/components/useCheckAlphaFoldDBExistence.js.map +0 -1
- package/dist/LaunchProteinView/useMyGeneInfo.js.map +0 -1
- package/dist/LaunchProteinView/useProteinSequences.d.ts +0 -10
- package/dist/LaunchProteinView/useProteinSequences.js.map +0 -1
- package/dist/LaunchProteinView/util.js.map +0 -1
- package/dist/ProteinModelSessionExtension.d.ts +0 -11
- package/dist/ProteinModelSessionExtension.js +0 -53
- package/dist/ProteinModelSessionExtension.js.map +0 -1
- package/src/LaunchProteinView/components/PreLoadedStructureMapping.tsx +0 -153
- package/src/LaunchProteinView/components/useCheckAlphaFoldDBExistence.ts +0 -31
- package/src/ProteinModelSessionExtension.ts +0 -71
- /package/dist/LaunchProteinView/{calculateProteinSequence.d.ts → components/calculateProteinSequence.d.ts} +0 -0
- /package/dist/LaunchProteinView/{calculateProteinSequence.js → components/calculateProteinSequence.js} +0 -0
- /package/src/LaunchProteinView/{calculateProteinSequence.ts → components/calculateProteinSequence.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.0.
|
|
2
|
+
"version": "0.0.3",
|
|
3
3
|
"name": "jbrowse-plugin-protein3d",
|
|
4
4
|
"keywords": [
|
|
5
5
|
"jbrowse",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"pako": "^2.1.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@eslint/compat": "^1.1.
|
|
31
|
+
"@eslint/compat": "^1.1.1",
|
|
32
32
|
"@fal-works/esbuild-plugin-global-externals": "^2.1.2",
|
|
33
33
|
"@jbrowse/core": "^2.0.0",
|
|
34
34
|
"@jbrowse/plugin-linear-genome-view": "^2.4.2",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useEffect, useState } from 'react'
|
|
2
2
|
import { observer } from 'mobx-react'
|
|
3
|
-
import { Button, DialogActions, DialogContent } from '@mui/material'
|
|
3
|
+
import { Button, DialogActions, DialogContent, Typography } from '@mui/material'
|
|
4
4
|
import { makeStyles } from 'tss-react/mui'
|
|
5
5
|
import {
|
|
6
6
|
AbstractTrackModel,
|
|
@@ -18,15 +18,17 @@ import {
|
|
|
18
18
|
getId,
|
|
19
19
|
getTranscriptDisplayName,
|
|
20
20
|
getTranscriptFeatures,
|
|
21
|
-
} from '
|
|
21
|
+
} from './util'
|
|
22
|
+
|
|
23
|
+
// components
|
|
22
24
|
import TranscriptSelector from './TranscriptSelector'
|
|
23
25
|
import HelpButton from './HelpButton'
|
|
26
|
+
import AlphaFoldDBSearchStatus from './AlphaFoldDBSearchStatus'
|
|
24
27
|
|
|
25
28
|
// hooks
|
|
26
|
-
import
|
|
27
|
-
import
|
|
28
|
-
import
|
|
29
|
-
import AlphaFoldDBSearchStatus from './AlphaFoldDBSearchStatus'
|
|
29
|
+
import useMyGeneInfoUniprotIdLookup from './useMyGeneInfoUniprotIdLookup'
|
|
30
|
+
import useRemoteStructureFileSequence from './useRemoteStructureFileSequence'
|
|
31
|
+
import useIsoformProteinSequences from './useIsoformProteinSequences'
|
|
30
32
|
|
|
31
33
|
const useStyles = makeStyles()(theme => ({
|
|
32
34
|
dialogContent: {
|
|
@@ -35,9 +37,7 @@ const useStyles = makeStyles()(theme => ({
|
|
|
35
37
|
},
|
|
36
38
|
}))
|
|
37
39
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const AlphaFoldDBSearch = observer(function AlphaFoldDBSearch({
|
|
40
|
+
const AlphaFoldDBSearch = observer(function ({
|
|
41
41
|
feature,
|
|
42
42
|
model,
|
|
43
43
|
handleClose,
|
|
@@ -53,59 +53,108 @@ const AlphaFoldDBSearch = observer(function AlphaFoldDBSearch({
|
|
|
53
53
|
// finding exon/CDS subfeatures. we want to select from transcript names
|
|
54
54
|
const options = getTranscriptFeatures(feature)
|
|
55
55
|
const [userSelection, setUserSelection] = useState<string>()
|
|
56
|
-
const view = getContainingView(model) as
|
|
56
|
+
const view = getContainingView(model) as LinearGenomeViewModel
|
|
57
57
|
const selectedTranscript = options.find(val => getId(val) === userSelection)
|
|
58
|
-
const {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
const {
|
|
59
|
+
isoformSequences,
|
|
60
|
+
isLoading: isIsoformProteinSequencesLoading,
|
|
61
|
+
error: isoformProteinSequencesError,
|
|
62
|
+
} = useIsoformProteinSequences({
|
|
63
|
+
feature,
|
|
64
|
+
view,
|
|
65
|
+
})
|
|
66
|
+
const userSelectedProteinSequence = isoformSequences?.[userSelection ?? '']
|
|
67
|
+
const {
|
|
68
|
+
uniprotId,
|
|
69
|
+
isLoading: isMyGeneLoading,
|
|
70
|
+
error: myGeneError,
|
|
71
|
+
} = useMyGeneInfoUniprotIdLookup({
|
|
72
|
+
id: selectedTranscript
|
|
73
|
+
? getDisplayName(selectedTranscript)
|
|
74
|
+
: getDisplayName(feature),
|
|
62
75
|
})
|
|
63
76
|
|
|
77
|
+
const url = uniprotId
|
|
78
|
+
? `https://alphafold.ebi.ac.uk/files/AF-${uniprotId}-F1-model_v4.cif`
|
|
79
|
+
: undefined
|
|
80
|
+
const {
|
|
81
|
+
seq: structureSequence,
|
|
82
|
+
isLoading: isRemoteStructureSequenceLoading,
|
|
83
|
+
error: remoteStructureSequenceError,
|
|
84
|
+
} = useRemoteStructureFileSequence({ url })
|
|
85
|
+
const e =
|
|
86
|
+
myGeneError || isoformProteinSequencesError || remoteStructureSequenceError
|
|
87
|
+
|
|
64
88
|
useEffect(() => {
|
|
65
|
-
if (
|
|
66
|
-
|
|
89
|
+
if (isoformSequences !== undefined) {
|
|
90
|
+
const ret =
|
|
91
|
+
options.find(
|
|
92
|
+
f =>
|
|
93
|
+
isoformSequences[f.id()]?.seq.replaceAll('*', '') ==
|
|
94
|
+
structureSequence,
|
|
95
|
+
) ?? options.find(f => !!isoformSequences[f.id()])
|
|
96
|
+
setUserSelection(ret?.id())
|
|
67
97
|
}
|
|
68
|
-
}, [options,
|
|
69
|
-
const {
|
|
70
|
-
success,
|
|
71
|
-
loading,
|
|
72
|
-
error: error3,
|
|
73
|
-
} = useCheckAlphaFoldDBExistence({
|
|
74
|
-
foundStructureId,
|
|
75
|
-
})
|
|
98
|
+
}, [options, structureSequence, isoformSequences])
|
|
76
99
|
|
|
77
|
-
const e = error || error2 || error3
|
|
78
|
-
const url = `https://alphafold.ebi.ac.uk/files/AF-${foundStructureId}-F1-model_v4.cif`
|
|
79
100
|
return (
|
|
80
101
|
<>
|
|
81
102
|
<DialogContent className={classes.dialogContent}>
|
|
82
103
|
{e ? <ErrorMessage error={e} /> : null}
|
|
83
|
-
<
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
104
|
+
<Typography>
|
|
105
|
+
Automatically find AlphaFoldDB entry for given transcript{' '}
|
|
106
|
+
<HelpButton />
|
|
107
|
+
</Typography>
|
|
108
|
+
{isRemoteStructureSequenceLoading ? (
|
|
109
|
+
<LoadingEllipses
|
|
110
|
+
variant="h6"
|
|
111
|
+
message="Loading sequence from remote structure file"
|
|
112
|
+
/>
|
|
113
|
+
) : null}
|
|
114
|
+
{isMyGeneLoading ? (
|
|
115
|
+
<LoadingEllipses
|
|
116
|
+
variant="h6"
|
|
117
|
+
message="Looking up UniProt ID from mygene.info"
|
|
118
|
+
/>
|
|
119
|
+
) : !uniprotId ? (
|
|
120
|
+
<div>
|
|
121
|
+
UniProt ID not found. Search sequence on AlphaFoldDB{' '}
|
|
122
|
+
<a
|
|
123
|
+
href={`https://alphafold.ebi.ac.uk/search/sequence/${userSelectedProteinSequence?.seq.replaceAll('*', '')}`}
|
|
124
|
+
target="_blank"
|
|
125
|
+
rel="noreferrer"
|
|
126
|
+
>
|
|
127
|
+
here
|
|
128
|
+
</a>{' '}
|
|
129
|
+
<br />
|
|
130
|
+
After visiting the above link, then paste the structure URL into the
|
|
131
|
+
Manual tab
|
|
132
|
+
</div>
|
|
133
|
+
) : null}
|
|
134
|
+
{isIsoformProteinSequencesLoading ? (
|
|
135
|
+
<LoadingEllipses
|
|
136
|
+
variant="h6"
|
|
137
|
+
message="Loading protein sequences from transcript isoforms"
|
|
138
|
+
/>
|
|
139
|
+
) : null}
|
|
140
|
+
{isoformSequences && structureSequence && selectedTranscript ? (
|
|
87
141
|
<>
|
|
88
142
|
<TranscriptSelector
|
|
89
143
|
val={userSelection ?? ''}
|
|
90
144
|
setVal={setUserSelection}
|
|
91
|
-
|
|
145
|
+
structureSequence={structureSequence}
|
|
92
146
|
feature={feature}
|
|
93
|
-
|
|
147
|
+
isoforms={options}
|
|
148
|
+
isoformSequences={isoformSequences}
|
|
149
|
+
/>
|
|
150
|
+
<AlphaFoldDBSearchStatus
|
|
151
|
+
uniprotId={uniprotId}
|
|
152
|
+
selectedTranscript={selectedTranscript}
|
|
153
|
+
structureSequence={structureSequence}
|
|
154
|
+
isoformSequences={isoformSequences}
|
|
94
155
|
/>
|
|
95
|
-
{selectedTranscript ? (
|
|
96
|
-
<AlphaFoldDBSearchStatus
|
|
97
|
-
foundStructureId={foundStructureId}
|
|
98
|
-
selectedTranscript={selectedTranscript}
|
|
99
|
-
success={success}
|
|
100
|
-
loading={loading}
|
|
101
|
-
/>
|
|
102
|
-
) : null}
|
|
103
156
|
</>
|
|
104
|
-
) :
|
|
105
|
-
<div style={{ margin: 20 }}>
|
|
106
|
-
<LoadingEllipses message="Loading protein sequences" variant="h6" />
|
|
107
|
-
</div>
|
|
108
|
-
)}
|
|
157
|
+
) : null}
|
|
109
158
|
</DialogContent>
|
|
110
159
|
<DialogActions>
|
|
111
160
|
<Button
|
|
@@ -118,12 +167,14 @@ const AlphaFoldDBSearch = observer(function AlphaFoldDBSearch({
|
|
|
118
167
|
<Button
|
|
119
168
|
variant="contained"
|
|
120
169
|
color="primary"
|
|
121
|
-
disabled={
|
|
170
|
+
disabled={
|
|
171
|
+
!uniprotId || !userSelectedProteinSequence || !selectedTranscript
|
|
172
|
+
}
|
|
122
173
|
onClick={() => {
|
|
123
174
|
session.addView('ProteinView', {
|
|
124
175
|
type: 'ProteinView',
|
|
125
176
|
url,
|
|
126
|
-
seq2:
|
|
177
|
+
seq2: userSelectedProteinSequence?.seq,
|
|
127
178
|
feature: selectedTranscript?.toJSON(),
|
|
128
179
|
connectedViewId: view.id,
|
|
129
180
|
displayName: `Protein view ${getGeneDisplayName(feature)} - ${getTranscriptDisplayName(selectedTranscript)}`,
|
|
@@ -1,43 +1,83 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import { Link, Typography } from '@mui/material'
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
import { Button, Link, Typography } from '@mui/material'
|
|
3
3
|
import { Feature } from '@jbrowse/core/util'
|
|
4
|
-
import { LoadingEllipses } from '@jbrowse/core/ui'
|
|
5
4
|
|
|
6
5
|
// locals
|
|
7
|
-
import { getDisplayName } from '
|
|
6
|
+
import { getDisplayName } from './util'
|
|
7
|
+
import MSATable from './MSATable'
|
|
8
|
+
|
|
9
|
+
function NotFound({ uniprotId }: { uniprotId: string }) {
|
|
10
|
+
return (
|
|
11
|
+
<Typography>
|
|
12
|
+
No structure found for this UniProtID in AlphaFoldDB{' '}
|
|
13
|
+
<Link
|
|
14
|
+
target="_blank"
|
|
15
|
+
href={`https://alphafold.ebi.ac.uk/search/text/${uniprotId}`}
|
|
16
|
+
>
|
|
17
|
+
(search for results)
|
|
18
|
+
</Link>
|
|
19
|
+
</Typography>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
8
22
|
|
|
9
23
|
export default function AlphaFoldDBSearchStatus({
|
|
10
|
-
|
|
24
|
+
uniprotId,
|
|
11
25
|
selectedTranscript,
|
|
12
|
-
|
|
13
|
-
|
|
26
|
+
structureSequence,
|
|
27
|
+
isoformSequences,
|
|
14
28
|
}: {
|
|
15
|
-
|
|
29
|
+
uniprotId?: string
|
|
16
30
|
selectedTranscript: Feature
|
|
17
|
-
|
|
18
|
-
|
|
31
|
+
structureSequence?: string
|
|
32
|
+
isoformSequences: Record<string, { feature: Feature; seq: string }>
|
|
19
33
|
}) {
|
|
20
|
-
|
|
34
|
+
const url = uniprotId
|
|
35
|
+
? `https://alphafold.ebi.ac.uk/files/AF-${uniprotId}-F1-model_v4.cif`
|
|
36
|
+
: undefined
|
|
37
|
+
const url2 = uniprotId
|
|
38
|
+
? `https://www.uniprot.org/uniprotkb/${uniprotId}/entry`
|
|
39
|
+
: undefined
|
|
40
|
+
const [showAllProteinSequences, setShowAllProteinSequences] = useState(false)
|
|
41
|
+
|
|
42
|
+
return !uniprotId ? (
|
|
21
43
|
<Typography>
|
|
22
44
|
Searching {getDisplayName(selectedTranscript)} for UniProt ID
|
|
23
45
|
</Typography>
|
|
24
46
|
) : (
|
|
25
47
|
<>
|
|
26
|
-
<Typography>
|
|
27
|
-
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
48
|
+
<Typography>
|
|
49
|
+
Found Uniprot ID:{' '}
|
|
50
|
+
<a href={url2} target="_blank" rel="noreferrer">
|
|
51
|
+
{uniprotId}
|
|
52
|
+
</a>
|
|
53
|
+
</Typography>
|
|
54
|
+
<Typography>
|
|
55
|
+
AlphaFoldDB link:{' '}
|
|
56
|
+
<a href={url} target="_blank" rel="noreferrer">
|
|
57
|
+
{url}
|
|
58
|
+
</a>
|
|
59
|
+
</Typography>
|
|
60
|
+
{structureSequence ? (
|
|
61
|
+
<div style={{ margin: 20 }}>
|
|
62
|
+
<Button
|
|
63
|
+
variant="contained"
|
|
64
|
+
color="primary"
|
|
65
|
+
onClick={() => setShowAllProteinSequences(!showAllProteinSequences)}
|
|
37
66
|
>
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
67
|
+
{showAllProteinSequences
|
|
68
|
+
? 'Hide all isoform protein sequences'
|
|
69
|
+
: 'Show all isoform protein sequences'}
|
|
70
|
+
</Button>
|
|
71
|
+
{showAllProteinSequences ? (
|
|
72
|
+
<MSATable
|
|
73
|
+
structureSequence={structureSequence}
|
|
74
|
+
structureName={uniprotId}
|
|
75
|
+
isoformSequences={isoformSequences}
|
|
76
|
+
/>
|
|
77
|
+
) : null}
|
|
78
|
+
</div>
|
|
79
|
+
) : (
|
|
80
|
+
<NotFound uniprotId={uniprotId} />
|
|
41
81
|
)}
|
|
42
82
|
</>
|
|
43
83
|
)
|
|
@@ -18,18 +18,46 @@ export default function HelpDialog({
|
|
|
18
18
|
handleClose: () => void
|
|
19
19
|
}) {
|
|
20
20
|
return (
|
|
21
|
-
<Dialog open maxWidth="lg" onClose={handleClose} title="
|
|
21
|
+
<Dialog open maxWidth="lg" onClose={handleClose} title="Help">
|
|
22
22
|
<DialogContent>
|
|
23
23
|
<Typography2>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
The procedure for the protein lookup is as follows:
|
|
25
|
+
<ul>
|
|
26
|
+
<li>
|
|
27
|
+
(Automatic lookup) Searches mygene.info for the transcript ID, in
|
|
28
|
+
order to retrieve the UniProt ID associated with a given
|
|
29
|
+
transcript ID and then, the UniProt ID is used to lookup the
|
|
30
|
+
structure in AlphaFoldDB
|
|
31
|
+
</li>
|
|
32
|
+
<li>
|
|
33
|
+
(Manual) Allows you to choose your own structure file from your
|
|
34
|
+
local machine (e.g. a PDB file predicted by e.g. ColabFold) or
|
|
35
|
+
supply a specific URL
|
|
36
|
+
</li>
|
|
37
|
+
<li>
|
|
38
|
+
The residues from the structure are downloaded, and then you can
|
|
39
|
+
choose the transcript isoform from the selected gene that best
|
|
40
|
+
represents the structure. Asterisks are displayed if there is an
|
|
41
|
+
exact sequence match
|
|
42
|
+
</li>
|
|
43
|
+
<li>
|
|
44
|
+
The residues from the structure are finally aligned to the to the
|
|
45
|
+
selected transcript's protein sequence representation, and
|
|
46
|
+
this creates a mapping from the reference genome coordinates to
|
|
47
|
+
positions in the 3-D structure
|
|
48
|
+
</li>
|
|
49
|
+
<li>
|
|
50
|
+
Finally the molstar panel is opened, and this contains many
|
|
51
|
+
specialized features features, plus additional mouseover and
|
|
52
|
+
selection features supplied by the plugin to connect mouse click
|
|
53
|
+
actions and mouse hover with coordinates on the linear genome view
|
|
54
|
+
</li>
|
|
55
|
+
</ul>
|
|
28
56
|
</Typography2>
|
|
29
57
|
<Typography2>
|
|
30
58
|
If you run into challenges with this workflow e.g. your transcripts
|
|
31
|
-
are not being found in mygene.info
|
|
32
|
-
|
|
59
|
+
are not being found in mygene.info then you can use the Manual import
|
|
60
|
+
form, or contact colin.diesh@gmail.com for troubleshooting
|
|
33
61
|
</Typography2>
|
|
34
62
|
</DialogContent>
|
|
35
63
|
<Divider />
|
|
@@ -4,7 +4,6 @@ import { Tab, Tabs } from '@mui/material'
|
|
|
4
4
|
import { AbstractTrackModel, Feature } from '@jbrowse/core/util'
|
|
5
5
|
|
|
6
6
|
// locals
|
|
7
|
-
import PreLoadedStructureMapping from './PreLoadedStructureMapping'
|
|
8
7
|
import AlphaFoldDBSearch from './AlphaFoldDBSearch'
|
|
9
8
|
import UserProvidedStructure from './UserProvidedStructure'
|
|
10
9
|
import TabPanel from './TabPanel'
|
|
@@ -27,9 +26,8 @@ export default function LaunchProteinViewDialog({
|
|
|
27
26
|
open
|
|
28
27
|
>
|
|
29
28
|
<Tabs value={choice} onChange={(_, val) => setChoice(val)}>
|
|
30
|
-
<Tab value={0} label="
|
|
29
|
+
<Tab value={0} label="Automatic lookup" />
|
|
31
30
|
<Tab value={1} label="Manual" />
|
|
32
|
-
<Tab value={2} label="Pre-configured" />
|
|
33
31
|
</Tabs>
|
|
34
32
|
<TabPanel value={choice} index={0}>
|
|
35
33
|
<AlphaFoldDBSearch
|
|
@@ -45,13 +43,6 @@ export default function LaunchProteinViewDialog({
|
|
|
45
43
|
handleClose={handleClose}
|
|
46
44
|
/>
|
|
47
45
|
</TabPanel>
|
|
48
|
-
<TabPanel value={choice} index={2}>
|
|
49
|
-
<PreLoadedStructureMapping
|
|
50
|
-
feature={feature}
|
|
51
|
-
model={model}
|
|
52
|
-
handleClose={handleClose}
|
|
53
|
-
/>
|
|
54
|
-
</TabPanel>
|
|
55
46
|
</Dialog>
|
|
56
47
|
)
|
|
57
48
|
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
import { Checkbox, FormControlLabel, TextField } from '@mui/material'
|
|
3
|
+
import { Feature, max } from '@jbrowse/core/util'
|
|
4
|
+
import { makeStyles } from 'tss-react/mui'
|
|
5
|
+
|
|
6
|
+
// locals
|
|
7
|
+
import { getTranscriptDisplayName } from './util'
|
|
8
|
+
|
|
9
|
+
const useStyles = makeStyles()({
|
|
10
|
+
textAreaFont: {
|
|
11
|
+
fontFamily: 'Courier New',
|
|
12
|
+
whiteSpace: 'pre',
|
|
13
|
+
},
|
|
14
|
+
margin: {
|
|
15
|
+
marginLeft: 20,
|
|
16
|
+
},
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
export default function MSATable({
|
|
20
|
+
structureName,
|
|
21
|
+
structureSequence,
|
|
22
|
+
isoformSequences,
|
|
23
|
+
}: {
|
|
24
|
+
structureName: string
|
|
25
|
+
structureSequence: string
|
|
26
|
+
isoformSequences: Record<string, { feature: Feature; seq: string }>
|
|
27
|
+
}) {
|
|
28
|
+
const { classes } = useStyles()
|
|
29
|
+
const [showInFastaFormat, setShowInFastaFormat] = useState(false)
|
|
30
|
+
const removedStars = Object.fromEntries(
|
|
31
|
+
Object.entries(isoformSequences).map(([key, val]) => [
|
|
32
|
+
key,
|
|
33
|
+
{ ...val, seq: val.seq.replaceAll('*', '') },
|
|
34
|
+
]),
|
|
35
|
+
)
|
|
36
|
+
const exactMatchIsoformAndStructureSeq = Object.entries(removedStars).find(
|
|
37
|
+
([_, val]) => structureSequence === val.seq,
|
|
38
|
+
)
|
|
39
|
+
const sname = `${structureName || ''} (structure residues)`
|
|
40
|
+
const maxKeyLen = max([
|
|
41
|
+
sname.length,
|
|
42
|
+
...Object.entries(removedStars).map(
|
|
43
|
+
([_, val]) => getTranscriptDisplayName(val.feature).length,
|
|
44
|
+
),
|
|
45
|
+
])
|
|
46
|
+
|
|
47
|
+
const l1 = [
|
|
48
|
+
`${sname.padEnd(maxKeyLen)}${exactMatchIsoformAndStructureSeq ? '*' : ' '} ${structureSequence}`,
|
|
49
|
+
exactMatchIsoformAndStructureSeq
|
|
50
|
+
? `${getTranscriptDisplayName(exactMatchIsoformAndStructureSeq[1].feature).padEnd(maxKeyLen)}* ${exactMatchIsoformAndStructureSeq[1].seq}`
|
|
51
|
+
: undefined,
|
|
52
|
+
...Object.entries(removedStars)
|
|
53
|
+
.map(
|
|
54
|
+
([_, val]) =>
|
|
55
|
+
`${getTranscriptDisplayName(val.feature).padEnd(maxKeyLen)} ${val.seq}`,
|
|
56
|
+
)
|
|
57
|
+
.filter(([k]) => k !== exactMatchIsoformAndStructureSeq?.[0]),
|
|
58
|
+
]
|
|
59
|
+
.filter(f => !!f)
|
|
60
|
+
.join('\n')
|
|
61
|
+
|
|
62
|
+
const l2 = [
|
|
63
|
+
`>${sname}\n${structureSequence}`,
|
|
64
|
+
...Object.values(removedStars).map(
|
|
65
|
+
({ feature, seq }) => `>${getTranscriptDisplayName(feature)}\n${seq}`,
|
|
66
|
+
),
|
|
67
|
+
].join('\n')
|
|
68
|
+
return (
|
|
69
|
+
<>
|
|
70
|
+
<FormControlLabel
|
|
71
|
+
className={classes.margin}
|
|
72
|
+
control={
|
|
73
|
+
<Checkbox
|
|
74
|
+
onChange={event => setShowInFastaFormat(event.target.checked)}
|
|
75
|
+
checked={showInFastaFormat}
|
|
76
|
+
/>
|
|
77
|
+
}
|
|
78
|
+
label="Show in FASTA format?"
|
|
79
|
+
/>
|
|
80
|
+
<TextField
|
|
81
|
+
variant="outlined"
|
|
82
|
+
multiline
|
|
83
|
+
minRows={5}
|
|
84
|
+
maxRows={10}
|
|
85
|
+
fullWidth
|
|
86
|
+
value={showInFastaFormat ? l2 : l1}
|
|
87
|
+
InputProps={{
|
|
88
|
+
readOnly: true,
|
|
89
|
+
classes: {
|
|
90
|
+
input: classes.textAreaFont,
|
|
91
|
+
},
|
|
92
|
+
}}
|
|
93
|
+
/>
|
|
94
|
+
</>
|
|
95
|
+
)
|
|
96
|
+
}
|
|
@@ -3,7 +3,7 @@ import { MenuItem, TextField, TextFieldProps } from '@mui/material'
|
|
|
3
3
|
import { Feature } from '@jbrowse/core/util'
|
|
4
4
|
|
|
5
5
|
// locals
|
|
6
|
-
import { getGeneDisplayName, getTranscriptDisplayName } from '
|
|
6
|
+
import { getGeneDisplayName, getTranscriptDisplayName } from './util'
|
|
7
7
|
|
|
8
8
|
function TextField2({ children, ...rest }: TextFieldProps) {
|
|
9
9
|
return (
|
|
@@ -16,15 +16,17 @@ function TextField2({ children, ...rest }: TextFieldProps) {
|
|
|
16
16
|
export default function TranscriptSelector({
|
|
17
17
|
val,
|
|
18
18
|
setVal,
|
|
19
|
-
|
|
19
|
+
isoforms,
|
|
20
|
+
isoformSequences,
|
|
21
|
+
structureSequence,
|
|
20
22
|
feature,
|
|
21
|
-
seqs,
|
|
22
23
|
}: {
|
|
23
|
-
|
|
24
|
+
isoforms: Feature[]
|
|
24
25
|
feature: Feature
|
|
25
26
|
val: string
|
|
26
27
|
setVal: (str: string) => void
|
|
27
|
-
|
|
28
|
+
structureSequence: string
|
|
29
|
+
isoformSequences: Record<string, { feature: Feature; seq: string }>
|
|
28
30
|
}) {
|
|
29
31
|
return (
|
|
30
32
|
<TextField2
|
|
@@ -33,16 +35,40 @@ export default function TranscriptSelector({
|
|
|
33
35
|
label="Choose transcript isoform"
|
|
34
36
|
select
|
|
35
37
|
>
|
|
36
|
-
{
|
|
37
|
-
.filter(f => !!
|
|
38
|
+
{isoforms
|
|
39
|
+
.filter(f => !!isoformSequences[f.id()])
|
|
40
|
+
.filter(
|
|
41
|
+
f =>
|
|
42
|
+
isoformSequences[f.id()].seq.replaceAll('*', '') ===
|
|
43
|
+
structureSequence,
|
|
44
|
+
)
|
|
38
45
|
.map(f => (
|
|
39
46
|
<MenuItem value={f.id()} key={f.id()}>
|
|
40
47
|
{getGeneDisplayName(feature)} - {getTranscriptDisplayName(f)} (
|
|
41
|
-
{
|
|
48
|
+
{isoformSequences[f.id()].seq.length}aa) (matches structure
|
|
49
|
+
residues)
|
|
42
50
|
</MenuItem>
|
|
43
51
|
))}
|
|
44
|
-
{
|
|
45
|
-
.filter(f =>
|
|
52
|
+
{isoforms
|
|
53
|
+
.filter(f => !!isoformSequences[f.id()])
|
|
54
|
+
.filter(
|
|
55
|
+
f =>
|
|
56
|
+
isoformSequences[f.id()].seq.replaceAll('*', '') !==
|
|
57
|
+
structureSequence,
|
|
58
|
+
)
|
|
59
|
+
.sort(
|
|
60
|
+
(a, b) =>
|
|
61
|
+
isoformSequences[b.id()].seq.length -
|
|
62
|
+
isoformSequences[a.id()].seq.length,
|
|
63
|
+
)
|
|
64
|
+
.map(f => (
|
|
65
|
+
<MenuItem value={f.id()} key={f.id()}>
|
|
66
|
+
{getGeneDisplayName(feature)} - {getTranscriptDisplayName(f)} (
|
|
67
|
+
{isoformSequences[f.id()].seq.length}aa)
|
|
68
|
+
</MenuItem>
|
|
69
|
+
))}
|
|
70
|
+
{isoforms
|
|
71
|
+
.filter(f => !isoformSequences[f.id()])
|
|
46
72
|
.map(f => (
|
|
47
73
|
<MenuItem value={f.id()} key={f.id()} disabled>
|
|
48
74
|
{getGeneDisplayName(feature)} - {getTranscriptDisplayName(f)} (no
|