Skip to content

Commit

Permalink
Add isRefOnlyBlock function... (#1215)
Browse files Browse the repository at this point in the history
* add isReferenceBlock function to VariantContext
  • Loading branch information
jsotobroad authored and Yossi Farjoun committed Dec 4, 2018
1 parent 4ff5190 commit 41c4634
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 34 deletions.
54 changes: 31 additions & 23 deletions src/main/java/htsjdk/variant/variantcontext/Allele.java
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,14 @@ public class Allele implements Comparable<Allele>, Serializable {
private byte[] bases = null;

/** A generic static NO_CALL allele for use */
public final static String NO_CALL_STRING = ".";
public static final String NO_CALL_STRING = ".";

/** A generic static SPAN_DEL allele for use */
public final static String SPAN_DEL_STRING = "*";
public static final String SPAN_DEL_STRING = "*";

/** A generic static NON_REF allele for use */
public final static String NON_REF_STRING = "<NON_REF>";
/** Non ref allele representations */
public static final String NON_REF_STRING = "<NON_REF>";
public static final String UNSPECIFIED_ALTERNATE_ALLELE_STRING = "<*>";

// no public way to create an allele
protected Allele(final byte[] bases, final boolean isRef) {
Expand Down Expand Up @@ -184,31 +185,31 @@ protected Allele(final Allele allele, final boolean ignoreRefState) {
this.isSymbolic = allele.isSymbolic;
}


private final static Allele REF_A = new Allele("A", true);
private final static Allele ALT_A = new Allele("A", false);
private final static Allele REF_C = new Allele("C", true);
private final static Allele ALT_C = new Allele("C", false);
private final static Allele REF_G = new Allele("G", true);
private final static Allele ALT_G = new Allele("G", false);
private final static Allele REF_T = new Allele("T", true);
private final static Allele ALT_T = new Allele("T", false);
private final static Allele REF_N = new Allele("N", true);
private final static Allele ALT_N = new Allele("N", false);
public final static Allele SPAN_DEL = new Allele(SPAN_DEL_STRING, false);
public final static Allele NO_CALL = new Allele(NO_CALL_STRING, false);
public final static Allele NON_REF_ALLELE = new Allele(NON_REF_STRING, false);
private static final Allele REF_A = new Allele("A", true);
private static final Allele ALT_A = new Allele("A", false);
private static final Allele REF_C = new Allele("C", true);
private static final Allele ALT_C = new Allele("C", false);
private static final Allele REF_G = new Allele("G", true);
private static final Allele ALT_G = new Allele("G", false);
private static final Allele REF_T = new Allele("T", true);
private static final Allele ALT_T = new Allele("T", false);
private static final Allele REF_N = new Allele("N", true);
private static final Allele ALT_N = new Allele("N", false);
public static final Allele SPAN_DEL = new Allele(SPAN_DEL_STRING, false);
public static final Allele NO_CALL = new Allele(NO_CALL_STRING, false);
public static final Allele NON_REF_ALLELE = new Allele(NON_REF_STRING, false);
public static final Allele UNSPECIFIED_ALTERNATE_ALLELE = new Allele(UNSPECIFIED_ALTERNATE_ALLELE_STRING, false);

// for simple deletion, e.g. "ALT==<DEL>" (note that the spec allows, for now at least, alt alleles like <DEL:ME>)
public final static Allele SV_SIMPLE_DEL = StructuralVariantType.DEL.toSymbolicAltAllele();
public static final Allele SV_SIMPLE_DEL = StructuralVariantType.DEL.toSymbolicAltAllele();
// for simple insertion, e.g. "ALT==<INS>"
public final static Allele SV_SIMPLE_INS = StructuralVariantType.INS.toSymbolicAltAllele();
public static final Allele SV_SIMPLE_INS = StructuralVariantType.INS.toSymbolicAltAllele();
// for simple inversion, e.g. "ALT==<INV>"
public final static Allele SV_SIMPLE_INV = StructuralVariantType.INV.toSymbolicAltAllele();
public static final Allele SV_SIMPLE_INV = StructuralVariantType.INV.toSymbolicAltAllele();
// for simple generic cnv, e.g. "ALT==<CNV>"
public final static Allele SV_SIMPLE_CNV = StructuralVariantType.CNV.toSymbolicAltAllele();
public static final Allele SV_SIMPLE_CNV = StructuralVariantType.CNV.toSymbolicAltAllele();
// for simple duplication, e.g. "ALT==<DUP>"
public final static Allele SV_SIMPLE_DUP = StructuralVariantType.DUP.toSymbolicAltAllele();
public static final Allele SV_SIMPLE_DUP = StructuralVariantType.DUP.toSymbolicAltAllele();

// ---------------------------------------------------------------------------------------------------------
//
Expand Down Expand Up @@ -558,4 +559,11 @@ private static boolean firstIsPrefixOfSecond(final Allele a1, final Allele a2) {
String a1String = a1.getBaseString();
return a2.getBaseString().substring(0, a1String.length()).equals(a1String);
}

/**
* @return true if Allele is either {@code <NON_REF>} or {@code <*>}
*/
public boolean isNonRefAllele() {
return equals(NON_REF_ALLELE) || equals(UNSPECIFIED_ALTERNATE_ALLELE);
}
}
26 changes: 18 additions & 8 deletions src/main/java/htsjdk/variant/variantcontext/VariantContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@

package htsjdk.variant.variantcontext;

import htsjdk.samtools.util.Locatable;
import htsjdk.tribble.Feature;
import htsjdk.tribble.TribbleException;
import htsjdk.tribble.util.ParsingUtils;
Expand Down Expand Up @@ -1248,24 +1247,24 @@ public void validateChromosomeCounts() {
validateAttributeIsExpectedSize(VCFConstants.ALLELE_COUNT_KEY, numberOfAlternateAlleles);
validateAttributeIsExpectedSize(VCFConstants.ALLELE_FREQUENCY_KEY, numberOfAlternateAlleles);

if ( !hasGenotypes() )
if (!hasGenotypes())
return;

// AN
if ( hasAttribute(VCFConstants.ALLELE_NUMBER_KEY) ) {
if (hasAttribute(VCFConstants.ALLELE_NUMBER_KEY)) {
final int reportedAN = Integer.valueOf(getAttribute(VCFConstants.ALLELE_NUMBER_KEY).toString());
final int observedAN = getCalledChrCount();
if ( reportedAN != observedAN )
throw new TribbleException.InternalCodecException(String.format("the Allele Number (AN) tag is incorrect for the record at position %s:%d, %d vs. %d", getContig(), getStart(), reportedAN, observedAN));
}

// AC
if ( hasAttribute(VCFConstants.ALLELE_COUNT_KEY) ) {
if (hasAttribute(VCFConstants.ALLELE_COUNT_KEY)) {
final ArrayList<Integer> observedACs = new ArrayList<>();

// if there are alternate alleles, record the relevant tags
if ( numberOfAlternateAlleles > 0 ) {
for ( Allele allele : getAlternateAlleles() ) {
if (numberOfAlternateAlleles > 0) {
for (Allele allele : getAlternateAlleles()) {
observedACs.add(getCalledChrCount(allele));
}
}
Expand All @@ -1278,7 +1277,7 @@ public void validateChromosomeCounts() {
for (int i = 0; i < observedACs.size(); i++) {
// need to cast to int to make sure we don't have an issue below with object equals (earlier bug) - EB
final int reportedAC = Integer.valueOf(reportedACs.get(i).toString());
if ( reportedAC != observedACs.get(i) )
if (reportedAC != observedACs.get(i))
throw new TribbleException.InternalCodecException(String.format("the Allele Count (AC) tag is incorrect for the record at position %s:%d, %s vs. %d", getContig(), getStart(), reportedAC, observedACs.get(i)));
}
}
Expand Down Expand Up @@ -1682,11 +1681,22 @@ public int getEnd() {
return (int)stop;
}

/**
*
* @return true if the variant context is a reference block
*
*/
public boolean isReferenceBlock() {
return getAlternateAlleles().size() == 1
&& getAlternateAllele(0).isNonRefAllele()
&& getAttribute(VCFConstants.END_KEY) != null;
}

public boolean hasSymbolicAlleles() {
return hasSymbolicAlleles(getAlleles());
}

public static boolean hasSymbolicAlleles( final List<Allele> alleles ) {
public static boolean hasSymbolicAlleles(final List<Allele> alleles) {
return alleles.stream().anyMatch(Allele::isSymbolic);
}

Expand Down
24 changes: 21 additions & 3 deletions src/test/java/htsjdk/variant/variantcontext/AlleleUnitTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
// the imports for unit testing.

import htsjdk.variant.VariantBaseTest;
import htsjdk.variant.variantcontext.Allele;

import org.testng.Assert;
import org.testng.annotations.BeforeSuite;
Expand All @@ -48,7 +47,7 @@
* Basic unit test for RecalData
*/
public class AlleleUnitTest extends VariantBaseTest {
Allele ARef, A, T, ATIns, ATCIns, NoCall, SpandDel;
private Allele ARef, A, T, ATIns, ATCIns, NoCall, SpandDel, NonRef, UnspecifiedAlternate;

@BeforeSuite
public void before() {
Expand All @@ -62,6 +61,9 @@ public void before() {
NoCall = Allele.create(Allele.NO_CALL_STRING);

SpandDel = Allele.create(Allele.SPAN_DEL_STRING);

NonRef = Allele.create(Allele.NON_REF_STRING);
UnspecifiedAlternate = Allele.create(Allele.UNSPECIFIED_ALTERNATE_ALLELE_STRING);
}

@Test
Expand Down Expand Up @@ -189,6 +191,22 @@ public void testSymbolic() {
Assert.assertEquals("<SYMBOLIC>", a.getDisplayString());
}

@Test
public void testNonRefAllele() {
Assert.assertTrue(NonRef.isNonRefAllele());
Assert.assertTrue(UnspecifiedAlternate.isNonRefAllele());

Assert.assertFalse(T.isNonRefAllele());
Assert.assertFalse(ATIns.isNonRefAllele());

Assert.assertTrue(Allele.NON_REF_ALLELE.isNonRefAllele());
Assert.assertTrue(Allele.UNSPECIFIED_ALTERNATE_ALLELE.isNonRefAllele());

Allele a = Allele.create(new String("<*>"));
Assert.assertTrue(a.isNonRefAllele());
}


@Test
public void testEquals() {
Assert.assertTrue(ARef.basesMatch(A));
Expand Down Expand Up @@ -259,4 +277,4 @@ public void testExtend() {
Assert.assertEquals("ATCGA", Allele.extend(Allele.create("AT"), "CGA".getBytes()).toString());
Assert.assertEquals("ATCGA", Allele.extend(Allele.create("ATC"), "GA".getBytes()).toString());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1552,6 +1552,28 @@ public void testExtractStructuralVariationsData(final File vcfFile) {
}
}

@DataProvider(name = "referenceBlockData")
public Object[][] referenceBlockData() {
return new Object[][]{
{Arrays.asList(Aref, Allele.UNSPECIFIED_ALTERNATE_ALLELE), false, false},
{Arrays.asList(Aref, Allele.UNSPECIFIED_ALTERNATE_ALLELE), true, true},
{Arrays.asList(Aref, Allele.NON_REF_ALLELE), true, true},
{Arrays.asList(Aref, C, Allele.UNSPECIFIED_ALTERNATE_ALLELE), true, false},
{Arrays.asList(Aref, C), false, false}
};
}

@Test(dataProvider = "referenceBlockData")
public void testReferenceBlock(List<Allele> alleles, boolean addEndAttribute, boolean isRefBlock) {
// create a context builder/context based on inputs provided
final VariantContextBuilder builder =
new VariantContextBuilder("test", snpLoc,snpLocStart, snpLocStop, alleles);
if (addEndAttribute) {
builder.attribute("END", 10);
}
Assert.assertEquals(builder.make().isReferenceBlock(), isRefBlock);
}

@Test
public void testGetAttributeAsIntList() {
final VariantContext context = basicBuilder
Expand Down

0 comments on commit 41c4634

Please sign in to comment.