Skip to content

Commit

Permalink
Small refactoring to avoid super deeply nested code
Browse files Browse the repository at this point in the history
  • Loading branch information
cmdcolin committed Aug 20, 2021
1 parent 1bebc1b commit 4b88afa
Showing 1 changed file with 145 additions and 159 deletions.
304 changes: 145 additions & 159 deletions plugins/dotplot-view/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
import ComparativeRender from './DotplotRenderer/ComparativeRenderRpc'
import { PluggableElementType } from '@jbrowse/core/pluggableElementTypes'
import { LinearPileupDisplayModel } from '@jbrowse/plugin-alignments'
import { IAnyStateTreeNode } from 'mobx-state-tree'

const { parseCigar } = MismatchParser

Expand Down Expand Up @@ -173,6 +174,149 @@ interface ReducedFeature {
seqLength: number
}

function onClick(feature: Feature, self: LinearPileupDisplayModel) {
const session = getSession(self)
try {
const cigar = feature.get('CIGAR')
const clipPos = getClip(cigar, 1)
const flags = feature.get('flags')
const origStrand = feature.get('strand')
const SA: string = getTag(feature, 'SA') || ''
const readName = feature.get('name')
const readAssembly = `${readName}_assembly`
const { parentTrack } = self
const [trackAssembly] = getConf(parentTrack, 'assemblyNames')
const assemblyNames = [trackAssembly, readAssembly]
const trackId = `track-${Date.now()}`
const trackName = `${readName}_vs_${trackAssembly}`
const supplementaryAlignments = SA.split(';')
.filter(aln => !!aln)
.map((aln, index) => {
const [saRef, saStart, saStrand, saCigar] = aln.split(',')
const saLengthOnRef = getLengthOnRef(saCigar)
const saLength = getLength(saCigar)
const saLengthSansClipping = getLengthSansClipping(saCigar)
const saStrandNormalized = saStrand === '-' ? -1 : 1
const saClipPos = getClip(saCigar, saStrandNormalized * origStrand)
const saRealStart = +saStart - 1
return {
refName: saRef,
start: saRealStart,
end: saRealStart + saLengthOnRef,
seqLength: saLength,
clipPos: saClipPos,
CIGAR: saCigar,
assemblyName: trackAssembly,
strand: origStrand * saStrandNormalized,
uniqueId: `${feature.id()}_SA${index}`,
mate: {
start: saClipPos,
end: saClipPos + saLengthSansClipping,
refName: readName,
},
}
})

const feat = feature.toJSON()
feat.strand = 1
feat.mate = {
refName: readName,
start: clipPos,
end: clipPos + getLengthSansClipping(cigar),
}

// if secondary alignment or supplementary, calculate length
// from SA[0]'s CIGAR which is the primary alignments.
// otherwise it is the primary alignment just use seq.length if
// primary alignment
const totalLength = getLength(
flags & 2048 ? supplementaryAlignments[0].CIGAR : cigar,
)

const features = [feat, ...supplementaryAlignments] as ReducedFeature[]

features.sort((a, b) => a.clipPos - b.clipPos)

const refLength = features.reduce((a, f) => a + f.end - f.start, 0)

session.addView('DotplotView', {
type: 'DotplotView',
hview: {
offsetPx: 0,
bpPerPx: refLength / 800,
displayedRegions: gatherOverlaps(
features.map((f, index) => {
const { start, end, refName } = f
return {
start,
end,
refName,
index,
assemblyName: trackAssembly,
}
}),
),
},
vview: {
offsetPx: 0,
bpPerPx: totalLength / 400,
minimumBlockWidth: 0,
interRegionPaddingWidth: 0,
displayedRegions: [
{
assemblyName: readAssembly,
start: 0,
end: totalLength,
refName: readName,
},
],
},
viewTrackConfigs: [
{
type: 'SyntenyTrack',
assemblyNames,
adapter: {
type: 'FromConfigAdapter',
features,
},
trackId,
name: trackName,
},
],
viewAssemblyConfigs: [
{
name: readAssembly,
sequence: {
type: 'ReferenceSequenceTrack',
trackId: `${readName}_${Date.now()}`,
adapter: {
type: 'FromConfigSequenceAdapter',
features: [feature.toJSON()],
},
},
},
],
assemblyNames,
tracks: [
{
configuration: trackId,
type: 'SyntenyTrack',
displays: [
{
type: 'DotplotDisplay',
configuration: `${trackId}-DotplotDisplay`,
},
],
},
],
displayName: `${readName} vs ${trackAssembly}`,
})
} catch (e) {
console.error(e)
session.notify(`${e}`, 'error')
}
}

export default class DotplotPlugin extends Plugin {
name = 'DotplotPlugin'

Expand Down Expand Up @@ -241,165 +385,7 @@ export default class DotplotPlugin extends Plugin {
{
label: 'Dotplot of read vs ref',
icon: AddIcon,
onClick: () => {
const session = getSession(self)
const cigar = feature.get('CIGAR')
const clipPos = getClip(cigar, 1)
const flags = feature.get('flags')
const origStrand = feature.get('strand')
const SA: string = getTag(feature, 'SA') || ''
const readName = feature.get('name')
const readAssembly = `${readName}_assembly`
const { parentTrack } = self
const [trackAssembly] = getConf(
parentTrack,
'assemblyNames',
)
const assemblyNames = [trackAssembly, readAssembly]
const trackId = `track-${Date.now()}`
const trackName = `${readName}_vs_${trackAssembly}`
const supplementaryAlignments = SA.split(';')
.filter(aln => !!aln)
.map((aln, index) => {
const [
saRef,
saStart,
saStrand,
saCigar,
] = aln.split(',')
const saLengthOnRef = getLengthOnRef(saCigar)
const saLength = getLength(saCigar)
const saLengthSansClipping = getLengthSansClipping(
saCigar,
)
const saStrandNormalized =
saStrand === '-' ? -1 : 1
const saClipPos = getClip(
saCigar,
saStrandNormalized * origStrand,
)
const saRealStart = +saStart - 1
return {
refName: saRef,
start: saRealStart,
end: saRealStart + saLengthOnRef,
seqLength: saLength,
clipPos: saClipPos,
CIGAR: saCigar,
assemblyName: trackAssembly,
strand: origStrand * saStrandNormalized,
uniqueId: `${feature.id()}_SA${index}`,
mate: {
start: saClipPos,
end: saClipPos + saLengthSansClipping,
refName: readName,
},
}
})

const feat = feature.toJSON()
feat.strand = 1
feat.mate = {
refName: readName,
start: clipPos,
end: clipPos + getLengthSansClipping(cigar),
}

// if secondary alignment or supplementary, calculate length
// from SA[0]'s CIGAR which is the primary alignments.
// otherwise it is the primary alignment just use seq.length if
// primary alignment
const totalLength = getLength(
flags & 2048
? supplementaryAlignments[0].CIGAR
: cigar,
)

const features = [
feat,
...supplementaryAlignments,
] as ReducedFeature[]

features.sort((a, b) => a.clipPos - b.clipPos)

const refLength = features.reduce(
(a, f) => a + f.end - f.start,
0,
)

session.addView('DotplotView', {
type: 'DotplotView',
hview: {
offsetPx: 0,
bpPerPx: refLength / 800,
displayedRegions: gatherOverlaps(
features.map((f, index) => {
const { start, end, refName } = f
return {
start,
end,
refName,
index,
assemblyName: trackAssembly,
}
}),
),
},
vview: {
offsetPx: 0,
bpPerPx: totalLength / 400,
minimumBlockWidth: 0,
interRegionPaddingWidth: 0,
displayedRegions: [
{
assemblyName: readAssembly,
start: 0,
end: totalLength,
refName: readName,
},
],
},
viewTrackConfigs: [
{
type: 'SyntenyTrack',
assemblyNames,
adapter: {
type: 'FromConfigAdapter',
features,
},
trackId,
name: trackName,
},
],
viewAssemblyConfigs: [
{
name: readAssembly,
sequence: {
type: 'ReferenceSequenceTrack',
trackId: `${readName}_${Date.now()}`,
adapter: {
type: 'FromConfigSequenceAdapter',
features: [feature.toJSON()],
},
},
},
],
assemblyNames,
tracks: [
{
configuration: trackId,
type: 'SyntenyTrack',
displays: [
{
type: 'DotplotDisplay',
configuration: `${trackId}-DotplotDisplay`,
},
],
},
],
displayName: `${readName} vs ${trackAssembly}`,
})
},
onClick: () => onClick(feature, self),
},
]

Expand Down

0 comments on commit 4b88afa

Please sign in to comment.