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.
Files changed (84) hide show
  1. package/dist/LaunchProteinView/components/AlphaFoldDBSearch.js +44 -27
  2. package/dist/LaunchProteinView/components/AlphaFoldDBSearch.js.map +1 -1
  3. package/dist/LaunchProteinView/components/AlphaFoldDBSearchStatus.d.ts +7 -4
  4. package/dist/LaunchProteinView/components/AlphaFoldDBSearchStatus.js +30 -11
  5. package/dist/LaunchProteinView/components/AlphaFoldDBSearchStatus.js.map +1 -1
  6. package/dist/LaunchProteinView/components/HelpDialog.js +10 -3
  7. package/dist/LaunchProteinView/components/HelpDialog.js.map +1 -1
  8. package/dist/LaunchProteinView/components/LaunchProteinViewDialog.js +3 -7
  9. package/dist/LaunchProteinView/components/LaunchProteinViewDialog.js.map +1 -1
  10. package/dist/LaunchProteinView/components/MSATable.d.ts +10 -0
  11. package/dist/LaunchProteinView/components/MSATable.js +53 -0
  12. package/dist/LaunchProteinView/components/MSATable.js.map +1 -0
  13. package/dist/LaunchProteinView/components/TranscriptSelector.d.ts +7 -3
  14. package/dist/LaunchProteinView/components/TranscriptSelector.js +22 -7
  15. package/dist/LaunchProteinView/components/TranscriptSelector.js.map +1 -1
  16. package/dist/LaunchProteinView/components/UserProvidedStructure.js +56 -43
  17. package/dist/LaunchProteinView/components/UserProvidedStructure.js.map +1 -1
  18. package/dist/LaunchProteinView/components/calculateProteinSequence.js.map +1 -0
  19. package/dist/LaunchProteinView/components/useIsoformProteinSequences.d.ts +14 -0
  20. package/dist/LaunchProteinView/{useProteinSequences.js → components/useIsoformProteinSequences.js} +11 -6
  21. package/dist/LaunchProteinView/components/useIsoformProteinSequences.js.map +1 -0
  22. package/dist/LaunchProteinView/components/useLocalStructureFileSequence.d.ts +7 -0
  23. package/dist/LaunchProteinView/components/useLocalStructureFileSequence.js +44 -0
  24. package/dist/LaunchProteinView/components/useLocalStructureFileSequence.js.map +1 -0
  25. package/dist/LaunchProteinView/{useMyGeneInfo.d.ts → components/useMyGeneInfoUniprotIdLookup.d.ts} +2 -2
  26. package/dist/LaunchProteinView/{useMyGeneInfo.js → components/useMyGeneInfoUniprotIdLookup.js} +15 -10
  27. package/dist/LaunchProteinView/components/useMyGeneInfoUniprotIdLookup.js.map +1 -0
  28. package/dist/LaunchProteinView/components/useRemoteStructureFileSequence.d.ts +7 -0
  29. package/dist/LaunchProteinView/components/useRemoteStructureFileSequence.js +42 -0
  30. package/dist/LaunchProteinView/components/useRemoteStructureFileSequence.js.map +1 -0
  31. package/dist/LaunchProteinView/{util.d.ts → components/util.d.ts} +0 -10
  32. package/dist/LaunchProteinView/{util.js → components/util.js} +3 -24
  33. package/dist/LaunchProteinView/components/util.js.map +1 -0
  34. package/dist/LaunchProteinView/index.js +1 -1
  35. package/dist/LaunchProteinView/index.js.map +1 -1
  36. package/dist/ProteinView/components/Header.js +1 -1
  37. package/dist/ProteinView/components/Header.js.map +1 -1
  38. package/dist/ProteinView/components/SplitString.js +1 -1
  39. package/dist/ProteinView/components/SplitString.js.map +1 -1
  40. package/dist/ProteinView/model.d.ts +8 -4
  41. package/dist/ProteinView/model.js +39 -13
  42. package/dist/ProteinView/model.js.map +1 -1
  43. package/dist/index.js +0 -9
  44. package/dist/index.js.map +1 -1
  45. package/dist/jbrowse-plugin-protein3d.umd.production.min.js +147 -148
  46. package/dist/jbrowse-plugin-protein3d.umd.production.min.js.map +4 -4
  47. package/package.json +2 -2
  48. package/src/LaunchProteinView/components/AlphaFoldDBSearch.tsx +98 -47
  49. package/src/LaunchProteinView/components/AlphaFoldDBSearchStatus.tsx +65 -25
  50. package/src/LaunchProteinView/components/HelpDialog.tsx +35 -7
  51. package/src/LaunchProteinView/components/LaunchProteinViewDialog.tsx +1 -10
  52. package/src/LaunchProteinView/components/MSATable.tsx +96 -0
  53. package/src/LaunchProteinView/components/TranscriptSelector.tsx +36 -10
  54. package/src/LaunchProteinView/components/UserProvidedStructure.tsx +110 -64
  55. package/src/LaunchProteinView/{useProteinSequences.ts → components/useIsoformProteinSequences.ts} +12 -7
  56. package/src/LaunchProteinView/components/useLocalStructureFileSequence.ts +53 -0
  57. package/src/LaunchProteinView/{useMyGeneInfo.ts → components/useMyGeneInfoUniprotIdLookup.ts} +16 -11
  58. package/src/LaunchProteinView/components/useRemoteStructureFileSequence.ts +44 -0
  59. package/src/LaunchProteinView/{util.ts → components/util.ts} +3 -35
  60. package/src/LaunchProteinView/index.ts +1 -1
  61. package/src/ProteinView/components/Header.tsx +7 -5
  62. package/src/ProteinView/components/SplitString.tsx +1 -1
  63. package/src/ProteinView/model.ts +40 -12
  64. package/src/index.ts +1 -12
  65. package/dist/LaunchProteinView/calculateProteinSequence.js.map +0 -1
  66. package/dist/LaunchProteinView/components/PreLoadedStructureMapping.d.ts +0 -8
  67. package/dist/LaunchProteinView/components/PreLoadedStructureMapping.js +0 -72
  68. package/dist/LaunchProteinView/components/PreLoadedStructureMapping.js.map +0 -1
  69. package/dist/LaunchProteinView/components/useCheckAlphaFoldDBExistence.d.ts +0 -7
  70. package/dist/LaunchProteinView/components/useCheckAlphaFoldDBExistence.js +0 -26
  71. package/dist/LaunchProteinView/components/useCheckAlphaFoldDBExistence.js.map +0 -1
  72. package/dist/LaunchProteinView/useMyGeneInfo.js.map +0 -1
  73. package/dist/LaunchProteinView/useProteinSequences.d.ts +0 -10
  74. package/dist/LaunchProteinView/useProteinSequences.js.map +0 -1
  75. package/dist/LaunchProteinView/util.js.map +0 -1
  76. package/dist/ProteinModelSessionExtension.d.ts +0 -11
  77. package/dist/ProteinModelSessionExtension.js +0 -53
  78. package/dist/ProteinModelSessionExtension.js.map +0 -1
  79. package/src/LaunchProteinView/components/PreLoadedStructureMapping.tsx +0 -153
  80. package/src/LaunchProteinView/components/useCheckAlphaFoldDBExistence.ts +0 -31
  81. package/src/ProteinModelSessionExtension.ts +0 -71
  82. /package/dist/LaunchProteinView/{calculateProteinSequence.d.ts → components/calculateProteinSequence.d.ts} +0 -0
  83. /package/dist/LaunchProteinView/{calculateProteinSequence.js → components/calculateProteinSequence.js} +0 -0
  84. /package/src/LaunchProteinView/{calculateProteinSequence.ts → components/calculateProteinSequence.ts} +0 -0
@@ -3,13 +3,13 @@ import { observer } from 'mobx-react'
3
3
  import {
4
4
  Button,
5
5
  DialogActions,
6
- Radio,
7
- RadioGroup,
8
6
  DialogContent,
9
- TextField,
10
7
  FormControlLabel,
11
8
  FormControl,
12
9
  Link,
10
+ Radio,
11
+ RadioGroup,
12
+ TextField,
13
13
  Typography,
14
14
  } from '@mui/material'
15
15
  import { makeStyles } from 'tss-react/mui'
@@ -28,11 +28,17 @@ import {
28
28
  getId,
29
29
  getTranscriptDisplayName,
30
30
  getTranscriptFeatures,
31
- } from '../util'
31
+ } from './util'
32
+
33
+ // components
32
34
  import TranscriptSelector from './TranscriptSelector'
35
+ import MSATable from './MSATable'
36
+ import HelpButton from './HelpButton'
33
37
 
34
38
  // hooks
35
- import useAllSequences from '../useProteinSequences'
39
+ import useIsoformProteinSequences from './useIsoformProteinSequences'
40
+ import useLocalStructureFileSequence from './useLocalStructureFileSequence'
41
+ import useRemoteStructureFileSequence from './useRemoteStructureFileSequence'
36
42
 
37
43
  const useStyles = makeStyles()(theme => ({
38
44
  dialogContent: {
@@ -73,62 +79,58 @@ const UserProvidedStructure = observer(function ({
73
79
  const { classes } = useStyles()
74
80
  const session = getSession(model)
75
81
  const [file, setFile] = useState<File>()
82
+ const [pdbId, setPdbId] = useState('')
76
83
  const [choice, setChoice] = useState('file')
77
84
  const [error2, setError] = useState<unknown>()
78
85
  const [structureURL, setStructureURL] = useState('')
79
- const [selection, setSelection] = useState<string>()
86
+ const [userSelection, setUserSelection] = useState<string>()
87
+ const [showAllProteinSequences, setShowAllProteinSequences] = useState(false)
80
88
 
81
89
  // check if we are looking at a 'two-level' or 'three-level' feature by
82
90
  // finding exon/CDS subfeatures. we want to select from transcript names
83
91
  const options = getTranscriptFeatures(feature)
84
92
  const view = getContainingView(model) as LGV
85
- const selectedTranscript = options.find(val => getId(val) === selection)
86
- const { seqs, error } = useAllSequences({ feature, view })
87
- const protein = seqs?.[selection ?? '']
93
+ const selectedTranscript = options.find(val => getId(val) === userSelection)
94
+ const { isoformSequences, error } = useIsoformProteinSequences({
95
+ feature,
96
+ view,
97
+ })
98
+ const protein = isoformSequences?.[userSelection ?? '']
99
+ const { seq: structureSequence1, error: error3 } =
100
+ useLocalStructureFileSequence({ file })
101
+
102
+ const { seq: structureSequence2, error: error4 } =
103
+ useRemoteStructureFileSequence({ url: structureURL })
104
+ const structureName =
105
+ file?.name ??
106
+ structureURL.slice(structureURL.lastIndexOf('/') + 1) ??
107
+ 'structureSequence'
108
+ const structureSequence = structureSequence1 ?? structureSequence2
109
+
88
110
  useEffect(() => {
89
- if (selection === undefined && seqs !== undefined) {
90
- setSelection(options.find(f => !!seqs[f.id()])?.id())
111
+ if (isoformSequences !== undefined) {
112
+ const ret =
113
+ options.find(
114
+ f =>
115
+ isoformSequences[f.id()]?.seq.replaceAll('*', '') ==
116
+ structureSequence,
117
+ ) ?? options.find(f => !!isoformSequences[f.id()])
118
+ setUserSelection(ret?.id())
91
119
  }
92
- }, [options, selection, seqs])
120
+ }, [options, structureSequence, isoformSequences])
93
121
 
94
- const e = error || error2
122
+ const e = error || error2 || error3 || error4
95
123
  return (
96
124
  <>
97
125
  <DialogContent className={classes.dialogContent}>
98
126
  {e ? <ErrorMessage error={e} /> : null}
99
127
  <HelpText />
100
- {seqs ? (
101
- <>
102
- <TranscriptSelector
103
- val={selection ?? ''}
104
- setVal={setSelection}
105
- options={options}
106
- feature={feature}
107
- seqs={seqs}
108
- />
109
- {selectedTranscript ? (
110
- <TextField
111
- variant="outlined"
112
- multiline
113
- minRows={5}
114
- maxRows={10}
115
- fullWidth
116
- value={`>${selectedTranscript.get('name') || selectedTranscript.get('id')}\n${protein}`}
117
- InputProps={{
118
- readOnly: true,
119
- classes: {
120
- input: classes.textAreaFont,
121
- },
122
- }}
123
- />
124
- ) : null}
125
- </>
126
- ) : (
127
- <div style={{ margin: 20 }}>
128
- <LoadingEllipses title="Loading protein sequences" variant="h6" />
129
- </div>
130
- )}
128
+
131
129
  <div style={{ display: 'flex', margin: 30 }}>
130
+ <Typography>
131
+ Open your structure file <HelpButton />
132
+ </Typography>
133
+
132
134
  <FormControl component="fieldset">
133
135
  <RadioGroup
134
136
  value={choice}
@@ -136,6 +138,11 @@ const UserProvidedStructure = observer(function ({
136
138
  >
137
139
  <FormControlLabel value="url" control={<Radio />} label="URL" />
138
140
  <FormControlLabel value="file" control={<Radio />} label="File" />
141
+ <FormControlLabel
142
+ value="pdb"
143
+ control={<Radio />}
144
+ label="PDB ID"
145
+ />
139
146
  </RadioGroup>
140
147
  </FormControl>
141
148
  {choice === 'url' ? (
@@ -170,6 +177,56 @@ const UserProvidedStructure = observer(function ({
170
177
  </Button>
171
178
  </div>
172
179
  ) : null}
180
+ {choice === 'pdb' ? (
181
+ <TextField
182
+ value={pdbId}
183
+ onChange={event => {
184
+ const s = event.target.value
185
+ setPdbId(s)
186
+ setStructureURL(`https://files.rcsb.org/download/${s}.cif`)
187
+ }}
188
+ label="PDB ID"
189
+ />
190
+ ) : null}
191
+ </div>
192
+ <div style={{ margin: 20 }}>
193
+ {isoformSequences ? (
194
+ structureSequence ? (
195
+ <>
196
+ <TranscriptSelector
197
+ val={userSelection ?? ''}
198
+ setVal={setUserSelection}
199
+ structureSequence={structureSequence}
200
+ isoforms={options}
201
+ feature={feature}
202
+ isoformSequences={isoformSequences}
203
+ />
204
+ <div style={{ margin: 10 }}>
205
+ <Button
206
+ variant="contained"
207
+ color="primary"
208
+ onClick={() =>
209
+ setShowAllProteinSequences(!showAllProteinSequences)
210
+ }
211
+ >
212
+ {showAllProteinSequences
213
+ ? 'Hide all isoform protein sequences'
214
+ : 'Show all isoform protein sequences'}
215
+ </Button>
216
+
217
+ {showAllProteinSequences ? (
218
+ <MSATable
219
+ structureSequence={structureSequence}
220
+ structureName={structureName}
221
+ isoformSequences={isoformSequences}
222
+ />
223
+ ) : null}
224
+ </div>
225
+ </>
226
+ ) : null
227
+ ) : (
228
+ <LoadingEllipses title="Loading protein sequences" variant="h6" />
229
+ )}
173
230
  </div>
174
231
  </DialogContent>
175
232
  <DialogActions>
@@ -188,26 +245,15 @@ const UserProvidedStructure = observer(function ({
188
245
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
189
246
  ;(async () => {
190
247
  try {
191
- if (file) {
192
- const data = await file.text()
193
- session.addView('ProteinView', {
194
- type: 'ProteinView',
195
- data,
196
- seq2: protein,
197
- feature: selectedTranscript?.toJSON(),
198
- connectedViewId: view.id,
199
- displayName: `Protein view ${getGeneDisplayName(feature)} - ${getTranscriptDisplayName(selectedTranscript)}`,
200
- })
201
- } else if (structureURL) {
202
- session.addView('ProteinView', {
203
- type: 'ProteinView',
204
- url: structureURL,
205
- seq2: protein,
206
- feature: selectedTranscript?.toJSON(),
207
- connectedViewId: view.id,
208
- displayName: `Protein view ${getGeneDisplayName(feature)} - ${getTranscriptDisplayName(selectedTranscript)}`,
209
- })
210
- }
248
+ session.addView('ProteinView', {
249
+ type: 'ProteinView',
250
+ seq2: protein,
251
+ feature: selectedTranscript?.toJSON(),
252
+ connectedViewId: view.id,
253
+ displayName: `Protein view ${getGeneDisplayName(feature)} - ${getTranscriptDisplayName(selectedTranscript)}`,
254
+ ...(file ? { data: await file.text() } : {}),
255
+ ...(structureURL ? { url: structureURL } : {}),
256
+ })
211
257
  handleClose()
212
258
  } catch (e) {
213
259
  console.error(e)
@@ -5,32 +5,37 @@ import { Feature } from '@jbrowse/core/util'
5
5
  import { getTranscriptFeatures } from './util'
6
6
  import { fetchProteinSeq } from './calculateProteinSequence'
7
7
 
8
- export default function useAllSequences({
8
+ export default function useIsoformProteinSequences({
9
9
  feature,
10
10
  view,
11
11
  }: {
12
12
  feature: Feature
13
- view: { assemblyNames?: string[] } | undefined
13
+ view?: { assemblyNames?: string[] }
14
14
  }) {
15
15
  const [error, setError] = useState<unknown>()
16
- const [seqs, setSeqs] = useState<Record<string, string>>()
16
+ const [isoformSequences, setIsoformSequences] =
17
+ useState<Record<string, { feature: Feature; seq: string }>>()
18
+ const [isLoading, setLoading] = useState(false)
17
19
  useEffect(() => {
18
20
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
19
21
  ;(async () => {
20
22
  try {
21
- const ret = [] as [string, string][]
23
+ setLoading(true)
24
+ const ret = [] as [string, { feature: Feature; seq: string }][]
22
25
  for (const f of getTranscriptFeatures(feature)) {
23
26
  const seq = await fetchProteinSeq({ view, feature: f })
24
27
  if (seq) {
25
- ret.push([f.id(), seq])
28
+ ret.push([f.id(), { feature: f, seq }])
26
29
  }
27
30
  }
28
- setSeqs(Object.fromEntries(ret))
31
+ setIsoformSequences(Object.fromEntries(ret))
29
32
  } catch (e) {
30
33
  console.error(e)
31
34
  setError(e)
35
+ } finally {
36
+ setLoading(false)
32
37
  }
33
38
  })()
34
39
  }, [feature, view])
35
- return { seqs, error }
40
+ return { isLoading, isoformSequences, error }
36
41
  }
@@ -0,0 +1,53 @@
1
+ import { useEffect, useState } from 'react'
2
+ import { createPluginUI } from 'molstar/lib/mol-plugin-ui'
3
+ import { renderReact18 } from 'molstar/lib/mol-plugin-ui/react18'
4
+ import { loadStructureFromData } from '../../ProteinView/loadStructureFromData'
5
+
6
+ async function structureFileSequenceFetcher(
7
+ file: File,
8
+ format: 'pdb' | 'mmcif',
9
+ ) {
10
+ const ret = document.createElement('div')
11
+ const p = await createPluginUI({
12
+ target: ret,
13
+ render: renderReact18,
14
+ })
15
+ const data = await file.text()
16
+ const { seq } = await loadStructureFromData({ data, plugin: p, format })
17
+ p.unmount()
18
+ ret.remove()
19
+ return seq
20
+ }
21
+
22
+ export default function useLocalStructureFileSequence({
23
+ file,
24
+ }: {
25
+ file?: File
26
+ }) {
27
+ const [error, setError] = useState<unknown>()
28
+ const [isLoading, setLoading] = useState(false)
29
+ const [seq, setSeq] = useState<string>()
30
+ useEffect(() => {
31
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
32
+ ;(async () => {
33
+ try {
34
+ if (file) {
35
+ setLoading(true)
36
+
37
+ const ext = file.name.slice(file.name.lastIndexOf('.') + 1) || 'pdb'
38
+ const seq = await structureFileSequenceFetcher(
39
+ file,
40
+ (ext === 'cif' ? 'mmcif' : ext) as 'pdb' | 'mmcif',
41
+ )
42
+ setSeq(seq)
43
+ }
44
+ } catch (e) {
45
+ console.error(e)
46
+ setError(e)
47
+ } finally {
48
+ setLoading(false)
49
+ }
50
+ })()
51
+ }, [file])
52
+ return { error, isLoading, seq }
53
+ }
@@ -1,5 +1,5 @@
1
1
  import { useEffect, useState } from 'react'
2
- import { jsonfetch } from '../fetchUtils'
2
+ import { jsonfetch } from '../../fetchUtils'
3
3
  import { stripTrailingVersion } from './util'
4
4
 
5
5
  interface MyGeneInfoResults {
@@ -13,25 +13,30 @@ interface MyGeneInfoResults {
13
13
  export default function useMyGeneInfo({ id }: { id: string }) {
14
14
  const [result, setResult] = useState<MyGeneInfoResults>()
15
15
  const [error, setError] = useState<unknown>()
16
- const [loading, setLoading] = useState(false)
16
+ const [isLoading, setLoading] = useState(false)
17
17
  useEffect(() => {
18
18
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
19
19
  ;(async () => {
20
20
  try {
21
- if (!id) {
22
- return
21
+ if (id) {
22
+ setLoading(true)
23
+ const res = await jsonfetch(
24
+ `https://mygene.info/v3/query?q=${stripTrailingVersion(id)}&fields=uniprot,symbol`,
25
+ )
26
+ setResult(res)
23
27
  }
24
- setLoading(true)
25
- const res = await jsonfetch(
26
- `https://mygene.info/v3/query?q=${stripTrailingVersion(id)}&fields=uniprot,symbol`,
27
- )
28
- setLoading(false)
29
- setResult(res)
30
28
  } catch (e) {
31
29
  console.error(e)
32
30
  setError(e)
31
+ } finally {
32
+ setLoading(false)
33
33
  }
34
34
  })()
35
35
  }, [id])
36
- return { loading, result: result?.hits[0]?.uniprot['Swiss-Prot'], error }
36
+
37
+ return {
38
+ isLoading,
39
+ uniprotId: result?.hits[0]?.uniprot?.['Swiss-Prot'],
40
+ error,
41
+ }
37
42
  }
@@ -0,0 +1,44 @@
1
+ import { useEffect, useState } from 'react'
2
+ import { createPluginUI } from 'molstar/lib/mol-plugin-ui'
3
+ import { renderReact18 } from 'molstar/lib/mol-plugin-ui/react18'
4
+ import { loadStructureFromURL } from '../../ProteinView/loadStructureFromURL'
5
+
6
+ async function structureFileSequenceFetcher(url: string) {
7
+ const ret = document.createElement('div')
8
+ const p = await createPluginUI({
9
+ target: ret,
10
+ render: renderReact18,
11
+ })
12
+ const { seq } = await loadStructureFromURL({ url, plugin: p })
13
+ p.unmount()
14
+ ret.remove()
15
+ return seq
16
+ }
17
+
18
+ export default function useRemoteStructureFileSequence({
19
+ url,
20
+ }: {
21
+ url?: string
22
+ }) {
23
+ const [error, setError] = useState<unknown>()
24
+ const [isLoading, setLoading] = useState(false)
25
+ const [seq, setSeq] = useState<string>()
26
+ useEffect(() => {
27
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
28
+ ;(async () => {
29
+ try {
30
+ if (url) {
31
+ setLoading(true)
32
+ const seq = await structureFileSequenceFetcher(url)
33
+ setSeq(seq)
34
+ }
35
+ } catch (e) {
36
+ console.error(e)
37
+ setError(e)
38
+ } finally {
39
+ setLoading(false)
40
+ }
41
+ })()
42
+ }, [url])
43
+ return { error, isLoading, seq }
44
+ }
@@ -1,15 +1,5 @@
1
1
  import { Feature } from '@jbrowse/core/util'
2
2
 
3
- export interface Row {
4
- gene_id: string
5
- gene_id_version: string
6
- transcript_id_version: string
7
- transcript_id: string
8
- pdb_id: string
9
- refseq_mrna_predicted_id: string
10
- refseq_mrna_id: string
11
- }
12
-
13
3
  export function getTranscriptFeatures(feature: Feature) {
14
4
  // check if we are looking at a 'two-level' or 'three-level' feature by
15
5
  // finding exon/CDS subfeatures. we want to select from transcript names
@@ -29,30 +19,8 @@ export function z(n: number) {
29
19
  return n.toLocaleString('en-US')
30
20
  }
31
21
 
32
- export function createMapFromData(data?: Row[]) {
33
- const map = new Map<string, string>()
34
- if (data) {
35
- for (const d of data) {
36
- const { pdb_id, transcript_id, refseq_mrna_id, transcript_id_version } = d
37
- if (!pdb_id) {
38
- continue
39
- }
40
- if (transcript_id) {
41
- map.set(transcript_id, pdb_id)
42
- }
43
- if (refseq_mrna_id) {
44
- map.set(refseq_mrna_id, pdb_id)
45
- }
46
- if (transcript_id_version) {
47
- map.set(transcript_id_version, pdb_id)
48
- }
49
- }
50
- }
51
- return map
52
- }
53
-
54
22
  export function getDisplayName(f: Feature): string {
55
- return f.get('id')
23
+ return f.get('name') || f.get('id')
56
24
  }
57
25
 
58
26
  export function getId(val?: Feature): string {
@@ -62,13 +30,13 @@ export function getId(val?: Feature): string {
62
30
  export function getTranscriptDisplayName(val?: Feature): string {
63
31
  return val === undefined
64
32
  ? ''
65
- : [val.get('name'), val.get('id')].filter(f => !!f).join(' ')
33
+ : [val.get('name') || val.get('id')].filter(f => !!f).join(' ')
66
34
  }
67
35
 
68
36
  export function getGeneDisplayName(val?: Feature): string {
69
37
  return val === undefined
70
38
  ? ''
71
- : [val.get('gene_name') || val.get('name'), val.get('id')]
39
+ : [val.get('gene_name') || val.get('name') || val.get('id')]
72
40
  .filter(f => !!f)
73
41
  .join(' ')
74
42
  }
@@ -26,7 +26,7 @@ function extendStateModel(stateModel: IAnyModelType) {
26
26
  ...(feature
27
27
  ? [
28
28
  {
29
- label: 'Launch protein view',
29
+ label: 'Launch 3-D protein view',
30
30
  icon: AddIcon,
31
31
  onClick: () => {
32
32
  getSession(track).queueDialog(handleClose => [
@@ -20,11 +20,13 @@ const ProteinViewHeader = observer(function ({
20
20
  return (
21
21
  <div>
22
22
  <InformativeHeaderArea model={model} />
23
- {showAlignment && alignment ? (
24
- <ProteinAlignment model={model} />
25
- ) : (
26
- <LoadingEllipses message="Loading pairwise alignment" />
27
- )}
23
+ {showAlignment ? (
24
+ alignment ? (
25
+ <ProteinAlignment model={model} />
26
+ ) : (
27
+ <LoadingEllipses message="Loading pairwise alignment" />
28
+ )
29
+ ) : null}
28
30
  </div>
29
31
  )
30
32
  })
@@ -23,7 +23,7 @@ export default function SplitString({
23
23
  style={{
24
24
  background:
25
25
  col !== undefined && i === col
26
- ? '#f69'
26
+ ? '#f698'
27
27
  : set?.has(i) && showHighlight
28
28
  ? '#33ff19'
29
29
  : undefined,
@@ -32,6 +32,7 @@ type MaybeLGV = LGV | undefined
32
32
  function stateModelFactory() {
33
33
  return types
34
34
  .compose(
35
+ 'ProteinView',
35
36
  BaseViewModel,
36
37
  types.model({
37
38
  /**
@@ -92,15 +93,15 @@ function stateModelFactory() {
92
93
  /**
93
94
  * #property
94
95
  */
95
- showHighlight: true,
96
+ showHighlight: false,
96
97
  /**
97
98
  * #property
98
99
  */
99
- zoomToBaseLevel: false,
100
+ zoomToBaseLevel: true,
100
101
  /**
101
102
  * #property
102
103
  */
103
- showAlignment: true,
104
+ showAlignment: false,
104
105
  }),
105
106
  )
106
107
  .volatile(() => ({
@@ -316,25 +317,52 @@ function stateModelFactory() {
316
317
  get structureSeqHoverPos(): number | undefined {
317
318
  return self.hoverPosition?.structureSeqPos
318
319
  },
320
+
321
+ get exactMatch() {
322
+ const r1 = self.seq1?.replaceAll('*', '')
323
+ const r2 = self.seq2?.replaceAll('*', '')
324
+ return r1 === r2
325
+ },
319
326
  }))
320
327
  .actions(self => ({
321
328
  afterAttach() {
322
- // pairwise align transcript sequence to structure sequence
329
+ // pairwise align transcript sequence to structure residues
323
330
  addDisposer(
324
331
  self,
325
332
  autorun(async () => {
326
333
  try {
327
- const { seq1, seq2 } = self
334
+ const { seq1, seq2, exactMatch } = self
328
335
  if (!!self.alignment || !seq1 || !seq2) {
329
336
  return
330
337
  }
331
- const alignment = await launchPairwiseAlignment({
332
- seq1,
333
- seq2,
334
- algorithm: 'emboss_needle',
335
- onProgress: arg => self.setProgress(arg),
336
- })
337
- self.setAlignment(alignment.alignment)
338
+ const r1 = seq1.replaceAll('*', '')
339
+ const r2 = seq2.replaceAll('*', '')
340
+ if (!exactMatch) {
341
+ const alignment = await launchPairwiseAlignment({
342
+ seq1: r1,
343
+ seq2: r2,
344
+ algorithm: 'emboss_needle',
345
+ onProgress: arg => self.setProgress(arg),
346
+ })
347
+ self.setAlignment(alignment.alignment)
348
+
349
+ // showHighlight when we are
350
+ self.setShowHighlight(true)
351
+ self.setShowAlignment(true)
352
+ } else {
353
+ let consensus = ''
354
+ // eslint-disable-next-line @typescript-eslint/prefer-for-of
355
+ for (let i = 0; i < r1.length; i++) {
356
+ consensus += '|'
357
+ }
358
+ self.setAlignment({
359
+ consensus,
360
+ alns: [
361
+ { id: 'seq1', seq: r1 },
362
+ { id: 'seq2', seq: r2 },
363
+ ],
364
+ })
365
+ }
338
366
  } catch (e) {
339
367
  console.error(e)
340
368
  self.setError(e)
package/src/index.ts CHANGED
@@ -1,12 +1,11 @@
1
1
  import Plugin from '@jbrowse/core/Plugin'
2
2
  import PluginManager from '@jbrowse/core/PluginManager'
3
- import { types } from 'mobx-state-tree'
3
+
4
4
  // locals
5
5
  import { version } from '../package.json'
6
6
  import ProteinViewF from './ProteinView'
7
7
  import LaunchProteinViewF from './LaunchProteinView'
8
8
  import AddHighlightModelF from './AddHighlightModel'
9
- import ProteinModelSessionExtension from './ProteinModelSessionExtension'
10
9
 
11
10
  export default class ProteinViewer extends Plugin {
12
11
  name = 'ProteinViewer'
@@ -16,16 +15,6 @@ export default class ProteinViewer extends Plugin {
16
15
  ProteinViewF(pluginManager)
17
16
  LaunchProteinViewF(pluginManager)
18
17
  AddHighlightModelF(pluginManager)
19
-
20
- pluginManager.addToExtensionPoint('Core-extendSession', session => {
21
- return types.compose(
22
- types.model({
23
- proteinModel: types.optional(ProteinModelSessionExtension, {}),
24
- }),
25
- // @ts-expect-error
26
- session,
27
- )
28
- })
29
18
  }
30
19
 
31
20
  configure(_pluginManager: PluginManager) {}
@@ -1 +0,0 @@
1
- {"version":3,"file":"calculateProteinSequence.js","sourceRoot":"","sources":["../../src/LaunchProteinView/calculateProteinSequence.ts"],"names":[],"mappings":"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"}
@@ -1,8 +0,0 @@
1
- import React from 'react';
2
- import { AbstractTrackModel, Feature } from '@jbrowse/core/util';
3
- declare const AutoForm: ({ model, feature, handleClose, }: {
4
- model: AbstractTrackModel;
5
- feature: Feature;
6
- handleClose: () => void;
7
- }) => React.JSX.Element;
8
- export default AutoForm;