Skip to content

Commit

Permalink
Calculate clipPos forward strand even on reverse strand reads to get …
Browse files Browse the repository at this point in the history
…sequence track right on both top and bottom
  • Loading branch information
cmdcolin committed Feb 14, 2021
1 parent f2b4688 commit 31f7313
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 65 deletions.
50 changes: 50 additions & 0 deletions packages/core/util/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -811,3 +811,53 @@ export function stringify({

export const isElectron =
typeof window !== 'undefined' && Boolean(window.electron)

export function revcom(seqString: string) {
return complement(seqString).split('').reverse().join('')
}

export const complement = (() => {
const complementRegex = /[ACGT]/gi

// from bioperl: tr/acgtrymkswhbvdnxACGTRYMKSWHBVDNX/tgcayrkmswdvbhnxTGCAYRKMSWDVBHNX/
// generated with:
// perl -MJSON -E '@l = split "","acgtrymkswhbvdnxACGTRYMKSWHBVDNX"; print to_json({ map { my $in = $_; tr/acgtrymkswhbvdnxACGTRYMKSWHBVDNX/tgcayrkmswdvbhnxTGCAYRKMSWDVBHNX/; $in => $_ } @l})'
const complementTable = {
S: 'S',
w: 'w',
T: 'A',
r: 'y',
a: 't',
N: 'N',
K: 'M',
x: 'x',
d: 'h',
Y: 'R',
V: 'B',
y: 'r',
M: 'K',
h: 'd',
k: 'm',
C: 'G',
g: 'c',
t: 'a',
A: 'T',
n: 'n',
W: 'W',
X: 'X',
m: 'k',
v: 'b',
B: 'V',
s: 's',
H: 'D',
c: 'g',
D: 'H',
b: 'v',
R: 'Y',
G: 'C',
} as { [key: string]: string }

return (seqString: string) => {
return seqString.replace(complementRegex, m => complementTable[m] || '')
}
})()
36 changes: 22 additions & 14 deletions plugins/linear-comparative-view/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/no-explicit-any,no-bitwise */
import React, { useState } from 'react'
import { makeStyles } from '@material-ui/core/styles'
import Button from '@material-ui/core/Button'
Expand Down Expand Up @@ -121,6 +121,7 @@ interface ReducedFeature {
start: number
clipPos: number
end: number
strand: number
seqLength: number
syntenyId?: number
uniqueId: string
Expand Down Expand Up @@ -164,8 +165,8 @@ function WindowSizeDlg(props: {
try {
const session = getSession(track)
const view = getContainingView(track)
const clipPos = feature.get('clipPos')
const cigar = feature.get('CIGAR')
const clipPos = getClip(cigar, 1)
const flags = feature.get('flags')
const SA: string =
(feature.get('tags') ? feature.get('tags').SA : feature.get('SA')) || ''
Expand All @@ -190,7 +191,7 @@ function WindowSizeDlg(props: {
const saLength = getLength(saCigar)
const saLengthSansClipping = getLengthSansClipping(saCigar)
const saStrandNormalized = saStrand === '-' ? -1 : 1
const saClipPos = getClip(saCigar, saStrandNormalized)
const saClipPos = getClip(saCigar, 1) // saStrandNormalized)
const saRealStart = +saStart - 1
return {
refName: saRef,
Expand All @@ -211,6 +212,7 @@ function WindowSizeDlg(props: {
})

const feat = feature.toJSON()
feat.clipPos = clipPos

feat.mate = {
refName: readName,
Expand All @@ -222,7 +224,6 @@ function WindowSizeDlg(props: {
// which is the primary alignments. otherwise it is the primary alignment just use
// seq.length if primary alignment
const totalLength =
// eslint-disable-next-line no-bitwise
flags & 2048
? getLength(supplementaryAlignments[0].CIGAR)
: getLength(cigar)
Expand All @@ -237,20 +238,34 @@ function WindowSizeDlg(props: {
})
features.sort((a, b) => a.clipPos - b.clipPos)

const featSeq = feature.get('seq')

// the config feature store includes synthetic mate features
// mapped to the read assembly
const configFeatureStore = features.concat(
// @ts-ignore
features.map(f => f.mate),
)

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

const seqTrackId = `${readName}_${Date.now()}`
const sequenceTrackConf = getConf(assembly, 'sequence')
const lgvRegions = features
.map(f => {
return {
...f,
start: f.start - windowSize,
end: f.end + windowSize,
refName: f.refName,
assemblyName: trackAssembly,
}
})
.sort((a, b) => a.clipPos - b.clipPos)

session.addView('LinearSyntenyView', {
type: 'LinearSyntenyView',
Expand All @@ -260,14 +275,7 @@ function WindowSizeDlg(props: {
hideHeader: true,
offsetPx: 0,
bpPerPx: refLength / view.width,
displayedRegions: features.map(f => {
return {
start: f.start - windowSize,
end: f.end + windowSize,
refName: f.refName,
assemblyName: trackAssembly,
}
}),
displayedRegions: lgvRegions,
tracks: [
{
id: `${Math.random()}`,
Expand Down Expand Up @@ -345,7 +353,7 @@ function WindowSizeDlg(props: {
{
start: 0,
end: totalLength,
seq: feat.seq,
seq: featSeq,
refName: readName,
uniqueId: `${Math.random()}`,
id: `${Math.random()}`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Region } from '@jbrowse/core/util/types'
import { createJBrowseTheme } from '@jbrowse/core/ui'
import { observer } from 'mobx-react'
import React from 'react'
import { bpSpanPx } from '@jbrowse/core/util'
import { bpSpanPx, revcom, complement } from '@jbrowse/core/util'

interface MyProps {
features: Map<string, Feature>
Expand All @@ -20,56 +20,6 @@ interface MyProps {
showTranslation: boolean
}

function revcom(seqString: string) {
return complement(seqString).split('').reverse().join('')
}

const complement = (() => {
const complementRegex = /[ACGT]/gi

// from bioperl: tr/acgtrymkswhbvdnxACGTRYMKSWHBVDNX/tgcayrkmswdvbhnxTGCAYRKMSWDVBHNX/
// generated with:
// perl -MJSON -E '@l = split "","acgtrymkswhbvdnxACGTRYMKSWHBVDNX"; print to_json({ map { my $in = $_; tr/acgtrymkswhbvdnxACGTRYMKSWHBVDNX/tgcayrkmswdvbhnxTGCAYRKMSWDVBHNX/; $in => $_ } @l})'
const complementTable = {
S: 'S',
w: 'w',
T: 'A',
r: 'y',
a: 't',
N: 'N',
K: 'M',
x: 'x',
d: 'h',
Y: 'R',
V: 'B',
y: 'r',
M: 'K',
h: 'd',
k: 'm',
C: 'G',
g: 'c',
t: 'a',
A: 'T',
n: 'n',
W: 'W',
X: 'X',
m: 'k',
v: 'b',
B: 'V',
s: 's',
H: 'D',
c: 'g',
D: 'H',
b: 'v',
R: 'Y',
G: 'C',
} as { [key: string]: string }

return (seqString: string) => {
return seqString.replace(complementRegex, m => complementTable[m] || '')
}
})()

const defaultStarts = ['ATG']
const defaultStops = ['TAA', 'TAG', 'TGA']
const defaultCodonTable = {
Expand Down

0 comments on commit 31f7313

Please sign in to comment.