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.
- package/README.md +3 -0
- package/dist/AddHighlightModel/GenomeMouseoverHighlight.d.ts +6 -0
- package/dist/AddHighlightModel/GenomeMouseoverHighlight.js +24 -0
- package/dist/AddHighlightModel/GenomeMouseoverHighlight.js.map +1 -0
- package/dist/AddHighlightModel/Highlight.d.ts +10 -0
- package/dist/AddHighlightModel/Highlight.js +24 -0
- package/dist/AddHighlightModel/Highlight.js.map +1 -0
- package/dist/AddHighlightModel/HighlightComponents.d.ts +7 -0
- package/dist/AddHighlightModel/HighlightComponents.js +14 -0
- package/dist/AddHighlightModel/HighlightComponents.js.map +1 -0
- package/dist/AddHighlightModel/ProteinToGenomeClickHighlight.d.ts +7 -0
- package/dist/AddHighlightModel/ProteinToGenomeClickHighlight.js +13 -0
- package/dist/AddHighlightModel/ProteinToGenomeClickHighlight.js.map +1 -0
- package/dist/AddHighlightModel/ProteinToGenomeHoverHighlight.d.ts +7 -0
- package/dist/AddHighlightModel/ProteinToGenomeHoverHighlight.js +13 -0
- package/dist/AddHighlightModel/ProteinToGenomeHoverHighlight.js.map +1 -0
- package/dist/AddHighlightModel/index.d.ts +2 -0
- package/dist/AddHighlightModel/index.js +14 -0
- package/dist/AddHighlightModel/index.js.map +1 -0
- package/dist/AddHighlightModel/util.d.ts +9 -0
- package/dist/AddHighlightModel/util.js +17 -0
- package/dist/AddHighlightModel/util.js.map +1 -0
- package/dist/LaunchProteinView/calculateProteinSequence.d.ts +28 -0
- package/dist/LaunchProteinView/calculateProteinSequence.js +77 -0
- package/dist/LaunchProteinView/calculateProteinSequence.js.map +1 -0
- package/dist/LaunchProteinView/components/AlphaFoldDBSearch.d.ts +8 -0
- package/dist/LaunchProteinView/components/AlphaFoldDBSearch.js +71 -0
- package/dist/LaunchProteinView/components/AlphaFoldDBSearch.js.map +1 -0
- package/dist/LaunchProteinView/components/AlphaFoldDBSearchStatus.d.ts +8 -0
- package/dist/LaunchProteinView/components/AlphaFoldDBSearchStatus.js +19 -0
- package/dist/LaunchProteinView/components/AlphaFoldDBSearchStatus.js.map +1 -0
- package/dist/LaunchProteinView/components/HelpButton.d.ts +2 -0
- package/dist/LaunchProteinView/components/HelpButton.js +15 -0
- package/dist/LaunchProteinView/components/HelpButton.js.map +1 -0
- package/dist/LaunchProteinView/components/HelpDialog.d.ts +4 -0
- package/dist/LaunchProteinView/components/HelpDialog.js +16 -0
- package/dist/LaunchProteinView/components/HelpDialog.js.map +1 -0
- package/dist/LaunchProteinView/components/LaunchProteinViewDialog.d.ts +7 -0
- package/dist/LaunchProteinView/components/LaunchProteinViewDialog.js +23 -0
- package/dist/LaunchProteinView/components/LaunchProteinViewDialog.js.map +1 -0
- package/dist/LaunchProteinView/components/PreLoadedStructureMapping.d.ts +8 -0
- package/dist/LaunchProteinView/components/PreLoadedStructureMapping.js +72 -0
- package/dist/LaunchProteinView/components/PreLoadedStructureMapping.js.map +1 -0
- package/dist/LaunchProteinView/components/TabPanel.d.ts +6 -0
- package/dist/LaunchProteinView/components/TabPanel.js +6 -0
- package/dist/LaunchProteinView/components/TabPanel.js.map +1 -0
- package/dist/LaunchProteinView/components/TranscriptSelector.d.ts +9 -0
- package/dist/LaunchProteinView/components/TranscriptSelector.js +28 -0
- package/dist/LaunchProteinView/components/TranscriptSelector.js.map +1 -0
- package/dist/LaunchProteinView/components/UserProvidedStructure.d.ts +8 -0
- package/dist/LaunchProteinView/components/UserProvidedStructure.js +118 -0
- package/dist/LaunchProteinView/components/UserProvidedStructure.js.map +1 -0
- package/dist/LaunchProteinView/components/useCheckAlphaFoldDBExistence.d.ts +7 -0
- package/dist/LaunchProteinView/components/useCheckAlphaFoldDBExistence.js +26 -0
- package/dist/LaunchProteinView/components/useCheckAlphaFoldDBExistence.js.map +1 -0
- package/dist/LaunchProteinView/index.d.ts +2 -0
- package/dist/LaunchProteinView/index.js +45 -0
- package/dist/LaunchProteinView/index.js.map +1 -0
- package/dist/LaunchProteinView/useMyGeneInfo.d.ts +7 -0
- package/dist/LaunchProteinView/useMyGeneInfo.js +29 -0
- package/dist/LaunchProteinView/useMyGeneInfo.js.map +1 -0
- package/dist/LaunchProteinView/useProteinSequences.d.ts +10 -0
- package/dist/LaunchProteinView/useProteinSequences.js +30 -0
- package/dist/LaunchProteinView/useProteinSequences.js.map +1 -0
- package/dist/LaunchProteinView/util.d.ts +18 -0
- package/dist/LaunchProteinView/util.js +54 -0
- package/dist/LaunchProteinView/util.js.map +1 -0
- package/dist/ProteinModelSessionExtension.d.ts +11 -0
- package/dist/ProteinModelSessionExtension.js +53 -0
- package/dist/ProteinModelSessionExtension.js.map +1 -0
- package/dist/ProteinView/clearSelection.d.ts +4 -0
- package/dist/ProteinView/clearSelection.js +4 -0
- package/dist/ProteinView/clearSelection.js.map +1 -0
- package/dist/ProteinView/components/Header.d.ts +6 -0
- package/dist/ProteinView/components/Header.js +49 -0
- package/dist/ProteinView/components/Header.js.map +1 -0
- package/dist/ProteinView/components/ProteinAlignment.d.ts +6 -0
- package/dist/ProteinView/components/ProteinAlignment.js +62 -0
- package/dist/ProteinView/components/ProteinAlignment.js.map +1 -0
- package/dist/ProteinView/components/ProteinAlignmentHelpButton.d.ts +5 -0
- package/dist/ProteinView/components/ProteinAlignmentHelpButton.js +14 -0
- package/dist/ProteinView/components/ProteinAlignmentHelpButton.js.map +1 -0
- package/dist/ProteinView/components/ProteinAlignmentHelpDialog.d.ts +4 -0
- package/dist/ProteinView/components/ProteinAlignmentHelpDialog.js +20 -0
- package/dist/ProteinView/components/ProteinAlignmentHelpDialog.js.map +1 -0
- package/dist/ProteinView/components/ProteinView.d.ts +6 -0
- package/dist/ProteinView/components/ProteinView.js +79 -0
- package/dist/ProteinView/components/ProteinView.js.map +1 -0
- package/dist/ProteinView/components/SplitString.d.ts +9 -0
- package/dist/ProteinView/components/SplitString.js +11 -0
- package/dist/ProteinView/components/SplitString.js.map +1 -0
- package/dist/ProteinView/css/molstar.d.ts +2 -0
- package/dist/ProteinView/css/molstar.js +3137 -0
- package/dist/ProteinView/css/molstar.js.map +1 -0
- package/dist/ProteinView/genomeToProtein.d.ts +4 -0
- package/dist/ProteinView/genomeToProtein.js +13 -0
- package/dist/ProteinView/genomeToProtein.js.map +1 -0
- package/dist/ProteinView/highlightResidue.d.ts +7 -0
- package/dist/ProteinView/highlightResidue.js +14 -0
- package/dist/ProteinView/highlightResidue.js.map +1 -0
- package/dist/ProteinView/index.d.ts +2 -0
- package/dist/ProteinView/index.js +15 -0
- package/dist/ProteinView/index.js.map +1 -0
- package/dist/ProteinView/launchRemotePairwiseAlignment.d.ts +14 -0
- package/dist/ProteinView/launchRemotePairwiseAlignment.js +72 -0
- package/dist/ProteinView/launchRemotePairwiseAlignment.js.map +1 -0
- package/dist/ProteinView/loadStructureFromData.d.ts +17 -0
- package/dist/ProteinView/loadStructureFromData.js +20 -0
- package/dist/ProteinView/loadStructureFromData.js.map +1 -0
- package/dist/ProteinView/loadStructureFromURL.d.ts +17 -0
- package/dist/ProteinView/loadStructureFromURL.js +17 -0
- package/dist/ProteinView/loadStructureFromURL.js.map +1 -0
- package/dist/ProteinView/model.d.ts +226 -0
- package/dist/ProteinView/model.js +324 -0
- package/dist/ProteinView/model.js.map +1 -0
- package/dist/ProteinView/proteinAbbreviationMapping.d.ts +7 -0
- package/dist/ProteinView/proteinAbbreviationMapping.js +23 -0
- package/dist/ProteinView/proteinAbbreviationMapping.js.map +1 -0
- package/dist/ProteinView/proteinToGenomeMapping.d.ts +13 -0
- package/dist/ProteinView/proteinToGenomeMapping.js +69 -0
- package/dist/ProteinView/proteinToGenomeMapping.js.map +1 -0
- package/dist/ProteinView/selectResidue.d.ts +7 -0
- package/dist/ProteinView/selectResidue.js +10 -0
- package/dist/ProteinView/selectResidue.js.map +1 -0
- package/dist/ProteinView/useProteinView.d.ts +11 -0
- package/dist/ProteinView/useProteinView.js +57 -0
- package/dist/ProteinView/useProteinView.js.map +1 -0
- package/dist/ProteinView/useProteinViewClickBehavior.d.ts +8 -0
- package/dist/ProteinView/useProteinViewClickBehavior.js +34 -0
- package/dist/ProteinView/useProteinViewClickBehavior.js.map +1 -0
- package/dist/ProteinView/useProteinViewHoverBehavior.d.ts +6 -0
- package/dist/ProteinView/useProteinViewHoverBehavior.js +31 -0
- package/dist/ProteinView/useProteinViewHoverBehavior.js.map +1 -0
- package/dist/ProteinView/util.d.ts +19 -0
- package/dist/ProteinView/util.js +32 -0
- package/dist/ProteinView/util.js.map +1 -0
- package/dist/fetchUtils.d.ts +5 -0
- package/dist/fetchUtils.js +23 -0
- package/dist/fetchUtils.js.map +1 -0
- package/dist/genomeToTranscriptMapping.d.ts +7 -0
- package/dist/genomeToTranscriptMapping.js +36 -0
- package/dist/genomeToTranscriptMapping.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/jbrowse-plugin-protein3d.umd.production.min.js +9298 -0
- package/dist/jbrowse-plugin-protein3d.umd.production.min.js.map +7 -0
- package/dist/mappings.d.ts +19 -0
- package/dist/mappings.js +67 -0
- package/dist/mappings.js.map +1 -0
- package/dist/mappings.test.d.ts +1 -0
- package/dist/mappings.test.js +27 -0
- package/dist/mappings.test.js.map +1 -0
- package/dist/test_data/gene.d.ts +67 -0
- package/dist/test_data/gene.js +603 -0
- package/dist/test_data/gene.js.map +1 -0
- package/package.json +70 -0
- package/src/AddHighlightModel/GenomeMouseoverHighlight.tsx +45 -0
- package/src/AddHighlightModel/Highlight.tsx +46 -0
- package/src/AddHighlightModel/HighlightComponents.tsx +26 -0
- package/src/AddHighlightModel/ProteinToGenomeClickHighlight.tsx +39 -0
- package/src/AddHighlightModel/ProteinToGenomeHoverHighlight.tsx +39 -0
- package/src/AddHighlightModel/index.tsx +25 -0
- package/src/AddHighlightModel/util.ts +17 -0
- package/src/LaunchProteinView/calculateProteinSequence.ts +127 -0
- package/src/LaunchProteinView/components/AlphaFoldDBSearch.tsx +141 -0
- package/src/LaunchProteinView/components/AlphaFoldDBSearchStatus.tsx +44 -0
- package/src/LaunchProteinView/components/HelpButton.tsx +23 -0
- package/src/LaunchProteinView/components/HelpDialog.tsx +43 -0
- package/src/LaunchProteinView/components/LaunchProteinViewDialog.tsx +57 -0
- package/src/LaunchProteinView/components/PreLoadedStructureMapping.tsx +153 -0
- package/src/LaunchProteinView/components/TabPanel.tsx +19 -0
- package/src/LaunchProteinView/components/TranscriptSelector.tsx +54 -0
- package/src/LaunchProteinView/components/UserProvidedStructure.tsx +226 -0
- package/src/LaunchProteinView/components/useCheckAlphaFoldDBExistence.ts +31 -0
- package/src/LaunchProteinView/index.ts +56 -0
- package/src/LaunchProteinView/useMyGeneInfo.ts +37 -0
- package/src/LaunchProteinView/useProteinSequences.ts +36 -0
- package/src/LaunchProteinView/util.ts +74 -0
- package/src/ProteinModelSessionExtension.ts +71 -0
- package/src/ProteinView/clearSelection.ts +5 -0
- package/src/ProteinView/components/Header.tsx +84 -0
- package/src/ProteinView/components/ProteinAlignment.tsx +119 -0
- package/src/ProteinView/components/ProteinAlignmentHelpButton.tsx +33 -0
- package/src/ProteinView/components/ProteinAlignmentHelpDialog.tsx +59 -0
- package/src/ProteinView/components/ProteinView.tsx +131 -0
- package/src/ProteinView/components/SplitString.tsx +35 -0
- package/src/ProteinView/css/molstar.ts +3136 -0
- package/src/ProteinView/genomeToProtein.ts +21 -0
- package/src/ProteinView/highlightResidue.ts +23 -0
- package/src/ProteinView/index.ts +18 -0
- package/src/ProteinView/launchRemotePairwiseAlignment.ts +113 -0
- package/src/ProteinView/loadStructureFromData.ts +48 -0
- package/src/ProteinView/loadStructureFromURL.ts +50 -0
- package/src/ProteinView/model.ts +384 -0
- package/src/ProteinView/proteinAbbreviationMapping.ts +24 -0
- package/src/ProteinView/proteinToGenomeMapping.ts +99 -0
- package/src/ProteinView/selectResidue.ts +19 -0
- package/src/ProteinView/useProteinView.ts +70 -0
- package/src/ProteinView/useProteinViewClickBehavior.ts +48 -0
- package/src/ProteinView/useProteinViewHoverBehavior.ts +44 -0
- package/src/ProteinView/util.ts +56 -0
- package/src/__snapshots__/mappings.test.ts.snap +1351 -0
- package/src/declare.d.ts +1 -0
- package/src/fetchUtils.ts +30 -0
- package/src/genomeToTranscriptMapping.ts +46 -0
- package/src/index.ts +32 -0
- package/src/mappings.test.ts +32 -0
- package/src/mappings.ts +89 -0
- 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,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's sequence with the
|
|
60
|
+
selected transcript'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 </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> </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 </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's representation of
|
|
42
|
+
the protein and the structure file'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 === ' ' ? <> </> : d}
|
|
33
|
+
</span>
|
|
34
|
+
))
|
|
35
|
+
}
|