Skip to content

Commit

Permalink
Support browsing past the ends of chromosomes if soft-clips is enable…
Browse files Browse the repository at this point in the history
  • Loading branch information
jrobinso committed Jul 27, 2022
1 parent 554528a commit d162b4e
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 37 deletions.
51 changes: 51 additions & 0 deletions dev/misc/overhanging_softclips.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="description" content="">
<meta name="author" content="">
<link rel="shortcut icon" href="https://igv.org/web/https://igv.org/web/img/favicon.ico">

<title>igv.js</title>
</head>

<body>

<div id="igvDiv" style="padding-top: 10px;padding-bottom: 10px; border:1px solid lightgray"></div>

<script type="module">

import igv from "../../js/index.js";

var options =
{
genome: "hg19",
locus: "chr1:1-100",
tracks: [
{
type: "alignment",
format: "bam",
url: "../../test/data/bam/overhanging_softclip.bam",
indexURL: "../../test/data/bam/overhanging_softclip.bam.bai",
showSoftClips: true,
showMismatches: false
}
]

};

var igvDiv = document.getElementById("igvDiv");

igv.createBrowser(igvDiv, options)
.then(function (browser) {
console.log("Created IGV browser");
})


</script>

</body>

</html>
11 changes: 6 additions & 5 deletions js/bam/bamTrack.js
Original file line number Diff line number Diff line change
Expand Up @@ -1161,14 +1161,18 @@ class AlignmentTrack {
const seq = alignment.seq ? alignment.seq.toUpperCase() : undefined
const qual = alignment.qual
const seqOffset = block.seqOffset
const widthPixel = Math.max(1, 1 / bpPerPixel)


for (let i = 0, len = block.len; i < len; i++) {

if (offsetBP + i < 0) continue
const xPixel = ((block.start + i) - bpStart) / bpPerPixel

if (xPixel + widthPixel < 0) continue // Off left edge
if (xPixel > pixelWidth) break // Off right edge

let readChar = seq ? seq.charAt(seqOffset + i) : ''
const refChar = referenceSequence.charAt(offsetBP + i)
const refChar = offsetBP + i >= 0 ? referenceSequence.charAt(offsetBP + i) : ''

if (readChar === "=") {
readChar = refChar
Expand All @@ -1183,9 +1187,6 @@ class AlignmentTrack {
baseColor = nucleotideColors[readChar]
}
if (baseColor) {
const xPixel = ((block.start + i) - bpStart) / bpPerPixel
const widthPixel = Math.max(1, 1 / bpPerPixel)

blockBasesToDraw.push({
bbox: {
x: xPixel,
Expand Down
11 changes: 9 additions & 2 deletions js/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -1476,7 +1476,7 @@ class Browser {
if (loci && loci.length > 0) {

// create reference frame list based on search loci
this.referenceFrameList = createReferenceFrameList(loci, this.genome, this.flanking, this.minimumBases(), this.calculateViewportWidth(loci.length))
this.referenceFrameList = createReferenceFrameList(loci, this.genome, this.flanking, this.minimumBases(), this.calculateViewportWidth(loci.length), this.isSoftclipped())

// discard viewport DOM elements
for (let trackView of this.trackViews) {
Expand Down Expand Up @@ -1715,6 +1715,11 @@ class Browser {
return this.dragObject
}

isSoftclipped() {
const result = this.trackViews.find(tv => tv.track.showSoftClips === true)
return result !== undefined
}


/**
* Track drag here refers to vertical dragging to reorder tracks, not horizontal panning.
Expand Down Expand Up @@ -1985,7 +1990,9 @@ function handleMouseMove(e) {
}

if (this.dragObject) {
const viewChanged = referenceFrame.shiftPixels(this.vpMouseDown.lastMouseX - x, viewport.$viewport.width())
const clampDrag = !this.isSoftclipped()
let deltaX = this.vpMouseDown.lastMouseX - x
const viewChanged = referenceFrame.shiftPixels(deltaX, viewport.$viewport.width(), clampDrag)
if (viewChanged) {
this.updateViews()
}
Expand Down
28 changes: 18 additions & 10 deletions js/referenceFrame.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ class ReferenceFrame {
this.id = DOMUtils.guid()
}

/**
* Extend this frame to accomodate the given locus. Used th CircularView methods to merge 2 frames.
* @param locus
*/
extend(locus) {
const newStart = Math.min(locus.start, this.start)
const newEnd = Math.max(locus.end, this.end)
Expand Down Expand Up @@ -77,28 +81,30 @@ class ReferenceFrame {

/**
* Shift frame by stated pixels. Return true if view changed, false if not.
*
* @param pixels
* @param clamp -- if true "clamp" shift to prevent panning off edge of chromosome. This is disabled if "show soft clipping" is on
* @param viewportWidth
*/
shiftPixels(pixels, viewportWidth) {
shiftPixels(pixels, viewportWidth, clamp) {

const currentStart = this.start

const deltaBP = pixels * this.bpPerPixel

this.start += deltaBP
this.clampStart(viewportWidth)

this.end += deltaBP
const {bpLength} = this.genome.getChromosome(this.chr)
this.end = Math.min(bpLength, this.end)
if(clamp) {
this.clampStart(viewportWidth)
}

this.end = this.start + viewportWidth * this.bpPerPixel

return currentStart !== this.start
}

clampStart(viewportWidth) {
// clamp left
const min = this.genome.getChromosome(this.chr).bpStart || 0
const min = (this.genome.getChromosome(this.chr).bpStart || 0)
this.start = Math.max(min, this.start)

// clamp right
Expand Down Expand Up @@ -184,7 +190,7 @@ class ReferenceFrame {
}
}

function createReferenceFrameList(loci, genome, browserFlanking, minimumBases, viewportWidth) {
function createReferenceFrameList(loci, genome, browserFlanking, minimumBases, viewportWidth, isSoftclipped) {

return loci.map(locus => {

Expand All @@ -195,8 +201,10 @@ function createReferenceFrameList(loci, genome, browserFlanking, minimumBases, v
}

// Validate the range. This potentionally modifies start & end of locus.
const chromosome = genome.getChromosome(locus.chr)
validateGenomicExtent(chromosome.bpLength, locus, minimumBases)
if(!isSoftclipped) {
const chromosome = genome.getChromosome(locus.chr)
validateGenomicExtent(chromosome.bpLength, locus, minimumBases)
}

const referenceFrame = new ReferenceFrame(genome,
locus.chr,
Expand Down
56 changes: 36 additions & 20 deletions js/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,34 +127,50 @@ function parseLocusString(browser, locus) {

if (a.length > 1) {

const b = a[1].split('-')
let b = a[1].split('-')
if (b.length > 2) {
// Allow for negative coordinates, which is possible if showing alignment soft clips
if (a[1].startsWith('-')) {
const i = a[1].indexOf('-', 1)
if (i > 0) {
const t1 = a[1].substring(0, i)
const t2 = a[1].substring(i + 1)
b = [t1, t2]
}
} else {
return undefined
}

}

let numeric
numeric = b[0].replace(/,/g, '')
if (isNaN(numeric)) {
return undefined
}

} else {
extent.start = parseInt(numeric, 10) - 1
extent.end = extent.start + 1

let numeric
numeric = b[0].replace(/,/g, '')
if (1 === b.length) {
extent.start -= 20
extent.end += 20
}

if (2 === b.length) {
numeric = b[1].replace(/,/g, '')
if (isNaN(numeric)) {
return undefined
} else {
extent.end = parseInt(numeric, 10)
}
}

extent.start = parseInt(numeric, 10) - 1
extent.end = extent.start + 1

if (1 === b.length) {
extent.start -= 20
extent.end += 20
}

if (2 === b.length) {
numeric = b[1].replace(/,/g, '')
if (isNaN(numeric)) {
return undefined
} else {
extent.end = parseInt(numeric, 10)
}
}
// Allow negative coordinates only if browser is softclipped, i.e. there is at least alignment track with softclipping on
if(extent.start < 0 && !browser.isSoftclipped()) {
const delta = -extent.start
extent.start += delta
extent.end += delta
}
}

Expand Down
Binary file added test/data/bam/overhanging_softclip.bam
Binary file not shown.
Binary file added test/data/bam/overhanging_softclip.bam.bai
Binary file not shown.
3 changes: 3 additions & 0 deletions test/data/bam/overhanging_softclip.sam
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@HD VN:1.0 SO:unsorted
@SQ SN:chr1 LN:247249719 AS:hg18 M5:9ebc6df9496613f373e73396d5b3b6b6
1487_1859_1707 89 chr1 1 26 14S24M * 0 0 ATAGCAATATGCAAGCCACTACACTACACTACAATTAT *88)%';9%%2795798/5<IIIIIIIIIIIHEIIIII NH:i:0 RG:Z:20100713212612939 CS:Z:T33303011321113211132110320131233033233003320201110 CQ:Z:>>@BB=)@@>=:AAA?:>-0&*/+-)1',%*0,'%%4%&)+81%)%*(4. SM:i:32 CM:i:4

0 comments on commit d162b4e

Please sign in to comment.