diff --git a/src/ProteinView/loadStructureFromData.ts b/src/ProteinView/addStructureFromData.ts
similarity index 94%
rename from src/ProteinView/loadStructureFromData.ts
rename to src/ProteinView/addStructureFromData.ts
index 0c469e1..d767ae4 100644
--- a/src/ProteinView/loadStructureFromData.ts
+++ b/src/ProteinView/addStructureFromData.ts
@@ -7,7 +7,7 @@ export interface LoadStructureOptions {
}
// adapted from https://github.com/molstar/molstar/blob/ab4130d42d0ab2591f62460292ade0203207d4d2/src/apps/viewer/app.ts#L255C1-L259C6
-export async function loadStructureFromData({
+export async function addStructureFromData({
data,
format = 'pdb',
options,
@@ -18,8 +18,6 @@ export async function loadStructureFromData({
options?: LoadStructureOptions & { label?: string; dataLabel?: string }
plugin: PluginContext
}) {
- await plugin.clear()
-
const _data = await plugin.builders.data.rawData({
data,
label: options?.dataLabel,
diff --git a/src/ProteinView/loadStructureFromURL.ts b/src/ProteinView/addStructureFromURL.ts
similarity index 89%
rename from src/ProteinView/loadStructureFromURL.ts
rename to src/ProteinView/addStructureFromURL.ts
index 70743e8..293ca87 100644
--- a/src/ProteinView/loadStructureFromURL.ts
+++ b/src/ProteinView/addStructureFromURL.ts
@@ -7,7 +7,7 @@ export interface LoadStructureOptions {
}
// adapted from https://github.com/molstar/molstar/blob/ab4130d42d0ab2591f62460292ade0203207d4d2/src/apps/viewer/app.ts#L230
-export async function loadStructureFromURL({
+export async function addStructureFromURL({
url,
format = 'mmcif',
isBinary,
@@ -20,11 +20,16 @@ export async function loadStructureFromURL({
options?: LoadStructureOptions & { label?: string }
plugin: PluginContext
}) {
- await plugin.clear()
-
const data = await plugin.builders.data.download(
- { url, isBinary },
- { state: { isGhost: true } },
+ {
+ url,
+ isBinary,
+ },
+ {
+ state: {
+ isGhost: true,
+ },
+ },
)
const trajectory = await plugin.builders.structure.parseTrajectory(
diff --git a/src/ProteinView/components/ProteinAlignment.tsx b/src/ProteinView/components/ProteinAlignment.tsx
index 2def2fc..5ae5ade 100644
--- a/src/ProteinView/components/ProteinAlignment.tsx
+++ b/src/ProteinView/components/ProteinAlignment.tsx
@@ -3,7 +3,7 @@ import { observer } from 'mobx-react'
import { Tooltip, Typography } from '@mui/material'
// locals
-import { JBrowsePluginProteinViewModel } from '../model'
+import { JBrowsePluginProteinStructureModel } from '../model'
import ProteinAlignmentHelpButton from './ProteinAlignmentHelpButton'
import {
clickProteinToGenome,
@@ -14,7 +14,7 @@ import SplitString from './SplitString'
const ProteinAlignment = observer(function ({
model,
}: {
- model: JBrowsePluginProteinViewModel
+ model: JBrowsePluginProteinStructureModel
}) {
const {
structureSeqHoverPos,
@@ -26,8 +26,8 @@ const ProteinAlignment = observer(function ({
if (!alignment) {
return
No alignment
}
- const a0 = alignment.alns[0]!.seq as string
- const a1 = alignment.alns[1]!.seq as string
+ const a0 = alignment.alns[0].seq
+ const a1 = alignment.alns[1].seq
const con = alignment.consensus
const set = new Set()
// eslint-disable-next-line unicorn/no-for-loop
diff --git a/src/ProteinView/components/ProteinView.tsx b/src/ProteinView/components/ProteinView.tsx
index e297e76..c5a1ee4 100644
--- a/src/ProteinView/components/ProteinView.tsx
+++ b/src/ProteinView/components/ProteinView.tsx
@@ -29,88 +29,75 @@ const ProteinView = observer(function ({
}: {
model: JBrowsePluginProteinViewModel
}) {
- const { url, data, showControls } = model
- const { plugin, seq, parentRef, error } = useProteinView({
- url,
- data,
+ const { showControls } = model
+ const { plugin, parentRef, error } = useProteinView({
showControls,
})
return error ? (
) : (
-
+
)
})
const ProteinViewContainer = observer(function ({
model,
plugin,
- seq,
parentRef,
}: {
model: JBrowsePluginProteinViewModel
plugin?: PluginContext
- seq?: string
parentRef?: React.RefObject
}) {
const {
width,
height,
- structureSeqToTranscriptSeqPosition,
- seq2,
- structureSeqHoverPos,
showHighlight,
- alignment,
+ // structureSeqToTranscriptSeqPosition,
+ // structureSeqHoverPos,
+ // alignment,
} = model
- const { error } = useProteinViewClickBehavior({ plugin, model })
- useProteinViewHoverBehavior({ plugin, model })
+ // const { error } = useProteinViewClickBehavior({ plugin, model })
+ // useProteinViewHoverBehavior({ plugin, model })
- const structure =
- plugin?.managers.structure.hierarchy.current.structures[0]?.cell.obj?.data
-
- useEffect(() => {
- model.setSeqs(seq, seq2)
- }, [seq, model, seq2])
-
- useEffect(() => {
- if (!plugin || !structureSeqToTranscriptSeqPosition || !structure) {
- return
- }
- if (showHighlight) {
- for (const coord of Object.keys(structureSeqToTranscriptSeqPosition)) {
- selectResidue({
- structure,
- plugin,
- selectedResidue: +coord + 1,
- })
- }
- } else {
- clearSelection({ plugin })
- }
- }, [plugin, structure, showHighlight, structureSeqToTranscriptSeqPosition])
-
- useEffect(() => {
- if (!plugin || !structure) {
- return
- }
-
- if (structureSeqHoverPos === undefined) {
- console.warn('not found')
- } else {
- highlightResidue({
- structure,
- plugin,
- selectedResidue: structureSeqHoverPos,
- })
- }
- }, [plugin, structure, structureSeqHoverPos])
+ // const structure =
+ // plugin?.managers.structure.hierarchy.current.structures[0]?.cell.obj?.data
+ // useEffect(() => {
+ // if (!plugin || !structureSeqToTranscriptSeqPosition || !structure) {
+ // return
+ // }
+ // if (showHighlight) {
+ // for (const coord of Object.keys(structureSeqToTranscriptSeqPosition)) {
+ // selectResidue({
+ // structure,
+ // plugin,
+ // selectedResidue: +coord + 1,
+ // })
+ // }
+ // } else {
+ // clearSelection({ plugin })
+ // }
+ // }, [plugin, structure, showHighlight, structureSeqToTranscriptSeqPosition])
+ //
+ // useEffect(() => {
+ // if (!plugin || !structure) {
+ // return
+ // }
+ //
+ // if (structureSeqHoverPos === undefined) {
+ // console.warn('not found')
+ // } else {
+ // highlightResidue({
+ // structure,
+ // plugin,
+ // selectedResidue: structureSeqHoverPos,
+ // })
+ // }
+ // }, [plugin, structure, structureSeqHoverPos])
+ const error = undefined
+ const alignment = undefined
return (
{error ?
: null}
diff --git a/src/ProteinView/genomeToProtein.ts b/src/ProteinView/genomeToProtein.ts
index 6bfb396..c6eb05f 100644
--- a/src/ProteinView/genomeToProtein.ts
+++ b/src/ProteinView/genomeToProtein.ts
@@ -1,21 +1,17 @@
import { getSession } from '@jbrowse/core/util'
import { checkHovered } from './util'
-import { JBrowsePluginProteinViewModel } from './model'
+import { JBrowsePluginProteinStructureModel } from './model'
export function genomeToProtein({
model,
}: {
- model: JBrowsePluginProteinViewModel
+ model: JBrowsePluginProteinStructureModel
}): number | undefined {
const { hovered } = getSession(model)
const { genomeToTranscriptSeqMapping, connectedView } = model
- if (
- !connectedView?.initialized ||
+ return !connectedView?.initialized ||
!genomeToTranscriptSeqMapping ||
!checkHovered(hovered)
- ) {
- return undefined
- }
-
- return genomeToTranscriptSeqMapping.g2p[hovered.hoverPosition.coord]
+ ? undefined
+ : genomeToTranscriptSeqMapping.g2p[hovered.hoverPosition.coord]
}
diff --git a/src/ProteinView/model.ts b/src/ProteinView/model.ts
index fba3a03..1dac78a 100644
--- a/src/ProteinView/model.ts
+++ b/src/ProteinView/model.ts
@@ -2,13 +2,12 @@ import { autorun } from 'mobx'
import { BaseViewModel } from '@jbrowse/core/pluggableElementTypes'
import { ElementId } from '@jbrowse/core/util/types/mst'
import { Region as IRegion } from '@jbrowse/core/util/types'
-import { Instance, addDisposer, types } from 'mobx-state-tree'
+import { Instance, addDisposer, getParent, types } from 'mobx-state-tree'
import {
SimpleFeature,
SimpleFeatureSerialized,
getSession,
} from '@jbrowse/core/util'
-import { parsePairwise } from 'clustal-js'
import { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
// locals
@@ -19,12 +18,12 @@ import {
genomeToTranscriptSeqMapping,
structurePositionToAlignmentMap,
transcriptPositionToAlignmentMap,
+ PairwiseAlignment,
} from '../mappings'
import { PluginContext } from 'molstar/lib/mol-plugin/context'
type LGV = LinearGenomeViewModel
type MaybeLGV = LGV | undefined
-type PairwiseAlignment = ReturnType
type MaybePairwiseAlignment = PairwiseAlignment | undefined
type StructureModel = Awaited<
ReturnType
@@ -40,9 +39,61 @@ const Structure = types
* #property
*/
data: types.maybe(types.string),
+ /**
+ * #property
+ */
+ connectedViewId: types.maybe(types.string),
+ /**
+ * #property
+ */
+ alignment: types.frozen(),
+ /**
+ * #property
+ */
+ feature: types.frozen(),
+ /**
+ * #property
+ */
+ userProvidedTranscriptSequence: types.string,
})
.volatile(() => ({
+ /**
+ * #volatile
+ */
model: undefined as StructureModel | undefined,
+ /**
+ * #volatile
+ */
+ clickGenomeHighlights: [] as IRegion[],
+ /**
+ * #volatile
+ */
+ hoverGenomeHighlights: [] as IRegion[],
+
+ /**
+ * #volatile
+ */
+ clickPosition: undefined as
+ | {
+ structureSeqPos: number
+ code: string
+ chain: string
+ }
+ | undefined,
+ /**
+ * #volatile
+ */
+ hoverPosition: undefined as
+ | {
+ structureSeqPos: number
+ code?: string
+ chain?: string
+ }
+ | undefined,
+ /**
+ * #volatile
+ */
+ alignmentStatus: '',
}))
.actions(self => ({
/**
@@ -53,6 +104,9 @@ const Structure = types
},
}))
.views(self => ({
+ /**
+ * #getter
+ */
get structureSequences() {
return self.model?.obj?.data.sequence.sequences.map(s => {
let seq = ''
@@ -64,7 +118,256 @@ const Structure = types
return seq
})
},
+ /**
+ * #getter
+ */
+ get connectedView() {
+ const { views } = getSession(self)
+ return views.find(f => f.id === self.connectedViewId) as MaybeLGV
+ },
+ }))
+ .actions(self => ({
+ /**
+ * #action
+ */
+ setClickedPosition(arg?: {
+ structureSeqPos: number
+ code: string
+ chain: string
+ }) {
+ self.clickPosition = arg
+ },
+ /**
+ * #action
+ */
+ setClickGenomeHighlights(r: IRegion[]) {
+ self.clickGenomeHighlights = r
+ },
+ /**
+ * #action
+ */
+ clearClickGenomeHighlights() {
+ self.clickGenomeHighlights = []
+ },
+ /**
+ * #action
+ */
+ setHoverGenomeHighlights(r: IRegion[]) {
+ self.hoverGenomeHighlights = r
+ },
+ /**
+ * #action
+ */
+ clearHoverGenomeHighlights() {
+ self.hoverGenomeHighlights = []
+ },
+ /**
+ * #action
+ */
+ setHoveredPosition(arg?: {
+ structureSeqPos: number
+ chain?: string
+ code?: string
+ }) {
+ self.hoverPosition = arg
+ },
+ /**
+ * #action
+ */
+ setAlignment(r?: PairwiseAlignment) {
+ self.alignment = r
+ },
+ /**
+ * #action
+ */
+ setAlignmentStatus(str: string) {
+ self.alignmentStatus = str
+ },
+ }))
+ .views(self => ({
+ /**
+ * #getter
+ */
+ get structureSeqToTranscriptSeqPosition() {
+ return self.alignment
+ ? structureSeqVsTranscriptSeqMap(self.alignment)
+ .structureSeqToTranscriptSeqPosition
+ : undefined
+ },
+ /**
+ * #getter
+ */
+ get transcriptSeqToStructureSeqPosition() {
+ return self.alignment
+ ? structureSeqVsTranscriptSeqMap(self.alignment)
+ .transcriptSeqToStructureSeqPosition
+ : undefined
+ },
+ /**
+ * #getter
+ */
+ get structurePositionToAlignmentMap() {
+ return self.alignment
+ ? structurePositionToAlignmentMap(self.alignment)
+ : undefined
+ },
+ /**
+ * #getter
+ */
+ get transcriptPositionToAlignmentMap() {
+ return self.alignment
+ ? transcriptPositionToAlignmentMap(self.alignment)
+ : undefined
+ },
+ /**
+ * #getter
+ */
+ get alignmentToTranscriptPosition() {
+ return this.transcriptPositionToAlignmentMap
+ ? invertMap(this.transcriptPositionToAlignmentMap)
+ : undefined
+ },
+ /**
+ * #getter
+ */
+ get alignmentToStructurePosition() {
+ return this.structurePositionToAlignmentMap
+ ? invertMap(this.structurePositionToAlignmentMap)
+ : undefined
+ },
+ /**
+ * #getter
+ */
+ get clickString() {
+ const r = self.clickPosition
+ return r ? toStr(r) : ''
+ },
+ /**
+ * #getter
+ */
+ get hoverString() {
+ const r = self.hoverPosition
+ return r ? toStr(r) : ''
+ },
+ /**
+ * #getter
+ */
+ get genomeToTranscriptSeqMapping() {
+ return self.feature
+ ? genomeToTranscriptSeqMapping(new SimpleFeature(self.feature))
+ : undefined
+ },
+ /**
+ * #getter
+ */
+ get structureSeqHoverPos(): number | undefined {
+ return self.hoverPosition?.structureSeqPos
+ },
+
+ /**
+ * #getter
+ */
+ get exactMatch() {
+ const r1 = self.userProvidedTranscriptSequence.replaceAll('*', '')
+ const r2 = self.structureSequences?.[0]?.replaceAll('*', '')
+ return r1 === r2
+ },
+ get zoomToBaseLevel(): boolean {
+ // @ts-expect-error
+ return getParent(self, 2).zoomToBaseLevel
+ },
+ get showHighlight(): boolean {
+ // @ts-expect-error
+ return getParent(self, 2).showHighlight
+ },
}))
+ .actions(self => ({
+ afterAttach() {
+ // pairwise align transcript sequence to structure residues
+ addDisposer(
+ self,
+ autorun(async () => {
+ try {
+ const {
+ userProvidedTranscriptSequence,
+ structureSequences,
+ exactMatch,
+ } = self
+ const seq1 = userProvidedTranscriptSequence
+ const seq2 = structureSequences?.[0]
+ if (!!self.alignment || !seq1 || !seq2) {
+ return
+ }
+ const r1 = seq1.replaceAll('*', '')
+ const r2 = seq2.replaceAll('*', '')
+ if (exactMatch) {
+ let consensus = ''
+ // eslint-disable-next-line @typescript-eslint/prefer-for-of
+ for (let i = 0; i < r1.length; i++) {
+ consensus += '|'
+ }
+ self.setAlignment({
+ consensus,
+ alns: [
+ { id: 'seq1', seq: r1 },
+ { id: 'seq2', seq: r2 },
+ ],
+ })
+ } else {
+ const alignment = await launchPairwiseAlignment({
+ seq1: r1,
+ seq2: r2,
+ algorithm: 'emboss_needle',
+ onProgress: arg => {
+ self.setAlignmentStatus(arg)
+ },
+ })
+ self.setAlignment(alignment.alignment)
+
+ // showHighlight when we are
+ getParent(self, 2).setShowHighlight(true)
+ getParent(self, 2).setShowAlignment(true)
+ }
+ } catch (e) {
+ console.error(e)
+ getParent(self, 2).setError(e)
+ }
+ }),
+ )
+
+ // convert hover over the genome to structure position
+ addDisposer(
+ self,
+ autorun(() => {
+ const { hovered } = getSession(self)
+ const {
+ transcriptSeqToStructureSeqPosition,
+ genomeToTranscriptSeqMapping,
+ connectedView,
+ } = self
+ if (
+ !connectedView?.initialized ||
+ !genomeToTranscriptSeqMapping ||
+ !checkHovered(hovered)
+ ) {
+ return undefined
+ }
+
+ const pos =
+ genomeToTranscriptSeqMapping.g2p[hovered.hoverPosition.coord]
+ const c0 = pos
+ ? transcriptSeqToStructureSeqPosition?.[pos]
+ : undefined
+ if (c0 !== undefined) {
+ self.setHoveredPosition({
+ structureSeqPos: c0,
+ })
+ }
+ }),
+ )
+ },
+ }))
+
/**
* #stateModel Protein3dViewPlugin
* extends
@@ -97,27 +400,7 @@ function stateModelFactory() {
* #property
*/
height: types.optional(types.number, 650),
- /**
- * #property
- */
- feature: types.frozen(),
- /**
- * #property
- */
- seq1: types.maybe(types.string),
- /**
- * #property
- */
- seq2: types.maybe(types.string),
- /**
- * #property
- */
- alignment: types.frozen(),
- /**
- * #property
- */
- connectedViewId: types.maybe(types.string),
/**
* #property
*/
@@ -133,52 +416,13 @@ function stateModelFactory() {
}),
)
.volatile(() => ({
- /**
- * #volatile
- */
- clickGenomeHighlights: [] as IRegion[],
- /**
- * #volatile
- */
- hoverGenomeHighlights: [] as IRegion[],
- /**
- * #volatile
- */
- error: undefined as unknown,
- /**
- * #volatile
- */
- clickPosition: undefined as
- | {
- structureSeqPos: number
- code: string
- chain: string
- }
- | undefined,
- /**
- * #volatile
- */
- hoverPosition: undefined as
- | {
- structureSeqPos: number
- code?: string
- chain?: string
- }
- | undefined,
/**
* #volatile
*/
progress: '',
+ error: undefined as unknown,
}))
- .views(self => ({
- /**
- * #getter
- */
- get connectedView() {
- const { views } = getSession(self)
- return views.find(f => f.id === self.connectedViewId) as MaybeLGV
- },
- }))
+
.actions(self => ({
/**
* #action
@@ -186,81 +430,21 @@ function stateModelFactory() {
setShowAlignment(f: boolean) {
self.showAlignment = f
},
- /**
- * #action
- */
- setHoveredPosition(arg?: {
- structureSeqPos: number
- chain?: string
- code?: string
- }) {
- self.hoverPosition = arg
- },
- /**
- * #action
- */
- setSeqs(str1?: string, str2?: string) {
- self.seq1 = str1
- self.seq2 = str2
- },
+
/**
* #action
*/
setShowControls(arg: boolean) {
self.showControls = arg
},
- /**
- * #action
- */
- setProgress(str: string) {
- self.progress = str
- },
- /**
- * #action
- */
- setClickedPosition(arg?: {
- structureSeqPos: number
- code: string
- chain: string
- }) {
- self.clickPosition = arg
- },
- /**
- * #action
- */
- setClickGenomeHighlights(r: IRegion[]) {
- self.clickGenomeHighlights = r
- },
- /**
- * #action
- */
- clearClickGenomeHighlights() {
- self.clickGenomeHighlights = []
- },
- /**
- * #action
- */
- setHoverGenomeHighlights(r: IRegion[]) {
- self.hoverGenomeHighlights = r
- },
- /**
- * #action
- */
- clearHoverGenomeHighlights() {
- self.hoverGenomeHighlights = []
- },
+
/**
* #action
*/
setError(e: unknown) {
self.error = e
},
- /**
- * #action
- */
- setAlignment(r?: PairwiseAlignment) {
- self.alignment = r
- },
+
/**
* #action
*/
@@ -274,172 +458,6 @@ function stateModelFactory() {
self.zoomToBaseLevel = arg
},
}))
- .views(self => ({
- /**
- * #getter
- */
- get structureSeqToTranscriptSeqPosition() {
- return self.alignment
- ? structureSeqVsTranscriptSeqMap(self.alignment)
- .structureSeqToTranscriptSeqPosition
- : undefined
- },
- /**
- * #getter
- */
- get transcriptSeqToStructureSeqPosition() {
- return self.alignment
- ? structureSeqVsTranscriptSeqMap(self.alignment)
- .transcriptSeqToStructureSeqPosition
- : undefined
- },
- /**
- * #getter
- */
- get structurePositionToAlignmentMap() {
- return self.alignment
- ? structurePositionToAlignmentMap(self.alignment)
- : undefined
- },
- /**
- * #getter
- */
- get transcriptPositionToAlignmentMap() {
- return self.alignment
- ? transcriptPositionToAlignmentMap(self.alignment)
- : undefined
- },
- /**
- * #getter
- */
- get alignmentToTranscriptPosition() {
- return this.transcriptPositionToAlignmentMap
- ? invertMap(this.transcriptPositionToAlignmentMap)
- : undefined
- },
- /**
- * #getter
- */
- get alignmentToStructurePosition() {
- return this.structurePositionToAlignmentMap
- ? invertMap(this.structurePositionToAlignmentMap)
- : undefined
- },
- /**
- * #getter
- */
- get clickString() {
- const r = self.clickPosition
- return r ? toStr(r) : ''
- },
- /**
- * #getter
- */
- get hoverString() {
- const r = self.hoverPosition
- return r ? toStr(r) : ''
- },
- /**
- * #getter
- */
- get genomeToTranscriptSeqMapping() {
- return self.feature
- ? genomeToTranscriptSeqMapping(new SimpleFeature(self.feature))
- : undefined
- },
- /**
- * #getter
- */
- get structureSeqHoverPos(): number | undefined {
- return self.hoverPosition?.structureSeqPos
- },
-
- get exactMatch() {
- const r1 = self.seq1?.replaceAll('*', '')
- const r2 = self.seq2?.replaceAll('*', '')
- return r1 === r2
- },
- }))
- .actions(self => ({
- afterAttach() {
- // pairwise align transcript sequence to structure residues
- addDisposer(
- self,
- autorun(async () => {
- try {
- const { seq1, seq2, exactMatch } = self
- if (!!self.alignment || !seq1 || !seq2) {
- return
- }
- const r1 = seq1.replaceAll('*', '')
- const r2 = seq2.replaceAll('*', '')
- if (exactMatch) {
- let consensus = ''
- // eslint-disable-next-line @typescript-eslint/prefer-for-of
- for (let i = 0; i < r1.length; i++) {
- consensus += '|'
- }
- self.setAlignment({
- consensus,
- alns: [
- { id: 'seq1', seq: r1 },
- { id: 'seq2', seq: r2 },
- ],
- })
- } else {
- const alignment = await launchPairwiseAlignment({
- seq1: r1,
- seq2: r2,
- algorithm: 'emboss_needle',
- onProgress: arg => {
- self.setProgress(arg)
- },
- })
- self.setAlignment(alignment.alignment)
-
- // showHighlight when we are
- self.setShowHighlight(true)
- self.setShowAlignment(true)
- }
- } catch (e) {
- console.error(e)
- self.setError(e)
- }
- }),
- )
-
- // convert hover over the genome to structure position
- addDisposer(
- self,
- autorun(() => {
- const { hovered } = getSession(self)
- const {
- transcriptSeqToStructureSeqPosition,
- genomeToTranscriptSeqMapping,
- connectedView,
- } = self
- if (
- !connectedView?.initialized ||
- !genomeToTranscriptSeqMapping ||
- !checkHovered(hovered)
- ) {
- return undefined
- }
-
- const pos =
- genomeToTranscriptSeqMapping.g2p[hovered.hoverPosition.coord]
- const c0 = pos
- ? transcriptSeqToStructureSeqPosition?.[pos]
- : undefined
- if (c0 !== undefined) {
- self.setHoveredPosition({
- structureSeqPos: c0,
- })
- }
- }),
- )
- },
- }))
}
export default stateModelFactory
@@ -449,3 +467,7 @@ export type JBrowsePluginProteinViewStateModel = ReturnType<
>
export type JBrowsePluginProteinViewModel =
Instance
+
+export type JBrowsePluginProteinStructureStateModel = typeof Structure
+export type JBrowsePluginProteinStructureModel =
+ Instance
diff --git a/src/ProteinView/proteinToGenomeMapping.ts b/src/ProteinView/proteinToGenomeMapping.ts
index 6339fe6..76034fd 100644
--- a/src/ProteinView/proteinToGenomeMapping.ts
+++ b/src/ProteinView/proteinToGenomeMapping.ts
@@ -2,14 +2,17 @@ import { getSession } from '@jbrowse/core/util'
import { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
// locals
-import { JBrowsePluginProteinViewModel } from './model'
+import {
+ JBrowsePluginProteinStructureModel,
+ JBrowsePluginProteinViewModel,
+} from './model'
export function proteinToGenomeMapping({
model,
structureSeqPos,
}: {
structureSeqPos: number
- model: JBrowsePluginProteinViewModel
+ model: JBrowsePluginProteinStructureModel
}) {
const {
genomeToTranscriptSeqMapping,
@@ -38,7 +41,7 @@ export async function clickProteinToGenome({
structureSeqPos,
}: {
structureSeqPos: number
- model: JBrowsePluginProteinViewModel
+ model: JBrowsePluginProteinStructureModel
}) {
const session = getSession(model)
const result = proteinToGenomeMapping({ structureSeqPos, model })
@@ -75,7 +78,7 @@ export function hoverProteinToGenome({
structureSeqPos,
}: {
structureSeqPos: number
- model: JBrowsePluginProteinViewModel
+ model: JBrowsePluginProteinStructureModel
}) {
const session = getSession(model)
const result = proteinToGenomeMapping({ structureSeqPos, model })
diff --git a/src/ProteinView/useProteinView.ts b/src/ProteinView/useProteinView.ts
index a134c9e..b3989e8 100644
--- a/src/ProteinView/useProteinView.ts
+++ b/src/ProteinView/useProteinView.ts
@@ -5,23 +5,14 @@ import { createPluginUI } from 'molstar/lib/mol-plugin-ui'
import { renderReact18 } from 'molstar/lib/mol-plugin-ui/react18'
import { DefaultPluginUISpec } from 'molstar/lib/mol-plugin-ui/spec'
-// locals
-import { loadStructureFromURL } from './loadStructureFromURL'
-import { loadStructureFromData } from './loadStructureFromData'
-
export default function useProteinView({
- url,
- data,
showControls,
}: {
- url?: string
- data?: string
showControls: boolean
}) {
const parentRef = useRef(null)
const [plugin, setPlugin] = useState()
const [error, setError] = useState()
- const [seq, setSeq] = useState('')
useEffect(() => {
let p: PluginContext | undefined
@@ -48,14 +39,6 @@ export default function useProteinView({
})
await p.initialized
setPlugin(p)
-
- if (url) {
- const { seq } = await loadStructureFromURL({ url, plugin: p })
- setSeq(seq)
- } else if (data) {
- const { seq } = await loadStructureFromData({ data, plugin: p })
- setSeq(seq)
- }
} catch (e) {
console.error(e)
setError(e)
@@ -64,7 +47,16 @@ export default function useProteinView({
return () => {
p?.unmount()
}
- }, [url, data, showControls])
+ }, [showControls])
- return { parentRef, error, plugin, seq }
+ return { parentRef, error, plugin }
}
+
+//
+// if (url) {
+// const { model } = await addStructureFromURL({ url, plugin: p })
+// setModel(model)
+// } else if (data) {
+// const { model } = await addStructureFromData({ data, plugin: p })
+// setModel(model)
+// }
diff --git a/src/ProteinView/useProteinViewClickBehavior.ts b/src/ProteinView/useProteinViewClickBehavior.ts
index 48d6b86..9c53cae 100644
--- a/src/ProteinView/useProteinViewClickBehavior.ts
+++ b/src/ProteinView/useProteinViewClickBehavior.ts
@@ -3,7 +3,7 @@ import { getSession } from '@jbrowse/core/util'
import { PluginContext } from 'molstar/lib/mol-plugin/context'
// local
-import { JBrowsePluginProteinViewModel } from './model'
+import { JBrowsePluginProteinStructureModel } from './model'
import { clickProteinToGenome } from './proteinToGenomeMapping'
import {
StructureElement,
@@ -15,7 +15,7 @@ export default function useProteinViewClickActionBehavior({
model,
}: {
plugin?: PluginContext
- model: JBrowsePluginProteinViewModel
+ model: JBrowsePluginProteinStructureModel
}) {
const [error, setError] = useState()
const session = getSession(model)
@@ -23,7 +23,7 @@ export default function useProteinViewClickActionBehavior({
if (!plugin) {
return
}
- plugin.behaviors.interaction.click.subscribe(event => {
+ const ret = plugin.behaviors.interaction.click.subscribe(event => {
if (StructureElement.Loci.is(event.current.loci)) {
const loc = StructureElement.Loci.getFirstLocation(event.current.loci)
if (loc) {
@@ -45,6 +45,10 @@ export default function useProteinViewClickActionBehavior({
}
}
})
+ return () => {
+ ret.unsubscribe()
+ }
}, [plugin, session, model])
+
return { error }
}
diff --git a/src/ProteinView/useProteinViewHoverBehavior.ts b/src/ProteinView/useProteinViewHoverBehavior.ts
index 43dc132..8304c8d 100644
--- a/src/ProteinView/useProteinViewHoverBehavior.ts
+++ b/src/ProteinView/useProteinViewHoverBehavior.ts
@@ -3,7 +3,7 @@ import { getSession } from '@jbrowse/core/util'
import { PluginContext } from 'molstar/lib/mol-plugin/context'
// local
-import { JBrowsePluginProteinViewModel } from './model'
+import { JBrowsePluginProteinStructureModel } from './model'
import {
StructureElement,
StructureProperties as Props,
@@ -15,7 +15,7 @@ export default function useProteinViewClickActionBehavior({
model,
}: {
plugin?: PluginContext
- model: JBrowsePluginProteinViewModel
+ model: JBrowsePluginProteinStructureModel
}) {
const session = getSession(model)
useEffect(() => {
diff --git a/src/mappings.test.ts b/src/mappings.test.ts
index 698f37b..c89ac07 100644
--- a/src/mappings.test.ts
+++ b/src/mappings.test.ts
@@ -11,6 +11,7 @@ test('test', () => {
})
test('mapping', () => {
+ // @ts-expect-error
const res = genomeToTranscriptSeqMapping(new SimpleFeature(feature))
const { p2g } = res
const aln = structureSeqVsTranscriptSeqMap(alignment)
diff --git a/src/mappings.ts b/src/mappings.ts
index 24ac624..2905034 100644
--- a/src/mappings.ts
+++ b/src/mappings.ts
@@ -1,14 +1,15 @@
import { Feature } from '@jbrowse/core/util'
import { genomeToTranscriptSeqMapping as g2p } from 'g2p_mapper'
-
-export interface Alignment {
- alns: {
- id: string
- seq: string
- }[]
+export interface AlignmentRow {
+ id: string
+ seq: string
+}
+export interface PairwiseAlignment {
+ consensus: string
+ alns: readonly [AlignmentRow, AlignmentRow]
}
-export function structureSeqVsTranscriptSeqMap(alignment: Alignment) {
+export function structureSeqVsTranscriptSeqMap(alignment: PairwiseAlignment) {
const structureSeq = alignment.alns[0].seq
const transcriptSeq = alignment.alns[1].seq
if (structureSeq.length !== transcriptSeq.length) {
@@ -54,9 +55,9 @@ export function structureSeqVsTranscriptSeqMap(alignment: Alignment) {
}
}
-export function structurePositionToAlignmentMap(alignment: Alignment) {
+export function structurePositionToAlignmentMap(alignment: PairwiseAlignment) {
const structureSeq = alignment.alns[0].seq
- const structurePositionToAlignment = {} as Record
+ const structurePositionToAlignment = {} as Record
for (let i = 0, j = 0; i < structureSeq.length; i++) {
if (structureSeq[i] !== '-') {
@@ -68,9 +69,9 @@ export function structurePositionToAlignmentMap(alignment: Alignment) {
return structurePositionToAlignment
}
-export function transcriptPositionToAlignmentMap(alignment: Alignment) {
+export function transcriptPositionToAlignmentMap(alignment: PairwiseAlignment) {
const transcriptSeq = alignment.alns[1].seq
- const transcriptPositionToAlignment = {} as Record
+ const transcriptPositionToAlignment = {} as Record
for (let i = 0, j = 0; i < transcriptSeq.length; i++) {
if (transcriptSeq[i] !== '-') {
diff --git a/src/test_data/gene.ts b/src/test_data/gene.ts
index a3e3c8f..4d76fe6 100644
--- a/src/test_data/gene.ts
+++ b/src/test_data/gene.ts
@@ -586,7 +586,7 @@ export const feature = {
uniqueId: '590611027-offset-601794870-0',
parentId: '590611027-offset-601794870',
__jbrowsefmt: {},
-}
+} as const
export const alignment = {
consensus:
@@ -601,4 +601,4 @@ export const alignment = {
seq: '--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------MKAAYLSMFGKEDHKPFGDDEVELFRAVPGLKLKIAGKSLPTEKFAIRKSRRYFSSNPISLPVPALEMMYIWNGYAVIGKQPKLTDGILEIITKAEEMLEKGPENEYSVDDECLVKLLKGLCLKYLGRVQEAEENFRSISANEKKIKYDHYLIPNALLELALLLMEQDRNEEAIKLLESAKQNYKNYSMESRTHFRIQAATLQAKSSLENSSRSMVSSVSL*',
},
],
-}
+} as const
diff --git a/yarn.lock b/yarn.lock
index 84c1428..95078cc 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -19,9 +19,9 @@
picocolors "^1.0.0"
"@babel/compat-data@^7.25.2":
- version "7.25.2"
- resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.2.tgz#e41928bd33475305c586f6acbbb7e3ade7a6f7f5"
- integrity sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==
+ version "7.25.4"
+ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.4.tgz#7d2a80ce229890edcf4cc259d4d696cb4dae2fcb"
+ integrity sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==
"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9":
version "7.25.2"
@@ -44,12 +44,12 @@
json5 "^2.2.3"
semver "^6.3.1"
-"@babel/generator@^7.25.0", "@babel/generator@^7.7.2":
- version "7.25.0"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.0.tgz#f858ddfa984350bc3d3b7f125073c9af6988f18e"
- integrity sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==
+"@babel/generator@^7.25.0", "@babel/generator@^7.25.4", "@babel/generator@^7.7.2":
+ version "7.25.4"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.4.tgz#1dc63c1c9caae9e6dc24e264eac254eb25005669"
+ integrity sha512-NFtZmZsyzDPJnk9Zg3BbTfKKc9UlHYzD0E//p2Z3B9nCwwtJW9T0gVbCz8+fBngnn4zf1Dr3IK8PHQQHq0lDQw==
dependencies:
- "@babel/types" "^7.25.0"
+ "@babel/types" "^7.25.4"
"@jridgewell/gen-mapping" "^0.3.5"
"@jridgewell/trace-mapping" "^0.3.25"
jsesc "^2.5.1"
@@ -83,7 +83,7 @@
"@babel/helper-validator-identifier" "^7.24.7"
"@babel/traverse" "^7.25.2"
-"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.24.7", "@babel/helper-plugin-utils@^7.8.0":
+"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.24.7", "@babel/helper-plugin-utils@^7.24.8", "@babel/helper-plugin-utils@^7.8.0":
version "7.24.8"
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz#94ee67e8ec0e5d44ea7baeb51e571bd26af07878"
integrity sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==
@@ -129,12 +129,12 @@
js-tokens "^4.0.0"
picocolors "^1.0.0"
-"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.25.0", "@babel/parser@^7.25.3":
- version "7.25.3"
- resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.3.tgz#91fb126768d944966263f0657ab222a642b82065"
- integrity sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==
+"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.25.0", "@babel/parser@^7.25.4":
+ version "7.25.4"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.4.tgz#af4f2df7d02440286b7de57b1c21acfb2a6f257a"
+ integrity sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA==
dependencies:
- "@babel/types" "^7.25.2"
+ "@babel/types" "^7.25.4"
"@babel/plugin-syntax-async-generators@^7.8.4":
version "7.8.4"
@@ -249,16 +249,16 @@
"@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-syntax-typescript@^7.7.2":
- version "7.24.7"
- resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz#58d458271b4d3b6bb27ee6ac9525acbb259bad1c"
- integrity sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==
+ version "7.25.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.4.tgz#04db9ce5a9043d9c635e75ae7969a2cd50ca97ff"
+ integrity sha512-uMOCoHVU52BsSWxPOMVv5qKRdeSlPuImUCB2dlPuBSU+W2/ROE7/Zg8F2Kepbk+8yBa68LlRKxO+xgEVWorsDg==
dependencies:
- "@babel/helper-plugin-utils" "^7.24.7"
+ "@babel/helper-plugin-utils" "^7.24.8"
"@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.17.9", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.6", "@babel/runtime@^7.23.9", "@babel/runtime@^7.25.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
- version "7.25.0"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.0.tgz#3af9a91c1b739c569d5d80cc917280919c544ecb"
- integrity sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==
+ version "7.25.4"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.4.tgz#6ef37d678428306e7d75f054d5b1bdb8cf8aa8ee"
+ integrity sha512-DSgLeL/FNcpXuzav5wfYvHCGvynXkJbn3Zvc3823AEe9nPwW9IK4UoCSS5yGymmQzN0pCPvivtgS6/8U2kkm1w==
dependencies:
regenerator-runtime "^0.14.0"
@@ -272,22 +272,22 @@
"@babel/types" "^7.25.0"
"@babel/traverse@^7.24.7", "@babel/traverse@^7.25.2":
- version "7.25.3"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.3.tgz#f1b901951c83eda2f3e29450ce92743783373490"
- integrity sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==
+ version "7.25.4"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.4.tgz#648678046990f2957407e3086e97044f13c3e18e"
+ integrity sha512-VJ4XsrD+nOvlXyLzmLzUs/0qjFS4sK30te5yEFlvbbUNEgKaVb2BHZUpAL+ttLPQAHNrsI3zZisbfha5Cvr8vg==
dependencies:
"@babel/code-frame" "^7.24.7"
- "@babel/generator" "^7.25.0"
- "@babel/parser" "^7.25.3"
+ "@babel/generator" "^7.25.4"
+ "@babel/parser" "^7.25.4"
"@babel/template" "^7.25.0"
- "@babel/types" "^7.25.2"
+ "@babel/types" "^7.25.4"
debug "^4.3.1"
globals "^11.1.0"
-"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.24.7", "@babel/types@^7.25.0", "@babel/types@^7.25.2", "@babel/types@^7.3.3":
- version "7.25.2"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.2.tgz#55fb231f7dc958cd69ea141a4c2997e819646125"
- integrity sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==
+"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.24.7", "@babel/types@^7.25.0", "@babel/types@^7.25.2", "@babel/types@^7.25.4", "@babel/types@^7.3.3":
+ version "7.25.4"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.4.tgz#6bcb46c72fdf1012a209d016c07f769e10adcb5f"
+ integrity sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ==
dependencies:
"@babel/helper-string-parser" "^7.24.8"
"@babel/helper-validator-identifier" "^7.24.7"
@@ -2019,9 +2019,9 @@ clsx@^2.1.0, clsx@^2.1.1:
integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==
clustal-js@^2.0.1:
- version "2.0.1"
- resolved "https://registry.yarnpkg.com/clustal-js/-/clustal-js-2.0.1.tgz#485b23334950fc2040067b799dda432b0a6a7273"
- integrity sha512-rdntqVPd4tromWENkOz1P/XACIFLaHPhQ1hwBmEbLFVBn5s6oRLMEvgMf63k0y2gk81ti2vecWwFOlhGLOuFfw==
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/clustal-js/-/clustal-js-2.0.2.tgz#db9b517c5232a3828d6d943e07f38955dc55c31e"
+ integrity sha512-50GM4CUEkvbW1ILF30TgDgaLuim0dg8S3MQfCeVk1VCJLx33IKuQHVrT7CBmhotF0T4cFbS/3LCPnCY0UcOwrg==
co@^4.6.0:
version "4.6.0"