Skip to content

Commit

Permalink
Wow
Browse files Browse the repository at this point in the history
  • Loading branch information
cmdcolin committed Nov 25, 2024
1 parent 9bc8564 commit d8ec45b
Show file tree
Hide file tree
Showing 12 changed files with 123 additions and 187 deletions.
5 changes: 2 additions & 3 deletions packages/core/util/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1342,12 +1342,11 @@ export interface BasicFeature {
end: number
start: number
refName: string
assemblyName?: string
}

// returns new array non-overlapping features
export function gatherOverlaps(regions: BasicFeature[], w = 5000) {
const memo = {} as Record<string, BasicFeature[]>
export function gatherOverlaps<T extends BasicFeature>(regions: T[], w = 5000) {
const memo = {} as Record<string, T[]>
for (const x of regions) {
if (!memo[x.refName]) {
memo[x.refName] = []
Expand Down
18 changes: 3 additions & 15 deletions packages/sv-core/src/BreakendMultiLevelOptionDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import { when } from 'mobx'
import { observer } from 'mobx-react'
import { getSnapshot } from 'mobx-state-tree'

// types
import Checkbox2 from './Checkbox2'
import { getBreakendCoveringRegions } from './util'

import type { Assembly } from '@jbrowse/core/assemblyManager/assembly'
// types
import type { AbstractSessionModel, Feature } from '@jbrowse/core/util'
import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'

Expand Down Expand Up @@ -38,7 +38,6 @@ const BreakendMultiLevelOptionDialog = observer(function ({
feature,
assemblyName,
stableViewId,
viewType,
view,
}: {
session: AbstractSessionModel
Expand All @@ -47,17 +46,6 @@ const BreakendMultiLevelOptionDialog = observer(function ({
view?: LinearGenomeViewModel
assemblyName: string
stableViewId?: string
viewType: {
getBreakendCoveringRegions: (arg: {
feature: Feature
assembly: Assembly
}) => {
pos: number
refName: string
mateRefName: string
matePos: number
}
}
}) {
const [copyTracks, setCopyTracks] = useState(true)
const [mirror, setMirror] = useState(true)
Expand Down Expand Up @@ -107,7 +95,7 @@ const BreakendMultiLevelOptionDialog = observer(function ({
}

const { refName, pos, mateRefName, matePos } =
viewType.getBreakendCoveringRegions({
getBreakendCoveringRegions({
feature,
assembly: assembly,
})
Expand Down
13 changes: 3 additions & 10 deletions packages/sv-core/src/BreakendSingleLevelOptionDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import Checkbox2 from './Checkbox2'
// types
import type { AbstractSessionModel, Feature } from '@jbrowse/core/util'
import type { LinearGenomeViewModel } from '@jbrowse/plugin-linear-genome-view'
import { singleLevelSnapshotFromBreakendFeature } from './util'

interface Display {
id: string
Expand All @@ -36,7 +37,6 @@ const BreakendSingleLevelOptionDialog = observer(function ({
feature,
stableViewId,
assemblyName,
viewType,
view,
}: {
session: AbstractSessionModel
Expand All @@ -45,13 +45,6 @@ const BreakendSingleLevelOptionDialog = observer(function ({
feature: Feature
view?: LinearGenomeViewModel
assemblyName: string
viewType: {
singleLevelSnapshotFromBreakendFeature: (arg: {
feature: Feature
assemblyName: string
session: AbstractSessionModel
}) => any
}
}) {
const [copyTracks, setCopyTracks] = useState(true)
const [windowSize, setWindowSize] = useLocalStorage(
Expand Down Expand Up @@ -101,7 +94,7 @@ const BreakendSingleLevelOptionDialog = observer(function ({
throw new Error('windowSize not a number')
}
const { snap, coverage } =
viewType.singleLevelSnapshotFromBreakendFeature({
singleLevelSnapshotFromBreakendFeature({
feature,
assemblyName,
session,
Expand Down Expand Up @@ -130,7 +123,7 @@ const BreakendSingleLevelOptionDialog = observer(function ({
}) as unknown as { views: LinearGenomeViewModel[] }
} else {
viewInStack.views[0]?.setDisplayedRegions(
snap.views[0].displayedRegions,
snap.views[0]!.displayedRegions,
)
// @ts-expect-error
viewInStack.setDisplayName(snap.displayName)
Expand Down
173 changes: 85 additions & 88 deletions packages/sv-core/src/util.ts
Original file line number Diff line number Diff line change
@@ -1,99 +1,96 @@
import { parseBreakend } from '@gmod/vcf'
import ViewType from '@jbrowse/core/pluggableElementTypes/ViewType'

import { gatherOverlaps } from '@jbrowse/core/util'
// types
import type { Assembly } from '@jbrowse/core/assemblyManager/assembly'
import {
gatherOverlaps,
type AbstractSessionModel,
type Feature,
} from '@jbrowse/core/util'
import type { AbstractSessionModel, Feature } from '@jbrowse/core/util'

export default class BreakpointSplitViewType extends ViewType {
getBreakendCoveringRegions({
feature,
assembly,
}: {
feature: Feature
assembly: Assembly
}) {
const alt = feature.get('ALT')?.[0]
const bnd = alt ? parseBreakend(alt) : undefined
const startPos = feature.get('start')
const refName = feature.get('refName')
const f = (ref: string) => assembly.getCanonicalRefName(ref) || ref
export function getBreakendCoveringRegions({
feature,
assembly,
}: {
feature: Feature
assembly: Assembly
}) {
const alt = feature.get('ALT')?.[0]
const bnd = alt ? parseBreakend(alt) : undefined
const startPos = feature.get('start')
const refName = feature.get('refName')
const f = (ref: string) => assembly.getCanonicalRefName(ref) || ref

if (alt === '<TRA>') {
const INFO = feature.get('INFO')
return {
pos: startPos,
refName: f(refName),
mateRefName: f(INFO.CHR2[0]),
matePos: INFO.END[0] - 1,
}
} else if (bnd?.MatePosition) {
const matePosition = bnd.MatePosition.split(':')
return {
pos: startPos,
refName: f(refName),
mateRefName: f(matePosition[0]!),
matePos: +matePosition[1]! - 1,
}
} else if (feature.get('mate')) {
const mate = feature.get('mate')
return {
pos: startPos,
refName: f(refName),
mateRefName: f(mate.refName),
matePos: mate.start,
}
} else {
return {
pos: startPos,
refName: f(refName),
mateRefName: f(refName),
matePos: feature.get('end'),
}
if (alt === '<TRA>') {
const INFO = feature.get('INFO')
return {
pos: startPos,
refName: f(refName),
mateRefName: f(INFO.CHR2[0]),
matePos: INFO.END[0] - 1,
}
}

singleLevelSnapshotFromBreakendFeature({
feature,
session,
assemblyName,
}: {
feature: Feature
session: AbstractSessionModel
assemblyName: string
}) {
const { assemblyManager } = session
const assembly = assemblyManager.get(assemblyName)
if (!assembly) {
throw new Error(`assembly ${assemblyName} not found`)
} else if (bnd?.MatePosition) {
const matePosition = bnd.MatePosition.split(':')
return {
pos: startPos,
refName: f(refName),
mateRefName: f(matePosition[0]!),
matePos: +matePosition[1]! - 1,
}
if (!assembly.regions) {
throw new Error(`assembly ${assemblyName} regions not loaded`)
} else if (feature.get('mate')) {
const mate = feature.get('mate')
return {
pos: startPos,
refName: f(refName),
mateRefName: f(mate.refName),
matePos: mate.start,
}
const coverage = this.getBreakendCoveringRegions({
feature,
assembly,
})
const { refName, mateRefName } = coverage
const topRegion = assembly.regions.find(f => f.refName === refName)!
const bottomRegion = assembly.regions.find(f => f.refName === mateRefName)!
} else {
return {
coverage,
snap: {
type: 'BreakpointSplitView',
views: [
{
type: 'LinearGenomeView',
displayedRegions: gatherOverlaps([topRegion, bottomRegion]),
},
],
displayName: `${
feature.get('name') || feature.get('id') || 'breakend'
} split detail`,
},
pos: startPos,
refName: f(refName),
mateRefName: f(refName),
matePos: feature.get('end'),
}
}
}

export function singleLevelSnapshotFromBreakendFeature({
feature,
session,
assemblyName,
}: {
feature: Feature
session: AbstractSessionModel
assemblyName: string
}) {
const { assemblyManager } = session
const assembly = assemblyManager.get(assemblyName)
if (!assembly) {
throw new Error(`assembly ${assemblyName} not found`)
}
if (!assembly.regions) {
throw new Error(`assembly ${assemblyName} regions not loaded`)
}
const coverage = getBreakendCoveringRegions({
feature,
assembly,
})
const { refName, mateRefName } = coverage
const topRegion = assembly.regions.find(f => f.refName === refName)!
const bottomRegion = assembly.regions.find(f => f.refName === mateRefName)!
return {
coverage,
snap: {
type: 'BreakpointSplitView',
views: [
{
type: 'LinearGenomeView',
displayedRegions: gatherOverlaps([
{ ...topRegion, assemblyName },
{ ...bottomRegion, assemblyName },
]),
},
],
displayName: `${
feature.get('name') || feature.get('id') || 'breakend'
} split detail`,
},
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@ import React, { lazy } from 'react'
import { SimpleFeature, getSession, toLocale } from '@jbrowse/core/util'
import { Link, Typography } from '@mui/material'

// types
import type { AlignmentFeatureWidgetModel } from './stateModelFactory'
import type { ViewType } from '@jbrowse/core/pluggableElementTypes'
import type { SimpleFeatureSerialized } from '@jbrowse/core/util'

// locals

// lazies
const BreakendMultiLevelOptionDialog = lazy(
() => import('./BreakendMultiLevelOptionDialog'),
Expand All @@ -20,11 +19,9 @@ const BreakendSingleLevelOptionDialog = lazy(
export default function LaunchPairedEndBreakpointSplitViewPanel({
model,
feature,
viewType,
}: {
model: AlignmentFeatureWidgetModel
feature: SimpleFeatureSerialized
viewType: ViewType
}) {
const session = getSession(model)
const f1 = {
Expand Down Expand Up @@ -56,10 +53,8 @@ export default function LaunchPairedEndBreakpointSplitViewPanel({
BreakendMultiLevelOptionDialog,
{
handleClose,
model,
session,
feature: new SimpleFeature({ ...f1, mate: f2 }),
// @ts-expect-error
viewType,
view: model.view,
assemblyName: model.view.displayedRegions[0].assemblyName,
},
Expand All @@ -76,10 +71,8 @@ export default function LaunchPairedEndBreakpointSplitViewPanel({
BreakendSingleLevelOptionDialog,
{
handleClose,
model,
session,
feature: new SimpleFeature({ ...f1, mate: f2 }),
// @ts-expect-error
viewType,
view: model.view,
assemblyName: model.view.displayedRegions[0].assemblyName,
},
Expand Down
Loading

0 comments on commit d8ec45b

Please sign in to comment.