jbrowse-plugin-protein3d 0.0.2

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 (210) hide show
  1. package/README.md +3 -0
  2. package/dist/AddHighlightModel/GenomeMouseoverHighlight.d.ts +6 -0
  3. package/dist/AddHighlightModel/GenomeMouseoverHighlight.js +24 -0
  4. package/dist/AddHighlightModel/GenomeMouseoverHighlight.js.map +1 -0
  5. package/dist/AddHighlightModel/Highlight.d.ts +10 -0
  6. package/dist/AddHighlightModel/Highlight.js +24 -0
  7. package/dist/AddHighlightModel/Highlight.js.map +1 -0
  8. package/dist/AddHighlightModel/HighlightComponents.d.ts +7 -0
  9. package/dist/AddHighlightModel/HighlightComponents.js +14 -0
  10. package/dist/AddHighlightModel/HighlightComponents.js.map +1 -0
  11. package/dist/AddHighlightModel/ProteinToGenomeClickHighlight.d.ts +7 -0
  12. package/dist/AddHighlightModel/ProteinToGenomeClickHighlight.js +13 -0
  13. package/dist/AddHighlightModel/ProteinToGenomeClickHighlight.js.map +1 -0
  14. package/dist/AddHighlightModel/ProteinToGenomeHoverHighlight.d.ts +7 -0
  15. package/dist/AddHighlightModel/ProteinToGenomeHoverHighlight.js +13 -0
  16. package/dist/AddHighlightModel/ProteinToGenomeHoverHighlight.js.map +1 -0
  17. package/dist/AddHighlightModel/index.d.ts +2 -0
  18. package/dist/AddHighlightModel/index.js +14 -0
  19. package/dist/AddHighlightModel/index.js.map +1 -0
  20. package/dist/AddHighlightModel/util.d.ts +9 -0
  21. package/dist/AddHighlightModel/util.js +17 -0
  22. package/dist/AddHighlightModel/util.js.map +1 -0
  23. package/dist/LaunchProteinView/calculateProteinSequence.d.ts +28 -0
  24. package/dist/LaunchProteinView/calculateProteinSequence.js +77 -0
  25. package/dist/LaunchProteinView/calculateProteinSequence.js.map +1 -0
  26. package/dist/LaunchProteinView/components/AlphaFoldDBSearch.d.ts +8 -0
  27. package/dist/LaunchProteinView/components/AlphaFoldDBSearch.js +71 -0
  28. package/dist/LaunchProteinView/components/AlphaFoldDBSearch.js.map +1 -0
  29. package/dist/LaunchProteinView/components/AlphaFoldDBSearchStatus.d.ts +8 -0
  30. package/dist/LaunchProteinView/components/AlphaFoldDBSearchStatus.js +19 -0
  31. package/dist/LaunchProteinView/components/AlphaFoldDBSearchStatus.js.map +1 -0
  32. package/dist/LaunchProteinView/components/HelpButton.d.ts +2 -0
  33. package/dist/LaunchProteinView/components/HelpButton.js +15 -0
  34. package/dist/LaunchProteinView/components/HelpButton.js.map +1 -0
  35. package/dist/LaunchProteinView/components/HelpDialog.d.ts +4 -0
  36. package/dist/LaunchProteinView/components/HelpDialog.js +16 -0
  37. package/dist/LaunchProteinView/components/HelpDialog.js.map +1 -0
  38. package/dist/LaunchProteinView/components/LaunchProteinViewDialog.d.ts +7 -0
  39. package/dist/LaunchProteinView/components/LaunchProteinViewDialog.js +23 -0
  40. package/dist/LaunchProteinView/components/LaunchProteinViewDialog.js.map +1 -0
  41. package/dist/LaunchProteinView/components/PreLoadedStructureMapping.d.ts +8 -0
  42. package/dist/LaunchProteinView/components/PreLoadedStructureMapping.js +72 -0
  43. package/dist/LaunchProteinView/components/PreLoadedStructureMapping.js.map +1 -0
  44. package/dist/LaunchProteinView/components/TabPanel.d.ts +6 -0
  45. package/dist/LaunchProteinView/components/TabPanel.js +6 -0
  46. package/dist/LaunchProteinView/components/TabPanel.js.map +1 -0
  47. package/dist/LaunchProteinView/components/TranscriptSelector.d.ts +9 -0
  48. package/dist/LaunchProteinView/components/TranscriptSelector.js +28 -0
  49. package/dist/LaunchProteinView/components/TranscriptSelector.js.map +1 -0
  50. package/dist/LaunchProteinView/components/UserProvidedStructure.d.ts +8 -0
  51. package/dist/LaunchProteinView/components/UserProvidedStructure.js +118 -0
  52. package/dist/LaunchProteinView/components/UserProvidedStructure.js.map +1 -0
  53. package/dist/LaunchProteinView/components/useCheckAlphaFoldDBExistence.d.ts +7 -0
  54. package/dist/LaunchProteinView/components/useCheckAlphaFoldDBExistence.js +26 -0
  55. package/dist/LaunchProteinView/components/useCheckAlphaFoldDBExistence.js.map +1 -0
  56. package/dist/LaunchProteinView/index.d.ts +2 -0
  57. package/dist/LaunchProteinView/index.js +45 -0
  58. package/dist/LaunchProteinView/index.js.map +1 -0
  59. package/dist/LaunchProteinView/useMyGeneInfo.d.ts +7 -0
  60. package/dist/LaunchProteinView/useMyGeneInfo.js +29 -0
  61. package/dist/LaunchProteinView/useMyGeneInfo.js.map +1 -0
  62. package/dist/LaunchProteinView/useProteinSequences.d.ts +10 -0
  63. package/dist/LaunchProteinView/useProteinSequences.js +30 -0
  64. package/dist/LaunchProteinView/useProteinSequences.js.map +1 -0
  65. package/dist/LaunchProteinView/util.d.ts +18 -0
  66. package/dist/LaunchProteinView/util.js +54 -0
  67. package/dist/LaunchProteinView/util.js.map +1 -0
  68. package/dist/ProteinModelSessionExtension.d.ts +11 -0
  69. package/dist/ProteinModelSessionExtension.js +53 -0
  70. package/dist/ProteinModelSessionExtension.js.map +1 -0
  71. package/dist/ProteinView/clearSelection.d.ts +4 -0
  72. package/dist/ProteinView/clearSelection.js +4 -0
  73. package/dist/ProteinView/clearSelection.js.map +1 -0
  74. package/dist/ProteinView/components/Header.d.ts +6 -0
  75. package/dist/ProteinView/components/Header.js +49 -0
  76. package/dist/ProteinView/components/Header.js.map +1 -0
  77. package/dist/ProteinView/components/ProteinAlignment.d.ts +6 -0
  78. package/dist/ProteinView/components/ProteinAlignment.js +62 -0
  79. package/dist/ProteinView/components/ProteinAlignment.js.map +1 -0
  80. package/dist/ProteinView/components/ProteinAlignmentHelpButton.d.ts +5 -0
  81. package/dist/ProteinView/components/ProteinAlignmentHelpButton.js +14 -0
  82. package/dist/ProteinView/components/ProteinAlignmentHelpButton.js.map +1 -0
  83. package/dist/ProteinView/components/ProteinAlignmentHelpDialog.d.ts +4 -0
  84. package/dist/ProteinView/components/ProteinAlignmentHelpDialog.js +20 -0
  85. package/dist/ProteinView/components/ProteinAlignmentHelpDialog.js.map +1 -0
  86. package/dist/ProteinView/components/ProteinView.d.ts +6 -0
  87. package/dist/ProteinView/components/ProteinView.js +79 -0
  88. package/dist/ProteinView/components/ProteinView.js.map +1 -0
  89. package/dist/ProteinView/components/SplitString.d.ts +9 -0
  90. package/dist/ProteinView/components/SplitString.js +11 -0
  91. package/dist/ProteinView/components/SplitString.js.map +1 -0
  92. package/dist/ProteinView/css/molstar.d.ts +2 -0
  93. package/dist/ProteinView/css/molstar.js +3137 -0
  94. package/dist/ProteinView/css/molstar.js.map +1 -0
  95. package/dist/ProteinView/genomeToProtein.d.ts +4 -0
  96. package/dist/ProteinView/genomeToProtein.js +13 -0
  97. package/dist/ProteinView/genomeToProtein.js.map +1 -0
  98. package/dist/ProteinView/highlightResidue.d.ts +7 -0
  99. package/dist/ProteinView/highlightResidue.js +14 -0
  100. package/dist/ProteinView/highlightResidue.js.map +1 -0
  101. package/dist/ProteinView/index.d.ts +2 -0
  102. package/dist/ProteinView/index.js +15 -0
  103. package/dist/ProteinView/index.js.map +1 -0
  104. package/dist/ProteinView/launchRemotePairwiseAlignment.d.ts +14 -0
  105. package/dist/ProteinView/launchRemotePairwiseAlignment.js +72 -0
  106. package/dist/ProteinView/launchRemotePairwiseAlignment.js.map +1 -0
  107. package/dist/ProteinView/loadStructureFromData.d.ts +17 -0
  108. package/dist/ProteinView/loadStructureFromData.js +20 -0
  109. package/dist/ProteinView/loadStructureFromData.js.map +1 -0
  110. package/dist/ProteinView/loadStructureFromURL.d.ts +17 -0
  111. package/dist/ProteinView/loadStructureFromURL.js +17 -0
  112. package/dist/ProteinView/loadStructureFromURL.js.map +1 -0
  113. package/dist/ProteinView/model.d.ts +226 -0
  114. package/dist/ProteinView/model.js +324 -0
  115. package/dist/ProteinView/model.js.map +1 -0
  116. package/dist/ProteinView/proteinAbbreviationMapping.d.ts +7 -0
  117. package/dist/ProteinView/proteinAbbreviationMapping.js +23 -0
  118. package/dist/ProteinView/proteinAbbreviationMapping.js.map +1 -0
  119. package/dist/ProteinView/proteinToGenomeMapping.d.ts +13 -0
  120. package/dist/ProteinView/proteinToGenomeMapping.js +69 -0
  121. package/dist/ProteinView/proteinToGenomeMapping.js.map +1 -0
  122. package/dist/ProteinView/selectResidue.d.ts +7 -0
  123. package/dist/ProteinView/selectResidue.js +10 -0
  124. package/dist/ProteinView/selectResidue.js.map +1 -0
  125. package/dist/ProteinView/useProteinView.d.ts +11 -0
  126. package/dist/ProteinView/useProteinView.js +57 -0
  127. package/dist/ProteinView/useProteinView.js.map +1 -0
  128. package/dist/ProteinView/useProteinViewClickBehavior.d.ts +8 -0
  129. package/dist/ProteinView/useProteinViewClickBehavior.js +34 -0
  130. package/dist/ProteinView/useProteinViewClickBehavior.js.map +1 -0
  131. package/dist/ProteinView/useProteinViewHoverBehavior.d.ts +6 -0
  132. package/dist/ProteinView/useProteinViewHoverBehavior.js +31 -0
  133. package/dist/ProteinView/useProteinViewHoverBehavior.js.map +1 -0
  134. package/dist/ProteinView/util.d.ts +19 -0
  135. package/dist/ProteinView/util.js +32 -0
  136. package/dist/ProteinView/util.js.map +1 -0
  137. package/dist/fetchUtils.d.ts +5 -0
  138. package/dist/fetchUtils.js +23 -0
  139. package/dist/fetchUtils.js.map +1 -0
  140. package/dist/genomeToTranscriptMapping.d.ts +7 -0
  141. package/dist/genomeToTranscriptMapping.js +36 -0
  142. package/dist/genomeToTranscriptMapping.js.map +1 -0
  143. package/dist/index.d.ts +8 -0
  144. package/dist/index.js +26 -0
  145. package/dist/index.js.map +1 -0
  146. package/dist/jbrowse-plugin-protein3d.umd.production.min.js +9298 -0
  147. package/dist/jbrowse-plugin-protein3d.umd.production.min.js.map +7 -0
  148. package/dist/mappings.d.ts +19 -0
  149. package/dist/mappings.js +67 -0
  150. package/dist/mappings.js.map +1 -0
  151. package/dist/mappings.test.d.ts +1 -0
  152. package/dist/mappings.test.js +27 -0
  153. package/dist/mappings.test.js.map +1 -0
  154. package/dist/test_data/gene.d.ts +67 -0
  155. package/dist/test_data/gene.js +603 -0
  156. package/dist/test_data/gene.js.map +1 -0
  157. package/package.json +70 -0
  158. package/src/AddHighlightModel/GenomeMouseoverHighlight.tsx +45 -0
  159. package/src/AddHighlightModel/Highlight.tsx +46 -0
  160. package/src/AddHighlightModel/HighlightComponents.tsx +26 -0
  161. package/src/AddHighlightModel/ProteinToGenomeClickHighlight.tsx +39 -0
  162. package/src/AddHighlightModel/ProteinToGenomeHoverHighlight.tsx +39 -0
  163. package/src/AddHighlightModel/index.tsx +25 -0
  164. package/src/AddHighlightModel/util.ts +17 -0
  165. package/src/LaunchProteinView/calculateProteinSequence.ts +127 -0
  166. package/src/LaunchProteinView/components/AlphaFoldDBSearch.tsx +141 -0
  167. package/src/LaunchProteinView/components/AlphaFoldDBSearchStatus.tsx +44 -0
  168. package/src/LaunchProteinView/components/HelpButton.tsx +23 -0
  169. package/src/LaunchProteinView/components/HelpDialog.tsx +43 -0
  170. package/src/LaunchProteinView/components/LaunchProteinViewDialog.tsx +57 -0
  171. package/src/LaunchProteinView/components/PreLoadedStructureMapping.tsx +153 -0
  172. package/src/LaunchProteinView/components/TabPanel.tsx +19 -0
  173. package/src/LaunchProteinView/components/TranscriptSelector.tsx +54 -0
  174. package/src/LaunchProteinView/components/UserProvidedStructure.tsx +226 -0
  175. package/src/LaunchProteinView/components/useCheckAlphaFoldDBExistence.ts +31 -0
  176. package/src/LaunchProteinView/index.ts +56 -0
  177. package/src/LaunchProteinView/useMyGeneInfo.ts +37 -0
  178. package/src/LaunchProteinView/useProteinSequences.ts +36 -0
  179. package/src/LaunchProteinView/util.ts +74 -0
  180. package/src/ProteinModelSessionExtension.ts +71 -0
  181. package/src/ProteinView/clearSelection.ts +5 -0
  182. package/src/ProteinView/components/Header.tsx +84 -0
  183. package/src/ProteinView/components/ProteinAlignment.tsx +119 -0
  184. package/src/ProteinView/components/ProteinAlignmentHelpButton.tsx +33 -0
  185. package/src/ProteinView/components/ProteinAlignmentHelpDialog.tsx +59 -0
  186. package/src/ProteinView/components/ProteinView.tsx +131 -0
  187. package/src/ProteinView/components/SplitString.tsx +35 -0
  188. package/src/ProteinView/css/molstar.ts +3136 -0
  189. package/src/ProteinView/genomeToProtein.ts +21 -0
  190. package/src/ProteinView/highlightResidue.ts +23 -0
  191. package/src/ProteinView/index.ts +18 -0
  192. package/src/ProteinView/launchRemotePairwiseAlignment.ts +113 -0
  193. package/src/ProteinView/loadStructureFromData.ts +48 -0
  194. package/src/ProteinView/loadStructureFromURL.ts +50 -0
  195. package/src/ProteinView/model.ts +384 -0
  196. package/src/ProteinView/proteinAbbreviationMapping.ts +24 -0
  197. package/src/ProteinView/proteinToGenomeMapping.ts +99 -0
  198. package/src/ProteinView/selectResidue.ts +19 -0
  199. package/src/ProteinView/useProteinView.ts +70 -0
  200. package/src/ProteinView/useProteinViewClickBehavior.ts +48 -0
  201. package/src/ProteinView/useProteinViewHoverBehavior.ts +44 -0
  202. package/src/ProteinView/util.ts +56 -0
  203. package/src/__snapshots__/mappings.test.ts.snap +1351 -0
  204. package/src/declare.d.ts +1 -0
  205. package/src/fetchUtils.ts +30 -0
  206. package/src/genomeToTranscriptMapping.ts +46 -0
  207. package/src/index.ts +32 -0
  208. package/src/mappings.test.ts +32 -0
  209. package/src/mappings.ts +89 -0
  210. package/src/test_data/gene.ts +604 -0
@@ -0,0 +1,74 @@
1
+ import { Feature } from '@jbrowse/core/util'
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
+ export function getTranscriptFeatures(feature: Feature) {
14
+ // check if we are looking at a 'two-level' or 'three-level' feature by
15
+ // finding exon/CDS subfeatures. we want to select from transcript names
16
+ const subfeatures = feature.get('subfeatures') ?? []
17
+ return subfeatures.some(
18
+ f => f.get('type') === 'CDS' || f.get('type') === 'exon',
19
+ )
20
+ ? [feature]
21
+ : subfeatures
22
+ }
23
+
24
+ export function stripTrailingVersion(s?: string) {
25
+ return s?.replace(/\.[^/.]+$/, '')
26
+ }
27
+
28
+ export function z(n: number) {
29
+ return n.toLocaleString('en-US')
30
+ }
31
+
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
+ export function getDisplayName(f: Feature): string {
55
+ return f.get('id')
56
+ }
57
+
58
+ export function getId(val?: Feature): string {
59
+ return val === undefined ? '' : val.id()
60
+ }
61
+
62
+ export function getTranscriptDisplayName(val?: Feature): string {
63
+ return val === undefined
64
+ ? ''
65
+ : [val.get('name'), val.get('id')].filter(f => !!f).join(' ')
66
+ }
67
+
68
+ export function getGeneDisplayName(val?: Feature): string {
69
+ return val === undefined
70
+ ? ''
71
+ : [val.get('gene_name') || val.get('name'), val.get('id')]
72
+ .filter(f => !!f)
73
+ .join(' ')
74
+ }
@@ -0,0 +1,71 @@
1
+ import { addDisposer, types } from 'mobx-state-tree'
2
+ import { autorun } from 'mobx'
3
+ import { ungzip } from 'pako'
4
+
5
+ // locals
6
+ import { Row } from './LaunchProteinView/util'
7
+ import { abfetch } from './fetchUtils'
8
+
9
+ const ProteinModelSessionExtension = types
10
+ .model({})
11
+ .volatile(() => ({
12
+ data: undefined as Row[] | undefined,
13
+ error: undefined as unknown,
14
+ }))
15
+ .actions(self => ({
16
+ setData(a?: Row[]) {
17
+ self.data = a
18
+ },
19
+ setError(e: unknown) {
20
+ self.error = e
21
+ },
22
+ }))
23
+ .actions(self => {
24
+ return {
25
+ afterCreate() {
26
+ const url = 'https://jbrowse.org/demos/protein3d/mart_export.txt.gz'
27
+ addDisposer(
28
+ self,
29
+ autorun(async () => {
30
+ try {
31
+ const ret = new TextDecoder('utf8').decode(
32
+ ungzip(await abfetch(url)),
33
+ )
34
+ const d = ret
35
+ .split('\n')
36
+ .slice(1)
37
+ .filter(line => !!line)
38
+ .map(line => {
39
+ const res = line.split('\t')
40
+ const [
41
+ gene_id,
42
+ gene_id_version,
43
+ transcript_id,
44
+ transcript_id_version,
45
+ pdb_id,
46
+ refseq_mrna_id,
47
+ refseq_mrna_predicted_id,
48
+ ] = res
49
+
50
+ return {
51
+ gene_id,
52
+ gene_id_version,
53
+ transcript_id_version,
54
+ transcript_id,
55
+ pdb_id,
56
+ refseq_mrna_predicted_id,
57
+ refseq_mrna_id,
58
+ }
59
+ })
60
+
61
+ self.setData(d)
62
+ } catch (error) {
63
+ self.setError(error)
64
+ }
65
+ }),
66
+ )
67
+ },
68
+ }
69
+ })
70
+
71
+ export default ProteinModelSessionExtension
@@ -0,0 +1,5 @@
1
+ import { PluginContext } from 'molstar/lib/mol-plugin/context'
2
+
3
+ export default function clearSelection({ plugin }: { plugin: PluginContext }) {
4
+ plugin?.managers.interactivity.lociSelects.deselectAll()
5
+ }
@@ -0,0 +1,84 @@
1
+ import React from 'react'
2
+ import { observer } from 'mobx-react'
3
+ import CascadingMenuButton from '@jbrowse/core/ui/CascadingMenuButton'
4
+
5
+ // icons
6
+ import MenuIcon from '@mui/icons-material/Menu'
7
+ import Visibility from '@mui/icons-material/Visibility'
8
+
9
+ // locals
10
+ import { JBrowsePluginProteinViewModel } from '../model'
11
+ import ProteinAlignment from './ProteinAlignment'
12
+ import { LoadingEllipses } from '@jbrowse/core/ui'
13
+
14
+ const ProteinViewHeader = observer(function ({
15
+ model,
16
+ }: {
17
+ model: JBrowsePluginProteinViewModel
18
+ }) {
19
+ const { alignment, showAlignment } = model
20
+ return (
21
+ <div>
22
+ <InformativeHeaderArea model={model} />
23
+ {showAlignment && alignment ? (
24
+ <ProteinAlignment model={model} />
25
+ ) : (
26
+ <LoadingEllipses message="Loading pairwise alignment" />
27
+ )}
28
+ </div>
29
+ )
30
+ })
31
+
32
+ const InformativeHeaderArea = observer(function ({
33
+ model,
34
+ }: {
35
+ model: JBrowsePluginProteinViewModel
36
+ }) {
37
+ const {
38
+ showAlignment,
39
+ clickString,
40
+ hoverString,
41
+ showHighlight,
42
+ zoomToBaseLevel,
43
+ } = model
44
+ return (
45
+ <div style={{ display: 'flex' }}>
46
+ <span>
47
+ {[
48
+ clickString ? `Click: ${clickString}` : '',
49
+ hoverString ? `Hover: ${hoverString}` : '',
50
+ ].join(' ')}
51
+ </span>
52
+ <span style={{ flexGrow: 1 }} />
53
+ <CascadingMenuButton
54
+ menuItems={[
55
+ {
56
+ label: 'Show pairwise alignment area',
57
+ type: 'checkbox',
58
+ checked: showAlignment,
59
+ icon: Visibility,
60
+ onClick: () => model.setShowAlignment(!showAlignment),
61
+ },
62
+ {
63
+ label: 'Show pairwise alignment as highlight',
64
+ type: 'checkbox',
65
+ checked: showHighlight,
66
+ icon: Visibility,
67
+ onClick: () => model.setShowHighlight(!showHighlight),
68
+ },
69
+ {
70
+ label: 'Zoom to base level on click',
71
+ type: 'checkbox',
72
+ checked: zoomToBaseLevel,
73
+ icon: Visibility,
74
+ onClick: () => model.setZoomToBaseLevel(!zoomToBaseLevel),
75
+ },
76
+ ]}
77
+ >
78
+ <MenuIcon />
79
+ </CascadingMenuButton>
80
+ </div>
81
+ )
82
+ })
83
+
84
+ export default ProteinViewHeader
@@ -0,0 +1,119 @@
1
+ import React from 'react'
2
+ import { observer } from 'mobx-react'
3
+ import { Tooltip, Typography } from '@mui/material'
4
+
5
+ // locals
6
+ import { JBrowsePluginProteinViewModel } from '../model'
7
+ import ProteinAlignmentHelpButton from './ProteinAlignmentHelpButton'
8
+ import {
9
+ clickProteinToGenome,
10
+ hoverProteinToGenome,
11
+ } from '../proteinToGenomeMapping'
12
+ import SplitString from './SplitString'
13
+
14
+ const ProteinAlignment = observer(function ({
15
+ model,
16
+ }: {
17
+ model: JBrowsePluginProteinViewModel
18
+ }) {
19
+ const {
20
+ structureSeqHoverPos,
21
+ alignment,
22
+ structurePositionToAlignmentMap,
23
+ alignmentToStructurePosition,
24
+ showHighlight,
25
+ } = model
26
+ const a0 = alignment!.alns[0].seq as string
27
+ const a1 = alignment!.alns[1].seq as string
28
+ const con = alignment!.consensus
29
+ const set = new Set<number>()
30
+ // eslint-disable-next-line unicorn/no-for-loop
31
+ for (let i = 0; i < con.length; i++) {
32
+ const letter = con[i]
33
+ if (letter === '|') {
34
+ set.add(i)
35
+ }
36
+ }
37
+
38
+ const alignmentHoverPos =
39
+ structureSeqHoverPos !== undefined
40
+ ? structurePositionToAlignmentMap?.[structureSeqHoverPos]
41
+ : undefined
42
+
43
+ function onMouseOver(alignmentPos: number) {
44
+ const structureSeqPos = alignmentToStructurePosition[alignmentPos]
45
+ model.setHoveredPosition({ structureSeqPos })
46
+ hoverProteinToGenome({ model, structureSeqPos })
47
+ }
48
+ function onClick(alignmentPos: number) {
49
+ const structureSeqPos = alignmentToStructurePosition[alignmentPos]
50
+ clickProteinToGenome({ model, structureSeqPos }).catch(e => {
51
+ console.error(e)
52
+ })
53
+ }
54
+ return (
55
+ <div>
56
+ <ProteinAlignmentHelpButton model={model} />
57
+
58
+ <Typography>
59
+ Alignment of the protein structure file&apos;s sequence with the
60
+ selected transcript&apos;s sequence. Green is the aligned portion
61
+ </Typography>
62
+ <div
63
+ style={{
64
+ fontSize: 9,
65
+ fontFamily: 'monospace',
66
+ cursor: 'pointer',
67
+ margin: 8,
68
+ paddingBottom: 8,
69
+ overflow: 'auto',
70
+ whiteSpace: 'nowrap',
71
+ }}
72
+ onMouseLeave={() => {
73
+ model.setHoveredPosition(undefined)
74
+ model.clearHoverGenomeHighlights()
75
+ }}
76
+ >
77
+ <div>
78
+ <Tooltip title="This is the sequence of the protein from the structure file">
79
+ <span>STRUCT&nbsp;</span>
80
+ </Tooltip>
81
+ <SplitString
82
+ str={a0}
83
+ showHighlight={showHighlight}
84
+ col={alignmentHoverPos}
85
+ set={set}
86
+ onMouseOver={onMouseOver}
87
+ onClick={onClick}
88
+ />
89
+ </div>
90
+ <div>
91
+ <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>
92
+ <SplitString
93
+ showHighlight={showHighlight}
94
+ str={con}
95
+ col={alignmentHoverPos}
96
+ set={set}
97
+ onMouseOver={onMouseOver}
98
+ onClick={onClick}
99
+ />
100
+ </div>
101
+ <div>
102
+ <Tooltip title="This is the sequence of the protein from the reference genome transcript">
103
+ <span>GENOME&nbsp;</span>
104
+ </Tooltip>
105
+ <SplitString
106
+ str={a1}
107
+ col={alignmentHoverPos}
108
+ showHighlight={showHighlight}
109
+ set={set}
110
+ onMouseOver={onMouseOver}
111
+ onClick={onClick}
112
+ />
113
+ </div>
114
+ </div>
115
+ </div>
116
+ )
117
+ })
118
+
119
+ export default ProteinAlignment
@@ -0,0 +1,33 @@
1
+ import React, { lazy } from 'react'
2
+ import { IconButton } from '@mui/material'
3
+ import { getSession } from '@jbrowse/core/util'
4
+
5
+ // locals
6
+ import { JBrowsePluginProteinViewModel } from '../model'
7
+
8
+ // icons
9
+ import Help from '@mui/icons-material/Help'
10
+
11
+ const ProteinAlignmentHelpDialog = lazy(
12
+ () => import('./ProteinAlignmentHelpDialog'),
13
+ )
14
+
15
+ export default function ProteinAlignmentHelpButton({
16
+ model,
17
+ }: {
18
+ model: JBrowsePluginProteinViewModel
19
+ }) {
20
+ return (
21
+ <IconButton
22
+ style={{ float: 'right' }}
23
+ onClick={() =>
24
+ getSession(model).queueDialog(handleClose => [
25
+ ProteinAlignmentHelpDialog,
26
+ { handleClose },
27
+ ])
28
+ }
29
+ >
30
+ <Help />
31
+ </IconButton>
32
+ )
33
+ }
@@ -0,0 +1,59 @@
1
+ import React from 'react'
2
+ import {
3
+ Button,
4
+ DialogActions,
5
+ DialogContent,
6
+ Divider,
7
+ Typography,
8
+ TypographyProps,
9
+ } from '@mui/material'
10
+ import { Dialog } from '@jbrowse/core/ui'
11
+
12
+ function Typography2({ children }: TypographyProps) {
13
+ return (
14
+ <Typography
15
+ style={{
16
+ margin: 4,
17
+ marginBottom: 12,
18
+ }}
19
+ >
20
+ {children}
21
+ </Typography>
22
+ )
23
+ }
24
+ export default function ProteinAlignmentHelpDialog({
25
+ handleClose,
26
+ }: {
27
+ handleClose: () => void
28
+ }) {
29
+ return (
30
+ <Dialog open maxWidth="lg" onClose={handleClose} title="Protein alignment">
31
+ <DialogContent>
32
+ <Typography2>
33
+ This panel shows the computed alignment of the reference genome
34
+ sequence to the structure sequence. The structure file (PDB file,
35
+ mmCIF file, etc) has a stored representation of the e.g. amino acid
36
+ sequence but the sequence in the structure file can differ from the
37
+ sequence from the gene on the genome browser
38
+ </Typography2>
39
+ <Typography2>
40
+ In order to resolve this, we align the two sequences together (using
41
+ EMBOSS needle) to get alignment of the genome&apos;s representation of
42
+ the protein and the structure file&apos;s representation of the
43
+ protein.
44
+ </Typography2>
45
+ <Typography2>
46
+ If you need a 100% fidelity protein, you can do a folding with e.g.
47
+ AlphaFold to make sure the structure you are using matches exactly the
48
+ sequence of the transcript
49
+ </Typography2>
50
+ </DialogContent>
51
+ <Divider />
52
+ <DialogActions>
53
+ <Button onClick={() => handleClose()} color="primary">
54
+ Close
55
+ </Button>
56
+ </DialogActions>
57
+ </Dialog>
58
+ )
59
+ }
@@ -0,0 +1,131 @@
1
+ import React, { useEffect } from 'react'
2
+ import { observer } from 'mobx-react'
3
+ import { ErrorMessage } from '@jbrowse/core/ui'
4
+ import { PluginContext } from 'molstar/lib/mol-plugin/context'
5
+
6
+ // locals
7
+ import { JBrowsePluginProteinViewModel } from '../model'
8
+ import Header from './Header'
9
+
10
+ // hooks
11
+ import useProteinView from '../useProteinView'
12
+ import useProteinViewClickBehavior from '../useProteinViewClickBehavior'
13
+ import useProteinViewHoverBehavior from '../useProteinViewHoverBehavior'
14
+
15
+ // utils
16
+ import selectResidue from '../selectResidue'
17
+ import highlightResidue from '../highlightResidue'
18
+ import clearSelection from '../clearSelection'
19
+
20
+ // css
21
+ import css from '../css/molstar'
22
+
23
+ if (document?.head) {
24
+ const style = document.createElement('style')
25
+ style.append(css)
26
+ document.head?.append(style)
27
+ }
28
+
29
+ const ProteinView = observer(function ({
30
+ model,
31
+ }: {
32
+ model: JBrowsePluginProteinViewModel
33
+ }) {
34
+ const { url, data, showControls } = model
35
+ const { plugin, seq, parentRef, error } = useProteinView({
36
+ url,
37
+ data,
38
+ showControls,
39
+ })
40
+ return error ? (
41
+ <ErrorMessage error={error} />
42
+ ) : (
43
+ <ProteinViewContainer
44
+ model={model}
45
+ plugin={plugin}
46
+ seq={seq}
47
+ parentRef={parentRef}
48
+ />
49
+ )
50
+ })
51
+
52
+ const ProteinViewContainer = observer(function ({
53
+ model,
54
+ plugin,
55
+ seq,
56
+ parentRef,
57
+ }: {
58
+ model: JBrowsePluginProteinViewModel
59
+ plugin?: PluginContext
60
+ seq?: string
61
+ parentRef?: React.RefObject<HTMLDivElement>
62
+ }) {
63
+ const {
64
+ width,
65
+ height,
66
+ structureSeqToTranscriptSeqPosition,
67
+ seq2,
68
+ structureSeqHoverPos,
69
+ showHighlight,
70
+ alignment,
71
+ } = model
72
+
73
+ const { error } = useProteinViewClickBehavior({ plugin, model })
74
+ useProteinViewHoverBehavior({ plugin, model })
75
+
76
+ const structure =
77
+ plugin?.managers.structure.hierarchy.current.structures[0]?.cell.obj?.data
78
+
79
+ useEffect(() => {
80
+ model.setSeqs(seq, seq2)
81
+ }, [seq, model, seq2])
82
+
83
+ useEffect(() => {
84
+ if (!plugin || !structureSeqToTranscriptSeqPosition || !structure) {
85
+ return
86
+ }
87
+ if (showHighlight) {
88
+ for (const coord of Object.keys(structureSeqToTranscriptSeqPosition)) {
89
+ selectResidue({
90
+ structure,
91
+ plugin,
92
+ selectedResidue: +coord + 1,
93
+ })
94
+ }
95
+ } else {
96
+ clearSelection({ plugin })
97
+ }
98
+ }, [plugin, structure, showHighlight, structureSeqToTranscriptSeqPosition])
99
+
100
+ useEffect(() => {
101
+ if (!plugin || !structure || structureSeqHoverPos === undefined) {
102
+ return
103
+ }
104
+ if (structureSeqHoverPos !== undefined) {
105
+ highlightResidue({
106
+ structure,
107
+ plugin,
108
+ selectedResidue: structureSeqHoverPos,
109
+ })
110
+ } else {
111
+ console.warn('not found')
112
+ }
113
+ }, [plugin, structure, structureSeqHoverPos])
114
+
115
+ return (
116
+ <div style={{ background: !alignment ? '#ccc' : undefined }}>
117
+ {error ? <ErrorMessage error={error} /> : null}
118
+ <Header model={model} />
119
+ <div
120
+ ref={parentRef}
121
+ style={{
122
+ position: 'relative',
123
+ width,
124
+ height,
125
+ }}
126
+ />
127
+ </div>
128
+ )
129
+ })
130
+
131
+ export default ProteinView
@@ -0,0 +1,35 @@
1
+ import React from 'react'
2
+
3
+ export default function SplitString({
4
+ str,
5
+ col,
6
+ set,
7
+ onMouseOver,
8
+ onClick,
9
+ showHighlight,
10
+ }: {
11
+ str: string
12
+ col?: number
13
+ set?: Set<number>
14
+ onMouseOver?: (arg: number) => void
15
+ onClick?: (arg: number) => void
16
+ showHighlight: boolean
17
+ }) {
18
+ return str.split('').map((d, i) => (
19
+ <span
20
+ key={`${d}-${i}`}
21
+ onMouseOver={() => onMouseOver?.(i)}
22
+ onClick={() => onClick?.(i)}
23
+ style={{
24
+ background:
25
+ col !== undefined && i === col
26
+ ? '#f69'
27
+ : set?.has(i) && showHighlight
28
+ ? '#33ff19'
29
+ : undefined,
30
+ }}
31
+ >
32
+ {d === ' ' ? <>&nbsp;</> : d}
33
+ </span>
34
+ ))
35
+ }