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,21 @@
1
+ import { getSession } from '@jbrowse/core/util'
2
+ import { checkHovered } from './util'
3
+ import { JBrowsePluginProteinViewModel } from './model'
4
+
5
+ export function genomeToProtein({
6
+ model,
7
+ }: {
8
+ model: JBrowsePluginProteinViewModel
9
+ }): number | undefined {
10
+ const { hovered } = getSession(model)
11
+ const { genomeToTranscriptSeqMapping, connectedView } = model
12
+ if (
13
+ !connectedView?.initialized ||
14
+ !genomeToTranscriptSeqMapping ||
15
+ !checkHovered(hovered)
16
+ ) {
17
+ return undefined
18
+ }
19
+
20
+ return genomeToTranscriptSeqMapping.g2p[hovered.hoverPosition.coord]
21
+ }
@@ -0,0 +1,23 @@
1
+ import { PluginContext } from 'molstar/lib/mol-plugin/context'
2
+ import { Structure, StructureSelection } from 'molstar/lib/mol-model/structure'
3
+ import { getMolstarStructureSelection } from './util'
4
+
5
+ export default function highlightResidue({
6
+ structure,
7
+ selectedResidue,
8
+ plugin,
9
+ }: {
10
+ structure: Structure
11
+ selectedResidue: number
12
+ plugin: PluginContext
13
+ }) {
14
+ const sel = getMolstarStructureSelection({
15
+ structure,
16
+ selectedResidue: selectedResidue + 1,
17
+ })
18
+ const loci = StructureSelection.toLociWithSourceUnits(sel)
19
+ plugin?.managers.interactivity.lociHighlights.clearHighlights()
20
+ plugin?.managers.interactivity.lociHighlights.highlight({
21
+ loci,
22
+ })
23
+ }
@@ -0,0 +1,18 @@
1
+ import { lazy } from 'react'
2
+ import PluginManager from '@jbrowse/core/PluginManager'
3
+ import { ViewType } from '@jbrowse/core/pluggableElementTypes'
4
+
5
+ import stateModelF from './model'
6
+
7
+ const ReactComponent = lazy(() => import('./components/ProteinView'))
8
+
9
+ export default function ProteinViewF(pluginManager: PluginManager) {
10
+ pluginManager.addViewType(() => {
11
+ return new ViewType({
12
+ name: 'ProteinView',
13
+ displayName: 'Protein view',
14
+ stateModel: stateModelF(),
15
+ ReactComponent,
16
+ })
17
+ })
18
+ }
@@ -0,0 +1,113 @@
1
+ import { textfetch, timeout } from '../fetchUtils'
2
+ import { parsePairwise } from 'clustal-js'
3
+
4
+ const base = `https://www.ebi.ac.uk/Tools/services/rest`
5
+
6
+ async function runEmbossMatcher({
7
+ seq1,
8
+ seq2,
9
+ onProgress,
10
+ }: {
11
+ seq1: string
12
+ seq2: string
13
+ onProgress: (arg: string) => void
14
+ }) {
15
+ const jobId = await textfetch(`${base}/emboss_matcher/run`, {
16
+ method: 'POST',
17
+ body: new URLSearchParams({
18
+ email: 'colin.diesh@gmail.com',
19
+ asequence: `>a\n${seq1}`,
20
+ bsequence: `>b\n${seq2}`,
21
+ }),
22
+ })
23
+ await wait({
24
+ jobId,
25
+ algorithm: 'emboss_matcher',
26
+ onProgress,
27
+ })
28
+ const ret = await textfetch(`${base}/emboss_matcher/result/${jobId}/aln`)
29
+ return {
30
+ alignment: parsePairwise(
31
+ ret
32
+ .split('\n')
33
+ .filter(line => !line.startsWith('#'))
34
+ .join('\n'),
35
+ ),
36
+ }
37
+ }
38
+
39
+ async function runEmbossNeedle({
40
+ seq1,
41
+ seq2,
42
+ onProgress,
43
+ }: {
44
+ seq1: string
45
+ seq2: string
46
+ onProgress: (arg: string) => void
47
+ }) {
48
+ const jobId = await textfetch(`${base}/emboss_needle/run`, {
49
+ method: 'POST',
50
+ body: new URLSearchParams({
51
+ email: 'colin.diesh@gmail.com',
52
+ asequence: `>a\n${seq1}`,
53
+ bsequence: `>b\n${seq2}`,
54
+ }),
55
+ })
56
+ await wait({
57
+ jobId,
58
+ algorithm: 'emboss_needle',
59
+ onProgress,
60
+ })
61
+
62
+ const ret = await textfetch(`${base}/emboss_needle/result/${jobId}/aln`)
63
+ return {
64
+ alignment: parsePairwise(
65
+ ret
66
+ .split('\n')
67
+ .filter(line => !line.startsWith('#'))
68
+ .join('\n'),
69
+ ),
70
+ }
71
+ }
72
+ async function wait({
73
+ onProgress,
74
+ jobId,
75
+ algorithm,
76
+ }: {
77
+ jobId: string
78
+ algorithm: string
79
+ onProgress: (arg: string) => void
80
+ }) {
81
+ while (true) {
82
+ for (let i = 0; i < 10; i++) {
83
+ await timeout(1000)
84
+ onProgress(`Re-checking alignment to PDB seq1,seq2 in... ${10 - i}`)
85
+ }
86
+ const result = await textfetch(`${base}/${algorithm}/status/${jobId}`)
87
+
88
+ if (result === 'FINISHED') {
89
+ break
90
+ }
91
+ }
92
+ }
93
+
94
+ export async function launchPairwiseAlignment({
95
+ algorithm,
96
+ seq1,
97
+ seq2,
98
+ onProgress,
99
+ }: {
100
+ algorithm: string
101
+ seq1: string
102
+ seq2: string
103
+ onProgress: (arg: string) => void
104
+ }) {
105
+ onProgress(`Launching ${algorithm} MSA...`)
106
+ if (algorithm === 'emboss_matcher') {
107
+ return runEmbossMatcher({ seq1, seq2, onProgress })
108
+ } else if (algorithm === 'emboss_needle') {
109
+ return runEmbossNeedle({ seq1, seq2, onProgress })
110
+ } else {
111
+ throw new Error('unknown algorithm')
112
+ }
113
+ }
@@ -0,0 +1,48 @@
1
+ import { PluginContext } from 'molstar/lib/mol-plugin/context'
2
+ import { BuiltInTrajectoryFormat } from 'molstar/lib/mol-plugin-state/formats/trajectory'
3
+ import { StructureRepresentationPresetProvider } from 'molstar/lib/mol-plugin-state/builder/structure/representation-preset'
4
+
5
+ export interface LoadStructureOptions {
6
+ representationParams?: StructureRepresentationPresetProvider.CommonParams
7
+ }
8
+
9
+ // adapted from https://github.com/molstar/molstar/blob/ab4130d42d0ab2591f62460292ade0203207d4d2/src/apps/viewer/app.ts#L255C1-L259C6
10
+ export async function loadStructureFromData({
11
+ data,
12
+ format = 'pdb',
13
+ options,
14
+ plugin,
15
+ }: {
16
+ data: string
17
+ format?: BuiltInTrajectoryFormat
18
+ options?: LoadStructureOptions & { label?: string; dataLabel?: string }
19
+ plugin: PluginContext
20
+ }) {
21
+ await plugin.clear()
22
+
23
+ const _data = await plugin.builders.data.rawData({
24
+ data,
25
+ label: options?.dataLabel,
26
+ })
27
+
28
+ const trajectory = await plugin.builders.structure.parseTrajectory(
29
+ _data,
30
+ format,
31
+ )
32
+ const model = await plugin.builders.structure.createModel(trajectory)
33
+ const seq = model.obj?.data.sequence.sequences[0].sequence.label
34
+ .toArray()
35
+ // @ts-expect-error
36
+ .join('')
37
+
38
+ await plugin.builders.structure.hierarchy.applyPreset(
39
+ trajectory,
40
+ 'all-models',
41
+ {
42
+ useDefaultIfSingleModel: true,
43
+ representationPresetParams: options?.representationParams,
44
+ },
45
+ )
46
+
47
+ return { seq: seq as string }
48
+ }
@@ -0,0 +1,50 @@
1
+ import { PluginContext } from 'molstar/lib/mol-plugin/context'
2
+ import { BuiltInTrajectoryFormat } from 'molstar/lib/mol-plugin-state/formats/trajectory'
3
+ import { StructureRepresentationPresetProvider } from 'molstar/lib/mol-plugin-state/builder/structure/representation-preset'
4
+
5
+ export interface LoadStructureOptions {
6
+ representationParams?: StructureRepresentationPresetProvider.CommonParams
7
+ }
8
+
9
+ // adapted from https://github.com/molstar/molstar/blob/ab4130d42d0ab2591f62460292ade0203207d4d2/src/apps/viewer/app.ts#L230
10
+ export async function loadStructureFromURL({
11
+ url,
12
+ format = 'mmcif',
13
+ isBinary,
14
+ options,
15
+ plugin,
16
+ }: {
17
+ url: string
18
+ format?: BuiltInTrajectoryFormat
19
+ isBinary?: boolean
20
+ options?: LoadStructureOptions & { label?: string }
21
+ plugin: PluginContext
22
+ }) {
23
+ await plugin.clear()
24
+
25
+ const data = await plugin.builders.data.download(
26
+ { url, isBinary },
27
+ { state: { isGhost: true } },
28
+ )
29
+
30
+ const trajectory = await plugin.builders.structure.parseTrajectory(
31
+ data,
32
+ format,
33
+ )
34
+ const model = await plugin.builders.structure.createModel(trajectory)
35
+ const seq = model.obj?.data.sequence.sequences[0].sequence.label
36
+ .toArray()
37
+ // @ts-expect-error
38
+ .join('')
39
+
40
+ await plugin.builders.structure.hierarchy.applyPreset(
41
+ trajectory,
42
+ 'all-models',
43
+ {
44
+ useDefaultIfSingleModel: true,
45
+ representationPresetParams: options?.representationParams,
46
+ },
47
+ )
48
+
49
+ return { seq: seq as string }
50
+ }
@@ -0,0 +1,384 @@
1
+ import { autorun } from 'mobx'
2
+ import { BaseViewModel } from '@jbrowse/core/pluggableElementTypes'
3
+ import { ElementId, Region } from '@jbrowse/core/util/types/mst'
4
+ import { Region as IRegion } from '@jbrowse/core/util/types'
5
+ import { Instance, addDisposer, cast, types } from 'mobx-state-tree'
6
+ import {
7
+ SimpleFeature,
8
+ SimpleFeatureSerialized,
9
+ getSession,
10
+ } from '@jbrowse/core/util'
11
+ import { parsePairwise } from 'clustal-js'
12
+ import { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
13
+
14
+ // locals
15
+ import { checkHovered, invertMap, toStr } from './util'
16
+ import { launchPairwiseAlignment } from './launchRemotePairwiseAlignment'
17
+ import {
18
+ structureSeqVsTranscriptSeqMap,
19
+ genomeToTranscriptSeqMapping,
20
+ structurePositionToAlignmentMap,
21
+ transcriptPositionToAlignmentMap,
22
+ } from '../mappings'
23
+
24
+ type LGV = LinearGenomeViewModel
25
+ type MaybeLGV = LGV | undefined
26
+
27
+ /**
28
+ * #stateModel Protein3dViewPlugin
29
+ * extends
30
+ * - BaseViewModel
31
+ */
32
+ function stateModelFactory() {
33
+ return types
34
+ .compose(
35
+ BaseViewModel,
36
+ types.model({
37
+ /**
38
+ * #property
39
+ */
40
+ id: ElementId,
41
+ /**
42
+ * #property
43
+ */
44
+ type: types.literal('ProteinView'),
45
+ /**
46
+ * #property
47
+ * url to structure file
48
+ */
49
+ url: types.maybe(types.string),
50
+ /**
51
+ * #property
52
+ * full string for structure data
53
+ */
54
+ data: types.maybe(types.string),
55
+ /**
56
+ * #property
57
+ */
58
+ clickGenomeHighlights: types.array(Region),
59
+ /**
60
+ * #property
61
+ */
62
+ hoverGenomeHighlights: types.array(Region),
63
+ /**
64
+ * #property
65
+ */
66
+ showControls: true,
67
+ /**
68
+ * #property
69
+ */
70
+ height: types.optional(types.number, 650),
71
+ /**
72
+ * #property
73
+ */
74
+ feature: types.frozen<SimpleFeatureSerialized>(),
75
+ /**
76
+ * #property
77
+ */
78
+ seq1: types.maybe(types.string),
79
+ /**
80
+ * #property
81
+ */
82
+ seq2: types.maybe(types.string),
83
+ /**
84
+ * #property
85
+ */
86
+ alignment: types.frozen<ReturnType<typeof parsePairwise> | undefined>(),
87
+
88
+ /**
89
+ * #property
90
+ */
91
+ connectedViewId: types.maybe(types.string),
92
+ /**
93
+ * #property
94
+ */
95
+ showHighlight: true,
96
+ /**
97
+ * #property
98
+ */
99
+ zoomToBaseLevel: false,
100
+ /**
101
+ * #property
102
+ */
103
+ showAlignment: true,
104
+ }),
105
+ )
106
+ .volatile(() => ({
107
+ /**
108
+ * #volatile
109
+ */
110
+ error: undefined as unknown,
111
+ /**
112
+ * #volatile
113
+ */
114
+ clickPosition: undefined as
115
+ | {
116
+ structureSeqPos: number
117
+ code: string
118
+ chain: string
119
+ }
120
+ | undefined,
121
+ /**
122
+ * #volatile
123
+ */
124
+ hoverPosition: undefined as
125
+ | {
126
+ structureSeqPos: number
127
+ code?: string
128
+ chain?: string
129
+ }
130
+ | undefined,
131
+ /**
132
+ * #volatile
133
+ */
134
+ progress: '',
135
+ }))
136
+ .views(self => ({
137
+ /**
138
+ * #getter
139
+ */
140
+ get connectedView() {
141
+ const { views } = getSession(self)
142
+ return views.find(f => f.id === self.connectedViewId) as MaybeLGV
143
+ },
144
+ }))
145
+ .actions(self => ({
146
+ /**
147
+ * #action
148
+ */
149
+ setShowAlignment(f: boolean) {
150
+ self.showAlignment = f
151
+ },
152
+ /**
153
+ * #action
154
+ */
155
+ setHoveredPosition(arg?: {
156
+ structureSeqPos: number
157
+ chain?: string
158
+ code?: string
159
+ }) {
160
+ self.hoverPosition = arg
161
+ },
162
+ /**
163
+ * #action
164
+ */
165
+ setSeqs(str1?: string, str2?: string) {
166
+ self.seq1 = str1
167
+ self.seq2 = str2
168
+ },
169
+ /**
170
+ * #action
171
+ */
172
+ setShowControls(arg: boolean) {
173
+ self.showControls = arg
174
+ },
175
+ /**
176
+ * #action
177
+ */
178
+ setProgress(str: string) {
179
+ self.progress = str
180
+ },
181
+ /**
182
+ * #action
183
+ */
184
+ setClickedPosition(arg?: {
185
+ structureSeqPos: number
186
+ code: string
187
+ chain: string
188
+ }) {
189
+ self.clickPosition = arg
190
+ },
191
+ /**
192
+ * #action
193
+ */
194
+ setClickGenomeHighlights(r: IRegion[]) {
195
+ self.clickGenomeHighlights = cast(r)
196
+ },
197
+ /**
198
+ * #action
199
+ */
200
+ clearClickGenomeHighlights() {
201
+ self.clickGenomeHighlights = cast([])
202
+ },
203
+ /**
204
+ * #action
205
+ */
206
+ setHoverGenomeHighlights(r: IRegion[]) {
207
+ self.hoverGenomeHighlights = cast(r)
208
+ },
209
+ /**
210
+ * #action
211
+ */
212
+ clearHoverGenomeHighlights() {
213
+ self.hoverGenomeHighlights = cast([])
214
+ },
215
+ /**
216
+ * #action
217
+ */
218
+ setError(e: unknown) {
219
+ self.error = e
220
+ },
221
+ /**
222
+ * #action
223
+ */
224
+ setAlignment(r?: ReturnType<typeof parsePairwise>) {
225
+ self.alignment = r
226
+ },
227
+ /**
228
+ * #action
229
+ */
230
+ setShowHighlight(arg: boolean) {
231
+ self.showHighlight = arg
232
+ },
233
+ /**
234
+ * #action
235
+ */
236
+ setZoomToBaseLevel(arg: boolean) {
237
+ self.zoomToBaseLevel = arg
238
+ },
239
+ }))
240
+ .views(self => ({
241
+ /**
242
+ * #getter
243
+ */
244
+ get structureSeqToTranscriptSeqPosition() {
245
+ return self.alignment
246
+ ? structureSeqVsTranscriptSeqMap(self.alignment)
247
+ .structureSeqToTranscriptSeqPosition
248
+ : undefined
249
+ },
250
+ /**
251
+ * #getter
252
+ */
253
+ get transcriptSeqToStructureSeqPosition() {
254
+ return self.alignment
255
+ ? structureSeqVsTranscriptSeqMap(self.alignment)
256
+ .transcriptSeqToStructureSeqPosition
257
+ : undefined
258
+ },
259
+ /**
260
+ * #getter
261
+ */
262
+ get structurePositionToAlignmentMap() {
263
+ return self.alignment
264
+ ? structurePositionToAlignmentMap(self.alignment)
265
+ : undefined
266
+ },
267
+ /**
268
+ * #getter
269
+ */
270
+ get transcriptPositionToAlignmentMap() {
271
+ return self.alignment
272
+ ? transcriptPositionToAlignmentMap(self.alignment)
273
+ : undefined
274
+ },
275
+ /**
276
+ * #getter
277
+ */
278
+ get alignmentToTranscriptPosition() {
279
+ return this.transcriptPositionToAlignmentMap
280
+ ? invertMap(this.transcriptPositionToAlignmentMap)
281
+ : undefined
282
+ },
283
+ /**
284
+ * #getter
285
+ */
286
+ get alignmentToStructurePosition() {
287
+ return this.structurePositionToAlignmentMap
288
+ ? invertMap(this.structurePositionToAlignmentMap)
289
+ : undefined
290
+ },
291
+ /**
292
+ * #getter
293
+ */
294
+ get clickString() {
295
+ const r = self.clickPosition
296
+ return r ? toStr(r) : ''
297
+ },
298
+ /**
299
+ * #getter
300
+ */
301
+ get hoverString() {
302
+ const r = self.hoverPosition
303
+ return r ? toStr(r) : ''
304
+ },
305
+ /**
306
+ * #getter
307
+ */
308
+ get genomeToTranscriptSeqMapping() {
309
+ return self.feature
310
+ ? genomeToTranscriptSeqMapping(new SimpleFeature(self.feature))
311
+ : undefined
312
+ },
313
+ /**
314
+ * #getter
315
+ */
316
+ get structureSeqHoverPos(): number | undefined {
317
+ return self.hoverPosition?.structureSeqPos
318
+ },
319
+ }))
320
+ .actions(self => ({
321
+ afterAttach() {
322
+ // pairwise align transcript sequence to structure sequence
323
+ addDisposer(
324
+ self,
325
+ autorun(async () => {
326
+ try {
327
+ const { seq1, seq2 } = self
328
+ if (!!self.alignment || !seq1 || !seq2) {
329
+ return
330
+ }
331
+ const alignment = await launchPairwiseAlignment({
332
+ seq1,
333
+ seq2,
334
+ algorithm: 'emboss_needle',
335
+ onProgress: arg => self.setProgress(arg),
336
+ })
337
+ self.setAlignment(alignment.alignment)
338
+ } catch (e) {
339
+ console.error(e)
340
+ self.setError(e)
341
+ }
342
+ }),
343
+ )
344
+
345
+ // convert hover over the genome to structure position
346
+ addDisposer(
347
+ self,
348
+ autorun(() => {
349
+ const { hovered } = getSession(self)
350
+ const {
351
+ transcriptSeqToStructureSeqPosition,
352
+ genomeToTranscriptSeqMapping,
353
+ connectedView,
354
+ } = self
355
+ if (
356
+ !connectedView?.initialized ||
357
+ !genomeToTranscriptSeqMapping ||
358
+ !checkHovered(hovered)
359
+ ) {
360
+ return undefined
361
+ }
362
+
363
+ const pos =
364
+ genomeToTranscriptSeqMapping.g2p[hovered.hoverPosition.coord]
365
+ const c0 = pos
366
+ ? transcriptSeqToStructureSeqPosition?.[pos]
367
+ : undefined
368
+ if (c0 !== undefined) {
369
+ self.setHoveredPosition({
370
+ structureSeqPos: c0,
371
+ })
372
+ }
373
+ }),
374
+ )
375
+ },
376
+ }))
377
+ }
378
+
379
+ export default stateModelFactory
380
+ export type JBrowsePluginProteinViewStateModel = ReturnType<
381
+ typeof stateModelFactory
382
+ >
383
+ export type JBrowsePluginProteinViewModel =
384
+ Instance<JBrowsePluginProteinViewStateModel>
@@ -0,0 +1,24 @@
1
+ export const proteinAbbreviationMapping = Object.fromEntries(
2
+ [
3
+ { name: 'alanine', abbreviation: 'Ala', singleLetterCode: 'A' },
4
+ { name: 'arginine', abbreviation: 'Arg', singleLetterCode: 'R' },
5
+ { name: 'asparagine', abbreviation: 'Asn', singleLetterCode: 'N' },
6
+ { name: 'aspartic acid', abbreviation: 'Asp', singleLetterCode: 'D' },
7
+ { name: 'cysteine', abbreviation: 'Cys', singleLetterCode: 'C' },
8
+ { name: 'glutamic acid', abbreviation: 'Glu', singleLetterCode: 'E' },
9
+ { name: 'glutamine', abbreviation: 'Gln', singleLetterCode: 'Q' },
10
+ { name: 'glycine', abbreviation: 'Gly', singleLetterCode: 'G' },
11
+ { name: 'histidine', abbreviation: 'His', singleLetterCode: 'H' },
12
+ { name: 'isoleucine', abbreviation: 'Ile', singleLetterCode: 'I' },
13
+ { name: 'leucine', abbreviation: 'Leu', singleLetterCode: 'L' },
14
+ { name: 'lysine', abbreviation: 'Lys', singleLetterCode: 'K' },
15
+ { name: 'methionine', abbreviation: 'Met', singleLetterCode: 'M' },
16
+ { name: 'phenylalanine', abbreviation: 'Phe', singleLetterCode: 'F' },
17
+ { name: 'proline', abbreviation: 'Pro', singleLetterCode: 'P' },
18
+ { name: 'serine', abbreviation: 'Ser', singleLetterCode: 'S' },
19
+ { name: 'threonine', abbreviation: 'Thr', singleLetterCode: 'T' },
20
+ { name: 'tryptophan', abbreviation: 'Trp', singleLetterCode: 'W' },
21
+ { name: 'tyrosine', abbreviation: 'Tyr', singleLetterCode: 'Y' },
22
+ { name: 'valine', abbreviation: 'Val', singleLetterCode: 'V' },
23
+ ].map(r => [r.abbreviation.toUpperCase(), r]),
24
+ )