Skip to content

Commit

Permalink
Wow
Browse files Browse the repository at this point in the history
  • Loading branch information
cmdcolin committed Aug 22, 2024
1 parent eb2f164 commit 613ebaf
Show file tree
Hide file tree
Showing 17 changed files with 221 additions and 99 deletions.
1 change: 1 addition & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export default tseslint.config(

'unicorn/no-null': 'off',
'unicorn/prefer-spread': 'off',
'unicorn/no-nested-ternary': 'off',
'unicorn/no-useless-undefined': 'off',
'unicorn/catch-error-name': 'off',
'unicorn/filename-case': 'off',
Expand Down
2 changes: 1 addition & 1 deletion src/AddHighlightModel/GenomeMouseoverHighlight.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const HoverHighlight = observer(function ({
start={coord - 1}
end={coord}
refName={refName}
assemblyName={assemblyNames[0]}
assemblyName={assemblyNames[0]!}
/>
)
}
Expand Down
24 changes: 13 additions & 11 deletions src/AddHighlightModel/ProteinToGenomeClickHighlight.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,25 @@ const ProteinToGenomeClickHighlight = observer(function ({
}) {
const { assemblyManager, views } = getSession(model)
const { assemblyNames } = model
const p = views.find(f => f.type === 'ProteinView') as
const proteinView = views.find(f => f.type === 'ProteinView') as
| JBrowsePluginProteinViewModel
| undefined
const assemblyName = assemblyNames[0]!
const assembly = assemblyManager.get(assemblyName)
return assembly ? (
<>
{p?.clickGenomeHighlights.map((r, idx) => (
<Highlight
key={`${JSON.stringify(r)}-${idx}}`}
start={r.start}
end={r.end}
refName={r.refName}
assemblyName={assemblyName}
model={model}
/>
))}
{proteinView?.structures.map(structure =>
structure.clickGenomeHighlights.map((r, idx) => (
<Highlight
key={`${JSON.stringify(r)}-${idx}}`}
start={r.start}
end={r.end}
refName={r.refName}
assemblyName={assemblyName}
model={model}
/>
)),
)}
</>
) : null
})
Expand Down
28 changes: 14 additions & 14 deletions src/AddHighlightModel/ProteinToGenomeHoverHighlight.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,32 @@ import { getSession } from '@jbrowse/core/util'
import { JBrowsePluginProteinViewModel } from '../ProteinView/model'
import Highlight from './Highlight'

type LGV = LinearGenomeViewModel

const ProteinToGenomeHoverHighlight = observer(function ({
model,
}: {
model: LGV
model: LinearGenomeViewModel
}) {
const { assemblyManager, views } = getSession(model)
const { assemblyNames } = model
const p = views.find(f => f.type === 'ProteinView') as
const proteinView = views.find(f => f.type === 'ProteinView') as
| JBrowsePluginProteinViewModel
| undefined
const assemblyName = assemblyNames[0]!
const assembly = assemblyManager.get(assemblyName)
return assembly ? (
<>
{p?.hoverGenomeHighlights.map((r, idx) => (
<Highlight
key={`${JSON.stringify(r)}-${idx}`}
start={r.start}
end={r.end}
refName={r.refName}
assemblyName={assemblyName}
model={model}
/>
))}
{proteinView?.structures.map(structure =>
structure.hoverGenomeHighlights.map((r, idx) => (
<Highlight
key={`${JSON.stringify(r)}-${idx}`}
start={r.start}
end={r.end}
refName={r.refName}
assemblyName={assemblyName}
model={model}
/>
)),
)}
</>
) : null
})
Expand Down
20 changes: 13 additions & 7 deletions src/LaunchProteinView/components/AlphaFoldDBSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,14 @@ const AlphaFoldDBSearch = observer(function ({
? `https://alphafold.ebi.ac.uk/files/AF-${uniprotId}-F1-model_v4.cif`
: undefined
const {
seq: structureSequence,
sequences: structureSequences,
isLoading: isRemoteStructureSequenceLoading,
error: remoteStructureSequenceError,
} = useRemoteStructureFileSequence({ url })
const e =
myGeneError || isoformProteinSequencesError || remoteStructureSequenceError

const structureSequence = structureSequences?.[0]!
useEffect(() => {
if (isoformSequences !== undefined) {
const ret =
Expand Down Expand Up @@ -116,7 +117,7 @@ const AlphaFoldDBSearch = observer(function ({
variant="h6"
message="Looking up UniProt ID from mygene.info"
/>
) : (uniprotId ? null : (
) : uniprotId ? null : (
<div>
UniProt ID not found. Search sequence on AlphaFoldDB{' '}
<a
Expand All @@ -130,7 +131,7 @@ const AlphaFoldDBSearch = observer(function ({
After visiting the above link, then paste the structure URL into the
Manual tab
</div>
))}
)}
{isIsoformProteinSequencesLoading ? (
<LoadingEllipses
variant="h6"
Expand Down Expand Up @@ -175,10 +176,15 @@ const AlphaFoldDBSearch = observer(function ({
onClick={() => {
session.addView('ProteinView', {
type: 'ProteinView',
url,
seq2: userSelectedProteinSequence?.seq,
feature: selectedTranscript?.toJSON(),
connectedViewId: view.id,
structures: [
{
url,
userProvidedTranscriptSequence:
userSelectedProteinSequence?.seq,
feature: selectedTranscript?.toJSON(),
connectedViewId: view.id,
},
],
displayName: `Protein view ${getGeneDisplayName(feature)} - ${getTranscriptDisplayName(selectedTranscript)}`,
})
handleClose()
Expand Down
12 changes: 6 additions & 6 deletions src/LaunchProteinView/components/TranscriptSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,32 +41,32 @@ export default function TranscriptSelector({
.filter(f => !!isoformSequences[f.id()])
.filter(
f =>
isoformSequences[f.id()].seq.replaceAll('*', '') ===
isoformSequences[f.id()]!.seq.replaceAll('*', '') ===
structureSequence,
)
.map(f => (
<MenuItem value={f.id()} key={f.id()}>
{getGeneDisplayName(feature)} - {getTranscriptDisplayName(f)} (
{isoformSequences[f.id()].seq.length}aa) (matches structure
{isoformSequences[f.id()]!.seq.length}aa) (matches structure
residues)
</MenuItem>
))}
{isoforms
.filter(f => !!isoformSequences[f.id()])
.filter(
f =>
isoformSequences[f.id()].seq.replaceAll('*', '') !==
isoformSequences[f.id()]!.seq.replaceAll('*', '') !==
structureSequence,
)
.sort(
(a, b) =>
isoformSequences[b.id()].seq.length -
isoformSequences[a.id()].seq.length,
isoformSequences[b.id()]!.seq.length -
isoformSequences[a.id()]!.seq.length,
)
.map(f => (
<MenuItem value={f.id()} key={f.id()}>
{getGeneDisplayName(feature)} - {getTranscriptDisplayName(f)} (
{isoformSequences[f.id()].seq.length}aa)
{isoformSequences[f.id()]!.seq.length}aa)
</MenuItem>
))}
{isoforms
Expand Down
7 changes: 4 additions & 3 deletions src/LaunchProteinView/components/UserProvidedStructure.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,15 @@ const UserProvidedStructure = observer(function ({
view,
})
const protein = isoformSequences?.[userSelection ?? '']
const { seq: structureSequence1, error: error3 } =
const { sequences: structureSequences1, error: error3 } =
useLocalStructureFileSequence({ file })

const { seq: structureSequence2, error: error4 } =
const { sequences: structureSequences2, error: error4 } =
useRemoteStructureFileSequence({ url: structureURL })
const structureName =
file?.name ?? structureURL.slice(structureURL.lastIndexOf('/') + 1)
const structureSequence = structureSequence1 ?? structureSequence2
const structureSequences = structureSequences1 ?? structureSequences2
const structureSequence = structureSequences?.[0]

useEffect(() => {
if (isoformSequences !== undefined) {
Expand Down
8 changes: 5 additions & 3 deletions src/LaunchProteinView/components/calculateProteinSequence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function getItemId(feat: Feat) {
// filters if successive elements share same start/end
export function dedupe(list: Feat[]) {
return list.filter(
(item, pos, ary) => !pos || getItemId(item) !== getItemId(ary[pos - 1]),
(item, pos, ary) => !pos || getItemId(item) !== getItemId(ary[pos - 1]!),
)
}

Expand Down Expand Up @@ -102,8 +102,10 @@ export async function fetchProteinSeq({
const refName = feature.get('refName')
const session = getSession(view)
const { assemblyManager, rpcManager } = session
const [assemblyName] = view?.assemblyNames ?? []
const assembly = await assemblyManager.waitForAssembly(assemblyName)
const assemblyName = view?.assemblyNames?.[0]
const assembly = assemblyName
? await assemblyManager.waitForAssembly(assemblyName)
: undefined
if (!assembly) {
throw new Error('assembly not found')
}
Expand Down
37 changes: 28 additions & 9 deletions src/LaunchProteinView/components/useLocalStructureFileSequence.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect, useState } from 'react'
import { createPluginUI } from 'molstar/lib/mol-plugin-ui'
import { renderReact18 } from 'molstar/lib/mol-plugin-ui/react18'
import { loadStructureFromData } from '../../ProteinView/loadStructureFromData'
import { addStructureFromData } from '../../ProteinView/addStructureFromData'

async function structureFileSequenceFetcher(
file: File,
Expand All @@ -12,11 +12,26 @@ async function structureFileSequenceFetcher(
target: ret,
render: renderReact18,
})
const data = await file.text()
const { seq } = await loadStructureFromData({ data, plugin: p, format })
p.unmount()
ret.remove()
return seq

try {
const { model } = await addStructureFromData({
data: await file.text(),
plugin: p,
format,
})
return model.obj?.data.sequence.sequences.map(s => {
let seq = ''
const arr = s.sequence.label.toArray()
// eslint-disable-next-line unicorn/no-for-loop,@typescript-eslint/prefer-for-of
for (let i = 0; i < arr.length; i++) {
seq += arr[i]!
}
return seq
})
} finally {
p.unmount()
ret.remove()
}
}

export default function useLocalStructureFileSequence({
Expand All @@ -26,7 +41,7 @@ export default function useLocalStructureFileSequence({
}) {
const [error, setError] = useState<unknown>()
const [isLoading, setLoading] = useState(false)
const [seq, setSeq] = useState<string>()
const [sequences, setSequences] = useState<string[]>()
useEffect(() => {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
;(async () => {
Expand All @@ -39,7 +54,11 @@ export default function useLocalStructureFileSequence({
file,
(ext === 'cif' ? 'mmcif' : ext) as 'pdb' | 'mmcif',
)
setSeq(seq)
if (seq) {
setSequences(seq)
} else {
throw new Error('no sequences detected in file')
}
}
} catch (e) {
console.error(e)
Expand All @@ -49,5 +68,5 @@ export default function useLocalStructureFileSequence({
}
})()
}, [file])
return { error, isLoading, seq }
return { error, isLoading, sequences }
}
31 changes: 23 additions & 8 deletions src/LaunchProteinView/components/useRemoteStructureFileSequence.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
import { useEffect, useState } from 'react'
import { createPluginUI } from 'molstar/lib/mol-plugin-ui'
import { renderReact18 } from 'molstar/lib/mol-plugin-ui/react18'
import { loadStructureFromURL } from '../../ProteinView/loadStructureFromURL'
import { addStructureFromURL } from '../../ProteinView/addStructureFromURL'

async function structureFileSequenceFetcher(url: string) {
const ret = document.createElement('div')
const p = await createPluginUI({
target: ret,
render: renderReact18,
})
const { seq } = await loadStructureFromURL({ url, plugin: p })
p.unmount()
ret.remove()
return seq
try {
const { model } = await addStructureFromURL({ url, plugin: p })
return model.obj?.data.sequence.sequences.map(s => {
let seq = ''
const arr = s.sequence.label.toArray()
// eslint-disable-next-line unicorn/no-for-loop,@typescript-eslint/prefer-for-of
for (let i = 0; i < arr.length; i++) {
seq += arr[i]!
}
return seq
})
} finally {
p.unmount()
ret.remove()
}
}

export default function useRemoteStructureFileSequence({
Expand All @@ -22,15 +33,19 @@ export default function useRemoteStructureFileSequence({
}) {
const [error, setError] = useState<unknown>()
const [isLoading, setLoading] = useState(false)
const [seq, setSeq] = useState<string>()
const [sequences, setSequences] = useState<string[]>()
useEffect(() => {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
;(async () => {
try {
if (url) {
setLoading(true)
const seq = await structureFileSequenceFetcher(url)
setSeq(seq)
if (seq) {
setSequences(seq)
} else {
throw new Error('no sequences detected in file')
}
}
} catch (e) {
console.error(e)
Expand All @@ -40,5 +55,5 @@ export default function useRemoteStructureFileSequence({
}
})()
}, [url])
return { error, isLoading, seq }
return { error, isLoading, sequences }
}
Loading

0 comments on commit 613ebaf

Please sign in to comment.