operators = buildOperators(cigarString);
+ for (CigarOperator operator : operators) {
+ if (operator.operator == HARD_CLIP) {
+ clipLength += operator.nBases;
+ } else {
+ break;
+ }
+ }
+ }
+ return clipLength;
+ }
+
/**
* Create the alignment blocks from the read bases and alignment information in the CIGAR
* string. The CIGAR string encodes insertions, deletions, skipped regions, and padding.
@@ -579,6 +607,14 @@ public String getClipboardString(double location, int mouseX) {
return getAlignmentValueString(location, mouseX, (AlignmentTrack.RenderOptions) null);
}
+ private Integer positionToReadIndex(double position) {
+ for (AlignmentBlock block : this.alignmentBlocks) {
+ if (block.contains((int) position)) {
+ return (int) (position - block.getStart()) + block.getBasesOffset();
+ }
+ }
+ return null;
+ }
public String getAlignmentValueString(double position, int mouseX, AlignmentTrack.RenderOptions renderOptions) {
@@ -614,12 +650,13 @@ public String getAlignmentValueString(double position, int mouseX, AlignmentTrac
}
}
- // Check base modifications
- if (renderOptions != null &&
- (renderOptions.getColorOption().isBaseMod())) {
- for (AlignmentBlock block : this.alignmentBlocks) {
- if (block.contains((int) position)) {
- int p = (int) (position - block.getStart()) + block.getBasesOffset();
+ // Check base modifications & kinetics
+ if (renderOptions != null) {
+ final AlignmentTrack.ColorOption colorOption = renderOptions.getColorOption();
+ if (colorOption.isBaseMod()) {
+ Integer readIndex = positionToReadIndex(position);
+ if (readIndex != null) {
+ int p = readIndex;
if (baseModificationSets != null) {
String modString = "";
for (BaseModificationSet bmSet : baseModificationSets) {
@@ -635,6 +672,36 @@ public String getAlignmentValueString(double position, int mouseX, AlignmentTrac
}
}
}
+ } else if (colorOption.isSMRTKinetics()) {
+ Integer readIndex = positionToReadIndex(position);
+ SMRTKinetics sk = getSmrtKinetics();
+ if (readIndex != null) {
+ if (colorOption == AlignmentTrack.ColorOption.SMRT_SUBREAD_IPD) {
+ short[] ipdVals = sk.getSmrtSubreadIpd();
+ if (ipdVals != null) {
+ return "Subread IPD: " + Short.toUnsignedInt(ipdVals[readIndex]) + " Frames";
+ }
+ } else if (colorOption == AlignmentTrack.ColorOption.SMRT_SUBREAD_PW) {
+ short[] pwVals = sk.getSmrtSubreadPw();
+ if (pwVals != null) {
+ return "Subread PW: " + Short.toUnsignedInt(pwVals[readIndex]) + " Frames";
+ }
+ } else if (colorOption == AlignmentTrack.ColorOption.SMRT_CCS_FWD_IPD || colorOption == AlignmentTrack.ColorOption.SMRT_CCS_REV_IPD) {
+ final boolean isForwardStrand = (colorOption == AlignmentTrack.ColorOption.SMRT_CCS_FWD_IPD);
+ short[] ipdVals = sk.getSmrtCcsIpd(isForwardStrand);
+ if (ipdVals != null) {
+ final String strand = (isForwardStrand ? "fwd" : "rev");
+ return "CCS " + strand + "-strand aligned IPD: " + Short.toUnsignedInt(ipdVals[readIndex]) + " Frames";
+ }
+ } else {
+ final boolean isForwardStrand = (colorOption == AlignmentTrack.ColorOption.SMRT_CCS_FWD_PW);
+ short[] pwVals = sk.getSmrtCcsPw(isForwardStrand);
+ if (pwVals != null) {
+ final String strand = (isForwardStrand ? "fwd" : "rev");
+ return "CCS " + strand + "-strand aligned PW: " + Short.toUnsignedInt(pwVals[readIndex]) + " Frames";
+ }
+ }
+ }
}
}
diff --git a/src/main/java/org/broad/igv/sam/SMRTKineticsDecoder.java b/src/main/java/org/broad/igv/sam/SMRTKineticsDecoder.java
new file mode 100644
index 0000000000..566913c204
--- /dev/null
+++ b/src/main/java/org/broad/igv/sam/SMRTKineticsDecoder.java
@@ -0,0 +1,40 @@
+package org.broad.igv.sam;
+
+/// Decode SMRT kinetic values from uint8 compressed code to an approximation of the
+/// original frame count.
+///
+public class SMRTKineticsDecoder {
+
+ private static final int base = 1 << 6;
+
+ private final short[] frameCounts;
+
+ public SMRTKineticsDecoder() {
+ frameCounts = new short[256];
+ for (int i = 0; i < 256; ++i) {
+ frameCounts[i] = decodeFrameCount((byte) i);
+ }
+ }
+
+ /// Convert compressed byte to frame count from cached LUT
+ public short lookupFrameCount(byte val) {
+ return frameCounts[val & 0xFF];
+ }
+
+ /// Compute frame count from compressed byte
+ ///
+ /// 8-bit compressed V1 codec:
+ ///
+ /// xxmm'mmmm
+ ///
+ /// where
+ /// * 'x' represents the exponent (2 MSBs)
+ /// * 'm' represents the mantissa (6 LSBs)
+ ///
+ private static short decodeFrameCount(byte val) {
+ int mantissa = val & 0b0011_1111;
+ int exponent = (val & 0b1100_0000) >> 6;
+ int exponentVal = 1 << exponent;
+ return (short) (base * (exponentVal - 1) + exponentVal * mantissa);
+ }
+}
diff --git a/src/main/java/org/broad/igv/sam/smrt/SMRTKinetics.java b/src/main/java/org/broad/igv/sam/smrt/SMRTKinetics.java
new file mode 100644
index 0000000000..d3f8bf5984
--- /dev/null
+++ b/src/main/java/org/broad/igv/sam/smrt/SMRTKinetics.java
@@ -0,0 +1,129 @@
+package org.broad.igv.sam.smrt;
+
+import org.broad.igv.sam.Alignment;
+import org.broad.igv.sam.SAMAlignment;
+
+public class SMRTKinetics {
+
+ private Alignment alignment;
+ private short[] smrtSubreadIpd;
+ private short[] smrtSubreadPw;
+ private short[] smrtCcsIpd;
+ private short[] smrtCcsPw;
+
+ private short[] smrtSubreadIpdVals;
+ private short[] smrtSubreadPwVals;
+ private short[] smrtCcsFwdIpdVals;
+ private short[] smrtCcsFwdPwVals;
+ private short[] smrtCcsRevIpdVals;
+ private short[] smrtCcsRevPwVals;
+
+ public SMRTKinetics(Alignment alignment) {
+ this.alignment = alignment;
+ }
+
+
+ /**
+ * Given the compressed byte code array of CCS kinetic values from the SAM aux field do the following:
+ * - Initialize frame count array, decode compressed kinetic byte codes into frame counts and copy these into it
+ * - Reverse frame count sequence if reverseSequence is true
+ * - If the read has a leading hard-clip, remove all frame counts from the hard-clipped region
+ *
+ * Returns the processed frame count array
+ */
+ private short[] parseSmrtKineticByteCodes(byte[] smrtKineticByteCodes, boolean reverseSequence) {
+ if (smrtKineticByteCodes.length == 0) {
+ return null;
+ }
+
+ int hardClipLength = alignment. getLeadingHardClipLength();
+ int kineticValLength = smrtKineticByteCodes.length - hardClipLength;
+ assert(kineticValLength > 0);
+ short[] ccsKineticVals = new short[kineticValLength];
+
+ int byteCodeIndex = 0;
+ for (byte ccsKineticByteCode : smrtKineticByteCodes) {
+ int valIndex = byteCodeIndex;
+ byteCodeIndex++;
+ if (reverseSequence) {
+ valIndex = smrtKineticByteCodes.length - (valIndex+1);
+ }
+ if (valIndex < hardClipLength) continue;
+ valIndex -= hardClipLength;
+ ccsKineticVals[valIndex] = SMRTKineticsDecoder.lookupFrameCount(ccsKineticByteCode);
+ }
+ return ccsKineticVals;
+ }
+
+ /**
+ * Given the original uint16 CCS kinetic frame count array from the SAM aux field do the following:
+ * - Initialize the processed frame count array and copy values into it
+ * - Reverse frame count sequence if reverseSequence is true
+ * - If the read has a leading hard-clip, remove all frame counts from the hard-clipped region
+ *
+ * Returns the processed frame count array
+ */
+ private short[] parseAuxSmrtKineticFrameCounts(short[] auxSmrtKineticFrameCounts, boolean reverseSequence) {
+ if (auxSmrtKineticFrameCounts.length == 0) {
+ return null;
+ }
+
+ int hardClipLength = alignment.getLeadingHardClipLength();
+ int kineticValLength = auxSmrtKineticFrameCounts.length - hardClipLength;
+ assert(kineticValLength > 0);
+ short[] ccsKineticVals = new short[kineticValLength];
+
+ int auxIndex = 0;
+ for (short ccsKineticFrameCount : auxSmrtKineticFrameCounts) {
+ int valIndex = auxIndex;
+ auxIndex++;
+ if (reverseSequence) {
+ valIndex = auxSmrtKineticFrameCounts.length - (valIndex+1);
+ }
+ if (valIndex < hardClipLength) continue;
+ valIndex -= hardClipLength;
+ ccsKineticVals[valIndex] = ccsKineticFrameCount;
+ }
+ return ccsKineticVals;
+ }
+
+ private short[] getSmrtKineticsVals(short[] smrtKineticVals, String tag, boolean bytesReversedInBam) {
+ if (smrtKineticVals == null && alignment.getAttribute(tag) != null) {
+ final boolean reverseSequence = (bytesReversedInBam ^ alignment.isNegativeStrand());
+ Object tagValue = alignment.getAttribute(tag);
+ if (tagValue instanceof byte[]) {
+ smrtKineticVals = parseSmrtKineticByteCodes((byte[]) (tagValue), reverseSequence);
+ } else if (tagValue instanceof short[]) {
+ smrtKineticVals = parseAuxSmrtKineticFrameCounts((short[]) (tagValue), reverseSequence);
+ } else {
+ throw new RuntimeException("Unexpected format in SMRT kinetic aux tag '" + tag + "'");
+ }
+ }
+ return smrtKineticVals;
+ }
+
+
+ public short[] getSmrtSubreadIpd() {
+ return getSmrtKineticsVals(smrtSubreadIpdVals, "ip", false);
+ }
+
+ public short[] getSmrtSubreadPw() {
+ return getSmrtKineticsVals(smrtSubreadPwVals, "pw", false);
+ }
+
+ public short[] getSmrtCcsIpd(boolean isForwardStrand) {
+ if (isForwardStrand ^ alignment.isNegativeStrand()) {
+ return getSmrtKineticsVals(smrtCcsFwdIpdVals, "fi", false);
+ } else {
+ return getSmrtKineticsVals(smrtCcsRevIpdVals, "ri", true);
+ }
+ }
+
+ public short[] getSmrtCcsPw(boolean isForwardStrand) {
+ if (isForwardStrand ^ alignment.isNegativeStrand()) {
+ return getSmrtKineticsVals(smrtCcsFwdPwVals, "fp", false);
+ } else {
+ return getSmrtKineticsVals(smrtCcsRevPwVals, "rp", true);
+ }
+ }
+}
diff --git a/src/main/java/org/broad/igv/sam/smrt/SMRTKineticsDecoder.java b/src/main/java/org/broad/igv/sam/smrt/SMRTKineticsDecoder.java
new file mode 100644
index 0000000000..518ff42e54
--- /dev/null
+++ b/src/main/java/org/broad/igv/sam/smrt/SMRTKineticsDecoder.java
@@ -0,0 +1,43 @@
+package org.broad.igv.sam.smrt;
+
+/// Decode SMRT kinetic values from uint8 compressed code to an approximation of the
+/// original frame count.
+///
+public class SMRTKineticsDecoder {
+
+ private static final int base = 1 << 6;
+
+ private static short[] frameCounts;
+
+ private SMRTKineticsDecoder() {
+
+ }
+
+ /// Convert compressed byte to frame count from cached LUT
+ public static short lookupFrameCount(byte val) {
+ if(frameCounts == null) {
+ frameCounts = new short[256];
+ for (int i = 0; i < 256; ++i) {
+ frameCounts[i] = decodeFrameCount((byte) i);
+ }
+ }
+ return frameCounts[val & 0xFF];
+ }
+
+ /// Compute frame count from compressed byte
+ ///
+ /// 8-bit compressed V1 codec:
+ ///
+ /// xxmm'mmmm
+ ///
+ /// where
+ /// * 'x' represents the exponent (2 MSBs)
+ /// * 'm' represents the mantissa (6 LSBs)
+ ///
+ private static short decodeFrameCount(byte val) {
+ int mantissa = val & 0b0011_1111;
+ int exponent = (val & 0b1100_0000) >> 6;
+ int exponentVal = 1 << exponent;
+ return (short) (base * (exponentVal - 1) + exponentVal * mantissa);
+ }
+}
diff --git a/src/main/java/org/broad/igv/sam/smrt/SMRTKineticsRenderer.java b/src/main/java/org/broad/igv/sam/smrt/SMRTKineticsRenderer.java
new file mode 100644
index 0000000000..087c5b2ec5
--- /dev/null
+++ b/src/main/java/org/broad/igv/sam/smrt/SMRTKineticsRenderer.java
@@ -0,0 +1,109 @@
+package org.broad.igv.sam.smrt;
+
+import org.broad.igv.sam.*;
+
+import java.awt.*;
+
+public class SMRTKineticsRenderer {
+ public static void drawSmrtKinetics(Alignment alignment, double bpStart, double locScale, Rectangle rowRect, Graphics g, AlignmentTrack.ColorOption colorOption) {
+ int dX;
+ short[] smrtFrameCounts;
+ SMRTKinetics smrtKinetics = alignment.getSmrtKinetics();
+ if (AlignmentTrack.ColorOption.SMRT_SUBREAD_IPD == colorOption) {
+ smrtFrameCounts = smrtKinetics.getSmrtSubreadIpd();
+ } else if (AlignmentTrack.ColorOption.SMRT_SUBREAD_PW == colorOption) {
+ smrtFrameCounts = smrtKinetics.getSmrtSubreadPw();
+ } else if (AlignmentTrack.ColorOption.SMRT_CCS_FWD_IPD == colorOption || AlignmentTrack.ColorOption.SMRT_CCS_REV_IPD == colorOption) {
+ final boolean isForwardStrand = (AlignmentTrack.ColorOption.SMRT_CCS_FWD_IPD == colorOption);
+ smrtFrameCounts = smrtKinetics.getSmrtCcsIpd(isForwardStrand);
+ } else {
+ final boolean isForwardStrand = (AlignmentTrack.ColorOption.SMRT_CCS_FWD_PW == colorOption);
+ smrtFrameCounts = smrtKinetics.getSmrtCcsPw(isForwardStrand);
+ }
+
+ if (smrtFrameCounts != null) {
+ // Compute bounds
+ int pY = (int) rowRect.getY();
+ int dY = (int) rowRect.getHeight();
+ dX = (int) Math.max(1, (1.0 / locScale));
+
+ for (AlignmentBlock block : alignment.getAlignmentBlocks()) {
+ ByteSubarray bases = block.getBases();
+ final int startOffset = bases.startOffset;
+ final int stopOffset = startOffset + bases.length;
+ for (int i = startOffset; i < stopOffset; i++) {
+ g.setColor(getSmrtFrameCountColor(smrtFrameCounts[i]));
+
+ int blockIdx = i - block.getBases().startOffset;
+ int pX = (int) ((block.getStart() + blockIdx - bpStart) / locScale);
+
+ // Don't draw out of clipping rect
+ if (pX > rowRect.getMaxX()) {
+ break;
+ } else if (pX + dX < rowRect.getX()) {
+ continue;
+ }
+
+ // Expand narrow width to make more visible
+ if (dX < 3) {
+ dX = 3;
+ pX--;
+ }
+ g.fillRect(pX, pY, dX, Math.max(1, dY - 2));
+ }
+ }
+ }
+ }
+
+ /**
+ * Set base color for SMRT sequencing frame count
+ *
+ * This color scheme uses multiple transitions to help visually distinguish a large range of time intervals.
+ *
+ * Color scheme:
+ * The color starts out as transparent at a frame count of 0.
+ * - Color transition 1 goes from transparent to opaque red
+ * - Color transition 2 goes from red to yellow
+ * - Color transition 3 goes from yellow to cyan
+ *
+ * Transition 3 will mostly be visible when uncompressed frame counts are used. It helps to visually distinguish
+ * exceptional polymerase stalling events.
+ */
+ private static Color getSmrtFrameCountColor(short shortFrameCount) {
+ final int transition1MaxFrameCount = 100;
+ final int transition2MaxFrameCount = 600;
+ final int transition3MaxFrameCount = 6000;
+ final Color color1 = Color.red;
+ final Color color2 = Color.yellow;
+ final Color color3 = Color.cyan;
+
+ final int frameCount = Short.toUnsignedInt(shortFrameCount);
+ final int alpha = Math.min(255, (frameCount * 255) / transition1MaxFrameCount);
+ Color blendedColor;
+ if (frameCount <= transition1MaxFrameCount) {
+ blendedColor = color1;
+ } else if (frameCount <= transition2MaxFrameCount) {
+ float color2Fraction = (frameCount - transition1MaxFrameCount) / ((float) (transition2MaxFrameCount - transition1MaxFrameCount));
+ blendedColor = blendColors(color1, color2, color2Fraction);
+ } else if (frameCount <= transition3MaxFrameCount) {
+ float color3Fraction = (frameCount - transition2MaxFrameCount) / ((float) (transition3MaxFrameCount - transition2MaxFrameCount));
+ blendedColor = blendColors(color2, color3, color3Fraction);
+ } else {
+ blendedColor = color3;
+ }
+ return new Color(blendedColor.getRed(), blendedColor.getGreen(), blendedColor.getBlue(), alpha);
+ }
+
+
+ private static int blendColorValue(int v1, int v2, float v2Frac) {
+ return Math.min(255, (int) (v1 + (v2 - v1) * v2Frac));
+ }
+
+ private static Color blendColors(Color c1, Color c2, float c2Frac) {
+ assert (c2Frac >= 0.0 && c2Frac <= 1.0);
+ return new Color(blendColorValue(c1.getRed(), c2.getRed(), c2Frac),
+ blendColorValue(c1.getGreen(), c2.getGreen(), c2Frac),
+ blendColorValue(c1.getBlue(), c2.getBlue(), c2Frac));
+ }
+
+}
diff --git a/src/main/resources/org/broad/igv/prefs/preferences.tab b/src/main/resources/org/broad/igv/prefs/preferences.tab
index cc4b8df723..9129618993 100644
--- a/src/main/resources/org/broad/igv/prefs/preferences.tab
+++ b/src/main/resources/org/broad/igv/prefs/preferences.tab
@@ -191,6 +191,9 @@ SAM.SHOW_INSERTION_MARKERS Show insertion markers boolean TRUE
SAM.LINK_READS Link alignments by tag boolean FALSE
SAM.LINK_TAG Linking tag string READNAME
+##SMRT Kinetics
+SMRT_KINETICS.SHOW_OPTIONS Show visibility options for SMRT kinetics data boolean FALSE
+
#Proxy
PROXY.DISABLE_CHECK Disable check for system proxy boolean FALSE
PROXY.USE Use proxy boolean FALSE
diff --git a/src/test/java/org/broad/igv/sam/smrt/SMRTKineticsDecoderTest.java b/src/test/java/org/broad/igv/sam/smrt/SMRTKineticsDecoderTest.java
new file mode 100644
index 0000000000..f258dd0b0c
--- /dev/null
+++ b/src/test/java/org/broad/igv/sam/smrt/SMRTKineticsDecoderTest.java
@@ -0,0 +1,48 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2007-2015 Broad Institute
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.broad.igv.sam.smrt;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class SMRTKineticsDecoderTest {
+
+ public SMRTKineticsDecoderTest() {
+ }
+
+ @Test
+ public void testDecoder() throws Exception {
+
+ short v0 = SMRTKineticsDecoder.lookupFrameCount((byte) 0);
+ short v128 = SMRTKineticsDecoder.lookupFrameCount((byte) 128);
+ short v255 = SMRTKineticsDecoder.lookupFrameCount((byte) 255);
+
+ assertEquals(0, v0);
+ assertEquals(192, v128);
+ assertEquals(952, v255);
+ }
+}
\ No newline at end of file
From f5ae7f471ffe2f831c7a48e6362e41e022454127 Mon Sep 17 00:00:00 2001
From: jrobinso <933148+jrobinso@users.noreply.github.com>
Date: Fri, 16 Dec 2022 09:26:37 -0800
Subject: [PATCH 017/116] Allow merging bam files with different chr name
conventions ("1" vs "chr1")
---
.../igv/sam/reader/MergedAlignmentReader.java | 66 ++++++++++---------
1 file changed, 35 insertions(+), 31 deletions(-)
diff --git a/src/main/java/org/broad/igv/sam/reader/MergedAlignmentReader.java b/src/main/java/org/broad/igv/sam/reader/MergedAlignmentReader.java
index 10e94799ef..f1794efcd7 100644
--- a/src/main/java/org/broad/igv/sam/reader/MergedAlignmentReader.java
+++ b/src/main/java/org/broad/igv/sam/reader/MergedAlignmentReader.java
@@ -49,7 +49,9 @@ public class MergedAlignmentReader implements AlignmentReader {
List readers;
List sequenceNames;
- Map chrNameIndex;
+
+ Map> readerChrNameMaps;
+
SAMFileHeader header;
public MergedAlignmentReader(List readers) throws IOException {
@@ -79,53 +81,64 @@ public Set getPlatforms() {
Set platforms = new HashSet();
for (AlignmentReader reader : readers) {
Set plf = reader.getPlatforms();
- if(plf != null){
+ if (plf != null) {
platforms.addAll(plf);
}
}
return platforms;
}
- public SAMFileHeader getFileHeader(){
- if(this.header == null){
+ public SAMFileHeader getFileHeader() {
+ if (this.header == null) {
this.header = loadHeaders();
}
return this.header;
}
/**
- * Return the merged list of all sequence names, maintaining order.
+ * Return the merged list of all sequence names, maintaining order. As sequence name conventions might
+ * vary between bam files ("1" vs "chr1", etc), the loaded genome canonical name is used for the sequence
+ * names of the merged bams. Consequentally we need to keep a seq name map per bam file (reader) to substitute
+ * back when querying.* * *
*
* @return
*/
public void loadSequenceNames() throws IOException {
- // Use a set for quick comparison
+
+ Genome genome = GenomeManager.getInstance().getCurrentGenome();
+
+ readerChrNameMaps = new HashMap<>();
+
LinkedHashSet names = new LinkedHashSet(50);
for (AlignmentReader reader : readers) {
- names.addAll(reader.getSequenceNames());
- }
- sequenceNames = new ArrayList(names);
- Genome genome = GenomeManager.getInstance().getCurrentGenome();
- chrNameIndex = new HashMap(sequenceNames.size());
- for (int i = 0; i < sequenceNames.size(); i++) {
- final String seqName = sequenceNames.get(i);
- String chr = genome == null ? seqName : genome.getCanonicalChrName(seqName);
- chrNameIndex.put(chr, i);
+ Map chrNameMap = new HashMap<>();
+
+ List readerSequenceNames = reader.getSequenceNames();
+ for (String seq : readerSequenceNames) {
+ String chr = genome.getCanonicalChrName(seq);
+ names.add(chr);
+
+ chrNameMap.put(chr, seq);
+ }
+ readerChrNameMaps.put(reader, chrNameMap);
}
+ sequenceNames = new ArrayList<>(names);
+
+
}
- private SAMFileHeader loadHeaders(){
+ private SAMFileHeader loadHeaders() {
List headersList = new ArrayList();
SAMFileHeader.SortOrder sortOrder = null;
- for(AlignmentReader reader: readers){
+ for (AlignmentReader reader : readers) {
SAMFileHeader curHeader = reader.getFileHeader();
- if(curHeader != null) {
+ if (curHeader != null) {
headersList.add(curHeader);
sortOrder = curHeader.getSortOrder();
}
}
- if(sortOrder != null){
+ if (sortOrder != null) {
SamFileHeaderMerger headerMerger = new SamFileHeaderMerger(sortOrder, headersList, true);
return headerMerger.getMergedHeader();
}
@@ -163,7 +176,8 @@ private void create(String chr, int start, int end, boolean contained) throws IO
if (iterate) {
iter = reader.iterator();
} else {
- iter = reader.query(chr, start, end, contained);
+ String seq = readerChrNameMaps.get(reader).get(chr);
+ iter = reader.query(seq, start, end, contained);
}
allIterators.add(iter);
if (iter.hasNext()) {
@@ -231,18 +245,8 @@ class AlignmentStartComparator implements Comparator {
public int compare(RecordIterWrapper wrapper1, RecordIterWrapper wrapper2) {
Alignment a1 = wrapper1.nextRecord;
Alignment a2 = wrapper2.nextRecord;
+ return a1.getAlignmentStart() - a2.getAlignmentStart();
- Integer idx1 = chrNameIndex.get(a1.getChr());
- Integer idx2 = chrNameIndex.get(a2.getChr());
- if(idx1==null) idx1 = Integer.MAX_VALUE;
- if(idx2== null) idx2 = Integer.MAX_VALUE; // Put these records at the end.
- if (idx1 > idx2) {
- return 1;
- } else if (idx1 < idx2) {
- return -1;
- } else {
- return a1.getAlignmentStart() - a2.getAlignmentStart();
- }
}
}
}
From bc32f74d6f6817fdb1ca967397f5668524282c0a Mon Sep 17 00:00:00 2001
From: jrobinso <933148+jrobinso@users.noreply.github.com>
Date: Fri, 16 Dec 2022 18:49:02 -0800
Subject: [PATCH 018/116] npe check
---
.../java/org/broad/igv/sam/reader/MergedAlignmentReader.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/org/broad/igv/sam/reader/MergedAlignmentReader.java b/src/main/java/org/broad/igv/sam/reader/MergedAlignmentReader.java
index f1794efcd7..e7a8b3dc90 100644
--- a/src/main/java/org/broad/igv/sam/reader/MergedAlignmentReader.java
+++ b/src/main/java/org/broad/igv/sam/reader/MergedAlignmentReader.java
@@ -176,7 +176,7 @@ private void create(String chr, int start, int end, boolean contained) throws IO
if (iterate) {
iter = reader.iterator();
} else {
- String seq = readerChrNameMaps.get(reader).get(chr);
+ String seq = readerChrNameMaps.containsKey(reader) ? readerChrNameMaps.get(reader).get(chr) : chr;
iter = reader.query(seq, start, end, contained);
}
allIterators.add(iter);
From b6337613dff7a6e46d35316c3d9d3876240665d8 Mon Sep 17 00:00:00 2001
From: jrobinso <933148+jrobinso@users.noreply.github.com>
Date: Fri, 16 Dec 2022 21:28:16 -0800
Subject: [PATCH 019/116] Fix alignment sort order for merged bams
---
.../igv/sam/reader/MergedAlignmentReader.java | 8 +++--
.../sam/reader/MergedAlignmentReaderTest.java | 30 +++++++++++++++++--
2 files changed, 34 insertions(+), 4 deletions(-)
diff --git a/src/main/java/org/broad/igv/sam/reader/MergedAlignmentReader.java b/src/main/java/org/broad/igv/sam/reader/MergedAlignmentReader.java
index e7a8b3dc90..f61a393bd6 100644
--- a/src/main/java/org/broad/igv/sam/reader/MergedAlignmentReader.java
+++ b/src/main/java/org/broad/igv/sam/reader/MergedAlignmentReader.java
@@ -245,8 +245,12 @@ class AlignmentStartComparator implements Comparator {
public int compare(RecordIterWrapper wrapper1, RecordIterWrapper wrapper2) {
Alignment a1 = wrapper1.nextRecord;
Alignment a2 = wrapper2.nextRecord;
- return a1.getAlignmentStart() - a2.getAlignmentStart();
-
+ int chrCompare = a1.getChr().compareTo(a2.getChr());
+ if (chrCompare != 0) {
+ return chrCompare;
+ } else {
+ return a1.getAlignmentStart() - a2.getAlignmentStart();
+ }
}
}
}
diff --git a/src/test/java/org/broad/igv/sam/reader/MergedAlignmentReaderTest.java b/src/test/java/org/broad/igv/sam/reader/MergedAlignmentReaderTest.java
index 471924d860..3a4cbf8808 100644
--- a/src/test/java/org/broad/igv/sam/reader/MergedAlignmentReaderTest.java
+++ b/src/test/java/org/broad/igv/sam/reader/MergedAlignmentReaderTest.java
@@ -42,6 +42,7 @@
import java.util.Map;
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
/**
* @author jacob
@@ -49,7 +50,7 @@
*/
public class MergedAlignmentReaderTest extends AbstractHeadlessTest {
- public static String[] generateRepLargebamsList(File listFile) throws IOException{
+ public static String[] generateRepLargebamsList(File listFile) throws IOException {
listFile.delete();
listFile.deleteOnExit();
String listPath = listFile.getPath();
@@ -57,7 +58,8 @@ public static String[] generateRepLargebamsList(File listFile) throws IOExceptio
return IGVToolsTest.generateRepLargebamsList(listPath, "HG00171.hg18.bam", 2);
}
- @Test @Ignore("Requires largedata bundle")
+ @Test
+ @Ignore("Requires largedata bundle")
public void testSimpleRead() throws Exception {
File listFile = new File(TestUtils.LARGE_DATA_DIR, "2largebams.bam.list");
@@ -109,4 +111,28 @@ public void testSimpleRead() throws Exception {
}
}
+
+ @Test
+ public void testSortOrder() throws Exception {
+ String listPath = TestUtils.DATA_DIR + "bam/test.unindexed.bam.list";
+
+ AlignmentReader mergedReader = AlignmentReaderFactory.getBamListReader(listPath, false);
+ CloseableIterator iter = mergedReader.iterator();
+
+ int lastPosition = 0;
+ String lastChr = "";
+ while (iter.hasNext()) {
+ Alignment a = iter.next();
+ String chr = a.getChr();
+ int pos = a.getAlignmentStart();
+ assertTrue(chr.compareTo(lastChr) >= 0);
+ if(lastChr.equals(chr)) {
+ assertTrue(pos >= lastPosition);
+ }
+ lastChr = chr;
+ lastPosition = pos;
+ }
+ iter.close();
+ }
+
}
From 639f20017cec098405e014f2f1c12a4a12530e1d Mon Sep 17 00:00:00 2001
From: jrobinso <933148+jrobinso@users.noreply.github.com>
Date: Fri, 16 Dec 2022 21:41:09 -0800
Subject: [PATCH 020/116] Account for chr name aliasing when sorting merged bam
alignments
---
.../org/broad/igv/sam/reader/MergedAlignmentReader.java | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/main/java/org/broad/igv/sam/reader/MergedAlignmentReader.java b/src/main/java/org/broad/igv/sam/reader/MergedAlignmentReader.java
index f61a393bd6..e2d2f2a27f 100644
--- a/src/main/java/org/broad/igv/sam/reader/MergedAlignmentReader.java
+++ b/src/main/java/org/broad/igv/sam/reader/MergedAlignmentReader.java
@@ -46,6 +46,7 @@
public class MergedAlignmentReader implements AlignmentReader {
private static Logger log = LogManager.getLogger(MergedAlignmentReader.class);
+ private final Genome genome;
List readers;
List sequenceNames;
@@ -56,6 +57,7 @@ public class MergedAlignmentReader implements AlignmentReader {
public MergedAlignmentReader(List readers) throws IOException {
this.readers = readers;
+ this.genome = GenomeManager.getInstance().getCurrentGenome();
loadSequenceNames();
}
@@ -105,8 +107,6 @@ public SAMFileHeader getFileHeader() {
*/
public void loadSequenceNames() throws IOException {
- Genome genome = GenomeManager.getInstance().getCurrentGenome();
-
readerChrNameMaps = new HashMap<>();
LinkedHashSet names = new LinkedHashSet(50);
@@ -245,7 +245,7 @@ class AlignmentStartComparator implements Comparator {
public int compare(RecordIterWrapper wrapper1, RecordIterWrapper wrapper2) {
Alignment a1 = wrapper1.nextRecord;
Alignment a2 = wrapper2.nextRecord;
- int chrCompare = a1.getChr().compareTo(a2.getChr());
+ int chrCompare = genome.getCanonicalChrName(a1.getChr()).compareTo(genome.getCanonicalChrName(a2.getChr()));
if (chrCompare != 0) {
return chrCompare;
} else {
From 8bbd1cdb60976d0eb1964ce1f718994a04646110 Mon Sep 17 00:00:00 2001
From: jrobinso <933148+jrobinso@users.noreply.github.com>
Date: Wed, 21 Dec 2022 21:51:30 -0800
Subject: [PATCH 021/116] Add preference to perform "group" menu action on all
alignmnet tracks at once. See issue #1275
* WORK IN PROGRESS *
---
.../java/org/broad/igv/prefs/Constants.java | 1 +
.../org/broad/igv/sam/AlignmentTrack.java | 9 +++++
.../org/broad/igv/sam/AlignmentTrackMenu.java | 39 +++++++++++++++----
.../java/org/broad/igv/util/HttpUtils.java | 18 +++++++++
.../org/broad/igv/prefs/preferences.tab | 1 +
5 files changed, 60 insertions(+), 8 deletions(-)
diff --git a/src/main/java/org/broad/igv/prefs/Constants.java b/src/main/java/org/broad/igv/prefs/Constants.java
index ce0f93e133..8723324578 100644
--- a/src/main/java/org/broad/igv/prefs/Constants.java
+++ b/src/main/java/org/broad/igv/prefs/Constants.java
@@ -145,6 +145,7 @@ private Constants() {
public static final String SAM_COLOR_BY_TAG = "SAM.COLOR_BY_TAG";
public static final String SAM_SORT_BY_TAG = "SAM.SORT_BY_TAG";
public static final String SAM_GROUP_BY_TAG = "SAM.GROUP_BY_TAG";
+ public static final String SAM_GROUP_ALL = "SAM.GROUP_ALL";
public static final String SAM_LINK_BY_TAGS = "SAM.LINK_BY_TAGS";
public static final String SAM_GROUP_BY_POS = "SAM.GROUP_BY_POS";
public static final String SAM_BISULFITE_CONTEXT = "SAM.BISULFITE_CONTEXT";
diff --git a/src/main/java/org/broad/igv/sam/AlignmentTrack.java b/src/main/java/org/broad/igv/sam/AlignmentTrack.java
index 117d9c0511..9d0596fbf3 100644
--- a/src/main/java/org/broad/igv/sam/AlignmentTrack.java
+++ b/src/main/java/org/broad/igv/sam/AlignmentTrack.java
@@ -1340,6 +1340,7 @@ public static class RenderOptions implements Cloneable, Persistable {
private Range groupByPos;
private Boolean invertSorting;
private boolean invertGroupSorting;
+ private boolean groupAll;
private Boolean showInsertionMarkers;
private Boolean hideSmallIndels;
private Integer smallIndelThreshold;
@@ -1426,6 +1427,10 @@ void setInvertGroupSorting(boolean invertGroupSorting) {
this.invertGroupSorting = invertGroupSorting;
}
+ public void setGroupAll(boolean groupAll) {
+ this.groupAll = groupAll;
+ }
+
void setLinkByTag(String linkByTag) {
this.linkByTag = linkByTag;
}
@@ -1582,6 +1587,10 @@ public boolean isInvertGroupSorting() {
return invertGroupSorting;
}
+ public boolean isGroupAll() {
+ return groupAll;
+ }
+
public String getLinkByTag() {
return linkByTag;
}
diff --git a/src/main/java/org/broad/igv/sam/AlignmentTrackMenu.java b/src/main/java/org/broad/igv/sam/AlignmentTrackMenu.java
index 13969b1dcf..88caf3c2f2 100644
--- a/src/main/java/org/broad/igv/sam/AlignmentTrackMenu.java
+++ b/src/main/java/org/broad/igv/sam/AlignmentTrackMenu.java
@@ -9,6 +9,7 @@
import org.broad.igv.lists.GeneList;
import org.broad.igv.logging.LogManager;
import org.broad.igv.logging.Logger;
+import org.broad.igv.prefs.Constants;
import org.broad.igv.prefs.PreferencesManager;
import org.broad.igv.sashimi.SashimiPlot;
import org.broad.igv.session.Session;
@@ -211,8 +212,7 @@ private void addHaplotype(TrackClickEvent e) {
boolean success = haplotypeUtils.clusterAlignments(frame.getChrName(), start, end, nClusters);
if (success) {
- alignmentTrack.groupAlignments(AlignmentTrack.GroupOption.HAPLOTYPE, null, null);
- alignmentTrack.repaint();
+ groupAlignments(AlignmentTrack.GroupOption.HAPLOTYPE, null, null);
}
//dataManager.sortRows(SortOption.HAPLOTYPE, frame, (end + start) / 2, null);
@@ -338,6 +338,9 @@ private JCheckBoxMenuItem getExperimentTypeMenuItem(String label, final Alignmen
}
void addGroupMenuItem(final TrackClickEvent te) {//ReferenceFrame frame) {
+
+
+
final MouseEvent me = te.getMouseEvent();
ReferenceFrame frame = te.getFrame();
if (frame == null) {
@@ -363,7 +366,8 @@ void addGroupMenuItem(final TrackClickEvent te) {//ReferenceFrame frame) {
JCheckBoxMenuItem mi = new JCheckBoxMenuItem(option.label);
mi.setSelected(renderOptions.getGroupByOption() == option);
mi.addActionListener(aEvt -> {
- alignmentTrack.groupAlignments(option, null, null);
+ groupAlignments(option, null, null);
+
});
groupMenu.add(mi);
group.add(mi);
@@ -374,9 +378,9 @@ void addGroupMenuItem(final TrackClickEvent te) {//ReferenceFrame frame) {
String tag = MessageUtils.showInputDialog("Enter tag", renderOptions.getGroupByTag());
if (tag != null) {
if (tag.trim().length() > 0) {
- alignmentTrack.groupAlignments(AlignmentTrack.GroupOption.TAG, tag, null);
+ groupAlignments(AlignmentTrack.GroupOption.TAG, tag, null);
} else {
- alignmentTrack.groupAlignments(AlignmentTrack.GroupOption.NONE, null, null);
+ groupAlignments(AlignmentTrack.GroupOption.NONE, null, null);
}
}
@@ -399,7 +403,7 @@ void addGroupMenuItem(final TrackClickEvent te) {//ReferenceFrame frame) {
":" + Globals.DECIMAL_FORMAT.format(1 + chromStart));
newGroupByPosOption.addActionListener(aEvt -> {
Range groupByPos = new Range(chrom, chromStart, chromStart + 1);
- alignmentTrack.groupAlignments(AlignmentTrack.GroupOption.BASE_AT_POS, null, groupByPos);
+ groupAlignments(AlignmentTrack.GroupOption.BASE_AT_POS, null, groupByPos);
});
groupMenu.add(newGroupByPosOption);
group.add(newGroupByPosOption);
@@ -415,6 +419,15 @@ void addGroupMenuItem(final TrackClickEvent te) {//ReferenceFrame frame) {
});
groupMenu.add(invertGroupNameSortingOption);
+ JCheckBoxMenuItem groupAllOption = new JCheckBoxMenuItem("Reverse group order");
+ groupAllOption.setSelected(renderOptions.isInvertGroupSorting());
+ groupAllOption.addActionListener(aEvt -> {
+ renderOptions.setGroupAll(!renderOptions.isGroupAll());
+ dataManager.packAlignments(renderOptions);
+ alignmentTrack.repaint();
+ });
+ groupMenu.add(invertGroupNameSortingOption);
+
add(groupMenu);
}
@@ -586,7 +599,7 @@ void addColorByMenuItem() {
mappings.put("SMRT CCS fwd-strand aligned IPD", AlignmentTrack.ColorOption.SMRT_CCS_FWD_IPD);
mappings.put("SMRT CCS fwd-strand aligned PW", AlignmentTrack.ColorOption.SMRT_CCS_FWD_PW);
mappings.put("SMRT CCS rev-strand aligned IPD", AlignmentTrack.ColorOption.SMRT_CCS_REV_IPD);
- mappings.put("SMRT CCS rev-strand aligned PW",AlignmentTrack.ColorOption.SMRT_CCS_REV_PW);
+ mappings.put("SMRT CCS rev-strand aligned PW", AlignmentTrack.ColorOption.SMRT_CCS_REV_PW);
colorMenu.addSeparator();
for (Map.Entry el : mappings.entrySet()) {
JRadioButtonMenuItem mi = getColorMenuItem(el.getKey(), el.getValue());
@@ -1184,7 +1197,7 @@ private void splitScreenMate(ReferenceFrame frame, Alignment alignment) {
GeneList geneList = new GeneList(listName.toString(), loci, false);
currentSession.setCurrentGeneList(geneList);
-
+
Comparator geneListComparator = (n0, n1) -> {
ReferenceFrame f0 = FrameManager.getFrame(n0);
ReferenceFrame f1 = FrameManager.getFrame(n1);
@@ -1251,6 +1264,16 @@ private void setLinkByTag(boolean linkReads, String tag) {
repaint();
}
+ private void groupAlignments(AlignmentTrack.GroupOption option, String tag, Range pos) {
+ if (alignmentTrack.getPreferences().getAsBoolean(SAM_GROUP_ALL)) {
+ for(AlignmentTrack t : IGV.getInstance().getAlignmentTracks()) {
+ t.groupAlignments(option, tag, pos);
+ }
+ } else {
+ alignmentTrack.groupAlignments(option, tag, pos);
+ }
+ }
+
/**
* Listener for deselecting one component when another is selected
diff --git a/src/main/java/org/broad/igv/util/HttpUtils.java b/src/main/java/org/broad/igv/util/HttpUtils.java
index 47fbd7ece0..bfa592479f 100644
--- a/src/main/java/org/broad/igv/util/HttpUtils.java
+++ b/src/main/java/org/broad/igv/util/HttpUtils.java
@@ -197,6 +197,11 @@ public static URL createURL(String urlString) throws MalformedURLException {
*/
public static String mapURL(String urlString) throws MalformedURLException {
+ // Check explicit mappings first
+ if(urlMappings.containsKey(urlString)) {
+ return urlMappings.get(urlString);
+ }
+
if (urlString.startsWith("htsget://")) {
urlString = urlString.replace("htsget://", "https://");
} else if (urlString.startsWith("gs://")) {
@@ -1189,4 +1194,17 @@ public long getMaxAge() {
return maxAge;
}
}
+
+ private static Map urlMappings;
+ static {
+ // mutable map
+ urlMappings = new HashMap<>();
+ urlMappings.put("https://s3.amazonaws.com/igv.broadinstitute.org/genomes/seq/hg19/hg19.fasta", "https://igv.genepattern.org/genomes/seq/hg19/hg19.fasta");
+ urlMappings.put("https://s3.amazonaws.com/igv.broadinstitute.org/genomes/seq/hg19/hg19.fasta.fai", "https://igv.genepattern.org/genomes/seq/hg19/hg19.fasta.fai");
+ urlMappings.put("https://s3.amazonaws.com/igv.broadinstitute.org/genomes/seq/hg19/cytoBand.txt", "https://igv.genepattern.org/genomes/seq/hg19/cytoBand.txt");
+ urlMappings.put("https://s3.amazonaws.com/igv.broadinstitute.org/genomes/seq/hg38/hg38.fa", "https://igv.genepattern.org/genomes/seq/hg38/hg38.fa");
+ urlMappings.put("https://s3.amazonaws.com/igv.broadinstitute.org/genomes/seq/hg38/hg38.fa.fai", "https://igv.genepattern.org/genomes/seq/hg38/hg38.fa.fai");
+ }
+
+
}
diff --git a/src/main/resources/org/broad/igv/prefs/preferences.tab b/src/main/resources/org/broad/igv/prefs/preferences.tab
index 9129618993..995013b641 100644
--- a/src/main/resources/org/broad/igv/prefs/preferences.tab
+++ b/src/main/resources/org/broad/igv/prefs/preferences.tab
@@ -88,6 +88,7 @@ SAM.COLOR_BY Color alignments by select NONE|READ_STRAND|FIRST_OF_PAIR_STRAND|PA
SAM.COLOR_BY_TAG Color by TAG string
SAM.GROUP_OPTION Group alignments by select NONE|STRAND|SAMPLE|READ_GROUP|LIBRARY|FIRST_OF_PAIR_STRAND|TAG|PAIR_ORIENTATION|MATE_CHROMOSOME|SV_ALIGNMENT|SUPPLEMENTARY|BASE_AT_POS|MOVIE|ZMW|HAPLOTYPE|READ_ORDER|LINKED|PHASE|MAPPING_QUALITY
SAM.GROUP_BY_TAG Group by TAG string
+SAM.GROUP_ALL Sync alignment track grouping boolean FALSE
SAM.MAX_VISIBLE_RANGE Visibility range threshold (kb) float 30 Range at which alignments become visibile
SAM.QUALITY_THRESHOLD Mapping quality threshold int 0 Hide alignments with MQ lower than this value
SAM.ALIGNMENT_SCORE_THRESHOLD Alignment score threshold int 0
From 26ac437182e83abdc3c02d191fcb5c694a2b5daa Mon Sep 17 00:00:00 2001
From: jrobinso <933148+jrobinso@users.noreply.github.com>
Date: Thu, 22 Dec 2022 10:31:35 -0800
Subject: [PATCH 022/116] set default for SMRT kinetics preference
---
src/main/resources/org/broad/igv/prefs/preferences.tab | 2 +-
test/data/bam/platinum.bam.list | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
create mode 100644 test/data/bam/platinum.bam.list
diff --git a/src/main/resources/org/broad/igv/prefs/preferences.tab b/src/main/resources/org/broad/igv/prefs/preferences.tab
index 995013b641..5d6a2707a7 100644
--- a/src/main/resources/org/broad/igv/prefs/preferences.tab
+++ b/src/main/resources/org/broad/igv/prefs/preferences.tab
@@ -241,7 +241,7 @@ CIRC_VIEW_PORT CircView port integer 60152
SAM.SHOW_JUNCTION_FLANKINGREGIONS FALSE
SAM.JUNCTION_MIN_FLANKING_WIDTH 0
SAM.JUNCTION_MIN_COVERAGE 1
-
+SMRT_KINETICS.SHOW_OPTIONS FALSE
SCORE_VARIANTS FALSE
diff --git a/test/data/bam/platinum.bam.list b/test/data/bam/platinum.bam.list
new file mode 100644
index 0000000000..3a6360b2df
--- /dev/null
+++ b/test/data/bam/platinum.bam.list
@@ -0,0 +1,3 @@
+gs://genomics-public-data/platinum-genomes/bam/NA12889_S1.bam
+gs://genomics-public-data/platinum-genomes/bam/NA12877_S1.bam
+gs://genomics-public-data/platinum-genomes/bam/NA12878_S1.bam
From 3a37c0c4d4fa0f88bea84321020060e74c83e3c8 Mon Sep 17 00:00:00 2001
From: jrobinso <933148+jrobinso@users.noreply.github.com>
Date: Thu, 22 Dec 2022 10:32:22 -0800
Subject: [PATCH 023/116] set default for SMRT kinetics preference
---
src/main/resources/org/broad/igv/prefs/preferences.tab | 2 +-
test/data/bam/platinum.bam.list | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
create mode 100644 test/data/bam/platinum.bam.list
diff --git a/src/main/resources/org/broad/igv/prefs/preferences.tab b/src/main/resources/org/broad/igv/prefs/preferences.tab
index 9129618993..8c66e1e92c 100644
--- a/src/main/resources/org/broad/igv/prefs/preferences.tab
+++ b/src/main/resources/org/broad/igv/prefs/preferences.tab
@@ -240,7 +240,7 @@ CIRC_VIEW_PORT CircView port integer 60152
SAM.SHOW_JUNCTION_FLANKINGREGIONS FALSE
SAM.JUNCTION_MIN_FLANKING_WIDTH 0
SAM.JUNCTION_MIN_COVERAGE 1
-
+SMRT_KINETICS.SHOW_OPTIONS FALSE
SCORE_VARIANTS FALSE
diff --git a/test/data/bam/platinum.bam.list b/test/data/bam/platinum.bam.list
new file mode 100644
index 0000000000..3a6360b2df
--- /dev/null
+++ b/test/data/bam/platinum.bam.list
@@ -0,0 +1,3 @@
+gs://genomics-public-data/platinum-genomes/bam/NA12889_S1.bam
+gs://genomics-public-data/platinum-genomes/bam/NA12877_S1.bam
+gs://genomics-public-data/platinum-genomes/bam/NA12878_S1.bam
From 548e34a455fa008bf19582c4de747b2410cfef5e Mon Sep 17 00:00:00 2001
From: jrobinso <933148+jrobinso@users.noreply.github.com>
Date: Wed, 4 Jan 2023 21:03:46 -0800
Subject: [PATCH 024/116] Allow "alias.tab.txt" extension in addition to
"alias.tab". Some plain text editors will append a ".txt" extension
---
src/main/java/org/broad/igv/feature/genome/GenomeManager.java | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/main/java/org/broad/igv/feature/genome/GenomeManager.java b/src/main/java/org/broad/igv/feature/genome/GenomeManager.java
index 444419056e..b43082b606 100644
--- a/src/main/java/org/broad/igv/feature/genome/GenomeManager.java
+++ b/src/main/java/org/broad/igv/feature/genome/GenomeManager.java
@@ -200,6 +200,9 @@ public Genome loadGenome(String genomePath, ProgressMonitor monitor) throws IOEx
// Load user-defined chr aliases, if any. This is done last so they have priority
try {
String aliasPath = (new File(DirectoryManager.getGenomeCacheDirectory(), newGenome.getId() + "_alias.tab")).getAbsolutePath();
+ if(!(new File(aliasPath)).exists()) {
+ aliasPath = (new File(DirectoryManager.getGenomeCacheDirectory(), newGenome.getId() + "_alias.tab.txt")).getAbsolutePath();
+ }
if ((new File(aliasPath)).exists()) {
newGenome.addChrAliases(GenomeLoader.loadChrAliases(aliasPath));
}
From 67f843a7eab6926bafa27779884d1e094f856aba Mon Sep 17 00:00:00 2001
From: jrobinso <933148+jrobinso@users.noreply.github.com>
Date: Thu, 5 Jan 2023 12:01:42 -0800
Subject: [PATCH 025/116] Fix broken blat export
---
.../java/org/broad/igv/feature/PSLRecord.java | 88 +++++++++++++++++--
.../broad/igv/feature/tribble/PSLCodec.java | 12 ++-
test/data/psl/humanBlat.psl | 7 ++
3 files changed, 94 insertions(+), 13 deletions(-)
create mode 100644 test/data/psl/humanBlat.psl
diff --git a/src/main/java/org/broad/igv/feature/PSLRecord.java b/src/main/java/org/broad/igv/feature/PSLRecord.java
index b7c7cd0554..39400f6c9d 100644
--- a/src/main/java/org/broad/igv/feature/PSLRecord.java
+++ b/src/main/java/org/broad/igv/feature/PSLRecord.java
@@ -30,9 +30,35 @@
/**
* @author jrobinso
- * Date: 11/29/12
- * Time: 6:59 PM
+ * Date: 11/29/12
+ * Time: 6:59 PM
+ *
+ *
+ * * 1. matches - Number of bases that match that aren't repeats
+ * * 2. misMatches - Number of bases that don't match
+ * * 3. repMatches - Number of bases that match but are part of repeats
+ * * 4. nCount - Number of 'N' bases
+ * * 5. qNumInsert - Number of inserts in query
+ * * 6. qBaseInsert - Number of bases inserted in query
+ * * 7. tNumInsert - Number of inserts in target
+ * * 8. tBaseInsert - Number of bases inserted in target
+ * * 9. strand - '+' or '-' for query strand. For translated alignments, second '+'or '-' is for genomic strand
+ * * 10. qName - Query sequence name
+ * * 11. qSize - Query sequence size
+ * * 12. qStart - Alignment start position in query
+ * * 13. qEnd - Alignment end position in query
+ * * 14. tName - Target sequence name
+ * * 15. tSize - Target sequence size
+ * * 16. tStart - Alignment start position in target
+ * * 17. tEnd - Alignment end position in target
+ * * 18. blockCount - Number of blocks in the alignment (a block contains no gaps)
+ * * 19. blockSizes - Comma-separated list of sizes of each block
+ * * 20. qStarts - Comma-separated list of starting positions of each block in query
+ * * 21. tStarts - Comma-separated list of starting positions of each block in target
+ * *
+ * * 59 9 0 0 1 823 1 96 +- FS_CONTIG_48080_1 1955 171 1062 chr22 47748585 13073589 13073753 2 48,20, 171,1042, 34674832,34674976,* *
*/
+
public class PSLRecord extends BasicFeature {
@@ -48,8 +74,11 @@ public class PSLRecord extends BasicFeature {
private int ns;
private int qGapBases;
private int tGapBases;
- private String text;
+ private String blockQueryStarts;
+
+ private int qStart;
+ private int qEnd;
public void setMatch(int match) {
this.match = match;
@@ -71,6 +100,14 @@ public void setTGapCount(int TNumInsert) {
this.tGapCount = TNumInsert;
}
+ public void setqStart(int qStart) {
+ this.qStart = qStart;
+ }
+
+ public void setqEnd(int qEnd) {
+ this.qEnd = qEnd;
+ }
+
public void setQSize(int qSize) {
this.qSize = qSize;
}
@@ -135,11 +172,50 @@ public int getTGapBases() {
return tGapBases;
}
- public void setText(String text) {
- this.text = text;
+ public void setBlockQueryStarts(String blockQueryStarts) {
+ this.blockQueryStarts = blockQueryStarts;
}
+// 128999999952YourSeq 1289128chr3 9364096243640974310119, 0 36409615,
public String getText() {
- return text;
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(match + "\t"); // 0
+ buffer.append(misMatch + "\t"); // 1
+ buffer.append(repMatch + "\t"); // 2
+ buffer.append(ns + "\t"); // 3
+ buffer.append(qGapCount + "\t"); // 4
+ buffer.append(qGapBases + "\t"); // 5
+ buffer.append(tGapCount + "\t"); // 6
+ buffer.append(tGapBases + "\t"); // 7
+ buffer.append((strand == Strand.POSITIVE ? '+' : '-') + "\t"); // 8
+ buffer.append(name + "\t"); // 9
+ buffer.append(qSize + "\t"); // 10
+ buffer.append(qStart + "\t"); // 11
+ buffer.append(qEnd + "\t"); // 12
+ buffer.append(chr + "\t"); // 13
+ buffer.append(tSize + "\t"); // 14
+ buffer.append(start + "\t"); // 15
+ buffer.append(end + "\t"); // 16
+ buffer.append(exons.size() + "\t"); // 17
+
+ // block sizes // 18
+ for (Exon exon : exons) {
+ buffer.append(exon.getLength() + ",");
+ }
+ buffer.append("\t");
+
+ buffer.append(blockQueryStarts + "\t"); // 19
+
+ // block target starts // 20
+ for (Exon exon : exons) {
+ buffer.append(exon.getStart() + ",");
+ }
+ buffer.append("\t");
+
+
+ /*
+
+ */
+ return buffer.toString();
}
}
diff --git a/src/main/java/org/broad/igv/feature/tribble/PSLCodec.java b/src/main/java/org/broad/igv/feature/tribble/PSLCodec.java
index 00753f324a..38643ce58d 100644
--- a/src/main/java/org/broad/igv/feature/tribble/PSLCodec.java
+++ b/src/main/java/org/broad/igv/feature/tribble/PSLCodec.java
@@ -98,10 +98,6 @@ public PSLRecord decode(String line) {
f = getPslRecord(tokens, genome);
if (f == null) return null;
- if(keepText) {
- f.setText(line);
- }
-
} catch (NumberFormatException e) {
return null;
}
@@ -167,9 +163,6 @@ public static PSLRecord getPslRecord(String[] tokens, Genome genome) {
for (int i = 0; i < startsBuffer.length; i++) {
int exonSize = Integer.parseInt(exonSizes[i]);
int exonStart = Integer.parseInt(startsBuffer[i]);
- if (gNeg) {
- exonStart = tSize - exonStart - exonSize;
- }
int exonEnd = exonStart + exonSize;
Exon exon = new Exon(chr, exonStart, exonEnd, strand);
f.addExon(exon);
@@ -188,6 +181,8 @@ public static PSLRecord getPslRecord(String[] tokens, Genome genome) {
int tGapCount = Integer.parseInt(tokens[6]);
int tGapBases = Integer.parseInt(tokens[7]);
int qSize = Integer.parseInt(tokens[10]);
+ int qStart = Integer.parseInt(tokens[11]);
+ int qEnd = Integer.parseInt(tokens[12]);
float score = (1000.0f * (match + repMatch - misMatch - qGapCount - tGapCount)) / qSize;
@@ -200,6 +195,9 @@ public static PSLRecord getPslRecord(String[] tokens, Genome genome) {
f.setTGapCount(tGapCount);
f.setTGapBases(tGapBases);
f.setQSize(qSize);
+ f.setqStart(qStart);
+ f.setqEnd(qEnd);
+ f.setBlockQueryStarts(tokens[19]);
f.setScore(score);
diff --git a/test/data/psl/humanBlat.psl b/test/data/psl/humanBlat.psl
new file mode 100644
index 0000000000..1858b111ef
--- /dev/null
+++ b/test/data/psl/humanBlat.psl
@@ -0,0 +1,7 @@
+#hg38 query - ATTCTGCACAGTGACACTGACTTGAAGATATCTTGTATCCACTCCATCCATCCACGTGCATCTTGGGGAAAAATAGAGGAGGCAAGTCATGCATTAAATTATCAAGGTAATATATTTCA
+119 0 0 0 0 0 0 0 + YourSeq 119 0 119 chr3 198295559 36409615 36409734 1 119, 0, 36409615,
+27 0 0 0 0 0 1 145 + YourSeq 119 92 119 chr6 170805979 84433944 84434116 2 18,9, 92,110, 84433944,84434107,
+23 0 0 0 0 0 0 0 - YourSeq 119 63 86 chr4 190214555 114187126 114187149 1 23, 33, 114187126,
+24 0 0 0 1 1 1 2 + YourSeq 119 56 81 chr5 181538259 165141490 165141516 2 7,17, 56,64, 165141490,165141499,
+23 0 0 0 1 1 0 0 + YourSeq 119 60 84 chr3 198295559 40347823 40347846 2 4,19, 60,65, 40347823,40347827,
+21 0 0 0 0 0 0 0 - YourSeq 119 3 24 chr10 133797422 96204441 96204462 1 21, 95, 96204441,
From 02287bf819652718ffac4f120f3b92dd54862472 Mon Sep 17 00:00:00 2001
From: jrobinso <933148+jrobinso@users.noreply.github.com>
Date: Mon, 9 Jan 2023 10:03:53 -0800
Subject: [PATCH 026/116] Updat info message for alignment track preferences
---
src/main/resources/org/broad/igv/prefs/preferences.tab | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/main/resources/org/broad/igv/prefs/preferences.tab b/src/main/resources/org/broad/igv/prefs/preferences.tab
index 8c66e1e92c..288fc8ca02 100644
--- a/src/main/resources/org/broad/igv/prefs/preferences.tab
+++ b/src/main/resources/org/broad/igv/prefs/preferences.tab
@@ -70,7 +70,8 @@ CN_FREQ.AMP_THRESHOLD CN freq amplification threshold float 0.1
CN_FREQ.DEL_THRESHOLD CN freq deletion threshold float -0.1
#Alignments
-info Settings for alignment tracks. See the RNA or Third Gen tabs to override for specific types.
+info Default settings for alignment tracks. A subset of these properties are overriden for RNA and 3rd generation data.
+info See the RNA or Third Gen tabs for those track types.
##Track Display
SAM.SHOW_ALIGNMENT_TRACK Show alignment track boolean TRUE
@@ -83,7 +84,6 @@ SAM.SAMPLING_WINDOW Sampling window size (bases) integer 50
SAM.MAX_LEVELS Number of reads per window integer 100
##Alignment Track Options
-
SAM.COLOR_BY Color alignments by select NONE|READ_STRAND|FIRST_OF_PAIR_STRAND|PAIR_ORIENTATION|UNEXPECTED_PAIR|INSERT_SIZE|SAMPLE|READ_GROUP|LIBRARY|MOVIE|ZMW|BISULFITE|NOMESEQ|TAG|MAPPED_SIZE|LINK_STRAND|YC_TAG UNEXPECTED_PAIR
SAM.COLOR_BY_TAG Color by TAG string
SAM.GROUP_OPTION Group alignments by select NONE|STRAND|SAMPLE|READ_GROUP|LIBRARY|FIRST_OF_PAIR_STRAND|TAG|PAIR_ORIENTATION|MATE_CHROMOSOME|SV_ALIGNMENT|SUPPLEMENTARY|BASE_AT_POS|MOVIE|ZMW|HAPLOTYPE|READ_ORDER|LINKED|PHASE|MAPPING_QUALITY
From 543f80d823de718b39f0856deab8c5af6179c068 Mon Sep 17 00:00:00 2001
From: Jim Robinson <933148+jrobinso@users.noreply.github.com>
Date: Tue, 10 Jan 2023 12:45:11 -0800
Subject: [PATCH 027/116] Group all (#1277)
* Updat info message for alignment track preferences
* Add option to group all alignment tracks. Fixes #1275
---
.../java/org/broad/igv/prefs/Constants.java | 2 ++
.../org/broad/igv/sam/AlignmentTrackMenu.java | 30 +++++++++++++++----
.../org/broad/igv/prefs/preferences.tab | 7 +++--
3 files changed, 31 insertions(+), 8 deletions(-)
diff --git a/src/main/java/org/broad/igv/prefs/Constants.java b/src/main/java/org/broad/igv/prefs/Constants.java
index ce0f93e133..787223c720 100644
--- a/src/main/java/org/broad/igv/prefs/Constants.java
+++ b/src/main/java/org/broad/igv/prefs/Constants.java
@@ -139,6 +139,8 @@ private Constants() {
public static final String SAM_SORT_OPTION = "SAM.SORT_OPTION";
public static final String SAM_INVERT_SORT = "SAM.INVERT_SORT";
public static final String SAM_GROUP_OPTION = "SAM.GROUP_OPTION";
+
+ public static final String SAM_GROUP_ALL = "SAM.GROUP_ALL";
public static final String SAM_SHOW_ALL_BASES = "SAM.SHOW_ALL_BASES";
public static final String SAM_SHOW_MISMATCHES = "SAM.SHOW_MISMATCHES";
public static final String SAM_COLOR_BY = "SAM.COLOR_BY";
diff --git a/src/main/java/org/broad/igv/sam/AlignmentTrackMenu.java b/src/main/java/org/broad/igv/sam/AlignmentTrackMenu.java
index 13969b1dcf..645ce451e7 100644
--- a/src/main/java/org/broad/igv/sam/AlignmentTrackMenu.java
+++ b/src/main/java/org/broad/igv/sam/AlignmentTrackMenu.java
@@ -9,6 +9,7 @@
import org.broad.igv.lists.GeneList;
import org.broad.igv.logging.LogManager;
import org.broad.igv.logging.Logger;
+import org.broad.igv.prefs.Constants;
import org.broad.igv.prefs.PreferencesManager;
import org.broad.igv.sashimi.SashimiPlot;
import org.broad.igv.session.Session;
@@ -211,7 +212,7 @@ private void addHaplotype(TrackClickEvent e) {
boolean success = haplotypeUtils.clusterAlignments(frame.getChrName(), start, end, nClusters);
if (success) {
- alignmentTrack.groupAlignments(AlignmentTrack.GroupOption.HAPLOTYPE, null, null);
+ groupAlignments(AlignmentTrack.GroupOption.HAPLOTYPE, null, null);
alignmentTrack.repaint();
}
@@ -363,7 +364,7 @@ void addGroupMenuItem(final TrackClickEvent te) {//ReferenceFrame frame) {
JCheckBoxMenuItem mi = new JCheckBoxMenuItem(option.label);
mi.setSelected(renderOptions.getGroupByOption() == option);
mi.addActionListener(aEvt -> {
- alignmentTrack.groupAlignments(option, null, null);
+ groupAlignments(option, null, null);
});
groupMenu.add(mi);
group.add(mi);
@@ -374,9 +375,9 @@ void addGroupMenuItem(final TrackClickEvent te) {//ReferenceFrame frame) {
String tag = MessageUtils.showInputDialog("Enter tag", renderOptions.getGroupByTag());
if (tag != null) {
if (tag.trim().length() > 0) {
- alignmentTrack.groupAlignments(AlignmentTrack.GroupOption.TAG, tag, null);
+ groupAlignments(AlignmentTrack.GroupOption.TAG, tag, null);
} else {
- alignmentTrack.groupAlignments(AlignmentTrack.GroupOption.NONE, null, null);
+ groupAlignments(AlignmentTrack.GroupOption.NONE, null, null);
}
}
@@ -399,7 +400,7 @@ void addGroupMenuItem(final TrackClickEvent te) {//ReferenceFrame frame) {
":" + Globals.DECIMAL_FORMAT.format(1 + chromStart));
newGroupByPosOption.addActionListener(aEvt -> {
Range groupByPos = new Range(chrom, chromStart, chromStart + 1);
- alignmentTrack.groupAlignments(AlignmentTrack.GroupOption.BASE_AT_POS, null, groupByPos);
+ groupAlignments(AlignmentTrack.GroupOption.BASE_AT_POS, null, groupByPos);
});
groupMenu.add(newGroupByPosOption);
group.add(newGroupByPosOption);
@@ -415,9 +416,28 @@ void addGroupMenuItem(final TrackClickEvent te) {//ReferenceFrame frame) {
});
groupMenu.add(invertGroupNameSortingOption);
+ JCheckBoxMenuItem groupAllOption = new JCheckBoxMenuItem("Group all tracks");
+ groupAllOption.setSelected(alignmentTrack.getPreferences().getAsBoolean(SAM_GROUP_ALL));
+ groupAllOption.addActionListener(aEvt -> {
+ alignmentTrack.getPreferences().put(SAM_GROUP_ALL, groupAllOption.getState());
+ });
+ groupMenu.add(groupAllOption);
+
add(groupMenu);
}
+ private void groupAlignments(AlignmentTrack.GroupOption option, String tag, Range pos) {
+
+ if(alignmentTrack.getPreferences().getAsBoolean(SAM_GROUP_ALL)) {
+ for(AlignmentTrack t : IGV.getInstance().getAlignmentTracks()) {
+ t.groupAlignments(option, tag, pos);
+ }
+ } else {
+ alignmentTrack.groupAlignments(option, tag, pos);
+ }
+ }
+
+
/**
* Sort menu
*/
diff --git a/src/main/resources/org/broad/igv/prefs/preferences.tab b/src/main/resources/org/broad/igv/prefs/preferences.tab
index 8c66e1e92c..c76beca360 100644
--- a/src/main/resources/org/broad/igv/prefs/preferences.tab
+++ b/src/main/resources/org/broad/igv/prefs/preferences.tab
@@ -70,7 +70,8 @@ CN_FREQ.AMP_THRESHOLD CN freq amplification threshold float 0.1
CN_FREQ.DEL_THRESHOLD CN freq deletion threshold float -0.1
#Alignments
-info Settings for alignment tracks. See the RNA or Third Gen tabs to override for specific types.
+info Default settings for alignment tracks. A subset of these properties are overriden for RNA and 3rd generation data.
+info See the RNA or Third Gen tabs for those track types.
##Track Display
SAM.SHOW_ALIGNMENT_TRACK Show alignment track boolean TRUE
@@ -83,7 +84,6 @@ SAM.SAMPLING_WINDOW Sampling window size (bases) integer 50
SAM.MAX_LEVELS Number of reads per window integer 100
##Alignment Track Options
-
SAM.COLOR_BY Color alignments by select NONE|READ_STRAND|FIRST_OF_PAIR_STRAND|PAIR_ORIENTATION|UNEXPECTED_PAIR|INSERT_SIZE|SAMPLE|READ_GROUP|LIBRARY|MOVIE|ZMW|BISULFITE|NOMESEQ|TAG|MAPPED_SIZE|LINK_STRAND|YC_TAG UNEXPECTED_PAIR
SAM.COLOR_BY_TAG Color by TAG string
SAM.GROUP_OPTION Group alignments by select NONE|STRAND|SAMPLE|READ_GROUP|LIBRARY|FIRST_OF_PAIR_STRAND|TAG|PAIR_ORIENTATION|MATE_CHROMOSOME|SV_ALIGNMENT|SUPPLEMENTARY|BASE_AT_POS|MOVIE|ZMW|HAPLOTYPE|READ_ORDER|LINKED|PHASE|MAPPING_QUALITY
@@ -252,7 +252,6 @@ SAM.BISULFITE_CONTEXT CG
SAM.NOMESEQ_ENABLED FALSE
SAM.COUNT_DELETED_BASES_COVERED FALSE
SAM.SORT_OPTION NUCLEOTIDE
-SAM.GROUP_OPTION NONE
SAM.COLOR_BY UNEXPECTED_PAIR
SAM.SHOW_GROUP_SEPARATOR TRUE
SAM.REDUCED_MEMORY_MODE FALSE
@@ -261,6 +260,8 @@ SAM.COLOR.C 0,0,255
SAM.COLOR.G 209,113,5
SAM.COLOR.N 182,182,182
SAM.COLOR.T 255,0,0
+SAM.GROUP_ALL FALSE
+SAM.INVERT_SORT FALSE
SEARCH_ZOOM TRUE
From fa6aea65249a050aa837ff603ba980d072e391d8 Mon Sep 17 00:00:00 2001
From: jrobinso <933148+jrobinso@users.noreply.github.com>
Date: Thu, 12 Jan 2023 11:15:27 -0800
Subject: [PATCH 028/116] insure experimentType preferences, e.g. hiding
junction track, get set even if # reads sampled is < threshold. See issue
#1276
---
src/main/java/org/broad/igv/sam/AlignmentTrack.java | 8 +++-----
src/main/java/org/broad/igv/sam/ReadStats.java | 2 +-
2 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/src/main/java/org/broad/igv/sam/AlignmentTrack.java b/src/main/java/org/broad/igv/sam/AlignmentTrack.java
index 117d9c0511..0a0b4570b2 100644
--- a/src/main/java/org/broad/igv/sam/AlignmentTrack.java
+++ b/src/main/java/org/broad/igv/sam/AlignmentTrack.java
@@ -348,11 +348,9 @@ public AlignmentTrack(ResourceLocator locator, AlignmentDataManager dataManager,
}
public void init() {
- if (experimentType == null) {
+ if (experimentType == null || experimentType == ExperimentType.UNKOWN) {
ExperimentType type = dataManager.inferType();
- if (type != null) {
- setExperimentType(type);
- }
+ setExperimentType(type);
}
}
@@ -1020,7 +1018,7 @@ public void setViewAsPairs(boolean vAP) {
}
- public enum ExperimentType {OTHER, RNA, BISULFITE, THIRD_GEN}
+ public enum ExperimentType {OTHER, RNA, BISULFITE, THIRD_GEN, UNKOWN}
class RenderRollback {
diff --git a/src/main/java/org/broad/igv/sam/ReadStats.java b/src/main/java/org/broad/igv/sam/ReadStats.java
index cf2981c509..14bd051722 100644
--- a/src/main/java/org/broad/igv/sam/ReadStats.java
+++ b/src/main/java/org/broad/igv/sam/ReadStats.java
@@ -134,7 +134,7 @@ private double[] downsample(DoubleArrayList list, int size) {
public AlignmentTrack.ExperimentType inferType() {
compute();
- if (readCount < 20) return null; // Not enough reads
+ if (readCount < 20) return AlignmentTrack.ExperimentType.UNKOWN; // Not enough reads
if ((readLengthStdDev > 100 || medianReadLength > 1000) && averageCigarLength > 10) { // Cigar length to filter consensus reads
return AlignmentTrack.ExperimentType.THIRD_GEN;
} else if (medianRefToReadRatio > 5 || fracReadsWithNs > 0.01) {
From 9b4af247f847fd5812433118a88555cce0191cbb Mon Sep 17 00:00:00 2001
From: jrobinso <933148+jrobinso@users.noreply.github.com>
Date: Thu, 12 Jan 2023 19:05:28 -0800
Subject: [PATCH 029/116] bug fix
---
src/main/java/org/broad/igv/prefs/Constants.java | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/main/java/org/broad/igv/prefs/Constants.java b/src/main/java/org/broad/igv/prefs/Constants.java
index cc5336644d..787223c720 100644
--- a/src/main/java/org/broad/igv/prefs/Constants.java
+++ b/src/main/java/org/broad/igv/prefs/Constants.java
@@ -147,7 +147,6 @@ private Constants() {
public static final String SAM_COLOR_BY_TAG = "SAM.COLOR_BY_TAG";
public static final String SAM_SORT_BY_TAG = "SAM.SORT_BY_TAG";
public static final String SAM_GROUP_BY_TAG = "SAM.GROUP_BY_TAG";
- public static final String SAM_GROUP_ALL = "SAM.GROUP_ALL";
public static final String SAM_LINK_BY_TAGS = "SAM.LINK_BY_TAGS";
public static final String SAM_GROUP_BY_POS = "SAM.GROUP_BY_POS";
public static final String SAM_BISULFITE_CONTEXT = "SAM.BISULFITE_CONTEXT";
From 990116866e9c46dd6947aa4b50585381bb20c891 Mon Sep 17 00:00:00 2001
From: jrobinso <933148+jrobinso@users.noreply.github.com>
Date: Fri, 20 Jan 2023 10:27:12 -0800
Subject: [PATCH 030/116] Make "Enter" from either url or index filed trigger
"Load from url" ok button. See #1273
---
src/main/java/org/broad/igv/ui/util/LoadFromURLDialog.java | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/main/java/org/broad/igv/ui/util/LoadFromURLDialog.java b/src/main/java/org/broad/igv/ui/util/LoadFromURLDialog.java
index 5416daa0b7..b1588c29af 100644
--- a/src/main/java/org/broad/igv/ui/util/LoadFromURLDialog.java
+++ b/src/main/java/org/broad/igv/ui/util/LoadFromURLDialog.java
@@ -181,6 +181,11 @@ private void initComponents() {
contentPane.add(dialogPane, BorderLayout.CENTER);
pack();
setLocationRelativeTo(getOwner());
+
+ // Make "enter" trigger the ok button
+ fileField.addActionListener(e -> okButtonActionPerformed(e));
+ indexField.addActionListener(e -> okButtonActionPerformed(e));
+ this.rootPane.setDefaultButton(okButton);
// JFormDesigner - End of component initialization //GEN-END:initComponents
}
From eb3edc7bbb03e1f409d9e9818af8a08c7c1fcc00 Mon Sep 17 00:00:00 2001
From: jrobinso <933148+jrobinso@users.noreply.github.com>
Date: Fri, 20 Jan 2023 16:15:43 -0800
Subject: [PATCH 031/116] Allow multiple URLs in load menu. Fixes #1273
---
.../igv/ui/action/LoadFromURLMenuAction.java | 125 +++++++-----------
.../java/org/broad/igv/util/GoogleUtils.java | 3 +-
2 files changed, 48 insertions(+), 80 deletions(-)
diff --git a/src/main/java/org/broad/igv/ui/action/LoadFromURLMenuAction.java b/src/main/java/org/broad/igv/ui/action/LoadFromURLMenuAction.java
index e46c76bd3b..6dac928b86 100644
--- a/src/main/java/org/broad/igv/ui/action/LoadFromURLMenuAction.java
+++ b/src/main/java/org/broad/igv/ui/action/LoadFromURLMenuAction.java
@@ -29,12 +29,10 @@
*/
package org.broad.igv.ui.action;
+import org.broad.igv.Globals;
import org.broad.igv.logging.*;
-import org.broad.igv.exceptions.HttpResponseException;
import org.broad.igv.feature.genome.GenomeManager;
import org.broad.igv.util.GoogleUtils;
-import org.broad.igv.oauth.OAuthProvider;
-import org.broad.igv.oauth.OAuthUtils;
import org.broad.igv.prefs.Constants;
import org.broad.igv.prefs.PreferencesManager;
import org.broad.igv.session.SessionReader;
@@ -43,18 +41,13 @@
import org.broad.igv.ui.util.LoadFromURLDialog;
import org.broad.igv.ui.util.MessageUtils;
import org.broad.igv.util.AmazonUtils;
-import org.broad.igv.util.HttpUtils;
import org.broad.igv.util.LongRunningTask;
import org.broad.igv.util.ResourceLocator;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.ArrayList;
import static org.broad.igv.util.AmazonUtils.isObjectAccessible;
@@ -64,9 +57,7 @@
public class LoadFromURLMenuAction extends MenuAction {
static Logger log = LogManager.getLogger(LoadFilesMenuAction.class);
- public static final String LOAD_FROM_DAS = "Load from DAS...";
public static final String LOAD_FROM_URL = "Load from URL...";
- public static final String LOAD_FILE_AND_INDEX_FROM_URLS = "Load file and index from URLs...";
public static final String LOAD_GENOME_FROM_URL = "Load Genome from URL...";
private IGV igv;
@@ -87,59 +78,58 @@ public void actionPerformed(ActionEvent e) {
if (!dlg.isCanceled()) {
- String inputURL = dlg.getFileURL();
+ String inputURLs = dlg.getFileURL();
+ if (inputURLs != null && inputURLs.trim().length() > 0) {
- if (inputURL != null && inputURL.trim().length() > 0) {
-
- final String url = mapURL(inputURL.trim());
-
- if (url.startsWith("s3://")) {
- checkAWSAccessbility(url);
- }
-
- if (SessionReader.isSessionFile(url)) {
+ String[] inputs = Globals.whitespacePattern.split(inputURLs.trim());
+ checkURLs(inputs);
+ if (inputs.length == 1 && SessionReader.isSessionFile(inputs[0])) {
+ // Session URL
+ String url = inputs[0];
+ if (url.startsWith("s3://")) {
+ checkAWSAccessbility(url);
+ }
try {
LongRunningTask.submit(() -> this.igv.loadSession(url, null));
} catch (Exception ex) {
MessageUtils.showMessage("Error loading url: " + url + " (" + ex.toString() + ")");
}
} else {
- ResourceLocator rl = new ResourceLocator(url.trim());
-
- if (dlg.getIndexURL() != null) {
- String indexUrl = dlg.getIndexURL().trim();
-
- if (GoogleUtils.isGoogleURL(indexUrl)) {
- enableGoogleMenu();
+ // Files, possibly indexed
+ String[] indexes = null;
+ String indexURLs = dlg.getIndexURL();
+ if (indexURLs != null && indexURLs.trim().length() > 0) {
+ indexes = Globals.whitespacePattern.split(indexURLs.trim());
+ if (indexes.length != inputs.length) {
+ throw new RuntimeException("The number of Index URLs must equal the number of File URLs");
}
-
- rl.setIndexPath(indexUrl);
+ checkURLs(indexes);
}
- igv.loadTracks(Arrays.asList(rl));
+ ArrayList locators = new ArrayList<>();
+ for (int i = 0; i < inputs.length; i++) {
+ String url = inputs[i];
+ ResourceLocator rl = new ResourceLocator(url.trim());
+ if (indexes != null) {
+ String indexUrl = indexes[i];
+ rl.setIndexPath(indexUrl);
+ }
+ locators.add(rl);
+ }
+ igv.loadTracks(locators);
}
}
}
- } else if ((e.getActionCommand().equalsIgnoreCase(LOAD_FROM_DAS))) {
- String url = JOptionPane.showInputDialog(IGV.getInstance().getMainFrame(), ta, "Enter DAS feature source URL",
- JOptionPane.QUESTION_MESSAGE);
- if (url != null && url.trim().length() > 0) {
- ResourceLocator rl = new ResourceLocator(url.trim());
- rl.setFormat("das");
- igv.loadTracks(Arrays.asList(rl));
- }
} else if ((e.getActionCommand().equalsIgnoreCase(LOAD_GENOME_FROM_URL))) {
+
String url = JOptionPane.showInputDialog(IGV.getInstance().getMainFrame(), ta, "Enter URL to .genome or FASTA file",
JOptionPane.QUESTION_MESSAGE);
+
if (url != null && url.trim().length() > 0) {
- if (url.startsWith("s3://")) {
- checkAWSAccessbility(url);
- } else if (url.startsWith("ftp://")) {
- MessageUtils.showMessage("FTP protocol is not supported");
- }
+ url = url.trim();
try {
- url = mapURL(url);
- GenomeManager.getInstance().loadGenome(url.trim(), null);
+ checkURLs(new String[]{url});
+ GenomeManager.getInstance().loadGenome(url, null);
} catch (Exception e1) {
MessageUtils.showMessage("Error loading genome: " + e1.getMessage());
}
@@ -148,16 +138,19 @@ public void actionPerformed(ActionEvent e) {
}
}
- private String mapURL(String url) {
-
- url = url.trim();
- if (GoogleUtils.isGoogleURL(url)) {
- enableGoogleMenu();
+ private void checkURLs(String[] urls) {
+ for (String url : urls) {
+ if (url.startsWith("s3://")) {
+ checkAWSAccessbility(url);
+ } else if (GoogleUtils.isGoogleURL(url)) {
+ enableGoogleMenu();
+ } else if (url.startsWith("ftp://")) {
+ MessageUtils.showMessage("FTP protocol is not supported");
+ }
}
-
- return url;
}
+
private void enableGoogleMenu() {
if (!PreferencesManager.getPreferences().getAsBoolean(Constants.ENABLE_GOOGLE_MENU)) {
@@ -184,31 +177,5 @@ private void checkAWSAccessbility(String url) {
AmazonUtils.checkLogin();
}
}
-
- private boolean ping(String url) {
- InputStream is = null;
- try {
- Map params = new HashMap();
- params.put("Range", "bytes=0-10");
- byte[] buffer = new byte[10];
- is = HttpUtils.getInstance().openConnectionStream(HttpUtils.createURL(url), params);
- is.read(buffer);
- is.close();
- } catch (HttpResponseException e1) {
- MessageUtils.showMessage(e1.getMessage());
- return false;
- } catch (IOException e) {
- log.error(e);
-
- } finally {
- if (is != null) try {
- is.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- return true;
- }
}
diff --git a/src/main/java/org/broad/igv/util/GoogleUtils.java b/src/main/java/org/broad/igv/util/GoogleUtils.java
index 079f724c3c..c8f47de7bf 100644
--- a/src/main/java/org/broad/igv/util/GoogleUtils.java
+++ b/src/main/java/org/broad/igv/util/GoogleUtils.java
@@ -39,7 +39,8 @@ public static boolean isGoogleDrive(String url) {
public static boolean isGoogleStorageURL(String url) {
return url != null &&
- (url.startsWith("https://www.googleapis.com/storage") ||
+ (url.startsWith("gs://") ||
+ url.startsWith("https://www.googleapis.com/storage") ||
url.startsWith("https://storage.cloud.google.com") ||
url.startsWith("https://storage.googleapis.com"));
}
From a41b0296aa4526232dc64bb41332cfddf15b7274 Mon Sep 17 00:00:00 2001
From: jrobinso <933148+jrobinso@users.noreply.github.com>
Date: Fri, 20 Jan 2023 16:26:39 -0800
Subject: [PATCH 032/116] Skip setting user preferences if in batch mode
(command runner or port command). See issue #1271
---
.../org/broad/igv/prefs/IGVPreferences.java | 32 ++++++++++++-------
1 file changed, 20 insertions(+), 12 deletions(-)
diff --git a/src/main/java/org/broad/igv/prefs/IGVPreferences.java b/src/main/java/org/broad/igv/prefs/IGVPreferences.java
index da1ba04361..325bff1ab2 100644
--- a/src/main/java/org/broad/igv/prefs/IGVPreferences.java
+++ b/src/main/java/org/broad/igv/prefs/IGVPreferences.java
@@ -262,19 +262,27 @@ private void clearCaches() {
mutationColorScheme = null;
}
+ /**
+ * Update preference. This command is ignored if in batch mode *
+ * @param key
+ * @param value
+ */
public void put(String key, String value) {
- key = key.trim();
- // Explicitly setting removes override
- overrideKeys.remove(key);
+ if (!Globals.isBatch()) {
+ key = key.trim();
- if (value == null || value.trim().length() == 0) {
- userPreferences.remove(key);
- } else {
- userPreferences.put(key, value);
+ // Explicitly setting removes override
+ overrideKeys.remove(key);
+
+ if (value == null || value.trim().length() == 0) {
+ userPreferences.remove(key);
+ } else {
+ userPreferences.put(key, value);
+ }
+ updateCaches(key, value);
+ IGVEventBus.getInstance().post(new PreferencesChangeEvent());
}
- updateCaches(key, value);
- IGVEventBus.getInstance().post(new PreferencesChangeEvent());
}
public void put(String key, boolean b) {
@@ -358,9 +366,9 @@ private void checkForCommandListenerChanges(Map updatedPreferenc
private void checkForAttributePanelChanges(Map updatedPreferenceMap) {
if (updatedPreferenceMap.containsKey(SHOW_ATTRIBUTE_VIEWS_KEY) || updatedPreferenceMap.containsKey(SHOW_DEFAULT_TRACK_ATTRIBUTES)) {
- if(IGV.hasInstance()) {
- IGV.getInstance().revalidateTrackPanels();
- }
+ if (IGV.hasInstance()) {
+ IGV.getInstance().revalidateTrackPanels();
+ }
}
}
From 0e41fbf1bcfd7c41005de665d16091b0fbb24481 Mon Sep 17 00:00:00 2001
From: Louis Bergelson
Date: Sat, 21 Jan 2023 00:36:58 -0500
Subject: [PATCH 033/116] Add feature threshold indicator to zoom widget
(#1196)
* implementing getVisibilityWindow()
* Add feature threshold indicator to zoom widget
* Add an indicator to show which zoom level will start dispalying features/reads
* closes https://github.com/igvteam/igv/issues/1192
* Reduce transparency value for zoom slider viz window indicator to "25".
Update text session xml
* fix exception when feature window size was larger than the contig length
* extracted a log2 function instead of using a wierd static log2 constant everywhere
Co-authored-by: jrobinso <933148+jrobinso@users.noreply.github.com>
---
src/main/java/org/broad/igv/Globals.java | 6 ++--
.../java/org/broad/igv/data/seg/FreqData.java | 2 +-
.../org/broad/igv/sam/AlignmentTrack.java | 7 +++-
.../java/org/broad/igv/sam/CoverageTrack.java | 7 +++-
.../igv/sashimi/SashimiJunctionRenderer.java | 2 +-
.../tools/converters/ExpressionFormatter.java | 2 +-
.../org/broad/igv/track/AbstractTrack.java | 2 +-
.../broad/igv/ui/panel/ReferenceFrame.java | 7 ++--
.../broad/igv/ui/panel/ZoomSliderPanel.java | 33 ++++++++++++++++++-
.../base_mods/HIFI_basemodifictions.xml | 14 ++++----
10 files changed, 62 insertions(+), 20 deletions(-)
diff --git a/src/main/java/org/broad/igv/Globals.java b/src/main/java/org/broad/igv/Globals.java
index c2737439ea..502eebaf88 100644
--- a/src/main/java/org/broad/igv/Globals.java
+++ b/src/main/java/org/broad/igv/Globals.java
@@ -26,9 +26,7 @@
package org.broad.igv;
import org.broad.igv.logging.*;
-import org.broad.igv.renderer.SequenceRenderer;
-import java.io.IOException;
import java.text.DecimalFormat;
import java.util.*;
import java.util.List;
@@ -88,7 +86,6 @@ public class Globals {
public static String VERSION;
public static String BUILD;
public static String TIMESTAMP;
- public static double log2 = Math.log(2);
final public static boolean IS_WINDOWS =
@@ -197,4 +194,7 @@ public static boolean checkJavaVersion(String minVersion) {
return curVersion.compareTo(minVersion) >= 0;
}
+ public static double log2(final double value) {
+ return Math.log(value) / Math.log(2);
+ }
}
diff --git a/src/main/java/org/broad/igv/data/seg/FreqData.java b/src/main/java/org/broad/igv/data/seg/FreqData.java
index 0f122a9142..e3473af0bf 100644
--- a/src/main/java/org/broad/igv/data/seg/FreqData.java
+++ b/src/main/java/org/broad/igv/data/seg/FreqData.java
@@ -120,7 +120,7 @@ public void compute(float ampThreshold, float delThreshold) {
for (LocusScore seg : segments) {
final float segScore = logNormalized ? seg.getScore() :
- (float) (Math.log(seg.getScore() / 2) / Globals.log2);
+ (float) (Globals.log2(seg.getScore() / 2));
if (segScore > ampThreshold || segScore < delThreshold) {
diff --git a/src/main/java/org/broad/igv/sam/AlignmentTrack.java b/src/main/java/org/broad/igv/sam/AlignmentTrack.java
index 0a0b4570b2..3f306adf42 100644
--- a/src/main/java/org/broad/igv/sam/AlignmentTrack.java
+++ b/src/main/java/org/broad/igv/sam/AlignmentTrack.java
@@ -506,10 +506,15 @@ public void load(ReferenceFrame referenceFrame) {
dataManager.load(referenceFrame, renderOptions, true);
}
+ @Override
+ public int getVisibilityWindow() {
+ return (int) dataManager.getVisibilityWindow();
+ }
+
public void render(RenderContext context, Rectangle rect) {
int viewWindowSize = context.getReferenceFrame().getCurrentRange().getLength();
- if (viewWindowSize > dataManager.getVisibilityWindow()) {
+ if (viewWindowSize > getVisibilityWindow()) {
Rectangle visibleRect = context.getVisibleRect().intersection(rect);
Graphics2D g2 = context.getGraphic2DForColor(Color.gray);
GraphicUtils.drawCenteredText("Zoom in to see alignments.", visibleRect, g2);
diff --git a/src/main/java/org/broad/igv/sam/CoverageTrack.java b/src/main/java/org/broad/igv/sam/CoverageTrack.java
index 5ff9f89d7e..e271bd767f 100644
--- a/src/main/java/org/broad/igv/sam/CoverageTrack.java
+++ b/src/main/java/org/broad/igv/sam/CoverageTrack.java
@@ -214,10 +214,15 @@ public void unload() {
setVisible(false);
}
+ @Override
+ public int getVisibilityWindow() {
+ return (int) dataManager.getVisibilityWindow();
+ }
+
public void render(RenderContext context, Rectangle rect) {
int viewWindowSize = context.getReferenceFrame().getCurrentRange().getLength();
- if (viewWindowSize > dataManager.getVisibilityWindow() && dataSource == null) {
+ if (viewWindowSize > getVisibilityWindow() && dataSource == null) {
Rectangle visibleRect = context.getVisibleRect().intersection(rect);
Graphics2D g = context.getGraphic2DForColor(Color.gray);
GraphicUtils.drawCenteredText("Zoom in to see coverage.", visibleRect, g);
diff --git a/src/main/java/org/broad/igv/sashimi/SashimiJunctionRenderer.java b/src/main/java/org/broad/igv/sashimi/SashimiJunctionRenderer.java
index b294da01f5..97694b1909 100644
--- a/src/main/java/org/broad/igv/sashimi/SashimiJunctionRenderer.java
+++ b/src/main/java/org/broad/igv/sashimi/SashimiJunctionRenderer.java
@@ -362,7 +362,7 @@ protected void drawFeature(int pixelYStartOffset, int pixelYEndOffset,
int length = pixelJunctionEnd - pixelJunctionStart;
int minArcHeight = (trackRectangle.height - 1) / 8;
//We adjust the height slightly by length of junction, just so arcs don't overlap as much
- int arcHeight = minArcHeight + (int) (Math.log(length) / Globals.log2);
+ int arcHeight = minArcHeight + (int) (Globals.log2(length));
int minY = (int) trackRectangle.getCenterY() + Math.min(pixelYStartOffset - arcHeight, pixelYEndOffset - arcHeight);
//Check if arc goes too high. All arcs going below have the same height,
diff --git a/src/main/java/org/broad/igv/tools/converters/ExpressionFormatter.java b/src/main/java/org/broad/igv/tools/converters/ExpressionFormatter.java
index b807887bf9..6b90a59aea 100644
--- a/src/main/java/org/broad/igv/tools/converters/ExpressionFormatter.java
+++ b/src/main/java/org/broad/igv/tools/converters/ExpressionFormatter.java
@@ -192,7 +192,7 @@ class DataRow {
throw new RuntimeException("Negative value detected in input file: " + line);
}
- double v = Math.log(data[dataIdx]) / Globals.log2;
+ double v = Globals.log2(data[dataIdx]);
scaledData[dataIdx] = v;
nonNullData[nNonNull] = v;
nNonNull++;
diff --git a/src/main/java/org/broad/igv/track/AbstractTrack.java b/src/main/java/org/broad/igv/track/AbstractTrack.java
index fda4333ca1..85893be5ab 100644
--- a/src/main/java/org/broad/igv/track/AbstractTrack.java
+++ b/src/main/java/org/broad/igv/track/AbstractTrack.java
@@ -806,7 +806,7 @@ public float logScaleData(float dataY) {
double centerValue = (getTrackType() == TrackType.ALLELE_SPECIFIC_COPY_NUMBER)
? 1.0 : 2.0;
- return (float) (Math.log(Math.max(Float.MIN_VALUE, dataY) / centerValue) / Globals.log2);
+ return (float) (Globals.log2(Math.max(Float.MIN_VALUE, dataY) / centerValue));
} else {
return dataY;
}
diff --git a/src/main/java/org/broad/igv/ui/panel/ReferenceFrame.java b/src/main/java/org/broad/igv/ui/panel/ReferenceFrame.java
index 6e261a778d..2758372c7a 100644
--- a/src/main/java/org/broad/igv/ui/panel/ReferenceFrame.java
+++ b/src/main/java/org/broad/igv/ui/panel/ReferenceFrame.java
@@ -498,7 +498,7 @@ private boolean shouldChangeChromosome(String newChrName) {
protected void calculateMaxZoom() {
this.maxZoom = Globals.CHR_ALL.equals(this.chrName) ? 0 :
- (int) Math.ceil(Math.log(getChromosomeLength() / minBP) / Globals.log2);
+ (int) Math.ceil(Globals.log2(getChromosomeLength() / minBP));
}
public String getChrName() {
@@ -714,8 +714,9 @@ private void beforeScaleZoom(Locus locus) {
* @param end
* @return
*/
- private int calculateZoom(double start, double end) {
- return (int) Math.round((Math.log((getChromosomeLength() / (end - start)) * (((double) widthInPixels) / binsPerTile)) / Globals.log2));
+ public int calculateZoom(double start, double end) {
+ final double windowLength = Math.min(end - start, getChromosomeLength());
+ return (int) Math.round(Globals.log2((getChromosomeLength() / windowLength) * (((double) widthInPixels) / binsPerTile)));
}
diff --git a/src/main/java/org/broad/igv/ui/panel/ZoomSliderPanel.java b/src/main/java/org/broad/igv/ui/panel/ZoomSliderPanel.java
index b3954207e0..c78082b958 100644
--- a/src/main/java/org/broad/igv/ui/panel/ZoomSliderPanel.java
+++ b/src/main/java/org/broad/igv/ui/panel/ZoomSliderPanel.java
@@ -33,13 +33,20 @@
*/
package org.broad.igv.ui.panel;
+import org.broad.igv.track.Track;
+import org.broad.igv.ui.IGV;
import org.broad.igv.ui.util.IGVMouseInputAdapter;
import org.broad.igv.ui.util.IconFactory;
import javax.swing.*;
import javax.swing.event.MouseInputAdapter;
+
+import java.util.List;
import java.awt.*;
import java.awt.event.MouseEvent;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
/**
* @author jrobinso
@@ -47,6 +54,7 @@
public class ZoomSliderPanel extends JPanel {
private static final Color TRANSPARENT_GRAY = new Color(200, 200, 200, 150);
+ private static final Color TRANSPARENT_BLUE = new Color(27, 96, 246, 25);
static Color TICK_GRAY = new Color(90, 90, 90);
static Color TICK_BLUE = new Color(25, 50, 200);
@@ -103,7 +111,6 @@ private void updateTickCount() {
numZoomLevels = tmp;
zoomLevelRects = new Rectangle[numZoomLevels];
}
-
}
@@ -193,9 +200,33 @@ protected void paintHorizontal(Graphics g) {
//g.drawImage(slider, x + 1, y, null);
}
}
+
+ paintVisibilityThresholds(transGraphics);
transGraphics.dispose();
}
+ //Adds an indicator of which zoom level will display reads/features
+ private void paintVisibilityThresholds(final Graphics2D transGraphics) {
+ if(numZoomLevels > 1) {
+ List visibilityThresholds = IGV.getInstance().getAllTracks().stream()
+ .map(Track::getVisibilityWindow)
+ .filter(i -> i > 0)
+ .sorted()
+ .distinct()
+ .map(threshold -> this.getReferenceFrame().calculateZoom(0, threshold))
+ .collect(Collectors.toList());
+
+ transGraphics.setColor(TRANSPARENT_BLUE);
+ Rectangle maxZoom = zoomLevelRects[zoomLevelRects.length - 1];
+ for (Integer window : visibilityThresholds) {
+ final Rectangle currentLevel = zoomLevelRects[window];
+ Rectangle windowBox = new Rectangle(currentLevel.x, currentLevel.y,
+ maxZoom.x + maxZoom.width - currentLevel.x, currentLevel.height);
+ transGraphics.fill(windowBox);
+ }
+ }
+ }
+
void setZoom(MouseEvent e) {
if (zoomPlusRect.contains(e.getX(), e.getY())) {
diff --git a/test/sessions/base_mods/HIFI_basemodifictions.xml b/test/sessions/base_mods/HIFI_basemodifictions.xml
index b8e02a156c..2c581bbe7f 100644
--- a/test/sessions/base_mods/HIFI_basemodifictions.xml
+++ b/test/sessions/base_mods/HIFI_basemodifictions.xml
@@ -1,22 +1,22 @@
-
+
-
+
-
+
-
+
-
+
From 441d13876911d2852d41a4a0f5844a8e78320b7d Mon Sep 17 00:00:00 2001
From: tomkp75
Date: Tue, 21 Feb 2023 12:40:43 -0500
Subject: [PATCH 034/116] Adding Access-Control-Allow-Headers (#1284)
* Adding Access-Control-Allow-Headers
Adding Access-Control-Allow-Headers to sendHTTPOptionsResponse for options preflight to pass
* Print CRLF vs println (cross-platform)
Print CRLF instead of using println for this to work on all platforms
---
src/main/java/org/broad/igv/batch/CommandListener.java | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/main/java/org/broad/igv/batch/CommandListener.java b/src/main/java/org/broad/igv/batch/CommandListener.java
index df99b658a2..ff0992fa46 100755
--- a/src/main/java/org/broad/igv/batch/CommandListener.java
+++ b/src/main/java/org/broad/igv/batch/CommandListener.java
@@ -312,7 +312,8 @@ private void closeSockets() {
private static final String CONNECTION_CLOSE = "Connection: close";
private static final String NO_CACHE = "Cache-Control: no-cache, no-store";
private static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin: *";
-
+ private static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers: access-control-allow-origin";
+
private void sendTextResponse(PrintWriter out, String result) {
sendHTTPResponse(out, result, "text/html", "GET");
}
@@ -348,6 +349,8 @@ private void sendHTTPOptionsResponse(PrintWriter out) {
out.print(CRLF);
out.print(ACCESS_CONTROL_ALLOW_ORIGIN);
out.print(CRLF);
+ out.print(ACCESS_CONTROL_ALLOW_HEADERS);
+ out.print(CRLF);
out.println("Access-Control-Allow-Methods: HEAD, GET, OPTIONS");
out.print(CRLF);
From 33e754dd430d351a8c8316f8922ccec3f1a8d856 Mon Sep 17 00:00:00 2001
From: jrobinso <933148+jrobinso@users.noreply.github.com>
Date: Tue, 21 Feb 2023 12:00:28 -0800
Subject: [PATCH 035/116] Reduce needless use of reflection to instantiate
renderer objects
---
.../igv/feature/EmblFeatureTableParser.java | 2 +-
.../igv/feature/dranger/DRangerParser.java | 2 +-
.../broad/igv/sam/SpliceJunctionTrack.java | 7 ++++--
.../org/broad/igv/sashimi/SashimiPlot.java | 2 +-
.../org/broad/igv/track/AbstractTrack.java | 2 +-
.../igv/track/CombinedDataSourceDialog.java | 2 +-
.../java/org/broad/igv/track/DataTrack.java | 2 +-
.../org/broad/igv/track/FeatureTrack.java | 2 +-
.../igv/track/SelectableFeatureTrack.java | 2 +-
.../java/org/broad/igv/track/TrackLoader.java | 14 +++++------
.../org/broad/igv/track/TrackMenuUtils.java | 25 ++-----------------
11 files changed, 22 insertions(+), 40 deletions(-)
diff --git a/src/main/java/org/broad/igv/feature/EmblFeatureTableParser.java b/src/main/java/org/broad/igv/feature/EmblFeatureTableParser.java
index 7d5d2ecd9a..ef5e202f34 100644
--- a/src/main/java/org/broad/igv/feature/EmblFeatureTableParser.java
+++ b/src/main/java/org/broad/igv/feature/EmblFeatureTableParser.java
@@ -78,7 +78,7 @@ public List loadTracks(ResourceLocator locator, Genome genome) {
track.setName(locator.getTrackName());
track.setMinimumHeight(35);
track.setHeight(45);
- track.setRendererClass(GeneTrackRenderer.class);
+ track.setRenderer(new GeneTrackRenderer());
List newTracks = new ArrayList();
diff --git a/src/main/java/org/broad/igv/feature/dranger/DRangerParser.java b/src/main/java/org/broad/igv/feature/dranger/DRangerParser.java
index 25a9216ca9..bd5e451dee 100644
--- a/src/main/java/org/broad/igv/feature/dranger/DRangerParser.java
+++ b/src/main/java/org/broad/igv/feature/dranger/DRangerParser.java
@@ -153,7 +153,7 @@ public List loadTracks(ResourceLocator locator, Genome genome) {
FeatureTrack track = new FeatureTrack(locator, new FeatureCollectionSource(features, genome));
track.setName(locator.getTrackName());
- track.setRendererClass(DRangerRenderer.class);
+ track.setRenderer(new DRangerRenderer());
tracks.add(track);
return tracks;
diff --git a/src/main/java/org/broad/igv/sam/SpliceJunctionTrack.java b/src/main/java/org/broad/igv/sam/SpliceJunctionTrack.java
index 325d9e2c23..d3078f25fd 100644
--- a/src/main/java/org/broad/igv/sam/SpliceJunctionTrack.java
+++ b/src/main/java/org/broad/igv/sam/SpliceJunctionTrack.java
@@ -81,7 +81,7 @@ public SpliceJunctionTrack(ResourceLocator locator, String name,
super(locator, locator.getPath() + "_junctions", name);
super.setDataRange(new DataRange(0, 0, 60));
- setRendererClass(SpliceJunctionRenderer.class);
+ this.renderer = new SpliceJunctionRenderer();
if (dataManager != null) {
dataManager.unsubscribe(this);
}
@@ -92,6 +92,7 @@ public SpliceJunctionTrack(ResourceLocator locator, String name,
}
public SpliceJunctionTrack() {
+ this.renderer = new SpliceJunctionRenderer();
}
@Override
@@ -384,7 +385,9 @@ public void unmarshalXML(Element element, Integer version) {
}
if(element.hasAttribute("maxdepth")) {
- ((SpliceJunctionRenderer) renderer).setMaxDepth((int) Float.parseFloat(element.getAttribute("maxdepth")));
+ if(renderer != null && renderer instanceof SpliceJunctionRenderer) {
+ ((SpliceJunctionRenderer) renderer).setMaxDepth((int) Float.parseFloat(element.getAttribute("maxdepth")));
+ }
}
}
diff --git a/src/main/java/org/broad/igv/sashimi/SashimiPlot.java b/src/main/java/org/broad/igv/sashimi/SashimiPlot.java
index dd27566ec7..78e7f1b33e 100644
--- a/src/main/java/org/broad/igv/sashimi/SashimiPlot.java
+++ b/src/main/java/org/broad/igv/sashimi/SashimiPlot.java
@@ -125,7 +125,7 @@ public SashimiPlot(ReferenceFrame iframe, Collection extends AlignmentTrack> a
// Override expand/collpase setting -- expanded sashimi plots make no sense
spliceJunctionTrack.setDisplayMode(Track.DisplayMode.COLLAPSED);
- spliceJunctionTrack.setRendererClass(SashimiJunctionRenderer.class);
+ spliceJunctionTrack.setRenderer(new SashimiJunctionRenderer());
Color color = plotColors.get(colorInd);
colorInd = (colorInd + 1) % plotColors.size();
diff --git a/src/main/java/org/broad/igv/track/AbstractTrack.java b/src/main/java/org/broad/igv/track/AbstractTrack.java
index 85893be5ab..206e8dbc24 100644
--- a/src/main/java/org/broad/igv/track/AbstractTrack.java
+++ b/src/main/java/org/broad/igv/track/AbstractTrack.java
@@ -934,7 +934,7 @@ public void unload() {
}
- protected void setRenderer(Renderer renderer) {
+ public void setRenderer(Renderer renderer) {
//Here as setter for corresponding getter, subclasses should override
}
diff --git a/src/main/java/org/broad/igv/track/CombinedDataSourceDialog.java b/src/main/java/org/broad/igv/track/CombinedDataSourceDialog.java
index de11206153..1f0697b04a 100644
--- a/src/main/java/org/broad/igv/track/CombinedDataSourceDialog.java
+++ b/src/main/java/org/broad/igv/track/CombinedDataSourceDialog.java
@@ -100,7 +100,7 @@ private void okButtonActionPerformed(ActionEvent e) {
CombinedDataTrack newTrack = new CombinedDataTrack(dataSource, id, name);
- TrackMenuUtils.changeRenderer(Arrays.asList(newTrack), track0.getRenderer().getClass());
+ TrackMenuUtils.changeRendererClass(Arrays.asList(newTrack), track0.getRenderer().getClass());
newTrack.setDataRange(track0.getDataRange());
newTrack.setColorScale(track0.getColorScale());
IGV.getInstance().addTracks(Arrays.asList(newTrack), PanelName.DATA_PANEL);
diff --git a/src/main/java/org/broad/igv/track/DataTrack.java b/src/main/java/org/broad/igv/track/DataTrack.java
index b78be82058..2340e91de1 100644
--- a/src/main/java/org/broad/igv/track/DataTrack.java
+++ b/src/main/java/org/broad/igv/track/DataTrack.java
@@ -251,7 +251,7 @@ public void setRendererClass(Class rc) {
}
@Override
- protected void setRenderer(Renderer renderer) {
+ public void setRenderer(Renderer renderer) {
this.renderer = (DataRenderer) renderer;
}
diff --git a/src/main/java/org/broad/igv/track/FeatureTrack.java b/src/main/java/org/broad/igv/track/FeatureTrack.java
index cec5aa9e5a..35865fbfa8 100644
--- a/src/main/java/org/broad/igv/track/FeatureTrack.java
+++ b/src/main/java/org/broad/igv/track/FeatureTrack.java
@@ -363,7 +363,7 @@ public float getRegionScore(String chr, int start, int end, int zoom, RegionScor
public Renderer getRenderer() {
if (renderer == null) {
- setRendererClass(IGVFeatureRenderer.class);
+ setRenderer(new IGVFeatureRenderer());
}
return renderer;
}
diff --git a/src/main/java/org/broad/igv/track/SelectableFeatureTrack.java b/src/main/java/org/broad/igv/track/SelectableFeatureTrack.java
index 9566897a3f..6ef69b93dd 100644
--- a/src/main/java/org/broad/igv/track/SelectableFeatureTrack.java
+++ b/src/main/java/org/broad/igv/track/SelectableFeatureTrack.java
@@ -50,7 +50,7 @@ public SelectableFeatureTrack() {
public SelectableFeatureTrack(FeatureTrack geneTrack) {
super(geneTrack);
- this.setRendererClass(SelectableFeatureRenderer.class);
+ this.setRenderer(new SelectableFeatureRenderer());
}
@Override
diff --git a/src/main/java/org/broad/igv/track/TrackLoader.java b/src/main/java/org/broad/igv/track/TrackLoader.java
index a4ca8716f3..856eff84bc 100644
--- a/src/main/java/org/broad/igv/track/TrackLoader.java
+++ b/src/main/java/org/broad/igv/track/TrackLoader.java
@@ -329,7 +329,7 @@ private void loadSMAPFile(ResourceLocator locator, List