jbrowse-plugin-msaview 2.0.6 → 2.1.0

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 (70) hide show
  1. package/dist/LaunchMsaView/components/EnsemblGeneTree/EnsemblGeneTree.d.ts +8 -0
  2. package/dist/LaunchMsaView/components/EnsemblGeneTree/EnsemblGeneTree.js +81 -0
  3. package/dist/LaunchMsaView/components/EnsemblGeneTree/EnsemblGeneTree.js.map +1 -0
  4. package/dist/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeLaunchView.d.ts +13 -0
  5. package/dist/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeLaunchView.js +18 -0
  6. package/dist/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeLaunchView.js.map +1 -0
  7. package/dist/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeUtils.d.ts +5 -0
  8. package/dist/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeUtils.js +35 -0
  9. package/dist/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeUtils.js.map +1 -0
  10. package/dist/LaunchMsaView/components/EnsemblGeneTree/fetchGeneList.d.ts +1 -0
  11. package/dist/LaunchMsaView/components/EnsemblGeneTree/fetchGeneList.js +12 -0
  12. package/dist/LaunchMsaView/components/EnsemblGeneTree/fetchGeneList.js.map +1 -0
  13. package/dist/LaunchMsaView/components/EnsemblGeneTree/util.d.ts +4 -0
  14. package/dist/LaunchMsaView/components/EnsemblGeneTree/util.js +38 -0
  15. package/dist/LaunchMsaView/components/EnsemblGeneTree/util.js.map +1 -0
  16. package/dist/LaunchMsaView/components/LaunchMsaViewDialog.js +20 -14
  17. package/dist/LaunchMsaView/components/LaunchMsaViewDialog.js.map +1 -1
  18. package/dist/LaunchMsaView/components/MSALoader/MSALoader.d.ts +8 -0
  19. package/dist/LaunchMsaView/components/MSALoader/MSALoader.js +94 -0
  20. package/dist/LaunchMsaView/components/MSALoader/MSALoader.js.map +1 -0
  21. package/dist/LaunchMsaView/components/MSALoader/fetchGeneList.d.ts +1 -0
  22. package/dist/LaunchMsaView/components/MSALoader/fetchGeneList.js +12 -0
  23. package/dist/LaunchMsaView/components/MSALoader/fetchGeneList.js.map +1 -0
  24. package/dist/LaunchMsaView/components/MSALoader/preCalculatedLaunchView.d.ts +9 -0
  25. package/dist/LaunchMsaView/components/MSALoader/preCalculatedLaunchView.js +36 -0
  26. package/dist/LaunchMsaView/components/MSALoader/preCalculatedLaunchView.js.map +1 -0
  27. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/calculateProteinSequence.d.ts +4 -12
  28. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/calculateProteinSequence.js +2 -3
  29. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/calculateProteinSequence.js.map +1 -1
  30. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/fetchSeq.d.ts +8 -0
  31. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/fetchSeq.js +23 -0
  32. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/fetchSeq.js.map +1 -0
  33. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/types.d.ts +10 -0
  34. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/types.js +2 -0
  35. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/types.js.map +1 -0
  36. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/useFeatureSequence.d.ts +2 -6
  37. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/useFeatureSequence.js +1 -22
  38. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/useFeatureSequence.js.map +1 -1
  39. package/dist/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.js +8 -10
  40. package/dist/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.js.map +1 -1
  41. package/dist/LaunchMsaView/components/TabPanel.d.ts +6 -0
  42. package/dist/LaunchMsaView/components/TabPanel.js +6 -0
  43. package/dist/LaunchMsaView/components/TabPanel.js.map +1 -0
  44. package/dist/MsaViewPanel/model.d.ts +12 -8
  45. package/dist/jbrowse-plugin-msaview.umd.production.min.js +52 -40
  46. package/dist/jbrowse-plugin-msaview.umd.production.min.js.map +4 -4
  47. package/package.json +1 -1
  48. package/src/LaunchMsaView/components/EnsemblGeneTree/EnsemblGeneTree.tsx +143 -0
  49. package/src/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeLaunchView.ts +36 -0
  50. package/src/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeUtils.ts +81 -0
  51. package/src/LaunchMsaView/components/EnsemblGeneTree/fetchGeneList.ts +13 -0
  52. package/src/LaunchMsaView/components/EnsemblGeneTree/util.ts +45 -0
  53. package/src/LaunchMsaView/components/LaunchMsaViewDialog.tsx +30 -19
  54. package/src/LaunchMsaView/components/MSALoader/MSALoader.tsx +130 -0
  55. package/src/LaunchMsaView/components/MSALoader/fetchGeneList.ts +13 -0
  56. package/src/LaunchMsaView/components/MSALoader/preCalculatedLaunchView.ts +55 -0
  57. package/src/LaunchMsaView/components/NewNCBIBlastQuery/calculateProteinSequence.ts +6 -20
  58. package/src/LaunchMsaView/components/NewNCBIBlastQuery/fetchSeq.ts +37 -0
  59. package/src/LaunchMsaView/components/NewNCBIBlastQuery/types.ts +11 -0
  60. package/src/LaunchMsaView/components/NewNCBIBlastQuery/useFeatureSequence.ts +5 -41
  61. package/src/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.tsx +10 -16
  62. package/src/LaunchMsaView/components/TabPanel.tsx +19 -0
  63. package/dist/LaunchMsaView/components/TabUtils.d.ts +0 -8
  64. package/dist/LaunchMsaView/components/TabUtils.js +0 -7
  65. package/dist/LaunchMsaView/components/TabUtils.js.map +0 -1
  66. package/dist/LaunchMsaView/components/tabUtil.d.ts +0 -4
  67. package/dist/LaunchMsaView/components/tabUtil.js +0 -7
  68. package/dist/LaunchMsaView/components/tabUtil.js.map +0 -1
  69. package/src/LaunchMsaView/components/TabUtils.tsx +0 -25
  70. package/src/LaunchMsaView/components/tabUtil.ts +0 -6
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.0.6",
2
+ "version": "2.1.0",
3
3
  "license": "MIT",
4
4
  "name": "jbrowse-plugin-msaview",
5
5
  "keywords": [
@@ -0,0 +1,143 @@
1
+ import React, { useEffect, useState } from 'react'
2
+
3
+ import { ErrorMessage, LoadingEllipses } from '@jbrowse/core/ui'
4
+ import {
5
+ AbstractTrackModel,
6
+ Feature,
7
+ getContainingView,
8
+ getSession,
9
+ } from '@jbrowse/core/util'
10
+ import {
11
+ Button,
12
+ DialogActions,
13
+ DialogContent,
14
+ MenuItem,
15
+ TextField,
16
+ Typography,
17
+ } from '@mui/material'
18
+ import { observer } from 'mobx-react'
19
+ import { makeStyles } from 'tss-react/mui'
20
+
21
+ import { ensemblGeneTreeLaunchView } from './ensemblGeneTreeLaunchView'
22
+ import { geneTreeFetcher } from './ensemblGeneTreeUtils'
23
+ import {
24
+ getGeneDisplayName,
25
+ getId,
26
+ getTranscriptDisplayName,
27
+ getTranscriptFeatures,
28
+ } from '../../util'
29
+
30
+ import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
31
+
32
+ const useStyles = makeStyles()({
33
+ dialogContent: {
34
+ width: '80em',
35
+ },
36
+ })
37
+
38
+ type Ret = Awaited<ReturnType<typeof geneTreeFetcher>>
39
+
40
+ const EnsemblGeneTree = observer(function ({
41
+ model,
42
+ feature,
43
+ handleClose,
44
+ }: {
45
+ model: AbstractTrackModel
46
+ feature: Feature
47
+ handleClose: () => void
48
+ }) {
49
+ const session = getSession(model)
50
+ const view = getContainingView(model) as LinearGenomeViewModel
51
+ const { classes } = useStyles()
52
+ const [error, setError] = useState<unknown>()
53
+ const [treeData, setTreeData] = useState<Ret>()
54
+ const [isTreeLoading, setIsTreeLoading] = useState(false)
55
+ const [treeError, setTreeError] = useState<unknown>()
56
+ const options = getTranscriptFeatures(feature)
57
+ const [userSelection, setUserSelection] = useState(getId(options[0]))
58
+
59
+ useEffect(() => {
60
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
61
+ ;(async () => {
62
+ try {
63
+ setIsTreeLoading(true)
64
+ const result = await geneTreeFetcher(userSelection)
65
+ setTreeData(result)
66
+ } catch (e) {
67
+ console.error(e)
68
+ setTreeError(e)
69
+ } finally {
70
+ setIsTreeLoading(false)
71
+ }
72
+ })()
73
+ }, [userSelection])
74
+
75
+ const loadingMessage = isTreeLoading
76
+ ? 'Loading tree data from Ensembl GeneTree'
77
+ : undefined
78
+ const e = treeError ?? error
79
+
80
+ return (
81
+ <>
82
+ <DialogContent className={classes.dialogContent}>
83
+ {e ? <ErrorMessage error={e} /> : null}
84
+ {loadingMessage ? <LoadingEllipses message={loadingMessage} /> : null}
85
+ <Typography>Load data from Ensembl GeneTree</Typography>
86
+ <TextField
87
+ select
88
+ label="Choose isoform to view MSA for"
89
+ value={userSelection}
90
+ onChange={event => {
91
+ setUserSelection(event.target.value)
92
+ }}
93
+ >
94
+ {options.map(val => (
95
+ <MenuItem value={getId(val)} key={val.id()}>
96
+ {getTranscriptDisplayName(val)}
97
+ </MenuItem>
98
+ ))}
99
+ </TextField>
100
+ </DialogContent>
101
+
102
+ <DialogActions>
103
+ <Button
104
+ color="primary"
105
+ variant="contained"
106
+ onClick={() => {
107
+ try {
108
+ if (!treeData) {
109
+ return
110
+ }
111
+ setError(undefined)
112
+
113
+ ensemblGeneTreeLaunchView({
114
+ feature,
115
+ view,
116
+ session,
117
+ newViewTitle: getGeneDisplayName(feature),
118
+ data: treeData,
119
+ })
120
+ handleClose()
121
+ } catch (e) {
122
+ console.error(e)
123
+ setError(e)
124
+ }
125
+ }}
126
+ >
127
+ Submit
128
+ </Button>
129
+ <Button
130
+ color="secondary"
131
+ variant="contained"
132
+ onClick={() => {
133
+ handleClose()
134
+ }}
135
+ >
136
+ Cancel
137
+ </Button>
138
+ </DialogActions>
139
+ </>
140
+ )
141
+ })
142
+
143
+ export default EnsemblGeneTree
@@ -0,0 +1,36 @@
1
+ import type { AbstractSessionModel, Feature } from '@jbrowse/core/util'
2
+ import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
3
+
4
+ export function ensemblGeneTreeLaunchView({
5
+ session,
6
+ newViewTitle,
7
+ view,
8
+ feature,
9
+ data,
10
+ }: {
11
+ session: AbstractSessionModel
12
+ newViewTitle: string
13
+ view: LinearGenomeViewModel
14
+ feature: Feature
15
+ data: {
16
+ tree: string
17
+ msa: string
18
+ treeMetadata: string
19
+ }
20
+ }) {
21
+ session.addView('MsaView', {
22
+ type: 'MsaView',
23
+ displayName: newViewTitle,
24
+ treeAreaWidth: 200,
25
+ treeWidth: 100,
26
+ drawNodeBubbles: false,
27
+ labelsAlignRight: true,
28
+ showBranchLen: false,
29
+ colWidth: 10,
30
+ rowHeight: 12,
31
+ colorSchemeName: 'percent_identity_dynamic',
32
+ data,
33
+ connectedViewId: view.id,
34
+ connectedFeature: feature.toJSON(),
35
+ })
36
+ }
@@ -0,0 +1,81 @@
1
+ import { fetchWithLocalStorageCache, jsonfetch, textfetch } from './util'
2
+
3
+ interface TreeNodeSequence {
4
+ mol_seq: {
5
+ seq: string
6
+ location?: string
7
+ }
8
+ id: {
9
+ accession: string
10
+ }[]
11
+ }
12
+
13
+ interface TreeNodeTaxonomy {
14
+ common_name: string
15
+ scientific_name: string
16
+ }
17
+
18
+ // This is a self-referential tree data structure
19
+ interface TreeNode {
20
+ children?: TreeNode[]
21
+ sequence?: TreeNodeSequence
22
+ taxonomy: TreeNodeTaxonomy
23
+ }
24
+
25
+ interface TreeRow {
26
+ id: string
27
+ seq: string
28
+ species: string
29
+ genomicLocString?: string
30
+ }
31
+
32
+ function gatherSequencesFromTree(tree: TreeNode, arr: TreeRow[] = []) {
33
+ if (tree.children) {
34
+ for (const child of tree.children) {
35
+ if (child.sequence) {
36
+ const id = child.sequence.id[0]?.accession
37
+ if (id) {
38
+ arr.push({
39
+ id,
40
+ seq: child.sequence.mol_seq.seq,
41
+ species:
42
+ child.taxonomy.common_name || child.taxonomy.scientific_name,
43
+ genomicLocString: child.sequence.mol_seq.location,
44
+ })
45
+ }
46
+ }
47
+ gatherSequencesFromTree(child, arr)
48
+ }
49
+ }
50
+ return arr
51
+ }
52
+
53
+ const base = 'https://rest.ensembl.org'
54
+
55
+ export async function geneTreeFetcher(id2: string) {
56
+ const id = id2.replace(/\..*/, '')
57
+ const { species } = await fetchWithLocalStorageCache(`${id}-ensembl`, () =>
58
+ jsonfetch<{ species: string }>(
59
+ `${base}/lookup/id/${id}?content-type=application/json`,
60
+ ),
61
+ )
62
+ const treeBase = `${base}/genetree/member/id/${species}/${id}`
63
+ const msa = await fetchWithLocalStorageCache(`${id}-msa`, () =>
64
+ jsonfetch<{ tree: TreeNode }>(
65
+ `${treeBase}?content-type=application/json;aligned=1;sequence=pep`,
66
+ ),
67
+ )
68
+
69
+ const tree = await fetchWithLocalStorageCache<string>(`${id}-tree`, () =>
70
+ textfetch(`${treeBase}?nh_format=simple;content-type=text/x-nh`),
71
+ )
72
+
73
+ const res = gatherSequencesFromTree(msa.tree)
74
+ return {
75
+ tree,
76
+ msa: res.map(r => `>${r.id}\n${r.seq}`).join('\n'),
77
+ treeMetadata: JSON.stringify(
78
+ Object.fromEntries(res.map(r => [r.id, { genome: r.species }] as const)),
79
+ ),
80
+ }
81
+ }
@@ -0,0 +1,13 @@
1
+ export async function fetchGeneList() {
2
+ const res = await fetch(
3
+ 'https://jbrowse.org/demos/msaview/knownCanonical/list.txt',
4
+ )
5
+ if (!res.ok) {
6
+ throw new Error(`HTTP ${res.status} fetching list ${await res.text()}`)
7
+ }
8
+ const result = await res.text()
9
+ return result
10
+ .split('\n')
11
+ .map(f => f.trim())
12
+ .filter(f => !!f)
13
+ }
@@ -0,0 +1,45 @@
1
+ import { ungzip } from 'pako'
2
+
3
+ export async function jsonfetch<T>(url: string, arg?: RequestInit) {
4
+ const res = await fetch(url, arg)
5
+ if (!res.ok) {
6
+ throw new Error(`HTTP ${res.status} from ${url}: ${await res.text()}`)
7
+ }
8
+ return res.json() as Promise<T>
9
+ }
10
+
11
+ export async function textfetch(url: string, arg?: RequestInit) {
12
+ const res = await fetch(url, arg)
13
+ if (!res.ok) {
14
+ throw new Error(`HTTP ${res.status} from ${url}`)
15
+ }
16
+ return res.text()
17
+ }
18
+
19
+ export async function fetchWithLocalStorageCache<T>(
20
+ key: string,
21
+ fetchFn: () => Promise<T>,
22
+ ): Promise<T> {
23
+ const cachedData = localStorage.getItem(key)
24
+
25
+ if (cachedData) {
26
+ try {
27
+ return JSON.parse(cachedData) as T
28
+ } catch (error) {
29
+ console.error(`Error parsing cached data for ${key}:`, error)
30
+ // Continue to fetch fresh data if parsing fails
31
+ }
32
+ }
33
+
34
+ const data = await fetchFn()
35
+ localStorage.setItem(key, JSON.stringify(data))
36
+ return data
37
+ }
38
+
39
+ export async function unzipfetch(url: string, arg?: RequestInit) {
40
+ const res = await fetch(url, arg)
41
+ if (!res.ok) {
42
+ throw new Error(`HTTP ${res.status} from ${url}: ${await res.text()}`)
43
+ }
44
+ return ungzip(await res.arrayBuffer(), { to: 'string' })
45
+ }
@@ -2,12 +2,13 @@ import React, { useState } from 'react'
2
2
 
3
3
  import { Dialog } from '@jbrowse/core/ui'
4
4
  import { AbstractTrackModel, Feature } from '@jbrowse/core/util'
5
- import { Box, Tab, Tabs } from '@mui/material'
5
+ import { Tab, Tabs } from '@mui/material'
6
6
 
7
+ import EnsemblGeneTree from './EnsemblGeneTree/EnsemblGeneTree'
8
+ import MSALoader from './MSALoader/MSALoader'
7
9
  import NewNcbiBlastQueryPanel from './NewNCBIBlastQuery'
8
10
  import PreLoadedMSA from './PreLoadedMSA/PreLoadedMSADataPanel'
9
- import CustomTabPanel from './TabUtils'
10
- import { a11yProps } from './tabUtil'
11
+ import TabPanel from './TabPanel'
11
12
 
12
13
  export default function LaunchProteinViewDialog({
13
14
  handleClose,
@@ -24,36 +25,46 @@ export default function LaunchProteinViewDialog({
24
25
  <Dialog
25
26
  maxWidth="xl"
26
27
  title="Launch MSA view"
28
+ open
27
29
  onClose={() => {
28
30
  handleClose()
29
31
  }}
30
- open
31
32
  >
32
- <Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
33
- <Tabs
34
- value={value}
35
- onChange={(_, val) => {
36
- setValue(val)
37
- }}
38
- >
39
- <Tab label="NCBI BLAST query" {...a11yProps(0)} />
40
- <Tab label="UCSC 100-way dataset" {...a11yProps(1)} />
41
- </Tabs>
42
- </Box>
43
- <CustomTabPanel value={value} index={0}>
33
+ <Tabs
34
+ value={value}
35
+ onChange={(_, val) => {
36
+ setValue(val)
37
+ }}
38
+ >
39
+ <Tab label="NCBI BLAST query" value={0} />
40
+ <Tab label="UCSC 100-way dataset" value={1} />
41
+ <Tab label="Ensembl GeneTree" value={2} />
42
+ <Tab label="Manually open MSA" value={3} />
43
+ </Tabs>
44
+ <TabPanel value={value} index={0}>
44
45
  <NewNcbiBlastQueryPanel
45
46
  handleClose={handleClose}
46
47
  feature={feature}
47
48
  model={model}
48
49
  />
49
- </CustomTabPanel>
50
- <CustomTabPanel value={value} index={1}>
50
+ </TabPanel>
51
+ <TabPanel value={value} index={1}>
51
52
  <PreLoadedMSA
52
53
  model={model}
53
54
  feature={feature}
54
55
  handleClose={handleClose}
55
56
  />
56
- </CustomTabPanel>
57
+ </TabPanel>
58
+ <TabPanel value={value} index={2}>
59
+ <EnsemblGeneTree
60
+ model={model}
61
+ feature={feature}
62
+ handleClose={handleClose}
63
+ />
64
+ </TabPanel>
65
+ <TabPanel value={value} index={3}>
66
+ <MSALoader model={model} feature={feature} handleClose={handleClose} />
67
+ </TabPanel>
57
68
  </Dialog>
58
69
  )
59
70
  }
@@ -0,0 +1,130 @@
1
+ import React, { useEffect, useState } from 'react'
2
+
3
+ import { FileSelector } from '@jbrowse/core/ui'
4
+ import {
5
+ AbstractTrackModel,
6
+ Feature,
7
+ FileLocation,
8
+ getContainingView,
9
+ getSession,
10
+ } from '@jbrowse/core/util'
11
+ import { openLocation } from '@jbrowse/core/util/io'
12
+ import { Button, DialogActions, DialogContent } from '@mui/material'
13
+ import { observer } from 'mobx-react'
14
+ import { makeStyles } from 'tss-react/mui'
15
+
16
+ import { fetchGeneList } from './fetchGeneList'
17
+ import { preCalculatedLaunchView } from './preCalculatedLaunchView'
18
+ import { getGeneDisplayName, getId, getTranscriptFeatures } from '../../util'
19
+
20
+ import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
21
+
22
+ const useStyles = makeStyles()({
23
+ dialogContent: {
24
+ width: '80em',
25
+ },
26
+ })
27
+
28
+ const PreLoadedMSA = observer(function PreLoadedMSA2({
29
+ model,
30
+ feature,
31
+ handleClose,
32
+ }: {
33
+ model: AbstractTrackModel
34
+ feature: Feature
35
+ handleClose: () => void
36
+ }) {
37
+ const session = getSession(model)
38
+ const view = getContainingView(model) as LinearGenomeViewModel
39
+ const { classes } = useStyles()
40
+ const [, setError] = useState<unknown>()
41
+ const [geneNameList, setGeneNameList] = useState<string[]>()
42
+ const [fileLocation, setFileLocation] = useState<FileLocation>()
43
+
44
+ useEffect(() => {
45
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
46
+ ;(async () => {
47
+ try {
48
+ const data = await fetchGeneList()
49
+ setGeneNameList(data)
50
+ const set = new Set(data)
51
+ const options = getTranscriptFeatures(feature)
52
+ const ret = options.find(val => set.has(getId(val)))
53
+ if (ret) {
54
+ setUserSelection(getId(ret))
55
+ }
56
+ } catch (e) {
57
+ console.error(e)
58
+ setError(e)
59
+ }
60
+ })()
61
+ }, [feature])
62
+
63
+ useEffect(() => {
64
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
65
+ ;(async () => {
66
+ try {
67
+ if (fileLocation) {
68
+ await openLocation(fileLocation).readFile()
69
+ }
70
+ } catch (e) {
71
+ console.error(e)
72
+ setError(e)
73
+ }
74
+ })()
75
+ }, [fileLocation, feature])
76
+
77
+ const set = new Set(geneNameList)
78
+ const options = getTranscriptFeatures(feature)
79
+ const ret = options.find(val => set.has(getId(val)))
80
+ const [userSelection, setUserSelection] = useState(getId(options[0]))
81
+
82
+ return (
83
+ <>
84
+ <DialogContent className={classes.dialogContent}>
85
+ <FileSelector location={fileLocation} setLocation={setFileLocation} />
86
+ </DialogContent>
87
+
88
+ <DialogActions>
89
+ <Button
90
+ color="primary"
91
+ variant="contained"
92
+ onClick={() => {
93
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
94
+ ;(async () => {
95
+ try {
96
+ if (!ret) {
97
+ return
98
+ }
99
+ await preCalculatedLaunchView({
100
+ userSelection,
101
+ session,
102
+ newViewTitle: getGeneDisplayName(ret),
103
+ view,
104
+ feature: ret,
105
+ })
106
+ handleClose()
107
+ } catch (e) {
108
+ console.error(e)
109
+ setError(e)
110
+ }
111
+ })()
112
+ }}
113
+ >
114
+ Submit
115
+ </Button>
116
+ <Button
117
+ color="secondary"
118
+ variant="contained"
119
+ onClick={() => {
120
+ handleClose()
121
+ }}
122
+ >
123
+ Cancel
124
+ </Button>
125
+ </DialogActions>
126
+ </>
127
+ )
128
+ })
129
+
130
+ export default PreLoadedMSA
@@ -0,0 +1,13 @@
1
+ export async function fetchGeneList() {
2
+ const res = await fetch(
3
+ 'https://jbrowse.org/demos/msaview/knownCanonical/list.txt',
4
+ )
5
+ if (!res.ok) {
6
+ throw new Error(`HTTP ${res.status} fetching list ${await res.text()}`)
7
+ }
8
+ const result = await res.text()
9
+ return result
10
+ .split('\n')
11
+ .map(f => f.trim())
12
+ .filter(f => !!f)
13
+ }
@@ -0,0 +1,55 @@
1
+ import { AbstractSessionModel, Feature } from '@jbrowse/core/util'
2
+ import { ungzip } from 'pako'
3
+
4
+ import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
5
+
6
+ async function myfetch(url: string) {
7
+ const res = await fetch(url)
8
+ if (!res.ok) {
9
+ throw new Error(`HTTP ${res.status} fetching ${await res.text()}`)
10
+ }
11
+ const data = await res.arrayBuffer()
12
+ return new TextDecoder().decode(ungzip(data))
13
+ }
14
+
15
+ export async function preCalculatedLaunchView({
16
+ userSelection,
17
+ session,
18
+ newViewTitle,
19
+ view,
20
+ feature,
21
+ }: {
22
+ session: AbstractSessionModel
23
+ userSelection: string
24
+ newViewTitle: string
25
+ view: LinearGenomeViewModel
26
+ feature: Feature
27
+ }) {
28
+ const d = await myfetch(
29
+ `https://jbrowse.org/demos/msaview/knownCanonical/${userSelection}.mfa.gz`,
30
+ )
31
+
32
+ session.addView('MsaView', {
33
+ type: 'MsaView',
34
+ displayName: newViewTitle,
35
+ treeAreaWidth: 200,
36
+ treeWidth: 100,
37
+ drawNodeBubbles: false,
38
+ labelsAlignRight: true,
39
+ showBranchLen: false,
40
+ colWidth: 10,
41
+ rowHeight: 12,
42
+ colorSchemeName: 'percent_identity_dynamic',
43
+ treeFilehandle: {
44
+ uri: 'https://hgdownload.soe.ucsc.edu/goldenPath/hg38/multiz100way/hg38.100way.nh',
45
+ },
46
+ treeMetadataFilehandle: {
47
+ uri: 'https://s3.amazonaws.com/jbrowse.org/demos/app/species.json',
48
+ },
49
+ data: {
50
+ msa: d,
51
+ },
52
+ connectedViewId: view.id,
53
+ connectedFeature: feature.toJSON(),
54
+ })
55
+ }
@@ -1,15 +1,11 @@
1
1
  import {
2
- Feature,
3
2
  defaultCodonTable,
4
3
  generateCodonTable,
5
4
  revcom,
6
5
  } from '@jbrowse/core/util'
7
6
 
8
- export interface Feat {
9
- start: number
10
- end: number
11
- type: string
12
- }
7
+ import type { Feat } from './types'
8
+ import type { Feature } from '@jbrowse/core/util'
13
9
 
14
10
  export function stitch(subfeats: Feat[], sequence: string) {
15
11
  return subfeats.map(sub => sequence.slice(sub.start, sub.end)).join('')
@@ -33,10 +29,7 @@ export function calculateProteinSequence({
33
29
  return protein
34
30
  }
35
31
 
36
- export function revlist(
37
- list: { start: number; end: number; type: string }[],
38
- seqlen: number,
39
- ) {
32
+ export function revlist(list: Feat[], seqlen: number) {
40
33
  return list
41
34
  .map(sub => ({
42
35
  ...sub,
@@ -65,23 +58,16 @@ export function getProteinSequence({
65
58
  seq: string
66
59
  selectedTranscript: Feature
67
60
  }) {
68
- // @ts-expect-error
69
- const f = selectedTranscript.toJSON() as {
70
- start: number
71
- end: number
72
- strand: number
73
- type: string
74
- subfeatures: { start: number; end: number; type: string }[]
75
- }
61
+ const f = selectedTranscript.toJSON()
76
62
  const cds = dedupe(
77
63
  f.subfeatures
78
- .sort((a, b) => a.start - b.start)
64
+ ?.sort((a, b) => a.start - b.start)
79
65
  .map(sub => ({
80
66
  ...sub,
81
67
  start: sub.start - f.start,
82
68
  end: sub.end - f.start,
83
69
  }))
84
- .filter(f => f.type === 'CDS'),
70
+ .filter(f => f.type === 'CDS') || [],
85
71
  )
86
72
 
87
73
  return calculateProteinSequence({