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
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "version": "0.0.2",
3
+ "name": "jbrowse-plugin-protein3d",
4
+ "keywords": [
5
+ "jbrowse",
6
+ "jbrowse2"
7
+ ],
8
+ "main": "dist/index.js",
9
+ "files": [
10
+ "dist",
11
+ "src"
12
+ ],
13
+ "scripts": {
14
+ "test": "jest",
15
+ "clean": "rimraf dist",
16
+ "prebuild": "npm run clean",
17
+ "start": "node esbuild.mjs",
18
+ "build": "tsc && NODE_ENV=production node esbuild.mjs",
19
+ "lint": "eslint --report-unused-disable-directives --max-warnings 0 src/",
20
+ "prepack": "npm run build",
21
+ "postversion": "git push --follow-tags"
22
+ },
23
+ "dependencies": {
24
+ "@mui/icons-material": "^5.15.10",
25
+ "clustal-js": "^2.0.1",
26
+ "g2p_mapper": "^1.0.3",
27
+ "molstar": "^4.0.0",
28
+ "pako": "^2.1.0"
29
+ },
30
+ "devDependencies": {
31
+ "@eslint/compat": "^1.1.0",
32
+ "@fal-works/esbuild-plugin-global-externals": "^2.1.2",
33
+ "@jbrowse/core": "^2.0.0",
34
+ "@jbrowse/plugin-linear-genome-view": "^2.4.2",
35
+ "@mui/material": "^5.12.0",
36
+ "@mui/system": "^5.12.0",
37
+ "@mui/x-data-grid": "^7.3.0",
38
+ "@types/jest": "^29.5.12",
39
+ "@types/node": "^20.11.16",
40
+ "@types/pako": "^2.0.0",
41
+ "@types/react": "^18.2.54",
42
+ "@typescript-eslint/eslint-plugin": "^7.0.1",
43
+ "@typescript-eslint/parser": "^7.0.1",
44
+ "esbuild": "^0.23.0",
45
+ "eslint": "^9.0.0",
46
+ "eslint-config-prettier": "^9.0.0",
47
+ "eslint-plugin-prettier": "^5.0.0",
48
+ "eslint-plugin-react": "^7.20.3",
49
+ "eslint-plugin-react-hooks": "^4.0.8",
50
+ "eslint-plugin-react-refresh": "^0.4.3",
51
+ "eslint-plugin-unicorn": "^54.0.0",
52
+ "jest": "^29.7.0",
53
+ "mobx": "^6.0.0",
54
+ "mobx-react": "^9.0.1",
55
+ "mobx-state-tree": "5.4.2",
56
+ "npm-run-all": "^4.1.5",
57
+ "prettier": "^3.2.5",
58
+ "pretty-bytes": "^6.1.1",
59
+ "react": "^18.2.0",
60
+ "react-dom": "^18.2.0",
61
+ "rimraf": "^5.0.0",
62
+ "rxjs": "^7.0.0",
63
+ "ts-jest": "^29.1.2",
64
+ "ts-node": "^10.3.0",
65
+ "tss-react": "^4.9.4",
66
+ "typescript": "^5.3.3"
67
+ },
68
+ "author": "Colin <colin.diesh@gmail.com>",
69
+ "license": "MIT"
70
+ }
@@ -0,0 +1,45 @@
1
+ import React from 'react'
2
+ import { observer } from 'mobx-react'
3
+ import { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
4
+ import { getSession } from '@jbrowse/core/util'
5
+ // locals
6
+ import Highlight from './Highlight'
7
+
8
+ const GenomeMouseoverHighlight = observer(function ({
9
+ model,
10
+ }: {
11
+ model: LinearGenomeViewModel
12
+ }) {
13
+ const { hovered } = getSession(model)
14
+ return hovered &&
15
+ typeof hovered === 'object' &&
16
+ 'hoverPosition' in hovered ? (
17
+ <HoverHighlight model={model} />
18
+ ) : null
19
+ })
20
+
21
+ const HoverHighlight = observer(function ({
22
+ model,
23
+ }: {
24
+ model: LinearGenomeViewModel
25
+ }) {
26
+ const session = getSession(model)
27
+ if (session.views.some(s => s.type === 'ProteinView')) {
28
+ const { hovered } = session
29
+ const { assemblyNames } = model
30
+ // @ts-expect-error
31
+ const { coord, refName } = hovered.hoverPosition
32
+ return (
33
+ <Highlight
34
+ model={model}
35
+ start={coord - 1}
36
+ end={coord}
37
+ refName={refName}
38
+ assemblyName={assemblyNames[0]}
39
+ />
40
+ )
41
+ }
42
+ return null
43
+ })
44
+
45
+ export default GenomeMouseoverHighlight
@@ -0,0 +1,46 @@
1
+ import React from 'react'
2
+ import { observer } from 'mobx-react'
3
+ import { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
4
+ import { getSession } from '@jbrowse/core/util'
5
+
6
+ // locals
7
+ import { useStyles } from './util'
8
+
9
+ const Highlight = observer(function Highlight({
10
+ assemblyName,
11
+ start,
12
+ end,
13
+ refName,
14
+ model,
15
+ }: {
16
+ model: LinearGenomeViewModel
17
+ assemblyName: string
18
+ start: number
19
+ end: number
20
+ refName: string
21
+ }) {
22
+ const { cx, classes } = useStyles()
23
+ const { assemblyManager } = getSession(model)
24
+ const { offsetPx } = model
25
+ const assembly = assemblyManager.get(assemblyName)
26
+ const ref = assembly?.getCanonicalRefName(refName) ?? refName
27
+ const s = model.bpToPx({ refName: ref, coord: start })
28
+ const e = model.bpToPx({ refName: ref, coord: end })
29
+ if (s && e) {
30
+ const width = Math.max(Math.abs(e.offsetPx - s.offsetPx), 3)
31
+ const left = Math.min(s.offsetPx, e.offsetPx) - offsetPx
32
+ return (
33
+ <div
34
+ className={cx(
35
+ classes.highlight,
36
+ width <= 3 ? classes.thinborder : undefined,
37
+ )}
38
+ style={{ left, width }}
39
+ />
40
+ )
41
+ } else {
42
+ return null
43
+ }
44
+ })
45
+
46
+ export default Highlight
@@ -0,0 +1,26 @@
1
+ import React from 'react'
2
+ import { observer } from 'mobx-react'
3
+ import { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
4
+
5
+ // locals
6
+ import ProteinToGenomeClickHighlight from './ProteinToGenomeClickHighlight'
7
+ import ProteinToGenomeHoverHighlight from './ProteinToGenomeHoverHighlight'
8
+ import GenomeMouseoverHighlight from './GenomeMouseoverHighlight'
9
+
10
+ type LGV = LinearGenomeViewModel
11
+
12
+ const HighlightComponents = observer(function Highlight({
13
+ model,
14
+ }: {
15
+ model: LGV
16
+ }) {
17
+ return (
18
+ <>
19
+ <ProteinToGenomeClickHighlight model={model} />
20
+ <ProteinToGenomeHoverHighlight model={model} />
21
+ <GenomeMouseoverHighlight model={model} />
22
+ </>
23
+ )
24
+ })
25
+
26
+ export default HighlightComponents
@@ -0,0 +1,39 @@
1
+ import React from 'react'
2
+ import { observer } from 'mobx-react'
3
+ import { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
4
+ import { getSession } from '@jbrowse/core/util'
5
+
6
+ // locals
7
+ import { JBrowsePluginProteinViewModel } from '../ProteinView/model'
8
+ import Highlight from './Highlight'
9
+
10
+ type LGV = LinearGenomeViewModel
11
+
12
+ const ProteinToGenomeClickHighlight = observer(function ({
13
+ model,
14
+ }: {
15
+ model: LGV
16
+ }) {
17
+ const { assemblyManager, views } = getSession(model)
18
+ const { assemblyNames } = model
19
+ const p = views.find(
20
+ f => f.type === 'ProteinView',
21
+ ) as JBrowsePluginProteinViewModel
22
+ const assembly = assemblyManager.get(assemblyNames[0])
23
+ return assembly ? (
24
+ <>
25
+ {p?.clickGenomeHighlights.map((r, idx) => (
26
+ <Highlight
27
+ key={`${JSON.stringify(r)}-${idx}}`}
28
+ start={r.start}
29
+ end={r.end}
30
+ refName={r.refName}
31
+ assemblyName={assemblyNames[0]}
32
+ model={model}
33
+ />
34
+ ))}
35
+ </>
36
+ ) : null
37
+ })
38
+
39
+ export default ProteinToGenomeClickHighlight
@@ -0,0 +1,39 @@
1
+ import React from 'react'
2
+ import { observer } from 'mobx-react'
3
+ import { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
4
+ import { getSession } from '@jbrowse/core/util'
5
+
6
+ // locals
7
+ import { JBrowsePluginProteinViewModel } from '../ProteinView/model'
8
+ import Highlight from './Highlight'
9
+
10
+ type LGV = LinearGenomeViewModel
11
+
12
+ const ProteinToGenomeHoverHighlight = observer(function ({
13
+ model,
14
+ }: {
15
+ model: LGV
16
+ }) {
17
+ const { assemblyManager, views } = getSession(model)
18
+ const { assemblyNames } = model
19
+ const p = views.find(
20
+ f => f.type === 'ProteinView',
21
+ ) as JBrowsePluginProteinViewModel
22
+ const assembly = assemblyManager.get(assemblyNames[0])
23
+ return assembly ? (
24
+ <>
25
+ {p?.hoverGenomeHighlights.map((r, idx) => (
26
+ <Highlight
27
+ key={`${JSON.stringify(r)}-${idx}`}
28
+ start={r.start}
29
+ end={r.end}
30
+ refName={r.refName}
31
+ assemblyName={assemblyNames[0]}
32
+ model={model}
33
+ />
34
+ ))}
35
+ </>
36
+ ) : null
37
+ })
38
+
39
+ export default ProteinToGenomeHoverHighlight
@@ -0,0 +1,25 @@
1
+ import React from 'react'
2
+ import PluginManager from '@jbrowse/core/PluginManager'
3
+ import { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
4
+
5
+ // locals
6
+ import HighlightComponents from './HighlightComponents'
7
+
8
+ export default function AddHighlightModelF(pluginManager: PluginManager) {
9
+ pluginManager.addToExtensionPoint(
10
+ 'LinearGenomeView-TracksContainerComponent',
11
+ // @ts-expect-error
12
+ (
13
+ rest: React.ReactNode[] = [],
14
+ { model }: { model: LinearGenomeViewModel },
15
+ ) => {
16
+ return [
17
+ ...rest,
18
+ <HighlightComponents
19
+ key="highlight_protein_viewer_protein3d"
20
+ model={model}
21
+ />,
22
+ ]
23
+ },
24
+ )
25
+ }
@@ -0,0 +1,17 @@
1
+ import { makeStyles } from 'tss-react/mui'
2
+
3
+ export const useStyles = makeStyles()({
4
+ highlight: {
5
+ height: '100%',
6
+ background: 'rgba(255,255,0,0.2)',
7
+ border: '1px solid rgba(50,50,0,0.2)',
8
+ position: 'absolute',
9
+ zIndex: 1000,
10
+ textAlign: 'center',
11
+ pointerEvents: 'none',
12
+ overflow: 'hidden',
13
+ },
14
+ thinborder: {
15
+ border: '1px solid black',
16
+ },
17
+ })
@@ -0,0 +1,127 @@
1
+ import { getConf } from '@jbrowse/core/configuration'
2
+ import {
3
+ Feature,
4
+ defaultCodonTable,
5
+ generateCodonTable,
6
+ getSession,
7
+ revcom,
8
+ } from '@jbrowse/core/util'
9
+
10
+ export interface Feat {
11
+ start: number
12
+ end: number
13
+ type: string
14
+ }
15
+
16
+ export function stitch(subfeats: Feat[], sequence: string) {
17
+ return subfeats.map(sub => sequence.slice(sub.start, sub.end)).join('')
18
+ }
19
+
20
+ export function calculateProteinSequence({
21
+ cds,
22
+ sequence,
23
+ codonTable,
24
+ }: {
25
+ cds: Feat[]
26
+ sequence: string
27
+ codonTable: Record<string, string>
28
+ }) {
29
+ const str = stitch(cds, sequence)
30
+ let protein = ''
31
+ for (let i = 0; i < str.length; i += 3) {
32
+ // use & symbol for undefined codon, or partial slice
33
+ protein += codonTable[str.slice(i, i + 3)] || '&'
34
+ }
35
+ return protein
36
+ }
37
+
38
+ export function revlist(list: Feat[], seqlen: number) {
39
+ return list
40
+ .map(sub => ({
41
+ ...sub,
42
+ start: seqlen - sub.end,
43
+ end: seqlen - sub.start,
44
+ }))
45
+ .sort((a, b) => a.start - b.start)
46
+ }
47
+
48
+ // filter items if they have the same "ID" or location
49
+ function getItemId(feat: Feat) {
50
+ return `${feat.start}-${feat.end}`
51
+ }
52
+
53
+ // filters if successive elements share same start/end
54
+ export function dedupe(list: Feat[]) {
55
+ return list.filter(
56
+ (item, pos, ary) => !pos || getItemId(item) !== getItemId(ary[pos - 1]),
57
+ )
58
+ }
59
+
60
+ export function getProteinSequence({
61
+ feature,
62
+ seq,
63
+ }: {
64
+ seq: string
65
+ feature: Feature
66
+ }) {
67
+ // @ts-expect-error
68
+ const f = feature.toJSON() as {
69
+ start: number
70
+ end: number
71
+ strand: number
72
+ type: string
73
+ subfeatures: { start: number; end: number; type: string }[]
74
+ }
75
+ const cds = dedupe(
76
+ f.subfeatures
77
+ .sort((a, b) => a.start - b.start)
78
+ .map(sub => ({
79
+ ...sub,
80
+ start: sub.start - f.start,
81
+ end: sub.end - f.start,
82
+ }))
83
+ .filter(f => f.type === 'CDS'),
84
+ )
85
+
86
+ return calculateProteinSequence({
87
+ cds: f.strand === -1 ? revlist(cds, seq.length) : cds,
88
+ sequence: f.strand === -1 ? revcom(seq) : seq,
89
+ codonTable: generateCodonTable(defaultCodonTable),
90
+ })
91
+ }
92
+
93
+ export async function fetchProteinSeq({
94
+ feature,
95
+ view,
96
+ }: {
97
+ feature: Feature
98
+ view: { assemblyNames?: string[] } | undefined
99
+ }) {
100
+ const start = feature.get('start')
101
+ const end = feature.get('end')
102
+ const refName = feature.get('refName')
103
+ const session = getSession(view)
104
+ const { assemblyManager, rpcManager } = session
105
+ const [assemblyName] = view?.assemblyNames ?? []
106
+ const assembly = await assemblyManager.waitForAssembly(assemblyName)
107
+ if (!assembly) {
108
+ throw new Error('assembly not found')
109
+ }
110
+ const sessionId = 'getSequence'
111
+ const feats = await rpcManager.call(sessionId, 'CoreGetFeatures', {
112
+ adapterConfig: getConf(assembly, ['sequence', 'adapter']),
113
+ sessionId,
114
+ regions: [
115
+ {
116
+ start,
117
+ end,
118
+ refName: assembly.getCanonicalRefName(refName),
119
+ assemblyName,
120
+ },
121
+ ],
122
+ })
123
+
124
+ const [feat] = feats as Feature[]
125
+ const seq = feat?.get('seq') as string | undefined
126
+ return seq ? getProteinSequence({ seq, feature }) : undefined
127
+ }
@@ -0,0 +1,141 @@
1
+ import React, { useEffect, useState } from 'react'
2
+ import { observer } from 'mobx-react'
3
+ import { Button, DialogActions, DialogContent } from '@mui/material'
4
+ import { makeStyles } from 'tss-react/mui'
5
+ import {
6
+ AbstractTrackModel,
7
+ Feature,
8
+ getContainingView,
9
+ getSession,
10
+ } from '@jbrowse/core/util'
11
+ import { ErrorMessage, LoadingEllipses } from '@jbrowse/core/ui'
12
+ import { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
13
+
14
+ // locals
15
+ import {
16
+ getDisplayName,
17
+ getGeneDisplayName,
18
+ getId,
19
+ getTranscriptDisplayName,
20
+ getTranscriptFeatures,
21
+ } from '../util'
22
+ import TranscriptSelector from './TranscriptSelector'
23
+ import HelpButton from './HelpButton'
24
+
25
+ // hooks
26
+ import useMyGeneInfo from '../useMyGeneInfo'
27
+ import useAllSequences from '../useProteinSequences'
28
+ import { useCheckAlphaFoldDBExistence } from './useCheckAlphaFoldDBExistence'
29
+ import AlphaFoldDBSearchStatus from './AlphaFoldDBSearchStatus'
30
+
31
+ const useStyles = makeStyles()(theme => ({
32
+ dialogContent: {
33
+ marginTop: theme.spacing(6),
34
+ width: '80em',
35
+ },
36
+ }))
37
+
38
+ type LGV = LinearGenomeViewModel
39
+
40
+ const AlphaFoldDBSearch = observer(function AlphaFoldDBSearch({
41
+ feature,
42
+ model,
43
+ handleClose,
44
+ }: {
45
+ feature: Feature
46
+ model: AbstractTrackModel
47
+ handleClose: () => void
48
+ }) {
49
+ const { classes } = useStyles()
50
+ const session = getSession(model)
51
+
52
+ // check if we are looking at a 'two-level' or 'three-level' feature by
53
+ // finding exon/CDS subfeatures. we want to select from transcript names
54
+ const options = getTranscriptFeatures(feature)
55
+ const [userSelection, setUserSelection] = useState<string>()
56
+ const view = getContainingView(model) as LGV
57
+ const selectedTranscript = options.find(val => getId(val) === userSelection)
58
+ const { seqs, error: error2 } = useAllSequences({ feature, view })
59
+ const protein = seqs?.[userSelection ?? '']
60
+ const { result: foundStructureId, error } = useMyGeneInfo({
61
+ id: selectedTranscript ? getDisplayName(selectedTranscript) : '',
62
+ })
63
+
64
+ useEffect(() => {
65
+ if (userSelection === undefined && seqs !== undefined) {
66
+ setUserSelection(options.find(f => !!seqs[f.id()])?.id())
67
+ }
68
+ }, [options, userSelection, seqs])
69
+ const {
70
+ success,
71
+ loading,
72
+ error: error3,
73
+ } = useCheckAlphaFoldDBExistence({
74
+ foundStructureId,
75
+ })
76
+
77
+ const e = error || error2 || error3
78
+ const url = `https://alphafold.ebi.ac.uk/files/AF-${foundStructureId}-F1-model_v4.cif`
79
+ return (
80
+ <>
81
+ <DialogContent className={classes.dialogContent}>
82
+ {e ? <ErrorMessage error={e} /> : null}
83
+ <div>
84
+ Look up AlphaFoldDB structure for given transcript <HelpButton />
85
+ </div>
86
+ {seqs ? (
87
+ <>
88
+ <TranscriptSelector
89
+ val={userSelection ?? ''}
90
+ setVal={setUserSelection}
91
+ options={options}
92
+ feature={feature}
93
+ seqs={seqs}
94
+ />
95
+ {selectedTranscript ? (
96
+ <AlphaFoldDBSearchStatus
97
+ foundStructureId={foundStructureId}
98
+ selectedTranscript={selectedTranscript}
99
+ success={success}
100
+ loading={loading}
101
+ />
102
+ ) : null}
103
+ </>
104
+ ) : (
105
+ <div style={{ margin: 20 }}>
106
+ <LoadingEllipses message="Loading protein sequences" variant="h6" />
107
+ </div>
108
+ )}
109
+ </DialogContent>
110
+ <DialogActions>
111
+ <Button
112
+ variant="contained"
113
+ color="secondary"
114
+ onClick={() => handleClose()}
115
+ >
116
+ Cancel
117
+ </Button>
118
+ <Button
119
+ variant="contained"
120
+ color="primary"
121
+ disabled={!foundStructureId || !protein || !selectedTranscript}
122
+ onClick={() => {
123
+ session.addView('ProteinView', {
124
+ type: 'ProteinView',
125
+ url,
126
+ seq2: protein,
127
+ feature: selectedTranscript?.toJSON(),
128
+ connectedViewId: view.id,
129
+ displayName: `Protein view ${getGeneDisplayName(feature)} - ${getTranscriptDisplayName(selectedTranscript)}`,
130
+ })
131
+ handleClose()
132
+ }}
133
+ >
134
+ Submit
135
+ </Button>
136
+ </DialogActions>
137
+ </>
138
+ )
139
+ })
140
+
141
+ export default AlphaFoldDBSearch
@@ -0,0 +1,44 @@
1
+ import React from 'react'
2
+ import { Link, Typography } from '@mui/material'
3
+ import { Feature } from '@jbrowse/core/util'
4
+ import { LoadingEllipses } from '@jbrowse/core/ui'
5
+
6
+ // locals
7
+ import { getDisplayName } from '../util'
8
+
9
+ export default function AlphaFoldDBSearchStatus({
10
+ foundStructureId,
11
+ selectedTranscript,
12
+ success,
13
+ loading,
14
+ }: {
15
+ foundStructureId?: string
16
+ selectedTranscript: Feature
17
+ success: boolean
18
+ loading: boolean
19
+ }) {
20
+ return !foundStructureId ? (
21
+ <Typography>
22
+ Searching {getDisplayName(selectedTranscript)} for UniProt ID
23
+ </Typography>
24
+ ) : (
25
+ <>
26
+ <Typography>Found Uniprot ID: {foundStructureId}</Typography>
27
+ {loading ? (
28
+ <LoadingEllipses title="Looking up structure in AlphaFoldDB" />
29
+ ) : success ? (
30
+ <Typography>Found structure in AlphaFoldDB</Typography>
31
+ ) : (
32
+ <Typography>
33
+ No structure found for this UniProtID in AlphaFoldDB{' '}
34
+ <Link
35
+ target="_blank"
36
+ href={`https://alphafold.ebi.ac.uk/search/text/${foundStructureId}`}
37
+ >
38
+ (search for results)
39
+ </Link>
40
+ </Typography>
41
+ )}
42
+ </>
43
+ )
44
+ }
@@ -0,0 +1,23 @@
1
+ import React, { Suspense, lazy, useState } from 'react'
2
+ import { IconButton } from '@mui/material'
3
+ // icons
4
+ import Help from '@mui/icons-material/Help'
5
+
6
+ // lazies
7
+ const HelpDialog = lazy(() => import('./HelpDialog'))
8
+
9
+ export default function HelpButton() {
10
+ const [show, setShow] = useState(false)
11
+ return (
12
+ <>
13
+ <IconButton onClick={() => setShow(true)}>
14
+ <Help />
15
+ </IconButton>
16
+ {show ? (
17
+ <Suspense fallback={null}>
18
+ <HelpDialog handleClose={() => setShow(false)} />
19
+ </Suspense>
20
+ ) : null}
21
+ </>
22
+ )
23
+ }
@@ -0,0 +1,43 @@
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 <Typography style={{ margin: 4 }}>{children}</Typography>
14
+ }
15
+ export default function HelpDialog({
16
+ handleClose,
17
+ }: {
18
+ handleClose: () => void
19
+ }) {
20
+ return (
21
+ <Dialog open maxWidth="lg" onClose={handleClose} title="Protein alignment">
22
+ <DialogContent>
23
+ <Typography2>
24
+ This process searches mygene.info for the transcript ID, in order to
25
+ retrieve the UniProt ID associated with a given transcript ID. Then,
26
+ it uses that UniProt ID to lookup the structure in AlphaFoldDB because
27
+ every UniProt ID has been processed by AlphaFold.
28
+ </Typography2>
29
+ <Typography2>
30
+ If you run into challenges with this workflow e.g. your transcripts
31
+ are not being found in mygene.info and you are interested in using
32
+ this plugin, contact colin.diesh@gmail.com
33
+ </Typography2>
34
+ </DialogContent>
35
+ <Divider />
36
+ <DialogActions>
37
+ <Button onClick={() => handleClose()} color="primary">
38
+ Close
39
+ </Button>
40
+ </DialogActions>
41
+ </Dialog>
42
+ )
43
+ }