Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ultima develop code merge #1423

Merged
merged 27 commits into from
Dec 11, 2023
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
6a45dcd
gradle build
dror27 Apr 27, 2020
dfda37a
Gradle Build in workflows
dror27 Apr 27, 2020
e0ee8ba
delete workflow put in wrong place
dror27 Apr 27, 2020
d54fd84
igv_ug_30
dror27 Jan 2, 2022
c1f875c
Merge branch 'master' of https://github.com/igvteam/igv into update
dror27 Oct 27, 2022
61da8d0
Merge branch 'update' into ultima-develop
dror27 Oct 27, 2022
77c05c5
Merge with master, when on 2.15.1 (at least)
dror27 Oct 27, 2022
15a9488
Fix reference access to be case independent
dror27 Oct 31, 2022
819d991
token updated
dror27 May 16, 2023
175043b
genomeId conversion to relative protection
dror27 Jul 21, 2023
648a6e1
token update
dror27 Aug 16, 2023
ab45699
Remove explicit token
dror27 Aug 17, 2023
e0363c7
java 11.0.19 update
dror27 Oct 11, 2023
5b710cb
Merge remote-tracking branch 'igv-private/ultima-develop' into ultima…
dror27 Oct 28, 2023
d6664a9
flow renderer test/example file added. data around chr1:10000
dror27 Nov 11, 2023
871f834
Documentation added
ilyasoifer Nov 19, 2023
e0e9270
protect against "tp" tag not indicating flow
dror27 Nov 20, 2023
d11c776
Goto mate added
dror27 Nov 29, 2023
53e973d
show "goto mate" only for mated variants
dror27 Nov 29, 2023
07fe838
Revert "show "goto mate" only for mated variants"
dror27 Dec 5, 2023
60a675b
Revert "Goto mate added"
dror27 Dec 5, 2023
432f906
Extension framework removed
dror27 Dec 5, 2023
6de1d10
Merge branch 'master' into ultima-develop
dror27 Dec 5, 2023
71cde5a
add missing import
dror27 Dec 5, 2023
e507cc5
remove LoadMultipleTracks and Relative Genome resolve ignoring
dror27 Dec 6, 2023
aa40613
remove drawInsertions method
dror27 Dec 10, 2023
28ffbcc
doc deleted from source tree
dror27 Dec 10, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 0 additions & 34 deletions .github/workflows/gradle_test.yml

This file was deleted.

65 changes: 65 additions & 0 deletions doc/igv.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# UG CRAM representation
In flow sequencing, each base is representing a homopolymer with length > 0. Each homopolymer is assigned with quality that represents the probability of calculating the length correctly. UG IGV view of variant calling includes additional graphical and information boxes on top of what is already available in IGV. These graphical indications provide information about the quality of the base and variant.

For more information about flow sequencing, please see [this preprint](https://www.biorxiv.org/content/10.1101/2022.05.29.493900).

**Example:**
![UG data alignment](igv/Picture1.png).

1. Read information: Variant quality and location
2. Feature description: Insertion or Deletion, count of bases in event, Quality, and direction

## Insertion graphic features
![Zoomed in data](igv/Picture2.png).

Base insertions are marked with a color range of red to blue boxes.

Red - ![Insertion 1](igv/Picture3.png)![Insertion 2](igv/Picture4.png) - indicate high quality/probability for an insertion

Blue - ![Insertion 3](igv/Picture5.png)![Insertion 4](igv/Picture6.png) - indicate low quality/probability for an insertion

## Deletion graphic features

![Zoomed in data](igv/Picture7.png).

Base deletions are marked as horizontal bars, with a box color ranging between red to blue.

Red - ![Deletion 1](igv/Picture8.png) - indicate high quality deletion

Blue - ![Deletion 3](igv/Picture9.png) - indicate low quality deletion

![Deletion 4](igv/Picture10.png) no box – non h-mer indel.

## Exploring data with enhanced flow features

### Insertions

Quality of insertions is represented by color and position of the bar across IGV’s vertical insertion mark. Ranging from Blue – low to Red – High. Bars represent the probability/quality of the call. Click on the feature will open a pop-up window with extra information about the event: Base count, Base letter, Variant quality and direction of error.

Variant quality (QV) is the FASTQ phred quality values, ranges between 0 to 40.

Direction value (TP) – Positive: Probability for insertion of additional base(s), Negative: Probability for insertion of fewer bases. Zero – Very low probability for error.

**Example:**

![Insertion examples](igv/Picture11.png)

Insertions with different probabilities and different directions

Top – Lower quality single base call with probability for no insertion (no extra G, ‘-1’)

Bottom – Higher quality single base call with probability of insertion of additional base (Additional G, ‘1’)

### Deletions

Quality of deletions is represented by color and position of the bar across IGV’s deletion mark

Ranging from Blue – low to Red – High. Bars represent the quality of the call.

Use: Exploration of the first or last base of the homopolymer next to the deletion reveals more information about the deletion. Right click on the base right to the deletion to get the info pop-up. If the quality of the deletion is low, expect to see a base with lower QV value and TP value > 1 indicating probable extra homopolymer length next to the loci of the called deletion.

Direction value (TP) – Positive: Probability for deletion of additional base(s), Negative: Probability for deletion of fewer bases. Zero – low probability for error.

** Examples of deletions with different error directions and qualities **

![Deletion examples](igv/Picture14.png)
Binary file added doc/igv/Picture1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/igv/Picture10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/igv/Picture11.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/igv/Picture12.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/igv/Picture13.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/igv/Picture14.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/igv/Picture15.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/igv/Picture16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/igv/Picture2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/igv/Picture3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/igv/Picture4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/igv/Picture5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/igv/Picture6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/igv/Picture7.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/igv/Picture8.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/igv/Picture9.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions src/main/java/org/broad/igv/ext/ExtensionManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.broad.igv.ext;

import org.broad.igv.ext.annotate.FlowBlockAnnotator;
import org.broad.igv.ext.load.LoadMultipleTracks;
import org.broad.igv.ext.render.ColorByTagValueList;
import org.broad.igv.ext.render.FlowIndelRendering;

public class ExtensionManager {

private static final IExtension EXTENSIONS[] = {
new LoadMultipleTracks(),
new FlowBlockAnnotator(),
new ColorByTagValueList(),
new FlowIndelRendering()
};

public static IExtension getExtentionFor(final Class<? extends IExtension> type, final Object context) {
for ( IExtension ext : EXTENSIONS ) {
if ( type.isInstance(ext) ) {
if ( ext.extendsContext(context) )
return ext;
}
}
return null;
}
}
6 changes: 6 additions & 0 deletions src/main/java/org/broad/igv/ext/IExtension.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.broad.igv.ext;

public interface IExtension {

public boolean extendsContext(final Object context);
}
133 changes: 133 additions & 0 deletions src/main/java/org/broad/igv/ext/annotate/FlowBlockAnnotator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package org.broad.igv.ext.annotate;

import htsjdk.samtools.SAMRecord;
import org.apache.commons.lang3.StringUtils;
import org.broad.igv.sam.AlignmentBlock;
import org.broad.igv.sam.ByteSubarray;
import org.broad.igv.sam.SAMAlignment;

public class FlowBlockAnnotator implements IAlignmentBlockAnnotationExtension {

private static final String KEY_ATTR = "ti,tp";

@Override
public boolean extendsContext(final Object context) {

// must be a block with qualities
if ( !(context instanceof AlignmentBlock) ) {
return false;
}
final AlignmentBlock block = (AlignmentBlock)context;

// sanity: bases and qualities
if ( (block.getBases() == null) || (block.getQualities() == null) ) {
return false;
}


return true;
}

@Override
public void appendBlockQualityAnnotation(SAMAlignment samAlignment, AlignmentBlock block, StringBuffer buf) {

if ( isFlow(samAlignment.getRecord()) ) {
buf.append(" @ QV " + qualsAsString(block.getQualities()) + attrAsString(samAlignment, block, "ti,tp", -1));
}
}

@Override
public void appendBlockAttrAnnotation(SAMAlignment samAlignment, AlignmentBlock block, int offset, StringBuffer buf) {

if ( isFlow(samAlignment.getRecord()) ) {
buf.append(attrAsString(samAlignment, block, KEY_ATTR, offset));
}
}

private boolean isFlow(SAMRecord record) {

// must have one of the key attributes
for ( String name : KEY_ATTR.split(",") ) {
if ( record.hasAttribute(name) ) {
return true;
}
}
return false;
}

private int[] attrAsIntegers(SAMAlignment samAlignment, AlignmentBlock block, String name, int offset, StringBuilder sbName) {

Object value = null;
for ( String name1 : name.split(",") ) {
value = samAlignment.getRecord().getAttribute(name1);
if ( value != null ) {
name = name1;
if ( sbName != null )
sbName.append(name);
break;
}
}
if ( value == null )
return new int[0];
byte[] arr = (byte[])value;

if ( offset >= 0 ) {
int[] integers = new int[1];
int start = block.getIndexOnRead();
integers[0] = (int)(arr[start + offset]);
return integers;

} else {
int start = block.getIndexOnRead();
int length = block.getLength();
int[] integers = new int[length];
for ( int ofs = start ; ofs < (start + length) ; ofs++ ) {
integers[ofs - start] = arr[ofs];
}
return integers;
}
}

private String attrAsString(SAMAlignment samAlignment, AlignmentBlock block, String name, int offset) {

StringBuilder sb = new StringBuilder(" ");
int[] integers = attrAsIntegers(samAlignment, block, name, offset, sb);
if ( integers == null )
return "";

sb.append(" ");
sb.append(StringUtils.join(integers, ','));

String r = sb.toString();
if ( r.length() > 40 )
r = r.substring(0, 40) + "...";

return r;
}

static public String qualsAsString(ByteSubarray quals) {

StringBuilder sb = new StringBuilder();
final int digestLength = 25;
boolean isDigest = quals.length >= (digestLength * 2);

// translate quals back into ASCII
for ( int i = 0 ; i < quals.length ; i++ ) {
final byte q = quals.getByte(i);
if ( !isDigest || (i < digestLength) || (i > quals.length - digestLength) ) {
if ( i > 0 )
sb.append(",");
if (q == 255)
sb.append('?');
else {
sb.append(Integer.toString(q));
}
}
if ( isDigest && (i == digestLength) )
sb.append("...");
i++;
}

return sb.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.broad.igv.ext.annotate;

import org.broad.igv.ext.IExtension;
import org.broad.igv.sam.AlignmentBlock;
import org.broad.igv.sam.SAMAlignment;

public interface IAlignmentBlockAnnotationExtension extends IExtension {

public void appendBlockQualityAnnotation(SAMAlignment samAlignment, AlignmentBlock block, StringBuffer buf);
public void appendBlockAttrAnnotation(SAMAlignment samAlignment, AlignmentBlock block, int offset, StringBuffer buf);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.broad.igv.ext.load;

import org.broad.igv.ext.IExtension;
import org.broad.igv.util.ResourceLocator;

import java.util.Collection;

public interface ILoadTracksFromUrlExtension extends IExtension {

public Collection<ResourceLocator> locatorsForUrl(final String url, final String indexUrl);
}
65 changes: 65 additions & 0 deletions src/main/java/org/broad/igv/ext/load/LoadMultipleTracks.java
jrobinso marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package org.broad.igv.ext.load;

import org.broad.igv.util.GoogleUtils;
import org.broad.igv.ui.action.LoadFromURLMenuAction;
import org.broad.igv.util.ResourceLocator;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;

public class LoadMultipleTracks implements ILoadTracksFromUrlExtension {

final static String SPLIT_REGEX = "\\s+";

@Override
public boolean extendsContext(final Object context) {

// context must be a url string
if ( !(context instanceof String) )
return false;
final String url = (String)context;

// url must not be a session
if (url.endsWith(".xml") || url.endsWith(".session")) {
return false;
}

// url should not be an s3:// url
if ( url.startsWith("s3://") ) {
return false;
}

// must contain multiple
String[] toks = url.split(SPLIT_REGEX);
if ( toks.length <= 1 )
return false;

// if here, url can be split into individual urls
return true;
}

@Override
public Collection<ResourceLocator> locatorsForUrl(final String url, final String indexUrl) {

List<ResourceLocator> locators = new LinkedList<>();
for ( String tok : url.split(SPLIT_REGEX) ) {

ResourceLocator rl = new ResourceLocator(LoadFromURLMenuAction.mapURL(tok));

if (indexUrl != null) {

final String index = indexUrl.trim();
if (GoogleUtils.isGoogleDrive(index) || GoogleUtils.isGoogleDrive(index)) {
LoadFromURLMenuAction.enableGoogleMenu();
}

rl.setIndexPath(index);
}

locators.add(rl);
}

return locators;
}
}
Loading