jbrowse-plugin-msaview 2.1.0 → 2.2.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 (174) hide show
  1. package/dist/AddHighlightModel/GenomeMouseoverHighlight.js +3 -3
  2. package/dist/AddHighlightModel/GenomeMouseoverHighlight.js.map +1 -1
  3. package/dist/AddHighlightModel/MsaToGenomeHighlight.js +3 -1
  4. package/dist/AddHighlightModel/MsaToGenomeHighlight.js.map +1 -1
  5. package/dist/ExternalLink.d.ts +3 -0
  6. package/dist/ExternalLink.js +11 -0
  7. package/dist/ExternalLink.js.map +1 -0
  8. package/dist/LaunchMsaView/components/EnsemblGeneTree/EnsemblGeneTree.js +28 -33
  9. package/dist/LaunchMsaView/components/EnsemblGeneTree/EnsemblGeneTree.js.map +1 -1
  10. package/dist/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeLaunchView.js +0 -6
  11. package/dist/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeLaunchView.js.map +1 -1
  12. package/dist/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeUtils.d.ts +1 -0
  13. package/dist/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeUtils.js +12 -22
  14. package/dist/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeUtils.js.map +1 -1
  15. package/dist/LaunchMsaView/components/EnsemblGeneTree/gatherSequencesFromTree.d.ts +2 -0
  16. package/dist/LaunchMsaView/components/EnsemblGeneTree/gatherSequencesFromTree.js +20 -0
  17. package/dist/LaunchMsaView/components/EnsemblGeneTree/gatherSequencesFromTree.js.map +1 -0
  18. package/dist/LaunchMsaView/components/EnsemblGeneTree/types.d.ts +24 -0
  19. package/dist/LaunchMsaView/components/EnsemblGeneTree/types.js.map +1 -0
  20. package/dist/LaunchMsaView/components/EnsemblGeneTree/useGeneTree.d.ts +10 -0
  21. package/dist/LaunchMsaView/components/EnsemblGeneTree/useGeneTree.js +27 -0
  22. package/dist/LaunchMsaView/components/EnsemblGeneTree/useGeneTree.js.map +1 -0
  23. package/dist/LaunchMsaView/components/LaunchMsaViewDialog.js +5 -5
  24. package/dist/LaunchMsaView/components/LaunchMsaViewDialog.js.map +1 -1
  25. package/dist/LaunchMsaView/components/{NewNCBIBlastQuery/NcbiBlastPanel.d.ts → ManualMSALoader/ManualMSALoader.d.ts} +2 -2
  26. package/dist/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.js +103 -0
  27. package/dist/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.js.map +1 -0
  28. package/dist/LaunchMsaView/components/{EnsemblGeneTree → ManualMSALoader}/fetchGeneList.js.map +1 -1
  29. package/dist/LaunchMsaView/components/ManualMSALoader/launchView.d.ts +14 -0
  30. package/dist/LaunchMsaView/components/ManualMSALoader/launchView.js +12 -0
  31. package/dist/LaunchMsaView/components/ManualMSALoader/launchView.js.map +1 -0
  32. package/dist/LaunchMsaView/components/{MSALoader/MSALoader.d.ts → NCBIBlastQuery/NCBIBlastAutomaticPanel.d.ts} +4 -2
  33. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastAutomaticPanel.js +89 -0
  34. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastAutomaticPanel.js.map +1 -0
  35. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastManualPanel.d.ts +10 -0
  36. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastManualPanel.js +55 -0
  37. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastManualPanel.js.map +1 -0
  38. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastMethodSelector.d.ts +5 -0
  39. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastMethodSelector.js +11 -0
  40. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastMethodSelector.js.map +1 -0
  41. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastPanel.d.ts +7 -0
  42. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastPanel.js +30 -0
  43. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastPanel.js.map +1 -0
  44. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBISettingsDialog.d.ts +5 -0
  45. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBISettingsDialog.js +26 -0
  46. package/dist/LaunchMsaView/components/NCBIBlastQuery/NCBISettingsDialog.js.map +1 -0
  47. package/dist/LaunchMsaView/components/{NewNCBIBlastQuery/ncbiBlastLaunchView.d.ts → NCBIBlastQuery/blastLaunchView.d.ts} +2 -1
  48. package/dist/LaunchMsaView/components/{NewNCBIBlastQuery/ncbiBlastLaunchView.js → NCBIBlastQuery/blastLaunchView.js} +3 -6
  49. package/dist/LaunchMsaView/components/NCBIBlastQuery/blastLaunchView.js.map +1 -0
  50. package/dist/LaunchMsaView/components/NCBIBlastQuery/consts.d.ts +1 -0
  51. package/dist/LaunchMsaView/components/NCBIBlastQuery/consts.js +2 -0
  52. package/dist/LaunchMsaView/components/NCBIBlastQuery/consts.js.map +1 -0
  53. package/dist/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.js +17 -16
  54. package/dist/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.js.map +1 -1
  55. package/dist/LaunchMsaView/components/TranscriptSelector.d.ts +10 -0
  56. package/dist/LaunchMsaView/components/TranscriptSelector.js +45 -0
  57. package/dist/LaunchMsaView/components/TranscriptSelector.js.map +1 -0
  58. package/dist/LaunchMsaView/components/{NewNCBIBlastQuery/calculateProteinSequence.d.ts → calculateProteinSequence.d.ts} +1 -2
  59. package/dist/LaunchMsaView/components/calculateProteinSequence.js +39 -0
  60. package/dist/LaunchMsaView/components/calculateProteinSequence.js.map +1 -0
  61. package/dist/LaunchMsaView/components/fetchSeq.js.map +1 -0
  62. package/dist/LaunchMsaView/components/types.js +2 -0
  63. package/dist/LaunchMsaView/components/types.js.map +1 -0
  64. package/dist/LaunchMsaView/components/{NewNCBIBlastQuery/useFeatureSequence.d.ts → useFeatureSequence.d.ts} +2 -1
  65. package/dist/LaunchMsaView/components/{NewNCBIBlastQuery/useFeatureSequence.js → useFeatureSequence.js} +12 -1
  66. package/dist/LaunchMsaView/components/useFeatureSequence.js.map +1 -0
  67. package/dist/LaunchMsaView/components/util.js.map +1 -0
  68. package/dist/LaunchMsaView/util.d.ts +5 -1
  69. package/dist/LaunchMsaView/util.js +15 -1
  70. package/dist/LaunchMsaView/util.js.map +1 -1
  71. package/dist/MsaViewPanel/components/LoadingBLAST.d.ts +2 -1
  72. package/dist/MsaViewPanel/components/LoadingBLAST.js +6 -6
  73. package/dist/MsaViewPanel/components/LoadingBLAST.js.map +1 -1
  74. package/dist/MsaViewPanel/components/MsaViewPanel.js +1 -1
  75. package/dist/MsaViewPanel/components/MsaViewPanel.js.map +1 -1
  76. package/dist/MsaViewPanel/components/RIDLink.d.ts +2 -1
  77. package/dist/MsaViewPanel/components/RIDLink.js +6 -9
  78. package/dist/MsaViewPanel/components/RIDLink.js.map +1 -1
  79. package/dist/MsaViewPanel/doLaunchBlast.js +18 -20
  80. package/dist/MsaViewPanel/doLaunchBlast.js.map +1 -1
  81. package/dist/MsaViewPanel/model.d.ts +3 -4
  82. package/dist/MsaViewPanel/model.js.map +1 -1
  83. package/dist/ReadOnlyTextField2.d.ts +4 -0
  84. package/dist/ReadOnlyTextField2.js +20 -0
  85. package/dist/ReadOnlyTextField2.js.map +1 -0
  86. package/dist/index.d.ts +15 -0
  87. package/dist/index.js +17 -0
  88. package/dist/index.js.map +1 -1
  89. package/dist/jbrowse-plugin-msaview.umd.production.min.js +41 -51
  90. package/dist/jbrowse-plugin-msaview.umd.production.min.js.map +4 -4
  91. package/dist/utils/fetch.d.ts +1 -1
  92. package/dist/utils/fetch.js.map +1 -1
  93. package/dist/utils/ncbiBlast.d.ts +2 -2
  94. package/dist/utils/ncbiBlast.js +29 -15
  95. package/dist/utils/ncbiBlast.js.map +1 -1
  96. package/dist/utils/types.d.ts +20 -0
  97. package/dist/utils/types.js +2 -0
  98. package/dist/utils/types.js.map +1 -0
  99. package/package.json +3 -3
  100. package/src/AddHighlightModel/GenomeMouseoverHighlight.tsx +3 -3
  101. package/src/AddHighlightModel/MsaToGenomeHighlight.tsx +2 -1
  102. package/src/ExternalLink.tsx +15 -0
  103. package/src/LaunchMsaView/components/EnsemblGeneTree/EnsemblGeneTree.tsx +39 -55
  104. package/src/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeLaunchView.ts +0 -6
  105. package/src/LaunchMsaView/components/EnsemblGeneTree/ensemblGeneTreeUtils.ts +19 -54
  106. package/src/LaunchMsaView/components/EnsemblGeneTree/gatherSequencesFromTree.ts +22 -0
  107. package/src/LaunchMsaView/components/EnsemblGeneTree/types.ts +28 -0
  108. package/src/LaunchMsaView/components/EnsemblGeneTree/useGeneTree.ts +29 -0
  109. package/src/LaunchMsaView/components/LaunchMsaViewDialog.tsx +9 -5
  110. package/src/LaunchMsaView/components/ManualMSALoader/ManualMSALoader.tsx +219 -0
  111. package/src/LaunchMsaView/components/ManualMSALoader/launchView.ts +34 -0
  112. package/src/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastAutomaticPanel.tsx +226 -0
  113. package/src/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastManualPanel.tsx +111 -0
  114. package/src/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastMethodSelector.tsx +34 -0
  115. package/src/LaunchMsaView/components/NCBIBlastQuery/NCBIBlastPanel.tsx +82 -0
  116. package/src/LaunchMsaView/components/NCBIBlastQuery/NCBISettingsDialog.tsx +75 -0
  117. package/src/LaunchMsaView/components/{NewNCBIBlastQuery/ncbiBlastLaunchView.ts → NCBIBlastQuery/blastLaunchView.ts} +4 -5
  118. package/src/LaunchMsaView/components/NCBIBlastQuery/consts.ts +1 -0
  119. package/src/LaunchMsaView/components/PreLoadedMSA/PreLoadedMSADataPanel.tsx +27 -37
  120. package/src/LaunchMsaView/components/TranscriptSelector.tsx +99 -0
  121. package/src/LaunchMsaView/components/{NewNCBIBlastQuery/calculateProteinSequence.ts → calculateProteinSequence.ts} +12 -22
  122. package/src/LaunchMsaView/components/{NewNCBIBlastQuery/useFeatureSequence.ts → useFeatureSequence.ts} +16 -2
  123. package/src/LaunchMsaView/util.ts +22 -2
  124. package/src/MsaViewPanel/components/LoadingBLAST.tsx +26 -8
  125. package/src/MsaViewPanel/components/MsaViewPanel.tsx +5 -1
  126. package/src/MsaViewPanel/components/RIDLink.tsx +8 -8
  127. package/src/MsaViewPanel/doLaunchBlast.ts +29 -30
  128. package/src/MsaViewPanel/model.ts +1 -0
  129. package/src/ReadOnlyTextField2.tsx +33 -0
  130. package/src/index.ts +23 -0
  131. package/src/utils/fetch.ts +2 -2
  132. package/src/utils/ncbiBlast.ts +40 -30
  133. package/src/utils/types.ts +14 -0
  134. package/dist/LaunchMsaView/components/MSALoader/MSALoader.js +0 -94
  135. package/dist/LaunchMsaView/components/MSALoader/MSALoader.js.map +0 -1
  136. package/dist/LaunchMsaView/components/MSALoader/fetchGeneList.d.ts +0 -1
  137. package/dist/LaunchMsaView/components/MSALoader/fetchGeneList.js +0 -12
  138. package/dist/LaunchMsaView/components/MSALoader/fetchGeneList.js.map +0 -1
  139. package/dist/LaunchMsaView/components/MSALoader/preCalculatedLaunchView.d.ts +0 -9
  140. package/dist/LaunchMsaView/components/MSALoader/preCalculatedLaunchView.js +0 -36
  141. package/dist/LaunchMsaView/components/MSALoader/preCalculatedLaunchView.js.map +0 -1
  142. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/NcbiBlastPanel.js +0 -85
  143. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/NcbiBlastPanel.js.map +0 -1
  144. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/calculateProteinSequence.js +0 -47
  145. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/calculateProteinSequence.js.map +0 -1
  146. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/fetchSeq.js.map +0 -1
  147. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/index.d.ts +0 -1
  148. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/index.js +0 -2
  149. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/index.js.map +0 -1
  150. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/ncbiBlastLaunchView.js.map +0 -1
  151. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/types.js.map +0 -1
  152. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/useFeatureSequence.js.map +0 -1
  153. package/dist/LaunchMsaView/components/NewNCBIBlastQuery/util.js.map +0 -1
  154. package/dist/OpenInNewIcon.d.ts +0 -3
  155. package/dist/OpenInNewIcon.js +0 -8
  156. package/dist/OpenInNewIcon.js.map +0 -1
  157. package/src/LaunchMsaView/components/MSALoader/MSALoader.tsx +0 -130
  158. package/src/LaunchMsaView/components/MSALoader/fetchGeneList.ts +0 -13
  159. package/src/LaunchMsaView/components/MSALoader/preCalculatedLaunchView.ts +0 -55
  160. package/src/LaunchMsaView/components/NewNCBIBlastQuery/NcbiBlastPanel.tsx +0 -171
  161. package/src/LaunchMsaView/components/NewNCBIBlastQuery/index.tsx +0 -1
  162. package/src/OpenInNewIcon.tsx +0 -14
  163. /package/dist/LaunchMsaView/components/{NewNCBIBlastQuery → EnsemblGeneTree}/types.js +0 -0
  164. /package/dist/LaunchMsaView/components/{EnsemblGeneTree → ManualMSALoader}/fetchGeneList.d.ts +0 -0
  165. /package/dist/LaunchMsaView/components/{EnsemblGeneTree → ManualMSALoader}/fetchGeneList.js +0 -0
  166. /package/dist/LaunchMsaView/components/{NewNCBIBlastQuery/fetchSeq.d.ts → fetchSeq.d.ts} +0 -0
  167. /package/dist/LaunchMsaView/components/{NewNCBIBlastQuery/fetchSeq.js → fetchSeq.js} +0 -0
  168. /package/dist/LaunchMsaView/components/{NewNCBIBlastQuery/types.d.ts → types.d.ts} +0 -0
  169. /package/dist/LaunchMsaView/components/{NewNCBIBlastQuery/util.d.ts → util.d.ts} +0 -0
  170. /package/dist/LaunchMsaView/components/{NewNCBIBlastQuery/util.js → util.js} +0 -0
  171. /package/src/LaunchMsaView/components/{EnsemblGeneTree → ManualMSALoader}/fetchGeneList.ts +0 -0
  172. /package/src/LaunchMsaView/components/{NewNCBIBlastQuery/fetchSeq.ts → fetchSeq.ts} +0 -0
  173. /package/src/LaunchMsaView/components/{NewNCBIBlastQuery/types.ts → types.ts} +0 -0
  174. /package/src/LaunchMsaView/components/{NewNCBIBlastQuery/util.ts → util.ts} +0 -0
@@ -0,0 +1,75 @@
1
+ import React, { useState } from 'react'
2
+
3
+ import {
4
+ Button,
5
+ Dialog,
6
+ DialogActions,
7
+ DialogContent,
8
+ DialogTitle,
9
+ } from '@mui/material'
10
+
11
+ import { BASE_BLAST_URL } from './consts'
12
+ import TextField2 from '../../../TextField2'
13
+
14
+ export default function NCBISettingsDialog({
15
+ handleClose,
16
+ baseUrl,
17
+ }: {
18
+ handleClose: (arg?: string) => void
19
+ baseUrl: string
20
+ }) {
21
+ const [tempBaseUrl, setTempBaseUrl] = useState(baseUrl)
22
+ return (
23
+ <Dialog
24
+ open
25
+ maxWidth="lg"
26
+ onClose={() => {
27
+ handleClose()
28
+ }}
29
+ >
30
+ <DialogTitle>BLAST Settings</DialogTitle>
31
+ <DialogContent>
32
+ <TextField2
33
+ autoFocus
34
+ margin="dense"
35
+ label="BLAST Base URL"
36
+ fullWidth
37
+ variant="outlined"
38
+ value={tempBaseUrl}
39
+ style={{ minWidth: '300px' }}
40
+ onChange={e => {
41
+ setTempBaseUrl(e.target.value)
42
+ }}
43
+ />
44
+ <Button
45
+ variant="contained"
46
+ onClick={() => {
47
+ setTempBaseUrl(BASE_BLAST_URL)
48
+ }}
49
+ >
50
+ Reset
51
+ </Button>
52
+ </DialogContent>
53
+ <DialogActions>
54
+ <Button
55
+ variant="contained"
56
+ color="secondary"
57
+ onClick={() => {
58
+ handleClose()
59
+ }}
60
+ >
61
+ Cancel
62
+ </Button>
63
+ <Button
64
+ color="primary"
65
+ variant="contained"
66
+ onClick={() => {
67
+ handleClose(tempBaseUrl)
68
+ }}
69
+ >
70
+ Save
71
+ </Button>
72
+ </DialogActions>
73
+ </Dialog>
74
+ )
75
+ }
@@ -3,26 +3,25 @@ import { Feature, getSession } from '@jbrowse/core/util'
3
3
  import type { JBrowsePluginMsaViewModel } from '../../../MsaViewPanel/model'
4
4
  import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
5
5
 
6
- export function ncbiBlastLaunchView({
6
+ export function blastLaunchView({
7
7
  newViewTitle,
8
8
  view,
9
9
  feature,
10
+ blastParams,
10
11
  }: {
11
12
  newViewTitle: string
12
13
  view: LinearGenomeViewModel
13
14
  feature: Feature
15
+ blastParams: Record<string, unknown>
14
16
  }) {
15
17
  return getSession(view).addView('MsaView', {
16
18
  type: 'MsaView',
17
19
  displayName: newViewTitle,
18
20
  connectedViewId: view.id,
19
21
  connectedFeature: feature.toJSON(),
20
- treeAreaWidth: 250,
21
- treeWidth: 100,
22
22
  drawNodeBubbles: true,
23
- labelsAlignRight: true,
24
23
  colWidth: 10,
25
24
  rowHeight: 12,
26
- colorSchemeName: 'percent_identity_dynamic',
25
+ blastParams,
27
26
  }) as JBrowsePluginMsaViewModel
28
27
  }
@@ -0,0 +1 @@
1
+ export const BASE_BLAST_URL = 'https://blast.ncbi.nlm.nih.gov/Blast.cgi'
@@ -7,28 +7,20 @@ import {
7
7
  getContainingView,
8
8
  getSession,
9
9
  } from '@jbrowse/core/util'
10
- import {
11
- Button,
12
- DialogActions,
13
- DialogContent,
14
- MenuItem,
15
- TextField,
16
- Typography,
17
- } from '@mui/material'
10
+ import { Button, DialogActions, DialogContent, Typography } from '@mui/material'
18
11
  import { observer } from 'mobx-react'
19
12
  import { makeStyles } from 'tss-react/mui'
20
13
 
21
14
  import { fetchGeneList } from './fetchGeneList'
22
15
  import { preCalculatedLaunchView } from './preCalculatedLaunchView'
23
- import {
24
- getGeneDisplayName,
25
- getId,
26
- getTranscriptDisplayName,
27
- getTranscriptFeatures,
28
- } from '../../util'
16
+ import ExternalLink from '../../../ExternalLink'
17
+ import { getGeneDisplayName, getId, getTranscriptFeatures } from '../../util'
18
+ import TranscriptSelector from '../TranscriptSelector'
19
+ import { useFeatureSequence } from '../useFeatureSequence'
29
20
 
30
21
  import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
31
22
 
23
+
32
24
  const useStyles = makeStyles()({
33
25
  dialogContent: {
34
26
  width: '80em',
@@ -47,7 +39,7 @@ const PreLoadedMSA = observer(function PreLoadedMSA2({
47
39
  const session = getSession(model)
48
40
  const view = getContainingView(model) as LinearGenomeViewModel
49
41
  const { classes } = useStyles()
50
- const [error, setError] = useState<unknown>()
42
+ const [error1, setError] = useState<unknown>()
51
43
  const [geneNameList, setGeneNameList] = useState<string[]>()
52
44
  useEffect(() => {
53
45
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
@@ -67,41 +59,39 @@ const PreLoadedMSA = observer(function PreLoadedMSA2({
67
59
  }
68
60
  })()
69
61
  }, [feature])
70
- const set = new Set(geneNameList)
62
+ const validSet = new Set(geneNameList)
71
63
  const options = getTranscriptFeatures(feature)
72
- const ret = options.find(val => set.has(getId(val)))
64
+ const ret = options.find(val => validSet.has(getId(val)))
73
65
  const [userSelection, setUserSelection] = useState(getId(options[0]))
66
+ const selectedTranscript = options.find(val => getId(val) === userSelection)!
67
+ const { proteinSequence, error: error2 } = useFeatureSequence({
68
+ view,
69
+ feature: selectedTranscript,
70
+ })
71
+
72
+ const e = error1 ?? error2
74
73
 
75
74
  return (
76
75
  <>
77
76
  <DialogContent className={classes.dialogContent}>
77
+ {e ? <ErrorMessage error={e} /> : null}
78
78
  <Typography>
79
79
  The source data for these multiple sequence alignments is from{' '}
80
- <a href="https://hgdownload.soe.ucsc.edu/goldenPath/hg38/multiz100way/alignments/">
80
+ <ExternalLink href="https://hgdownload.soe.ucsc.edu/goldenPath/hg38/multiz100way/alignments/">
81
81
  knownCanonical.multiz100way.protAA.fa.gz
82
- </a>
82
+ </ExternalLink>
83
83
  </Typography>
84
- {error ? <ErrorMessage error={error} /> : null}
85
84
  {geneNameList && !ret ? (
86
85
  <Typography color="error">No MSA data for this gene found</Typography>
87
86
  ) : null}
88
- <TextField
89
- select
90
- label="Choose isoform to view MSA for"
91
- value={userSelection}
92
- onChange={event => {
93
- setUserSelection(event.target.value)
94
- }}
95
- >
96
- {options.map(val => {
97
- const inSet = set.has(getId(val))
98
- return (
99
- <MenuItem value={getId(val)} key={val.id()} disabled={!inSet}>
100
- {getTranscriptDisplayName(val)} {inSet ? ' (has data)' : ''}
101
- </MenuItem>
102
- )
103
- })}
104
- </TextField>
87
+ <TranscriptSelector
88
+ feature={feature}
89
+ options={options}
90
+ selectedTranscriptId={userSelection}
91
+ onTranscriptChange={setUserSelection}
92
+ proteinSequence={proteinSequence}
93
+ validSet={validSet}
94
+ />
105
95
  </DialogContent>
106
96
 
107
97
  <DialogActions>
@@ -0,0 +1,99 @@
1
+ import React, { useState } from 'react'
2
+
3
+ import { Feature } from '@jbrowse/core/util'
4
+ import { Button, MenuItem } from '@mui/material'
5
+ import { makeStyles } from 'tss-react/mui'
6
+
7
+ import ReadOnlyTextField2 from '../../ReadOnlyTextField2'
8
+ import TextField2 from '../../TextField2'
9
+ import {
10
+ getGeneDisplayName,
11
+ getId,
12
+ getTranscriptDisplayName,
13
+ getTranscriptLength,
14
+ } from '../util'
15
+
16
+ const useStyles = makeStyles()({
17
+ flex: {
18
+ display: 'flex',
19
+ },
20
+ minWidth: {
21
+ minWidth: 300,
22
+ },
23
+ })
24
+
25
+ export default function TranscriptSelector({
26
+ feature,
27
+ options,
28
+ selectedTranscriptId,
29
+ onTranscriptChange,
30
+ proteinSequence,
31
+ validSet,
32
+ }: {
33
+ feature: Feature
34
+ options: Feature[]
35
+ selectedTranscriptId: string
36
+ onTranscriptChange: (transcriptId: string) => void
37
+ proteinSequence: string | undefined
38
+ validSet?: Set<string>
39
+ }) {
40
+ const { classes } = useStyles()
41
+ const [showSequence, setShowSequence] = useState(false)
42
+ const selectedTranscript = options.find(
43
+ val => getId(val) === selectedTranscriptId,
44
+ )!
45
+
46
+ return (
47
+ <>
48
+ <div className={classes.flex}>
49
+ <TextField2
50
+ variant="outlined"
51
+ label={`Choose isoform of ${getGeneDisplayName(feature)}`}
52
+ select
53
+ className={classes.minWidth}
54
+ value={selectedTranscriptId}
55
+ onChange={event => {
56
+ onTranscriptChange(event.target.value)
57
+ }}
58
+ >
59
+ {options
60
+ .toSorted(
61
+ (a, b) => getTranscriptLength(b).len - getTranscriptLength(a).len,
62
+ )
63
+ .map(val => {
64
+ const inSet = validSet ? validSet.has(getId(val)) : true
65
+ const { len, mod } = getTranscriptLength(val)
66
+ return (
67
+ <MenuItem value={getId(val)} key={val.id()} disabled={!inSet}>
68
+ {getTranscriptDisplayName(val)} ({len} aa){' '}
69
+ {mod ? ` (possible fragment)` : ''}
70
+ {validSet ? (inSet ? ' (has data)' : ' (no data)') : ''}
71
+ </MenuItem>
72
+ )
73
+ })}
74
+ </TextField2>
75
+ <div style={{ alignContent: 'center', marginLeft: 20 }}>
76
+ <Button
77
+ variant="contained"
78
+ color="primary"
79
+ onClick={() => {
80
+ setShowSequence(!showSequence)
81
+ }}
82
+ >
83
+ {showSequence ? 'Hide sequence' : 'Show sequence'}
84
+ </Button>
85
+ </div>
86
+ </div>
87
+
88
+ {showSequence && (
89
+ <ReadOnlyTextField2
90
+ value={
91
+ proteinSequence
92
+ ? `>${getTranscriptDisplayName(selectedTranscript)}\n${proteinSequence}`
93
+ : 'Loading...'
94
+ }
95
+ />
96
+ )}
97
+ </>
98
+ )
99
+ }
@@ -1,4 +1,5 @@
1
1
  import {
2
+ dedupe,
2
3
  defaultCodonTable,
3
4
  generateCodonTable,
4
5
  revcom,
@@ -36,43 +37,32 @@ export function revlist(list: Feat[], seqlen: number) {
36
37
  start: seqlen - sub.end,
37
38
  end: seqlen - sub.start,
38
39
  }))
39
- .sort((a, b) => a.start - b.start)
40
+ .toSorted((a, b) => a.start - b.start)
40
41
  }
41
42
 
42
- // filter items if they have the same "ID" or location
43
- function getItemId(feat: Feat) {
44
- return `${feat.start}-${feat.end}`
45
- }
46
-
47
- // filters if successive elements share same start/end
48
- export function dedupe(list: Feat[]) {
49
- return list.filter(
50
- (item, pos, ary) => !pos || getItemId(item) !== getItemId(ary[pos - 1]!),
51
- )
52
- }
53
-
54
- export function getProteinSequence({
43
+ export function getProteinSequenceFromFeature({
55
44
  selectedTranscript,
56
45
  seq,
57
46
  }: {
58
47
  seq: string
59
48
  selectedTranscript: Feature
60
49
  }) {
61
- const f = selectedTranscript.toJSON()
50
+ const { subfeatures, start, strand } = selectedTranscript.toJSON()
62
51
  const cds = dedupe(
63
- f.subfeatures
64
- ?.sort((a, b) => a.start - b.start)
52
+ subfeatures
53
+ ?.toSorted((a, b) => a.start - b.start)
65
54
  .map(sub => ({
66
55
  ...sub,
67
- start: sub.start - f.start,
68
- end: sub.end - f.start,
56
+ start: sub.start - start,
57
+ end: sub.end - start,
69
58
  }))
70
- .filter(f => f.type === 'CDS') || [],
59
+ .filter(subfeature => subfeature.type === 'CDS') ?? [],
60
+ feat => `${feat.start}-${feat.end}`,
71
61
  )
72
62
 
73
63
  return calculateProteinSequence({
74
- cds: f.strand === -1 ? revlist(cds, seq.length) : cds,
75
- sequence: f.strand === -1 ? revcom(seq) : seq,
64
+ cds: strand === -1 ? revlist(cds, seq.length) : cds,
65
+ sequence: strand === -1 ? revcom(seq) : seq,
76
66
  codonTable: generateCodonTable(defaultCodonTable),
77
67
  })
78
68
  }
@@ -2,10 +2,11 @@ import { useEffect, useState } from 'react'
2
2
 
3
3
  import { getSession } from '@jbrowse/core/util'
4
4
 
5
+ import { getProteinSequenceFromFeature } from './calculateProteinSequence'
5
6
  import { fetchSeq } from './fetchSeq'
6
7
 
7
- import type { Feature } from '@jbrowse/core/util'
8
8
  import type { SeqState } from './types'
9
+ import type { Feature } from '@jbrowse/core/util'
9
10
 
10
11
  export interface ErrorState {
11
12
  error: string
@@ -80,5 +81,18 @@ export function useFeatureSequence({
80
81
  })()
81
82
  }
82
83
  }, [feature, view, upDownBp, assemblyName, forceLoad])
83
- return { sequence, error }
84
+
85
+ const proteinSequence =
86
+ sequence && !('error' in sequence)
87
+ ? getProteinSequenceFromFeature({
88
+ seq: sequence.seq,
89
+ selectedTranscript: feature,
90
+ })
91
+ : ''
92
+
93
+ return {
94
+ proteinSequence,
95
+ sequence,
96
+ error,
97
+ }
84
98
  }
@@ -1,4 +1,6 @@
1
- import { Feature } from '@jbrowse/core/util'
1
+ import { sum } from '@jbrowse/core/util'
2
+
3
+ import type { Feature } from '@jbrowse/core/util'
2
4
 
3
5
  export function getTranscriptFeatures(feature: Feature) {
4
6
  // check if we are looking at a 'two-level' or 'three-level' feature by
@@ -11,6 +13,21 @@ export function getTranscriptFeatures(feature: Feature) {
11
13
  f.get('subfeatures')?.some(f => f.get('type') === 'CDS'),
12
14
  )
13
15
  }
16
+
17
+ export function getTranscriptLength(feature: Feature) {
18
+ const cdsLen = sum(
19
+ feature
20
+ .get('subfeatures')
21
+ ?.filter(
22
+ f => (f.get('type') as string | undefined)?.toLowerCase() === 'cds',
23
+ )
24
+ .map(s => s.get('end') - s.get('start')) ?? [],
25
+ )
26
+ return {
27
+ len: Math.floor(cdsLen / 3),
28
+ mod: cdsLen % 3,
29
+ }
30
+ }
14
31
  export function getId(val?: Feature): string {
15
32
  return val?.get('name') ?? val?.get('id') ?? ''
16
33
  }
@@ -24,7 +41,10 @@ export function getTranscriptDisplayName(val?: Feature) {
24
41
  export function getGeneDisplayName(val?: Feature) {
25
42
  return val === undefined
26
43
  ? ''
27
- : [val.get('gene_name') ?? val.get('name'), val.get('id')]
44
+ : [
45
+ val.get('gene_name') ?? val.get('name'),
46
+ val.get('id') ? `(${val.get('id')})` : '',
47
+ ]
28
48
  .filter(f => !!f)
29
49
  .join(' ')
30
50
  }
@@ -17,20 +17,36 @@ const useStyles = makeStyles()(theme => ({
17
17
  },
18
18
  }))
19
19
 
20
- function RIDError({ rid, error }: { rid?: string; error: unknown }) {
20
+ function RIDError({
21
+ baseUrl,
22
+ rid,
23
+ error,
24
+ }: {
25
+ baseUrl: string
26
+ rid?: string
27
+ error: unknown
28
+ }) {
21
29
  return (
22
30
  <div>
23
- {rid ? <RIDLink rid={rid} /> : null}
31
+ {rid ? <RIDLink rid={rid} baseUrl={baseUrl} /> : null}
24
32
  <ErrorMessage error={error} />
25
33
  </div>
26
34
  )
27
35
  }
28
36
 
29
- function RIDProgress({ rid, progress }: { rid: string; progress: string }) {
37
+ function RIDProgress({
38
+ baseUrl,
39
+ rid,
40
+ progress,
41
+ }: {
42
+ baseUrl: string
43
+ rid: string
44
+ progress: string
45
+ }) {
30
46
  const { classes } = useStyles()
31
47
  return (
32
48
  <div className={classes.loading}>
33
- {rid ? <RIDLink rid={rid} /> : null}
49
+ {rid ? <RIDLink baseUrl={baseUrl} rid={rid} /> : null}
34
50
  <Typography>{progress}</Typography>
35
51
  </div>
36
52
  )
@@ -38,8 +54,10 @@ function RIDProgress({ rid, progress }: { rid: string; progress: string }) {
38
54
 
39
55
  const LoadingBLAST = observer(function LoadingBLAST2({
40
56
  model,
57
+ baseUrl,
41
58
  }: {
42
59
  model: JBrowsePluginMsaViewModel
60
+ baseUrl: string
43
61
  }) {
44
62
  const { progress, rid, error, processing } = model
45
63
  const { classes } = useStyles()
@@ -47,10 +65,10 @@ const LoadingBLAST = observer(function LoadingBLAST2({
47
65
  <div className={classes.margin}>
48
66
  <LoadingEllipses message="Running NCBI BLAST" variant="h5" />
49
67
  {error ? (
50
- <RIDError rid={rid} error={error} />
51
- ) : (rid ? (
52
- <RIDProgress rid={rid} progress={progress} />
53
- ) : null)}
68
+ <RIDError baseUrl={baseUrl} rid={rid} error={error} />
69
+ ) : rid ? (
70
+ <RIDProgress baseUrl={baseUrl} rid={rid} progress={progress} />
71
+ ) : null}
54
72
  <Typography>{processing || 'Initializing BLAST query'}</Typography>
55
73
  </div>
56
74
  )
@@ -14,7 +14,11 @@ const MsaViewPanel = observer(function MsaViewPanel2({
14
14
  const { blastParams } = model
15
15
  return (
16
16
  <div>
17
- {blastParams ? <LoadingBLAST model={model} /> : <MSAView model={model} />}
17
+ {blastParams ? (
18
+ <LoadingBLAST model={model} baseUrl={blastParams.baseUrl} />
19
+ ) : (
20
+ <MSAView model={model} />
21
+ )}
18
22
  </div>
19
23
  )
20
24
  })
@@ -1,17 +1,17 @@
1
1
  import React from 'react'
2
2
 
3
- import { Link, Typography } from '@mui/material'
3
+ import { Typography } from '@mui/material'
4
4
 
5
- import OpenInNewIcon from '../../OpenInNewIcon'
6
- import { BLAST_URL } from '../../utils/ncbiBlast'
5
+ import ExternalLink from '../../ExternalLink'
7
6
 
8
- function RIDLink({ rid }: { rid: string }) {
7
+ function RIDLink({ baseUrl, rid }: { rid: string; baseUrl: string }) {
9
8
  return (
10
9
  <Typography>
11
- RID {rid}{' '}
12
- <Link target="_black" href={`${BLAST_URL}?CMD=Get&RID=${rid}`}>
13
- (see status at NCBI <OpenInNewIcon />)
14
- </Link>
10
+ RID {rid} (
11
+ <ExternalLink href={`${baseUrl}?CMD=Get&RID=${rid}`}>
12
+ see status
13
+ </ExternalLink>
14
+ )
15
15
  </Typography>
16
16
  )
17
17
  }
@@ -1,8 +1,5 @@
1
1
  import { JBrowsePluginMsaViewModel } from './model'
2
- import {
3
- makeId,
4
- strip,
5
- } from '../LaunchMsaView/components/NewNCBIBlastQuery/util'
2
+ import { makeId, strip } from '../LaunchMsaView/components/util'
6
3
  import { launchMSA } from '../utils/msa'
7
4
  import { queryBlast } from '../utils/ncbiBlast'
8
5
 
@@ -11,13 +8,18 @@ export async function doLaunchBlast({
11
8
  }: {
12
9
  self: JBrowsePluginMsaViewModel
13
10
  }) {
14
- const { blastDatabase, blastProgram, msaAlgorithm, proteinSequence } =
15
- self.blastParams!
16
- const query = proteinSequence.replaceAll('*', '').replaceAll('&', '')
11
+ const {
12
+ baseUrl,
13
+ blastDatabase,
14
+ blastProgram,
15
+ msaAlgorithm,
16
+ proteinSequence,
17
+ } = self.blastParams!
17
18
  const { hits } = await queryBlast({
18
- query,
19
+ query: proteinSequence.replaceAll('*', '').replaceAll('&', ''),
19
20
  blastDatabase,
20
21
  blastProgram,
22
+ baseUrl,
21
23
  onProgress: arg => {
22
24
  self.setProgress(arg)
23
25
  },
@@ -26,31 +28,28 @@ export async function doLaunchBlast({
26
28
  },
27
29
  })
28
30
 
29
- const sequence = [
30
- `>QUERY\n${query}`,
31
- ...hits
32
- .map(
33
- h =>
34
- [
35
- makeId(
36
- h.description[0] ?? {
37
- accession: 'unknown',
38
- id: 'unknown',
39
- sciname: 'unknown',
40
- },
41
- ),
42
- strip(h.hsps[0]?.hseq ?? ''),
43
- ] as const,
44
- )
45
- .map(([id, seq]) => `>${id}\n${seq}`),
46
- ].join('\n')
47
-
48
- const data = await launchMSA({
31
+ return launchMSA({
49
32
  algorithm: msaAlgorithm,
50
- sequence,
33
+ sequence: [
34
+ `>QUERY\n${proteinSequence.replaceAll('*', '').replaceAll('&', '')}`,
35
+ ...hits
36
+ .map(
37
+ h =>
38
+ [
39
+ makeId(
40
+ h.description[0] ?? {
41
+ accession: 'unknown',
42
+ id: 'unknown',
43
+ sciname: 'unknown',
44
+ },
45
+ ),
46
+ strip(h.hsps[0]?.hseq ?? ''),
47
+ ] as const,
48
+ )
49
+ .map(([id, seq]) => `>${id}\n${seq}`),
50
+ ].join('\n'),
51
51
  onProgress: arg => {
52
52
  self.setProgress(arg)
53
53
  },
54
54
  })
55
- return data
56
55
  }
@@ -24,6 +24,7 @@ export interface IRegion {
24
24
  }
25
25
 
26
26
  export interface BlastParams {
27
+ baseUrl: string
27
28
  blastDatabase: string
28
29
  msaAlgorithm: string
29
30
  blastProgram: string
@@ -0,0 +1,33 @@
1
+ import React from 'react'
2
+
3
+ import { makeStyles } from 'tss-react/mui'
4
+
5
+ import TextField2 from './TextField2'
6
+
7
+ const useStyles = makeStyles()({
8
+ textAreaFont: {
9
+ fontFamily: 'Courier New',
10
+ },
11
+ })
12
+
13
+ export default function ReadOnlyTextField2({ value }: { value: string }) {
14
+ const { classes } = useStyles()
15
+ return (
16
+ <TextField2
17
+ variant="outlined"
18
+ multiline
19
+ minRows={5}
20
+ maxRows={10}
21
+ fullWidth
22
+ value={value}
23
+ slotProps={{
24
+ input: {
25
+ readOnly: true,
26
+ classes: {
27
+ input: classes.textAreaFont,
28
+ },
29
+ },
30
+ }}
31
+ />
32
+ )
33
+ }