@apollo-annotation/jbrowse-plugin-apollo 0.3.4 → 0.3.6
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/dist/index.esm.js +5466 -4490
- package/dist/index.esm.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.development.js +5283 -4318
- package/dist/jbrowse-plugin-apollo.cjs.development.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.production.min.js +1 -1
- package/dist/jbrowse-plugin-apollo.cjs.production.min.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.umd.development.js +6806 -4088
- package/dist/jbrowse-plugin-apollo.umd.development.js.map +1 -1
- package/dist/jbrowse-plugin-apollo.umd.production.min.js +1 -1
- package/dist/jbrowse-plugin-apollo.umd.production.min.js.map +1 -1
- package/package.json +4 -4
- package/src/ApolloInternetAccount/addMenuItems.ts +5 -2
- package/src/ApolloInternetAccount/components/AuthTypeSelector.tsx +1 -0
- package/src/ApolloInternetAccount/components/LoginButtons.tsx +1 -1
- package/src/ApolloInternetAccount/components/LoginIcons.tsx +1 -1
- package/src/ApolloInternetAccount/configSchema.ts +1 -1
- package/src/ApolloInternetAccount/model.ts +11 -10
- package/src/ApolloJobModel.ts +1 -1
- package/src/ApolloRefNameAliasAdapter/ApolloRefNameAliasAdapter.ts +8 -6
- package/src/ApolloRefNameAliasAdapter/index.ts +2 -2
- package/src/ApolloSequenceAdapter/ApolloSequenceAdapter.ts +17 -4
- package/src/ApolloSequenceAdapter/index.ts +1 -1
- package/src/ApolloTextSearchAdapter/ApolloTextSearchAdapter.ts +8 -7
- package/src/ApolloTextSearchAdapter/index.ts +1 -1
- package/src/BackendDrivers/BackendDriver.ts +7 -7
- package/src/BackendDrivers/CollaborationServerDriver.ts +14 -10
- package/src/BackendDrivers/DesktopFileDriver.ts +11 -10
- package/src/BackendDrivers/InMemoryFileDriver.ts +10 -6
- package/src/ChangeManager.ts +5 -5
- package/src/FeatureDetailsWidget/ApolloFeatureDetailsWidget.tsx +92 -20
- package/src/FeatureDetailsWidget/ApolloTranscriptDetailsWidget.tsx +170 -27
- package/src/FeatureDetailsWidget/AttributeKey.tsx +50 -0
- package/src/FeatureDetailsWidget/AttributeKeySelector.tsx +104 -0
- package/src/FeatureDetailsWidget/Attributes.tsx +213 -320
- package/src/FeatureDetailsWidget/BasicInformation.tsx +8 -9
- package/src/FeatureDetailsWidget/DefaultAttributeEditor.tsx +104 -0
- package/src/FeatureDetailsWidget/DefaultAttributeViewer.tsx +22 -0
- package/src/FeatureDetailsWidget/FeatureDetailsNavigation.tsx +10 -8
- package/src/FeatureDetailsWidget/NumberTextField.tsx +1 -1
- package/src/FeatureDetailsWidget/Sequence.tsx +18 -35
- package/src/FeatureDetailsWidget/StringTextField.tsx +1 -1
- package/src/FeatureDetailsWidget/TranscriptSequence.tsx +140 -95
- package/src/FeatureDetailsWidget/TranscriptWidgetEditLocation.tsx +600 -0
- package/src/FeatureDetailsWidget/TranscriptWidgetSummary.tsx +54 -0
- package/src/FeatureDetailsWidget/model.ts +8 -3
- package/src/LinearApolloDisplay/components/LinearApolloDisplay.tsx +19 -12
- package/src/LinearApolloDisplay/glyphs/BoxGlyph.ts +19 -41
- package/src/LinearApolloDisplay/glyphs/GeneGlyph.ts +44 -22
- package/src/LinearApolloDisplay/glyphs/GenericChildGlyph.ts +6 -5
- package/src/LinearApolloDisplay/glyphs/Glyph.ts +7 -7
- package/src/LinearApolloDisplay/stateModel/base.ts +52 -10
- package/src/LinearApolloDisplay/stateModel/index.ts +4 -3
- package/src/LinearApolloDisplay/stateModel/layouts.ts +8 -34
- package/src/LinearApolloDisplay/stateModel/mouseEvents.ts +13 -12
- package/src/LinearApolloDisplay/stateModel/rendering.ts +63 -31
- package/src/LinearApolloSixFrameDisplay/components/LinearApolloSixFrameDisplay.tsx +221 -0
- package/src/LinearApolloSixFrameDisplay/components/TrackLines.tsx +40 -0
- package/src/LinearApolloSixFrameDisplay/components/index.ts +2 -0
- package/src/LinearApolloSixFrameDisplay/configSchema.ts +7 -0
- package/src/LinearApolloSixFrameDisplay/glyphs/GeneGlyph.ts +821 -0
- package/src/LinearApolloSixFrameDisplay/glyphs/Glyph.ts +63 -0
- package/src/LinearApolloSixFrameDisplay/glyphs/index.ts +1 -0
- package/src/LinearApolloSixFrameDisplay/index.ts +2 -0
- package/src/LinearApolloSixFrameDisplay/stateModel/base.ts +261 -0
- package/src/LinearApolloSixFrameDisplay/stateModel/index.ts +27 -0
- package/src/LinearApolloSixFrameDisplay/stateModel/layouts.ts +236 -0
- package/src/LinearApolloSixFrameDisplay/stateModel/mouseEvents.ts +349 -0
- package/src/LinearApolloSixFrameDisplay/stateModel/rendering.ts +199 -0
- package/src/LinearApolloSixFrameDisplay/types.ts +1 -0
- package/src/OntologyManager/OntologyStore/fulltext-stopwords.ts +10 -1
- package/src/OntologyManager/OntologyStore/fulltext.test.ts +1 -1
- package/src/OntologyManager/OntologyStore/fulltext.ts +8 -3
- package/src/OntologyManager/OntologyStore/index.test.ts +4 -1
- package/src/OntologyManager/OntologyStore/index.ts +19 -14
- package/src/OntologyManager/OntologyStore/indexeddb-schema.ts +6 -5
- package/src/OntologyManager/OntologyStore/indexeddb-storage.ts +11 -5
- package/src/OntologyManager/index.ts +10 -6
- package/src/OntologyManager/util.ts +3 -2
- package/src/TabularEditor/HybridGrid/ChangeHandling.ts +2 -2
- package/src/TabularEditor/HybridGrid/Feature.tsx +9 -8
- package/src/TabularEditor/HybridGrid/FeatureAttributes.tsx +1 -1
- package/src/TabularEditor/HybridGrid/HybridGrid.tsx +3 -2
- package/src/TabularEditor/HybridGrid/NumberCell.tsx +8 -1
- package/src/TabularEditor/HybridGrid/ToolBar.tsx +15 -13
- package/src/TabularEditor/HybridGrid/featureContextMenuItems.ts +9 -33
- package/src/TabularEditor/TabularEditorPane.tsx +1 -1
- package/src/TabularEditor/model.ts +2 -2
- package/src/TabularEditor/types.ts +5 -2
- package/src/components/AddAssembly.tsx +611 -291
- package/src/components/AddChildFeature.tsx +6 -5
- package/src/components/AddFeature.tsx +211 -38
- package/src/components/AddRefSeqAliases.tsx +14 -12
- package/src/components/CopyFeature.tsx +8 -7
- package/src/components/CreateApolloAnnotation.tsx +154 -46
- package/src/components/DeleteAssembly.tsx +9 -8
- package/src/components/DeleteFeature.tsx +5 -4
- package/src/components/Dialog.tsx +1 -1
- package/src/components/DownloadGFF3.tsx +11 -10
- package/src/components/FilterFeatures.tsx +6 -4
- package/src/components/ImportFeatures.tsx +7 -6
- package/src/components/LogOut.tsx +5 -4
- package/src/components/ManageChecks.tsx +9 -8
- package/src/components/ManageUsers.tsx +11 -10
- package/src/components/OntologyTermAutocomplete.tsx +5 -5
- package/src/components/OntologyTermMultiSelect.tsx +9 -6
- package/src/components/OpenLocalFile.tsx +4 -3
- package/src/components/ViewChangeLog.tsx +7 -6
- package/src/components/ViewCheckResults.tsx +8 -7
- package/src/components/index.ts +0 -1
- package/src/extensions/annotationFromJBrowseFeature.test.ts +1 -0
- package/src/extensions/annotationFromJBrowseFeature.ts +14 -12
- package/src/extensions/annotationFromPileup.ts +6 -6
- package/src/index.ts +33 -50
- package/src/makeDisplayComponent.tsx +93 -41
- package/src/session/ClientDataStore.ts +21 -17
- package/src/session/session.ts +20 -26
- package/src/types.ts +4 -4
- package/src/util/annotationFeatureUtils.ts +53 -0
- package/src/util/index.ts +4 -3
- package/src/util/loadAssemblyIntoClient.ts +10 -3
- package/src/ApolloSixFrameRenderer/ApolloSixFrameRenderer.tsx +0 -13
- package/src/ApolloSixFrameRenderer/components/ApolloRendering.tsx +0 -707
- package/src/ApolloSixFrameRenderer/configSchema.ts +0 -7
- package/src/ApolloSixFrameRenderer/index.ts +0 -3
- package/src/FeatureDetailsWidget/TranscriptBasic.tsx +0 -200
- package/src/SixFrameFeatureDisplay/components/TrackLines.tsx +0 -19
- package/src/SixFrameFeatureDisplay/components/index.ts +0 -1
- package/src/SixFrameFeatureDisplay/configSchema.ts +0 -21
- package/src/SixFrameFeatureDisplay/index.ts +0 -2
- package/src/SixFrameFeatureDisplay/stateModel.ts +0 -439
- package/src/components/ModifyFeatureAttribute.tsx +0 -460
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
import { AnnotationFeature } from '@apollo-annotation/mst'
|
|
2
|
-
import {
|
|
3
|
-
LocationEndChange,
|
|
4
|
-
LocationStartChange,
|
|
5
|
-
} from '@apollo-annotation/shared'
|
|
6
|
-
import { AbstractSessionModel, getFrame, revcom } from '@jbrowse/core/util'
|
|
7
|
-
import {
|
|
8
|
-
Paper,
|
|
9
|
-
Typography,
|
|
10
|
-
Table,
|
|
11
|
-
TableBody,
|
|
12
|
-
TableCell,
|
|
13
|
-
TableContainer,
|
|
14
|
-
TableRow,
|
|
15
|
-
useTheme,
|
|
16
|
-
} from '@mui/material'
|
|
17
|
-
import { observer } from 'mobx-react'
|
|
18
|
-
import React from 'react'
|
|
19
|
-
|
|
20
|
-
import { ApolloSessionModel } from '../session'
|
|
21
|
-
import { NumberTextField } from './NumberTextField'
|
|
22
|
-
|
|
23
|
-
export const TranscriptBasicInformation = observer(
|
|
24
|
-
function TranscriptBasicInformation({
|
|
25
|
-
assembly,
|
|
26
|
-
feature,
|
|
27
|
-
refName,
|
|
28
|
-
session,
|
|
29
|
-
}: {
|
|
30
|
-
feature: AnnotationFeature
|
|
31
|
-
session: ApolloSessionModel
|
|
32
|
-
assembly: string
|
|
33
|
-
refName: string
|
|
34
|
-
}) {
|
|
35
|
-
const { notify } = session as unknown as AbstractSessionModel
|
|
36
|
-
const currentAssembly = session.apolloDataStore.assemblies.get(assembly)
|
|
37
|
-
const refData = currentAssembly?.getByRefName(refName)
|
|
38
|
-
const { changeManager } = session.apolloDataStore
|
|
39
|
-
const theme = useTheme()
|
|
40
|
-
|
|
41
|
-
function handleLocationChange(
|
|
42
|
-
oldLocation: number,
|
|
43
|
-
newLocation: number,
|
|
44
|
-
feature: AnnotationFeature,
|
|
45
|
-
isMin: boolean,
|
|
46
|
-
) {
|
|
47
|
-
if (!feature.children) {
|
|
48
|
-
throw new Error('Transcript should have child features')
|
|
49
|
-
}
|
|
50
|
-
for (const [, child] of feature.children) {
|
|
51
|
-
if (isMin && oldLocation - 1 === child.min) {
|
|
52
|
-
const change = new LocationStartChange({
|
|
53
|
-
typeName: 'LocationStartChange',
|
|
54
|
-
changedIds: [child._id],
|
|
55
|
-
featureId: feature._id,
|
|
56
|
-
oldStart: oldLocation - 1,
|
|
57
|
-
newStart: newLocation - 1,
|
|
58
|
-
assembly,
|
|
59
|
-
})
|
|
60
|
-
changeManager.submit(change).catch(() => {
|
|
61
|
-
notify('Error updating feature start position', 'error')
|
|
62
|
-
})
|
|
63
|
-
return
|
|
64
|
-
}
|
|
65
|
-
if (!isMin && newLocation === child.max) {
|
|
66
|
-
const change = new LocationEndChange({
|
|
67
|
-
typeName: 'LocationEndChange',
|
|
68
|
-
changedIds: [child._id],
|
|
69
|
-
featureId: feature._id,
|
|
70
|
-
oldEnd: child.max,
|
|
71
|
-
newEnd: newLocation,
|
|
72
|
-
assembly,
|
|
73
|
-
})
|
|
74
|
-
changeManager.submit(change).catch(() => {
|
|
75
|
-
notify('Error updating feature start position', 'error')
|
|
76
|
-
})
|
|
77
|
-
return
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (!refData) {
|
|
83
|
-
return null
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
let strand, transcriptParts
|
|
87
|
-
try {
|
|
88
|
-
;({ strand, transcriptParts } = feature)
|
|
89
|
-
} catch {
|
|
90
|
-
return null
|
|
91
|
-
}
|
|
92
|
-
const [firstLocation] = transcriptParts
|
|
93
|
-
|
|
94
|
-
const locationData = firstLocation
|
|
95
|
-
.map((loc, idx) => {
|
|
96
|
-
const { max, min, type } = loc
|
|
97
|
-
let label: string = type
|
|
98
|
-
if (label === 'threePrimeUTR') {
|
|
99
|
-
label = '3` UTR'
|
|
100
|
-
} else if (label === 'fivePrimeUTR') {
|
|
101
|
-
label = '5` UTR'
|
|
102
|
-
}
|
|
103
|
-
let fivePrimeSpliceSite
|
|
104
|
-
let threePrimeSpliceSite
|
|
105
|
-
let frameColor
|
|
106
|
-
if (type === 'CDS') {
|
|
107
|
-
const { phase } = loc
|
|
108
|
-
const frame = getFrame(min, max, strand ?? 1, phase)
|
|
109
|
-
frameColor = theme.palette.framesCDS.at(frame)?.main
|
|
110
|
-
const previousLoc = firstLocation.at(idx - 1)
|
|
111
|
-
const nextLoc = firstLocation.at(idx + 1)
|
|
112
|
-
if (strand === 1) {
|
|
113
|
-
if (previousLoc?.type === 'intron') {
|
|
114
|
-
fivePrimeSpliceSite = refData.getSequence(min - 2, min)
|
|
115
|
-
}
|
|
116
|
-
if (nextLoc?.type === 'intron') {
|
|
117
|
-
threePrimeSpliceSite = refData.getSequence(max, max + 2)
|
|
118
|
-
}
|
|
119
|
-
} else {
|
|
120
|
-
if (previousLoc?.type === 'intron') {
|
|
121
|
-
fivePrimeSpliceSite = revcom(refData.getSequence(max, max + 2))
|
|
122
|
-
}
|
|
123
|
-
if (nextLoc?.type === 'intron') {
|
|
124
|
-
threePrimeSpliceSite = revcom(refData.getSequence(min - 2, min))
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
return {
|
|
129
|
-
min,
|
|
130
|
-
max,
|
|
131
|
-
label,
|
|
132
|
-
fivePrimeSpliceSite,
|
|
133
|
-
threePrimeSpliceSite,
|
|
134
|
-
frameColor,
|
|
135
|
-
}
|
|
136
|
-
})
|
|
137
|
-
.filter((loc) => loc.label !== 'intron')
|
|
138
|
-
|
|
139
|
-
return (
|
|
140
|
-
<>
|
|
141
|
-
<Typography variant="h5">Structure</Typography>
|
|
142
|
-
<Typography variant="h6">
|
|
143
|
-
{strand === 1 ? 'Forward' : 'Reverse'} strand
|
|
144
|
-
</Typography>
|
|
145
|
-
<TableContainer component={Paper}>
|
|
146
|
-
<Table size="small">
|
|
147
|
-
<TableBody>
|
|
148
|
-
{locationData.map((loc) => (
|
|
149
|
-
<TableRow key={`${loc.label}:${loc.min}-${loc.max}`}>
|
|
150
|
-
<TableCell
|
|
151
|
-
component="th"
|
|
152
|
-
scope="row"
|
|
153
|
-
style={{ background: loc.frameColor }}
|
|
154
|
-
>
|
|
155
|
-
{loc.label}
|
|
156
|
-
</TableCell>
|
|
157
|
-
<TableCell>{loc.fivePrimeSpliceSite ?? ''}</TableCell>
|
|
158
|
-
<TableCell padding="none">
|
|
159
|
-
<NumberTextField
|
|
160
|
-
margin="dense"
|
|
161
|
-
variant="outlined"
|
|
162
|
-
value={strand === 1 ? loc.min + 1 : loc.max}
|
|
163
|
-
onChangeCommitted={(newLocation: number) => {
|
|
164
|
-
handleLocationChange(
|
|
165
|
-
strand === 1 ? loc.min + 1 : loc.max,
|
|
166
|
-
newLocation,
|
|
167
|
-
feature,
|
|
168
|
-
strand === 1,
|
|
169
|
-
)
|
|
170
|
-
}}
|
|
171
|
-
/>
|
|
172
|
-
{/* {strand === 1 ? loc.min : loc.max} */}
|
|
173
|
-
</TableCell>
|
|
174
|
-
<TableCell padding="none">
|
|
175
|
-
<NumberTextField
|
|
176
|
-
margin="dense"
|
|
177
|
-
// disabled={item.type !== 'CDS'}
|
|
178
|
-
variant="outlined"
|
|
179
|
-
value={strand === 1 ? loc.max : loc.min + 1}
|
|
180
|
-
onChangeCommitted={(newLocation: number) => {
|
|
181
|
-
handleLocationChange(
|
|
182
|
-
strand === 1 ? loc.max : loc.min + 1,
|
|
183
|
-
newLocation,
|
|
184
|
-
feature,
|
|
185
|
-
strand !== 1,
|
|
186
|
-
)
|
|
187
|
-
}}
|
|
188
|
-
/>
|
|
189
|
-
{/* {strand === 1 ? loc.max : loc.min} */}
|
|
190
|
-
</TableCell>
|
|
191
|
-
<TableCell>{loc.threePrimeSpliceSite ?? ''}</TableCell>
|
|
192
|
-
</TableRow>
|
|
193
|
-
))}
|
|
194
|
-
</TableBody>
|
|
195
|
-
</Table>
|
|
196
|
-
</TableContainer>
|
|
197
|
-
</>
|
|
198
|
-
)
|
|
199
|
-
},
|
|
200
|
-
)
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { observer } from 'mobx-react'
|
|
2
|
-
import React from 'react'
|
|
3
|
-
|
|
4
|
-
import { SixFrameFeatureDisplay } from '../stateModel'
|
|
5
|
-
|
|
6
|
-
export const TrackLines = observer(function TrackLines({
|
|
7
|
-
model,
|
|
8
|
-
}: {
|
|
9
|
-
model: SixFrameFeatureDisplay
|
|
10
|
-
}) {
|
|
11
|
-
const { height } = model
|
|
12
|
-
return (
|
|
13
|
-
<div
|
|
14
|
-
style={{ position: 'absolute', left: 0, top: height / 2, width: '100%' }}
|
|
15
|
-
>
|
|
16
|
-
<hr style={{ margin: 0, top: 0, color: 'black' }} />
|
|
17
|
-
</div>
|
|
18
|
-
)
|
|
19
|
-
})
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './TrackLines'
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { ConfigurationSchema } from '@jbrowse/core/configuration'
|
|
2
|
-
import PluginManager from '@jbrowse/core/PluginManager'
|
|
3
|
-
import type LinearGenomeViewPlugin from '@jbrowse/plugin-linear-genome-view'
|
|
4
|
-
|
|
5
|
-
import { configSchema as apolloRendererConfigSchema } from '../ApolloSixFrameRenderer'
|
|
6
|
-
|
|
7
|
-
export function configSchemaFactory(pluginManager: PluginManager) {
|
|
8
|
-
const LGVPlugin = pluginManager.getPlugin(
|
|
9
|
-
'LinearGenomeViewPlugin',
|
|
10
|
-
) as LinearGenomeViewPlugin
|
|
11
|
-
const { baseLinearDisplayConfigSchema } = LGVPlugin.exports
|
|
12
|
-
|
|
13
|
-
return ConfigurationSchema(
|
|
14
|
-
'SixFrameFeatureDisplay',
|
|
15
|
-
{
|
|
16
|
-
renderer: apolloRendererConfigSchema,
|
|
17
|
-
height: { type: 'number', defaultValue: 120 },
|
|
18
|
-
},
|
|
19
|
-
{ baseConfiguration: baseLinearDisplayConfigSchema, explicitlyTyped: true },
|
|
20
|
-
)
|
|
21
|
-
}
|
|
@@ -1,439 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/restrict-plus-operands */
|
|
2
|
-
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
|
3
|
-
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
4
|
-
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
|
|
5
|
-
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
6
|
-
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
7
|
-
/* eslint-disable @typescript-eslint/unbound-method */
|
|
8
|
-
import { AnnotationFeature } from '@apollo-annotation/mst'
|
|
9
|
-
import { ConfigurationReference } from '@jbrowse/core/configuration'
|
|
10
|
-
import { AnyConfigurationSchemaType } from '@jbrowse/core/configuration/configurationSchema'
|
|
11
|
-
import PluginManager from '@jbrowse/core/PluginManager'
|
|
12
|
-
import {
|
|
13
|
-
defaultStarts,
|
|
14
|
-
defaultStops,
|
|
15
|
-
getContainingView,
|
|
16
|
-
getSession,
|
|
17
|
-
revcom,
|
|
18
|
-
reverse,
|
|
19
|
-
} from '@jbrowse/core/util'
|
|
20
|
-
import { BaseBlock } from '@jbrowse/core/util/blockTypes'
|
|
21
|
-
import { getParentRenderProps } from '@jbrowse/core/util/tracks'
|
|
22
|
-
import type LinearGenomeViewPlugin from '@jbrowse/plugin-linear-genome-view'
|
|
23
|
-
import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
|
|
24
|
-
import { autorun } from 'mobx'
|
|
25
|
-
import { Instance, addDisposer, types } from 'mobx-state-tree'
|
|
26
|
-
|
|
27
|
-
import { ApolloSession, ApolloSessionModel } from '../session'
|
|
28
|
-
|
|
29
|
-
const forwardPhaseMap: Record<number, number> = { 0: 2, 1: 1, 2: 0 }
|
|
30
|
-
const reversePhaseMap: Record<number, number> = { 3: 0, 4: 1, 5: 2 }
|
|
31
|
-
|
|
32
|
-
export function stateModelFactory(
|
|
33
|
-
pluginManager: PluginManager,
|
|
34
|
-
configSchema: AnyConfigurationSchemaType,
|
|
35
|
-
) {
|
|
36
|
-
const LGVPlugin = pluginManager.getPlugin(
|
|
37
|
-
'LinearGenomeViewPlugin',
|
|
38
|
-
) as LinearGenomeViewPlugin
|
|
39
|
-
const { BaseLinearDisplay } = LGVPlugin.exports
|
|
40
|
-
|
|
41
|
-
return BaseLinearDisplay.named('SixFrameFeatureDisplay')
|
|
42
|
-
.props({
|
|
43
|
-
type: types.literal('SixFrameFeatureDisplay'),
|
|
44
|
-
configuration: ConfigurationReference(configSchema),
|
|
45
|
-
apolloRowHeight: 20,
|
|
46
|
-
detailsMinHeight: 200,
|
|
47
|
-
showStartCodons: false,
|
|
48
|
-
showStopCodons: true,
|
|
49
|
-
showIntronLines: true,
|
|
50
|
-
})
|
|
51
|
-
.volatile(() => ({
|
|
52
|
-
apolloFeatureUnderMouse: undefined as AnnotationFeature | undefined,
|
|
53
|
-
apolloRowUnderMouse: undefined as number | undefined,
|
|
54
|
-
}))
|
|
55
|
-
.views((self) => {
|
|
56
|
-
const { configuration, renderProps: superRenderProps } = self
|
|
57
|
-
return {
|
|
58
|
-
renderProps() {
|
|
59
|
-
return {
|
|
60
|
-
...superRenderProps(),
|
|
61
|
-
...getParentRenderProps(self),
|
|
62
|
-
config: configuration.renderer,
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
}
|
|
66
|
-
})
|
|
67
|
-
.views((self) => ({
|
|
68
|
-
get regions() {
|
|
69
|
-
let blockDefinitions
|
|
70
|
-
try {
|
|
71
|
-
;({ blockDefinitions } = self)
|
|
72
|
-
} catch {
|
|
73
|
-
return []
|
|
74
|
-
}
|
|
75
|
-
const regions = blockDefinitions.contentBlocks.map(
|
|
76
|
-
({ assemblyName, end, refName, start }) => ({
|
|
77
|
-
assemblyName,
|
|
78
|
-
refName,
|
|
79
|
-
start,
|
|
80
|
-
end,
|
|
81
|
-
}),
|
|
82
|
-
)
|
|
83
|
-
return regions
|
|
84
|
-
},
|
|
85
|
-
regionCannotBeRendered(/* region */) {
|
|
86
|
-
const view = getContainingView(self) as unknown as LinearGenomeViewModel
|
|
87
|
-
if (view && view.bpPerPx >= 200) {
|
|
88
|
-
return 'Zoom in to see annotations'
|
|
89
|
-
}
|
|
90
|
-
return
|
|
91
|
-
},
|
|
92
|
-
get session() {
|
|
93
|
-
return getSession(self) as unknown as ApolloSessionModel
|
|
94
|
-
},
|
|
95
|
-
}))
|
|
96
|
-
.actions((self) => {
|
|
97
|
-
let previousBlockKeys: string[] = []
|
|
98
|
-
return {
|
|
99
|
-
afterAttach() {
|
|
100
|
-
addDisposer(
|
|
101
|
-
self,
|
|
102
|
-
autorun(
|
|
103
|
-
() => {
|
|
104
|
-
const session = getSession(self) as ApolloSession
|
|
105
|
-
const view = getContainingView(
|
|
106
|
-
self,
|
|
107
|
-
) as unknown as LinearGenomeViewModel
|
|
108
|
-
if (view.initialized) {
|
|
109
|
-
if (self.regionCannotBeRendered()) {
|
|
110
|
-
return
|
|
111
|
-
}
|
|
112
|
-
const blockKeys: string[] = []
|
|
113
|
-
const newBlocks: BaseBlock[] = []
|
|
114
|
-
for (const block of self.blockDefinitions.contentBlocks) {
|
|
115
|
-
blockKeys.push(block.key)
|
|
116
|
-
if (!previousBlockKeys.includes(block.key)) {
|
|
117
|
-
newBlocks.push(block)
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
session.apolloDataStore.loadFeatures(
|
|
121
|
-
newBlocks.map(({ assemblyName, end, refName, start }) => ({
|
|
122
|
-
assemblyName,
|
|
123
|
-
refName,
|
|
124
|
-
start,
|
|
125
|
-
end,
|
|
126
|
-
})),
|
|
127
|
-
)
|
|
128
|
-
session.apolloDataStore.loadRefSeq(
|
|
129
|
-
newBlocks.map(({ assemblyName, end, refName, start }) => ({
|
|
130
|
-
assemblyName,
|
|
131
|
-
refName,
|
|
132
|
-
start,
|
|
133
|
-
end,
|
|
134
|
-
})),
|
|
135
|
-
)
|
|
136
|
-
previousBlockKeys = blockKeys
|
|
137
|
-
}
|
|
138
|
-
},
|
|
139
|
-
{ name: 'SixFrameFeatureDisplay' },
|
|
140
|
-
),
|
|
141
|
-
)
|
|
142
|
-
},
|
|
143
|
-
}
|
|
144
|
-
})
|
|
145
|
-
.views((self) => ({
|
|
146
|
-
get rendererTypeName() {
|
|
147
|
-
return self.configuration.renderer.type
|
|
148
|
-
},
|
|
149
|
-
get changeManager() {
|
|
150
|
-
const session = getSession(self) as ApolloSession
|
|
151
|
-
return session.apolloDataStore.changeManager
|
|
152
|
-
},
|
|
153
|
-
get sequence() {
|
|
154
|
-
const { regions } = self
|
|
155
|
-
const session = getSession(self) as ApolloSession
|
|
156
|
-
const seq = new Map<number, string>()
|
|
157
|
-
for (const region of regions) {
|
|
158
|
-
const assembly = session.apolloDataStore.assemblies.get(
|
|
159
|
-
region.assemblyName,
|
|
160
|
-
)
|
|
161
|
-
const ref = assembly?.getByRefName(region.refName)
|
|
162
|
-
const refSeq: string | undefined = ref?.getSequence(
|
|
163
|
-
region.start,
|
|
164
|
-
region.end,
|
|
165
|
-
)
|
|
166
|
-
seq.set(region.start, refSeq ?? '')
|
|
167
|
-
}
|
|
168
|
-
return seq
|
|
169
|
-
},
|
|
170
|
-
get features() {
|
|
171
|
-
const { regions } = self
|
|
172
|
-
const session = getSession(self) as ApolloSession
|
|
173
|
-
const features = new Map<string, Map<string, AnnotationFeature>>()
|
|
174
|
-
for (const region of regions) {
|
|
175
|
-
const assembly = session.apolloDataStore.assemblies.get(
|
|
176
|
-
region.assemblyName,
|
|
177
|
-
)
|
|
178
|
-
const ref = assembly?.getByRefName(region.refName)
|
|
179
|
-
let filteredRef = features.get(region.refName)
|
|
180
|
-
if (!filteredRef) {
|
|
181
|
-
filteredRef = new Map<string, AnnotationFeature>()
|
|
182
|
-
features.set(region.refName, filteredRef)
|
|
183
|
-
}
|
|
184
|
-
for (const [featureId, feature] of ref?.features.entries() ??
|
|
185
|
-
new Map()) {
|
|
186
|
-
if (region.start < feature.end && region.end > feature.start) {
|
|
187
|
-
filteredRef.set(featureId, feature)
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
return features
|
|
192
|
-
},
|
|
193
|
-
get featuresMinMax() {
|
|
194
|
-
const minMax: Record<string, [number, number]> = {}
|
|
195
|
-
for (const [refSeq, featuresForRefSeq] of this.features || []) {
|
|
196
|
-
let min: number | undefined
|
|
197
|
-
let max: number | undefined
|
|
198
|
-
for (const [, featureLocation] of featuresForRefSeq) {
|
|
199
|
-
if (min === undefined) {
|
|
200
|
-
;({ min } = featureLocation)
|
|
201
|
-
}
|
|
202
|
-
if (max === undefined) {
|
|
203
|
-
;({ max } = featureLocation)
|
|
204
|
-
}
|
|
205
|
-
if (featureLocation.min < min) {
|
|
206
|
-
;({ min } = featureLocation)
|
|
207
|
-
}
|
|
208
|
-
if (featureLocation.max > max) {
|
|
209
|
-
;({ max } = featureLocation)
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
if (min !== undefined && max !== undefined) {
|
|
213
|
-
minMax[refSeq] = [min, max]
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
return minMax
|
|
217
|
-
},
|
|
218
|
-
get codonLayout() {
|
|
219
|
-
const codonLayout = new Map<
|
|
220
|
-
number,
|
|
221
|
-
{ starts: number[]; stops: number[] }
|
|
222
|
-
>()
|
|
223
|
-
let fullSeq = ''
|
|
224
|
-
let fullStart = 0
|
|
225
|
-
for (const [regionStart, seq] of this.sequence || []) {
|
|
226
|
-
if (!seq) {
|
|
227
|
-
continue
|
|
228
|
-
}
|
|
229
|
-
if (!fullSeq) {
|
|
230
|
-
fullStart = regionStart
|
|
231
|
-
}
|
|
232
|
-
fullSeq += seq
|
|
233
|
-
}
|
|
234
|
-
const rowCount = 6
|
|
235
|
-
for (let i = 0; i < rowCount; i++) {
|
|
236
|
-
const starts: number[] = []
|
|
237
|
-
const stops: number[] = []
|
|
238
|
-
const reversed = i in reversePhaseMap
|
|
239
|
-
// the tilt variable normalizes the frame to where we are starting from,
|
|
240
|
-
// which increases consistency across blocks
|
|
241
|
-
let tilt
|
|
242
|
-
// the effectiveFrame incorporates tilt and the frame to say what the
|
|
243
|
-
// effective frame that is plotted. The +3 is for when frame is -2 and this
|
|
244
|
-
// can otherwise result in effectiveFrame -1
|
|
245
|
-
let effectiveFrame
|
|
246
|
-
let seqSliced
|
|
247
|
-
if (reversed) {
|
|
248
|
-
tilt = (fullSeq.length + fullStart) % 3
|
|
249
|
-
effectiveFrame = (reversePhaseMap[i] + tilt + 3) % 3
|
|
250
|
-
seqSliced = reverse(fullSeq).slice(effectiveFrame)
|
|
251
|
-
} else {
|
|
252
|
-
tilt = 3 - (fullStart % 3)
|
|
253
|
-
effectiveFrame = (forwardPhaseMap[i] + tilt + 3) % 3
|
|
254
|
-
seqSliced = fullSeq.slice(effectiveFrame)
|
|
255
|
-
}
|
|
256
|
-
for (let j = 0; j < seqSliced.length; j += 3) {
|
|
257
|
-
const codon = seqSliced.slice(j, j + 3)
|
|
258
|
-
const normalizedCodon = reversed ? reverse(revcom(codon)) : codon
|
|
259
|
-
const start = reversed
|
|
260
|
-
? fullStart + seqSliced.length - (3 + j)
|
|
261
|
-
: fullStart + j + effectiveFrame
|
|
262
|
-
if (defaultStarts.includes(normalizedCodon.toUpperCase())) {
|
|
263
|
-
starts.push(start)
|
|
264
|
-
} else if (defaultStops.includes(normalizedCodon.toUpperCase())) {
|
|
265
|
-
stops.push(start)
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
codonLayout.set(i, { starts, stops })
|
|
269
|
-
}
|
|
270
|
-
return codonLayout
|
|
271
|
-
},
|
|
272
|
-
get featureLayout() {
|
|
273
|
-
const { featureTypeOntology } =
|
|
274
|
-
self.session.apolloDataStore.ontologyManager
|
|
275
|
-
if (!featureTypeOntology) {
|
|
276
|
-
throw new Error('featureTypeOntology is undefined')
|
|
277
|
-
}
|
|
278
|
-
const featureLayout = new Map<number, [string, AnnotationFeature][]>()
|
|
279
|
-
for (const [refSeq, featuresForRefSeq] of this.features || []) {
|
|
280
|
-
if (!featuresForRefSeq) {
|
|
281
|
-
continue
|
|
282
|
-
}
|
|
283
|
-
const minMaxfeatures = this.featuresMinMax[refSeq]
|
|
284
|
-
if (!minMaxfeatures) {
|
|
285
|
-
continue
|
|
286
|
-
}
|
|
287
|
-
const [min, max] = minMaxfeatures
|
|
288
|
-
const rows: boolean[][] = []
|
|
289
|
-
const rowCount = 6
|
|
290
|
-
for (let i = 0; i < rowCount; i++) {
|
|
291
|
-
const newRowNumber = rows.length
|
|
292
|
-
rows[newRowNumber] = Array.from({ length: max - min })
|
|
293
|
-
featureLayout.set(newRowNumber, [])
|
|
294
|
-
}
|
|
295
|
-
for (const feature of [...featuresForRefSeq.values()].sort(
|
|
296
|
-
(f1, f2) => {
|
|
297
|
-
const { max: end1, min: start1 } = f1
|
|
298
|
-
const { max: end2, min: start2 } = f2
|
|
299
|
-
return start1 - start2 || end1 - end2
|
|
300
|
-
},
|
|
301
|
-
)) {
|
|
302
|
-
for (const [, childFeature] of feature.children ?? new Map()) {
|
|
303
|
-
if (
|
|
304
|
-
featureTypeOntology.isTypeOf(childFeature.type, 'transcript')
|
|
305
|
-
) {
|
|
306
|
-
for (const [, grandChildFeature] of childFeature.children ||
|
|
307
|
-
new Map()) {
|
|
308
|
-
let startingRow
|
|
309
|
-
if (
|
|
310
|
-
featureTypeOntology.isTypeOf(grandChildFeature.type, 'CDS')
|
|
311
|
-
) {
|
|
312
|
-
let discontinuousLocations
|
|
313
|
-
if (grandChildFeature.discontinuousLocations.length > 0) {
|
|
314
|
-
;({ discontinuousLocations } = grandChildFeature)
|
|
315
|
-
} else {
|
|
316
|
-
discontinuousLocations = [grandChildFeature]
|
|
317
|
-
}
|
|
318
|
-
for (const cds of discontinuousLocations) {
|
|
319
|
-
const min = cds.start + 3
|
|
320
|
-
const max = cds.end - 3
|
|
321
|
-
// Remove codons either end of feature when considering intersect.
|
|
322
|
-
for (const [row, { stops }] of this.codonLayout) {
|
|
323
|
-
if (
|
|
324
|
-
(row < 3 && feature.strand === 1) ||
|
|
325
|
-
(row >= 3 && feature.strand === -1)
|
|
326
|
-
) {
|
|
327
|
-
const filteredArray = stops.filter(
|
|
328
|
-
(value) => value >= min && value <= max,
|
|
329
|
-
)
|
|
330
|
-
if (filteredArray.length === 0) {
|
|
331
|
-
startingRow = row
|
|
332
|
-
const layoutRow = featureLayout.get(startingRow)
|
|
333
|
-
layoutRow?.push([childFeature.featureId, cds])
|
|
334
|
-
break
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
return featureLayout
|
|
346
|
-
},
|
|
347
|
-
getAssemblyId(assemblyName: string) {
|
|
348
|
-
const { assemblyManager } = getSession(self)
|
|
349
|
-
const assembly = assemblyManager.get(assemblyName)
|
|
350
|
-
if (!assembly) {
|
|
351
|
-
throw new Error(`Could not find assembly named ${assemblyName}`)
|
|
352
|
-
}
|
|
353
|
-
return assembly.name
|
|
354
|
-
},
|
|
355
|
-
get selectedFeature(): AnnotationFeature | undefined {
|
|
356
|
-
const session = getSession(self) as ApolloSession
|
|
357
|
-
return session.apolloSelectedFeature
|
|
358
|
-
},
|
|
359
|
-
get setSelectedFeature() {
|
|
360
|
-
const session = getSession(self) as ApolloSession
|
|
361
|
-
return session.apolloSetSelectedFeature
|
|
362
|
-
},
|
|
363
|
-
}))
|
|
364
|
-
.actions((self) => ({
|
|
365
|
-
setSelectedFeature(feature?: AnnotationFeature) {
|
|
366
|
-
const session = getSession(self) as ApolloSession
|
|
367
|
-
session.apolloSetSelectedFeature(feature)
|
|
368
|
-
},
|
|
369
|
-
setApolloFeatureUnderMouse(feature?: AnnotationFeature) {
|
|
370
|
-
self.apolloFeatureUnderMouse = feature
|
|
371
|
-
},
|
|
372
|
-
setApolloRowUnderMouse(row?: number) {
|
|
373
|
-
self.apolloRowUnderMouse = row
|
|
374
|
-
},
|
|
375
|
-
toggleShowStartCodons() {
|
|
376
|
-
self.showStartCodons = !self.showStartCodons
|
|
377
|
-
},
|
|
378
|
-
toggleShowStopCodons() {
|
|
379
|
-
self.showStopCodons = !self.showStopCodons
|
|
380
|
-
},
|
|
381
|
-
toggleShowIntronLines() {
|
|
382
|
-
self.showIntronLines = !self.showIntronLines
|
|
383
|
-
},
|
|
384
|
-
}))
|
|
385
|
-
.views((self) => ({
|
|
386
|
-
get highestRow() {
|
|
387
|
-
if (self.featureLayout.size === 0) {
|
|
388
|
-
return 0
|
|
389
|
-
}
|
|
390
|
-
return Math.max(...self.featureLayout.keys())
|
|
391
|
-
},
|
|
392
|
-
get featuresHeight() {
|
|
393
|
-
return (this.highestRow + 1) * self.apolloRowHeight
|
|
394
|
-
},
|
|
395
|
-
get detailsHeight() {
|
|
396
|
-
return Math.max(
|
|
397
|
-
self.detailsMinHeight,
|
|
398
|
-
self.height - this.featuresHeight,
|
|
399
|
-
)
|
|
400
|
-
},
|
|
401
|
-
trackMenuItems() {
|
|
402
|
-
return [
|
|
403
|
-
{
|
|
404
|
-
label: 'Show start codons',
|
|
405
|
-
type: 'checkbox',
|
|
406
|
-
checked: self.showStartCodons,
|
|
407
|
-
onClick: () => {
|
|
408
|
-
self.toggleShowStartCodons()
|
|
409
|
-
},
|
|
410
|
-
},
|
|
411
|
-
{
|
|
412
|
-
label: 'Show stop codons',
|
|
413
|
-
type: 'checkbox',
|
|
414
|
-
checked: self.showStopCodons,
|
|
415
|
-
onClick: () => {
|
|
416
|
-
self.toggleShowStopCodons()
|
|
417
|
-
},
|
|
418
|
-
},
|
|
419
|
-
{
|
|
420
|
-
label: 'Show intron lines',
|
|
421
|
-
type: 'checkbox',
|
|
422
|
-
checked: self.showIntronLines,
|
|
423
|
-
onClick: () => {
|
|
424
|
-
self.toggleShowIntronLines()
|
|
425
|
-
},
|
|
426
|
-
},
|
|
427
|
-
]
|
|
428
|
-
},
|
|
429
|
-
}))
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
export type SixFrameFeatureDisplayStateModel = ReturnType<
|
|
433
|
-
typeof stateModelFactory
|
|
434
|
-
>
|
|
435
|
-
// eslint disable because of
|
|
436
|
-
// https://mobx-state-tree.js.org/tips/typescript#using-a-mst-type-at-design-time
|
|
437
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
438
|
-
export interface SixFrameFeatureDisplay
|
|
439
|
-
extends Instance<SixFrameFeatureDisplayStateModel> {}
|