jbrowse-plugin-protein3d 0.0.2 → 0.0.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.
Files changed (220) hide show
  1. package/dist/AddHighlightModel/GenomeMouseoverHighlight.js +3 -9
  2. package/dist/AddHighlightModel/GenomeMouseoverHighlight.js.map +1 -1
  3. package/dist/AddHighlightModel/ProteinToGenomeClickHighlight.js +4 -3
  4. package/dist/AddHighlightModel/ProteinToGenomeClickHighlight.js.map +1 -1
  5. package/dist/AddHighlightModel/ProteinToGenomeHoverHighlight.d.ts +1 -2
  6. package/dist/AddHighlightModel/ProteinToGenomeHoverHighlight.js +4 -3
  7. package/dist/AddHighlightModel/ProteinToGenomeHoverHighlight.js.map +1 -1
  8. package/dist/AddHighlightModel/util.js +1 -1
  9. package/dist/AddHighlightModel/util.js.map +1 -1
  10. package/dist/AlphaFoldConfidenceAdapter/AlphaFoldConfidenceAdapter.d.ts +16 -0
  11. package/dist/AlphaFoldConfidenceAdapter/AlphaFoldConfidenceAdapter.js +43 -0
  12. package/dist/AlphaFoldConfidenceAdapter/AlphaFoldConfidenceAdapter.js.map +1 -0
  13. package/dist/AlphaFoldConfidenceAdapter/configSchema.d.ts +13 -0
  14. package/dist/AlphaFoldConfidenceAdapter/configSchema.js +16 -0
  15. package/dist/AlphaFoldConfidenceAdapter/configSchema.js.map +1 -0
  16. package/dist/AlphaFoldConfidenceAdapter/index.d.ts +2 -0
  17. package/dist/AlphaFoldConfidenceAdapter/index.js +11 -0
  18. package/dist/AlphaFoldConfidenceAdapter/index.js.map +1 -0
  19. package/dist/AlphaMissensePathogenicityAdapter/AlphaMissensePathogenicityAdapter.d.ts +30 -0
  20. package/dist/AlphaMissensePathogenicityAdapter/AlphaMissensePathogenicityAdapter.js +78 -0
  21. package/dist/AlphaMissensePathogenicityAdapter/AlphaMissensePathogenicityAdapter.js.map +1 -0
  22. package/dist/AlphaMissensePathogenicityAdapter/configSchema.d.ts +13 -0
  23. package/dist/AlphaMissensePathogenicityAdapter/configSchema.js +16 -0
  24. package/dist/AlphaMissensePathogenicityAdapter/configSchema.js.map +1 -0
  25. package/dist/AlphaMissensePathogenicityAdapter/index.d.ts +2 -0
  26. package/dist/AlphaMissensePathogenicityAdapter/index.js +11 -0
  27. package/dist/AlphaMissensePathogenicityAdapter/index.js.map +1 -0
  28. package/dist/LaunchProteinView/components/AlphaFoldDBSearch.js +201 -34
  29. package/dist/LaunchProteinView/components/AlphaFoldDBSearch.js.map +1 -1
  30. package/dist/LaunchProteinView/components/AlphaFoldDBSearchStatus.d.ts +7 -4
  31. package/dist/LaunchProteinView/components/AlphaFoldDBSearchStatus.js +35 -14
  32. package/dist/LaunchProteinView/components/AlphaFoldDBSearchStatus.js.map +1 -1
  33. package/dist/LaunchProteinView/components/HelpButton.js +6 -2
  34. package/dist/LaunchProteinView/components/HelpButton.js.map +1 -1
  35. package/dist/LaunchProteinView/components/HelpDialog.js +13 -4
  36. package/dist/LaunchProteinView/components/HelpDialog.js.map +1 -1
  37. package/dist/LaunchProteinView/components/LaunchProteinViewDialog.js +9 -9
  38. package/dist/LaunchProteinView/components/LaunchProteinViewDialog.js.map +1 -1
  39. package/dist/LaunchProteinView/components/MSATable.d.ts +10 -0
  40. package/dist/LaunchProteinView/components/MSATable.js +55 -0
  41. package/dist/LaunchProteinView/components/MSATable.js.map +1 -0
  42. package/dist/LaunchProteinView/components/TranscriptSelector.d.ts +7 -3
  43. package/dist/LaunchProteinView/components/TranscriptSelector.js +25 -8
  44. package/dist/LaunchProteinView/components/TranscriptSelector.js.map +1 -1
  45. package/dist/LaunchProteinView/components/UserProvidedStructure.js +67 -47
  46. package/dist/LaunchProteinView/components/UserProvidedStructure.js.map +1 -1
  47. package/dist/LaunchProteinView/{calculateProteinSequence.js → components/calculateProteinSequence.js} +5 -3
  48. package/dist/LaunchProteinView/components/calculateProteinSequence.js.map +1 -0
  49. package/dist/LaunchProteinView/components/useIsoformProteinSequences.d.ts +14 -0
  50. package/dist/LaunchProteinView/{useProteinSequences.js → components/useIsoformProteinSequences.js} +11 -6
  51. package/dist/LaunchProteinView/components/useIsoformProteinSequences.js.map +1 -0
  52. package/dist/LaunchProteinView/components/useLocalStructureFileSequence.d.ts +7 -0
  53. package/dist/LaunchProteinView/components/useLocalStructureFileSequence.js +64 -0
  54. package/dist/LaunchProteinView/components/useLocalStructureFileSequence.js.map +1 -0
  55. package/dist/LaunchProteinView/{useMyGeneInfo.d.ts → components/useMyGeneInfoUniprotIdLookup.d.ts} +2 -2
  56. package/dist/LaunchProteinView/{useMyGeneInfo.js → components/useMyGeneInfoUniprotIdLookup.js} +15 -10
  57. package/dist/LaunchProteinView/components/useMyGeneInfoUniprotIdLookup.js.map +1 -0
  58. package/dist/LaunchProteinView/components/useRemoteStructureFileSequence.d.ts +7 -0
  59. package/dist/LaunchProteinView/components/useRemoteStructureFileSequence.js +59 -0
  60. package/dist/LaunchProteinView/components/useRemoteStructureFileSequence.js.map +1 -0
  61. package/dist/LaunchProteinView/{util.d.ts → components/util.d.ts} +0 -10
  62. package/dist/LaunchProteinView/{util.js → components/util.js} +4 -25
  63. package/dist/LaunchProteinView/components/util.js.map +1 -0
  64. package/dist/LaunchProteinView/index.js +6 -2
  65. package/dist/LaunchProteinView/index.js.map +1 -1
  66. package/dist/ProteinView/{loadStructureFromData.d.ts → addStructureFromData.d.ts} +2 -2
  67. package/dist/ProteinView/{loadStructureFromData.js → addStructureFromData.js} +3 -8
  68. package/dist/ProteinView/addStructureFromData.js.map +1 -0
  69. package/dist/ProteinView/{loadStructureFromURL.d.ts → addStructureFromURL.d.ts} +2 -2
  70. package/dist/ProteinView/{loadStructureFromURL.js → addStructureFromURL.js} +11 -9
  71. package/dist/ProteinView/addStructureFromURL.js.map +1 -0
  72. package/dist/ProteinView/clearSelection.js +1 -1
  73. package/dist/ProteinView/clearSelection.js.map +1 -1
  74. package/dist/ProteinView/components/ProteinAlignment.d.ts +2 -2
  75. package/dist/ProteinView/components/ProteinAlignment.js +37 -26
  76. package/dist/ProteinView/components/ProteinAlignment.js.map +1 -1
  77. package/dist/ProteinView/components/ProteinAlignmentHelpButton.d.ts +2 -2
  78. package/dist/ProteinView/components/ProteinAlignmentHelpButton.js +6 -4
  79. package/dist/ProteinView/components/ProteinAlignmentHelpButton.js.map +1 -1
  80. package/dist/ProteinView/components/ProteinAlignmentHelpDialog.js +6 -5
  81. package/dist/ProteinView/components/ProteinAlignmentHelpDialog.js.map +1 -1
  82. package/dist/ProteinView/components/ProteinView.js +18 -60
  83. package/dist/ProteinView/components/ProteinView.js.map +1 -1
  84. package/dist/ProteinView/components/{Header.js → ProteinViewHeader.js} +29 -12
  85. package/dist/ProteinView/components/ProteinViewHeader.js.map +1 -0
  86. package/dist/ProteinView/components/SplitString.d.ts +4 -4
  87. package/dist/ProteinView/components/SplitString.js +4 -4
  88. package/dist/ProteinView/components/SplitString.js.map +1 -1
  89. package/dist/ProteinView/genomeToProtein.d.ts +2 -2
  90. package/dist/ProteinView/genomeToProtein.js +4 -5
  91. package/dist/ProteinView/genomeToProtein.js.map +1 -1
  92. package/dist/ProteinView/highlightResidue.js +2 -2
  93. package/dist/ProteinView/highlightResidue.js.map +1 -1
  94. package/dist/ProteinView/launchRemotePairwiseAlignment.d.ts +2 -5
  95. package/dist/ProteinView/launchRemotePairwiseAlignment.js +7 -3
  96. package/dist/ProteinView/launchRemotePairwiseAlignment.js.map +1 -1
  97. package/dist/ProteinView/model.d.ts +496 -156
  98. package/dist/ProteinView/model.js +66 -225
  99. package/dist/ProteinView/model.js.map +1 -1
  100. package/dist/ProteinView/proteinToGenomeMapping.d.ts +6 -6
  101. package/dist/ProteinView/proteinToGenomeMapping.js +29 -28
  102. package/dist/ProteinView/proteinToGenomeMapping.js.map +1 -1
  103. package/dist/ProteinView/selectResidue.js +1 -1
  104. package/dist/ProteinView/selectResidue.js.map +1 -1
  105. package/dist/ProteinView/structureModel.d.ts +183 -0
  106. package/dist/ProteinView/structureModel.js +407 -0
  107. package/dist/ProteinView/structureModel.js.map +1 -0
  108. package/dist/ProteinView/useProteinView.d.ts +1 -4
  109. package/dist/ProteinView/useProteinView.js +3 -15
  110. package/dist/ProteinView/useProteinView.js.map +1 -1
  111. package/dist/ProteinView/util.d.ts +3 -3
  112. package/dist/ProteinView/util.js +8 -6
  113. package/dist/ProteinView/util.js.map +1 -1
  114. package/dist/UniProtVariationAdapter/UniProtVariationAdapter.d.ts +15 -0
  115. package/dist/UniProtVariationAdapter/UniProtVariationAdapter.js +55 -0
  116. package/dist/UniProtVariationAdapter/UniProtVariationAdapter.js.map +1 -0
  117. package/dist/UniProtVariationAdapter/configSchema.d.ts +17 -0
  118. package/dist/UniProtVariationAdapter/configSchema.js +20 -0
  119. package/dist/UniProtVariationAdapter/configSchema.js.map +1 -0
  120. package/dist/UniProtVariationAdapter/index.d.ts +2 -0
  121. package/dist/UniProtVariationAdapter/index.js +11 -0
  122. package/dist/UniProtVariationAdapter/index.js.map +1 -0
  123. package/dist/genomeToTranscriptMapping.d.ts +2 -2
  124. package/dist/genomeToTranscriptMapping.js +3 -3
  125. package/dist/genomeToTranscriptMapping.js.map +1 -1
  126. package/dist/index.js +6 -9
  127. package/dist/index.js.map +1 -1
  128. package/dist/jbrowse-plugin-protein3d.umd.production.min.js +1473 -1489
  129. package/dist/jbrowse-plugin-protein3d.umd.production.min.js.map +4 -4
  130. package/dist/mappings.d.ts +12 -10
  131. package/dist/mappings.js +7 -7
  132. package/dist/mappings.js.map +1 -1
  133. package/dist/mappings.test.js +7 -5
  134. package/dist/mappings.test.js.map +1 -1
  135. package/dist/test_data/gene.d.ts +577 -64
  136. package/dist/test_data/gene.js +1 -1
  137. package/dist/test_data/gene.js.map +1 -1
  138. package/package.json +17 -16
  139. package/src/AddHighlightModel/GenomeMouseoverHighlight.tsx +4 -17
  140. package/src/AddHighlightModel/ProteinToGenomeClickHighlight.tsx +17 -14
  141. package/src/AddHighlightModel/ProteinToGenomeHoverHighlight.tsx +18 -17
  142. package/src/AddHighlightModel/util.ts +1 -1
  143. package/src/AlphaFoldConfidenceAdapter/AlphaFoldConfidenceAdapter.ts +63 -0
  144. package/src/AlphaFoldConfidenceAdapter/configSchema.ts +21 -0
  145. package/src/AlphaFoldConfidenceAdapter/index.ts +19 -0
  146. package/src/AlphaMissensePathogenicityAdapter/AlphaMissensePathogenicityAdapter.ts +109 -0
  147. package/src/AlphaMissensePathogenicityAdapter/configSchema.ts +21 -0
  148. package/src/AlphaMissensePathogenicityAdapter/index.ts +19 -0
  149. package/src/LaunchProteinView/components/AlphaFoldDBSearch.tsx +266 -53
  150. package/src/LaunchProteinView/components/AlphaFoldDBSearchStatus.tsx +71 -29
  151. package/src/LaunchProteinView/components/HelpButton.tsx +10 -2
  152. package/src/LaunchProteinView/components/HelpDialog.tsx +41 -8
  153. package/src/LaunchProteinView/components/LaunchProteinViewDialog.tsx +10 -12
  154. package/src/LaunchProteinView/components/MSATable.tsx +98 -0
  155. package/src/LaunchProteinView/components/TranscriptSelector.tsx +39 -11
  156. package/src/LaunchProteinView/components/UserProvidedStructure.tsx +119 -68
  157. package/src/LaunchProteinView/{calculateProteinSequence.ts → components/calculateProteinSequence.ts} +6 -4
  158. package/src/LaunchProteinView/{useProteinSequences.ts → components/useIsoformProteinSequences.ts} +12 -7
  159. package/src/LaunchProteinView/components/useLocalStructureFileSequence.ts +72 -0
  160. package/src/LaunchProteinView/{useMyGeneInfo.ts → components/useMyGeneInfoUniprotIdLookup.ts} +16 -11
  161. package/src/LaunchProteinView/components/useRemoteStructureFileSequence.ts +59 -0
  162. package/src/LaunchProteinView/{util.ts → components/util.ts} +4 -36
  163. package/src/LaunchProteinView/index.ts +36 -26
  164. package/src/ProteinView/{loadStructureFromData.ts → addStructureFromData.ts} +2 -8
  165. package/src/ProteinView/{loadStructureFromURL.ts → addStructureFromURL.ts} +11 -11
  166. package/src/ProteinView/clearSelection.ts +1 -1
  167. package/src/ProteinView/components/ProteinAlignment.tsx +51 -35
  168. package/src/ProteinView/components/ProteinAlignmentHelpButton.tsx +4 -4
  169. package/src/ProteinView/components/ProteinAlignmentHelpDialog.tsx +15 -11
  170. package/src/ProteinView/components/ProteinView.tsx +22 -82
  171. package/src/ProteinView/components/{Header.tsx → ProteinViewHeader.tsx} +44 -21
  172. package/src/ProteinView/components/SplitString.tsx +9 -9
  173. package/src/ProteinView/genomeToProtein.ts +5 -9
  174. package/src/ProteinView/highlightResidue.ts +2 -2
  175. package/src/ProteinView/launchRemotePairwiseAlignment.ts +6 -3
  176. package/src/ProteinView/model.ts +80 -265
  177. package/src/ProteinView/proteinToGenomeMapping.ts +40 -38
  178. package/src/ProteinView/selectResidue.ts +1 -1
  179. package/src/ProteinView/structureModel.ts +512 -0
  180. package/src/ProteinView/useProteinView.ts +2 -19
  181. package/src/ProteinView/util.ts +20 -9
  182. package/src/UniProtVariationAdapter/UniProtVariationAdapter.ts +99 -0
  183. package/src/UniProtVariationAdapter/configSchema.ts +25 -0
  184. package/src/UniProtVariationAdapter/index.ts +17 -0
  185. package/src/__snapshots__/mappings.test.ts.snap +224 -224
  186. package/src/genomeToTranscriptMapping.ts +9 -9
  187. package/src/index.ts +7 -12
  188. package/src/mappings.test.ts +7 -5
  189. package/src/mappings.ts +25 -23
  190. package/src/test_data/gene.ts +3 -3
  191. package/dist/LaunchProteinView/calculateProteinSequence.js.map +0 -1
  192. package/dist/LaunchProteinView/components/PreLoadedStructureMapping.d.ts +0 -8
  193. package/dist/LaunchProteinView/components/PreLoadedStructureMapping.js +0 -72
  194. package/dist/LaunchProteinView/components/PreLoadedStructureMapping.js.map +0 -1
  195. package/dist/LaunchProteinView/components/useCheckAlphaFoldDBExistence.d.ts +0 -7
  196. package/dist/LaunchProteinView/components/useCheckAlphaFoldDBExistence.js +0 -26
  197. package/dist/LaunchProteinView/components/useCheckAlphaFoldDBExistence.js.map +0 -1
  198. package/dist/LaunchProteinView/useMyGeneInfo.js.map +0 -1
  199. package/dist/LaunchProteinView/useProteinSequences.d.ts +0 -10
  200. package/dist/LaunchProteinView/useProteinSequences.js.map +0 -1
  201. package/dist/LaunchProteinView/util.js.map +0 -1
  202. package/dist/ProteinModelSessionExtension.d.ts +0 -11
  203. package/dist/ProteinModelSessionExtension.js +0 -53
  204. package/dist/ProteinModelSessionExtension.js.map +0 -1
  205. package/dist/ProteinView/components/Header.js.map +0 -1
  206. package/dist/ProteinView/loadStructureFromData.js.map +0 -1
  207. package/dist/ProteinView/loadStructureFromURL.js.map +0 -1
  208. package/dist/ProteinView/useProteinViewClickBehavior.d.ts +0 -8
  209. package/dist/ProteinView/useProteinViewClickBehavior.js +0 -34
  210. package/dist/ProteinView/useProteinViewClickBehavior.js.map +0 -1
  211. package/dist/ProteinView/useProteinViewHoverBehavior.d.ts +0 -6
  212. package/dist/ProteinView/useProteinViewHoverBehavior.js +0 -31
  213. package/dist/ProteinView/useProteinViewHoverBehavior.js.map +0 -1
  214. package/src/LaunchProteinView/components/PreLoadedStructureMapping.tsx +0 -153
  215. package/src/LaunchProteinView/components/useCheckAlphaFoldDBExistence.ts +0 -31
  216. package/src/ProteinModelSessionExtension.ts +0 -71
  217. package/src/ProteinView/useProteinViewClickBehavior.ts +0 -48
  218. package/src/ProteinView/useProteinViewHoverBehavior.ts +0 -44
  219. /package/dist/LaunchProteinView/{calculateProteinSequence.d.ts → components/calculateProteinSequence.d.ts} +0 -0
  220. /package/dist/ProteinView/components/{Header.d.ts → ProteinViewHeader.d.ts} +0 -0
@@ -0,0 +1,98 @@
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 => {
75
+ setShowInFastaFormat(event.target.checked)
76
+ }}
77
+ checked={showInFastaFormat}
78
+ />
79
+ }
80
+ label="Show in FASTA format?"
81
+ />
82
+ <TextField
83
+ variant="outlined"
84
+ multiline
85
+ minRows={5}
86
+ maxRows={10}
87
+ fullWidth
88
+ value={showInFastaFormat ? l2 : l1}
89
+ InputProps={{
90
+ readOnly: true,
91
+ classes: {
92
+ input: classes.textAreaFont,
93
+ },
94
+ }}
95
+ />
96
+ </>
97
+ )
98
+ }
@@ -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 '../util'
6
+ import { getGeneDisplayName, getTranscriptDisplayName } from './util'
7
7
 
8
8
  function TextField2({ children, ...rest }: TextFieldProps) {
9
9
  return (
@@ -16,33 +16,61 @@ function TextField2({ children, ...rest }: TextFieldProps) {
16
16
  export default function TranscriptSelector({
17
17
  val,
18
18
  setVal,
19
- options,
19
+ isoforms,
20
+ isoformSequences,
21
+ structureSequence,
20
22
  feature,
21
- seqs,
22
23
  }: {
23
- options: Feature[]
24
+ isoforms: Feature[]
24
25
  feature: Feature
25
26
  val: string
26
27
  setVal: (str: string) => void
27
- seqs: Record<string, string>
28
+ structureSequence: string
29
+ isoformSequences: Record<string, { feature: Feature; seq: string }>
28
30
  }) {
29
31
  return (
30
32
  <TextField2
31
33
  value={val}
32
- onChange={event => setVal(event.target.value)}
34
+ onChange={event => {
35
+ setVal(event.target.value)
36
+ }}
33
37
  label="Choose transcript isoform"
34
38
  select
35
39
  >
36
- {options
37
- .filter(f => !!seqs[f.id()])
40
+ {isoforms
41
+ .filter(f => !!isoformSequences[f.id()])
42
+ .filter(
43
+ f =>
44
+ isoformSequences[f.id()]!.seq.replaceAll('*', '') ===
45
+ structureSequence,
46
+ )
38
47
  .map(f => (
39
48
  <MenuItem value={f.id()} key={f.id()}>
40
49
  {getGeneDisplayName(feature)} - {getTranscriptDisplayName(f)} (
41
- {seqs[f.id()].length}aa)
50
+ {isoformSequences[f.id()]!.seq.length}aa) (matches structure
51
+ residues)
42
52
  </MenuItem>
43
53
  ))}
44
- {options
45
- .filter(f => !seqs[f.id()])
54
+ {isoforms
55
+ .filter(f => !!isoformSequences[f.id()])
56
+ .filter(
57
+ f =>
58
+ isoformSequences[f.id()]!.seq.replaceAll('*', '') !==
59
+ structureSequence,
60
+ )
61
+ .sort(
62
+ (a, b) =>
63
+ isoformSequences[b.id()]!.seq.length -
64
+ isoformSequences[a.id()]!.seq.length,
65
+ )
66
+ .map(f => (
67
+ <MenuItem value={f.id()} key={f.id()}>
68
+ {getGeneDisplayName(feature)} - {getTranscriptDisplayName(f)} (
69
+ {isoformSequences[f.id()]!.seq.length}aa)
70
+ </MenuItem>
71
+ ))}
72
+ {isoforms
73
+ .filter(f => !isoformSequences[f.id()])
46
74
  .map(f => (
47
75
  <MenuItem value={f.id()} key={f.id()} disabled>
48
76
  {getGeneDisplayName(feature)} - {getTranscriptDisplayName(f)} (no
@@ -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,69 +79,71 @@ 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 { sequences: structureSequences1, error: error3 } =
100
+ useLocalStructureFileSequence({ file })
101
+
102
+ const { sequences: structureSequences2, error: error4 } =
103
+ useRemoteStructureFileSequence({ url: structureURL })
104
+ const structureName =
105
+ file?.name ?? structureURL.slice(structureURL.lastIndexOf('/') + 1)
106
+ const structureSequences = structureSequences1 ?? structureSequences2
107
+ const structureSequence = structureSequences?.[0]
108
+
88
109
  useEffect(() => {
89
- if (selection === undefined && seqs !== undefined) {
90
- setSelection(options.find(f => !!seqs[f.id()])?.id())
110
+ if (isoformSequences !== undefined) {
111
+ const ret =
112
+ options.find(
113
+ f =>
114
+ isoformSequences[f.id()]?.seq.replaceAll('*', '') ==
115
+ structureSequence,
116
+ ) ?? options.find(f => !!isoformSequences[f.id()])
117
+ setUserSelection(ret?.id())
91
118
  }
92
- }, [options, selection, seqs])
119
+ }, [options, structureSequence, isoformSequences])
93
120
 
94
- const e = error || error2
121
+ const e = error || error2 || error3 || error4
95
122
  return (
96
123
  <>
97
124
  <DialogContent className={classes.dialogContent}>
98
125
  {e ? <ErrorMessage error={e} /> : null}
99
126
  <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
- )}
127
+
131
128
  <div style={{ display: 'flex', margin: 30 }}>
129
+ <Typography>
130
+ Open your structure file <HelpButton />
131
+ </Typography>
132
+
132
133
  <FormControl component="fieldset">
133
134
  <RadioGroup
134
135
  value={choice}
135
- onChange={event => setChoice(event.target.value)}
136
+ onChange={event => {
137
+ setChoice(event.target.value)
138
+ }}
136
139
  >
137
140
  <FormControlLabel value="url" control={<Radio />} label="URL" />
138
141
  <FormControlLabel value="file" control={<Radio />} label="File" />
142
+ <FormControlLabel
143
+ value="pdb"
144
+ control={<Radio />}
145
+ label="PDB ID"
146
+ />
139
147
  </RadioGroup>
140
148
  </FormControl>
141
149
  {choice === 'url' ? (
@@ -146,7 +154,9 @@ const UserProvidedStructure = observer(function ({
146
154
  <TextField
147
155
  label="URL"
148
156
  value={structureURL}
149
- onChange={event => setStructureURL(event.target.value)}
157
+ onChange={event => {
158
+ setStructureURL(event.target.value)
159
+ }}
150
160
  />
151
161
  </div>
152
162
  ) : null}
@@ -161,7 +171,7 @@ const UserProvidedStructure = observer(function ({
161
171
  type="file"
162
172
  hidden
163
173
  onChange={({ target }) => {
164
- const file = target?.files?.[0]
174
+ const file = target.files?.[0]
165
175
  if (file) {
166
176
  setFile(file)
167
177
  }
@@ -170,13 +180,65 @@ const UserProvidedStructure = observer(function ({
170
180
  </Button>
171
181
  </div>
172
182
  ) : null}
183
+ {choice === 'pdb' ? (
184
+ <TextField
185
+ value={pdbId}
186
+ onChange={event => {
187
+ const s = event.target.value
188
+ setPdbId(s)
189
+ setStructureURL(`https://files.rcsb.org/download/${s}.cif`)
190
+ }}
191
+ label="PDB ID"
192
+ />
193
+ ) : null}
194
+ </div>
195
+ <div style={{ margin: 20 }}>
196
+ {isoformSequences ? (
197
+ structureSequence ? (
198
+ <>
199
+ <TranscriptSelector
200
+ val={userSelection ?? ''}
201
+ setVal={setUserSelection}
202
+ structureSequence={structureSequence}
203
+ isoforms={options}
204
+ feature={feature}
205
+ isoformSequences={isoformSequences}
206
+ />
207
+ <div style={{ margin: 10 }}>
208
+ <Button
209
+ variant="contained"
210
+ color="primary"
211
+ onClick={() => {
212
+ setShowAllProteinSequences(!showAllProteinSequences)
213
+ }}
214
+ >
215
+ {showAllProteinSequences
216
+ ? 'Hide all isoform protein sequences'
217
+ : 'Show all isoform protein sequences'}
218
+ </Button>
219
+
220
+ {showAllProteinSequences ? (
221
+ <MSATable
222
+ structureSequence={structureSequence}
223
+ structureName={structureName}
224
+ isoformSequences={isoformSequences}
225
+ />
226
+ ) : null}
227
+ </div>
228
+ </>
229
+ ) : null
230
+ ) : (
231
+ <LoadingEllipses title="Loading protein sequences" variant="h6" />
232
+ )}
173
233
  </div>
174
234
  </DialogContent>
175
235
  <DialogActions>
176
236
  <Button
177
237
  variant="contained"
178
238
  color="secondary"
179
- onClick={() => handleClose()}
239
+ onClick={() => {
240
+ handleClose()
241
+ }}
180
242
  >
181
243
  Cancel
182
244
  </Button>
@@ -188,26 +250,15 @@ const UserProvidedStructure = observer(function ({
188
250
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
189
251
  ;(async () => {
190
252
  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
- }
253
+ session.addView('ProteinView', {
254
+ type: 'ProteinView',
255
+ seq2: protein,
256
+ feature: selectedTranscript?.toJSON(),
257
+ connectedViewId: view.id,
258
+ displayName: `Protein view ${getGeneDisplayName(feature)} - ${getTranscriptDisplayName(selectedTranscript)}`,
259
+ ...(file ? { data: await file.text() } : {}),
260
+ ...(structureURL ? { url: structureURL } : {}),
261
+ })
211
262
  handleClose()
212
263
  } catch (e) {
213
264
  console.error(e)
@@ -30,7 +30,7 @@ export function calculateProteinSequence({
30
30
  let protein = ''
31
31
  for (let i = 0; i < str.length; i += 3) {
32
32
  // use & symbol for undefined codon, or partial slice
33
- protein += codonTable[str.slice(i, i + 3)] || '&'
33
+ protein += codonTable[str.slice(i, i + 3)] ?? '&'
34
34
  }
35
35
  return protein
36
36
  }
@@ -53,7 +53,7 @@ function getItemId(feat: Feat) {
53
53
  // filters if successive elements share same start/end
54
54
  export function dedupe(list: Feat[]) {
55
55
  return list.filter(
56
- (item, pos, ary) => !pos || getItemId(item) !== getItemId(ary[pos - 1]),
56
+ (item, pos, ary) => !pos || getItemId(item) !== getItemId(ary[pos - 1]!),
57
57
  )
58
58
  }
59
59
 
@@ -102,8 +102,10 @@ export async function fetchProteinSeq({
102
102
  const refName = feature.get('refName')
103
103
  const session = getSession(view)
104
104
  const { assemblyManager, rpcManager } = session
105
- const [assemblyName] = view?.assemblyNames ?? []
106
- const assembly = await assemblyManager.waitForAssembly(assemblyName)
105
+ const assemblyName = view?.assemblyNames?.[0]
106
+ const assembly = assemblyName
107
+ ? await assemblyManager.waitForAssembly(assemblyName)
108
+ : undefined
107
109
  if (!assembly) {
108
110
  throw new Error('assembly not found')
109
111
  }
@@ -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,72 @@
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 { addStructureFromData } from '../../ProteinView/addStructureFromData'
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
+
16
+ try {
17
+ const { model } = await addStructureFromData({
18
+ data: await file.text(),
19
+ plugin: p,
20
+ format,
21
+ })
22
+ return model.obj?.data.sequence.sequences.map(s => {
23
+ let seq = ''
24
+ const arr = s.sequence.label.toArray()
25
+ // eslint-disable-next-line unicorn/no-for-loop,@typescript-eslint/prefer-for-of
26
+ for (let i = 0; i < arr.length; i++) {
27
+ seq += arr[i]!
28
+ }
29
+ return seq
30
+ })
31
+ } finally {
32
+ p.unmount()
33
+ ret.remove()
34
+ }
35
+ }
36
+
37
+ export default function useLocalStructureFileSequence({
38
+ file,
39
+ }: {
40
+ file?: File
41
+ }) {
42
+ const [error, setError] = useState<unknown>()
43
+ const [isLoading, setLoading] = useState(false)
44
+ const [sequences, setSequences] = useState<string[]>()
45
+ useEffect(() => {
46
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
47
+ ;(async () => {
48
+ try {
49
+ if (file) {
50
+ setLoading(true)
51
+
52
+ const ext = file.name.slice(file.name.lastIndexOf('.') + 1) || 'pdb'
53
+ const seq = await structureFileSequenceFetcher(
54
+ file,
55
+ (ext === 'cif' ? 'mmcif' : ext) as 'pdb' | 'mmcif',
56
+ )
57
+ if (seq) {
58
+ setSequences(seq)
59
+ } else {
60
+ throw new Error('no sequences detected in file')
61
+ }
62
+ }
63
+ } catch (e) {
64
+ console.error(e)
65
+ setError(e)
66
+ } finally {
67
+ setLoading(false)
68
+ }
69
+ })()
70
+ }, [file])
71
+ return { error, isLoading, sequences }
72
+ }
@@ -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
  }