Skip to content

Commit

Permalink
Merge pull request #41 from molgenis/feat/more_possible
Browse files Browse the repository at this point in the history
Variants without a gene and pedigrees with missing GT should have possible match
  • Loading branch information
dennishendriksen authored Nov 7, 2023
2 parents e998b0d + 5540f64 commit c42e0f1
Show file tree
Hide file tree
Showing 17 changed files with 94 additions and 70 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.molgenis.vcf.inheritance.matcher;

import static org.molgenis.vcf.inheritance.matcher.model.InheritanceMatch.TRUE;
import static org.molgenis.vcf.inheritance.matcher.model.InheritanceMatch.POTENTIAL;
import static org.molgenis.vcf.utils.utils.HeaderUtils.fixVcfFilterHeaderLines;
import static org.molgenis.vcf.utils.utils.HeaderUtils.fixVcfFormatHeaderLines;
import static org.molgenis.vcf.utils.utils.HeaderUtils.fixVcfInfoHeaderLines;
Expand Down Expand Up @@ -57,7 +58,7 @@ VCFHeader annotateHeader(VCFHeader vcfHeader) {
"Inheritance Match: Genotypes, affected statuses and known gene inheritance patterns match."));
vcfHeader.addMetaDataLine(new VCFFormatHeaderLine(MATCHING_GENES, VCFHeaderLineCount.UNBOUNDED,
VCFHeaderLineType.String,
"Genes with an inheritance match."));
"Genes with a (potential) inheritance match."));

Set<VCFHeaderLine> headerLines = new LinkedHashSet<>();
//workaround for "Escaped doublequotes in INFO descriptions result in invalid VCF file"
Expand Down Expand Up @@ -112,7 +113,7 @@ private void annotateGenotype(VariantContext vc, Annotation annotation,
String inheritanceMatch = mapInheritanceMatch(match);
genotypeBuilder
.attribute(INHERITANCE_MATCH, inheritanceMatch);
if (match == TRUE) {
if ((match == TRUE || match == POTENTIAL) && annotation.getMatchingGenes() != null && !annotation.getMatchingGenes().isEmpty()) {
genotypeBuilder
.attribute(MATCHING_GENES, annotation.getMatchingGenes().stream().sorted().collect(
Collectors.joining(",")));
Expand All @@ -127,7 +128,7 @@ private static String mapInheritanceMatch(InheritanceMatch match) {
switch (match){
case TRUE -> inheritanceMatch = "1";
case FALSE -> inheritanceMatch = "0";
case UNKNOWN -> inheritanceMatch = null;
case POTENTIAL -> inheritanceMatch = null;
default -> throw new UnexpectedEnumException(match);
}
return inheritanceMatch;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.molgenis.vcf.inheritance.matcher;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
Expand All @@ -17,7 +16,7 @@ private InheritanceMatcher() {
}

public static Map<String, Annotation> matchInheritance(
Map<String, Inheritance> inheritanceMap, Collection<Gene> genes) {
Map<String, Inheritance> inheritanceMap, VariantContextGenes genes) {
Map<String, Annotation> sampleAnnotationMap = new HashMap<>();
for (Entry<String, Inheritance> entry : inheritanceMap.entrySet()) {
Set<String> matchingGenes = new HashSet<>();
Expand All @@ -44,9 +43,9 @@ public static Map<String, Annotation> matchInheritance(
* - inheritance match is unknown if any genes for the variant have unknown inheritance pattern.
* - inheritance match is false if all genes for the variant have known (but mismatching) inheritance pattern.
*/
private static void matchGeneInheritance(Collection<Gene> genes, Set<String> matchingGenes, Inheritance inheritance) {
private static void matchGeneInheritance(VariantContextGenes genes, Set<String> matchingGenes, Inheritance inheritance) {
boolean containsUnknownGene = false;
for (Gene gene : genes) {
for (Gene gene : genes.getGenes().values()) {
Set<InheritanceMode> geneInheritanceModes = gene
.getInheritanceModes();
if( geneInheritanceModes.isEmpty() ){
Expand All @@ -55,12 +54,16 @@ private static void matchGeneInheritance(Collection<Gene> genes, Set<String> mat
if (geneInheritanceModes.stream()
.anyMatch(mode -> inheritance.getInheritanceModes().contains(mode))) {
matchingGenes.add(gene.getId());
inheritance.setMatch(TRUE);
if(inheritance.isFamilyWithMissingGT()){
inheritance.setMatch(POTENTIAL);
}else {
inheritance.setMatch(TRUE);
}
}
}
if(matchingGenes.isEmpty()) {
if (containsUnknownGene) {
inheritance.setMatch(UNKNOWN);
if (containsUnknownGene || genes.isContainsVcWithoutGene()) {
inheritance.setMatch(POTENTIAL);
} else {
inheritance.setMatch(FALSE);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import static org.molgenis.vcf.utils.sample.mapper.PedToSamplesMapper.mapPedFileToPedigrees;

import htsjdk.variant.variantcontext.Allele;
import htsjdk.variant.variantcontext.Genotype;
import htsjdk.variant.variantcontext.VariantContext;
import htsjdk.variant.variantcontext.writer.VariantContextWriter;
import htsjdk.variant.variantcontext.writer.VariantContextWriterBuilder;
Expand All @@ -27,12 +28,7 @@
import org.molgenis.vcf.inheritance.matcher.checker.DeNovoChecker;
import org.molgenis.vcf.inheritance.matcher.checker.XldChecker;
import org.molgenis.vcf.inheritance.matcher.checker.XlrChecker;
import org.molgenis.vcf.inheritance.matcher.model.Annotation;
import org.molgenis.vcf.inheritance.matcher.model.Gene;
import org.molgenis.vcf.inheritance.matcher.model.Inheritance;
import org.molgenis.vcf.inheritance.matcher.model.InheritanceMode;
import org.molgenis.vcf.inheritance.matcher.model.Settings;
import org.molgenis.vcf.inheritance.matcher.model.SubInheritanceMode;
import org.molgenis.vcf.inheritance.matcher.model.*;
import org.molgenis.vcf.inheritance.matcher.util.InheritanceUtils;
import org.molgenis.vcf.utils.metadata.FieldMetadataService;
import org.molgenis.vcf.utils.sample.model.AffectedStatus;
Expand Down Expand Up @@ -103,7 +99,7 @@ private VariantContext processSingleVariantcontext(List<String> probands, VepMap
Map<String, Inheritance> inheritanceMap = matchInheritanceForVariant(geneVariantMap,
vc, pedigreeList, probands);
Map<String, Annotation> annotationMap = matchInheritance(inheritanceMap,
vepMapper.getGenes(vc).values());
vepMapper.getGenes(vc));
return annotator.annotateInheritance(vc, pedigreeList, annotationMap);
}

Expand All @@ -112,9 +108,9 @@ private Map<String, List<VariantContext>> createGeneVariantMap(VepMapper vepMapp
List<VariantContext> variantContextList) {
Map<String, List<VariantContext>> geneVariantMap = new HashMap<>();
for (VariantContext vc : variantContextList) {
Map<String, Gene> genes = vepMapper.getGenes(vc, knownGenes);
knownGenes.putAll(genes);
for (Gene gene : genes.values()) {
VariantContextGenes variantContextGenes = vepMapper.getGenes(vc, knownGenes);
knownGenes.putAll(variantContextGenes.getGenes());
for (Gene gene : variantContextGenes.getGenes().values()) {
List<VariantContext> geneVariantList;
if (geneVariantMap.containsKey(gene.getId())) {
geneVariantList = geneVariantMap.get(gene.getId());
Expand Down Expand Up @@ -172,10 +168,18 @@ private Inheritance matchInheritanceForSample(
checkAd(variantContext, filteredFamily, inheritance);
checkXl(variantContext, filteredFamily, inheritance);
inheritance.setDenovo(deNovoChecker.checkDeNovo(variantContext, filteredFamily, sample));
inheritance.setFamilyWithMissingGT(checkMissingGTs(filteredFamily, variantContext));

return inheritance;
}

private boolean checkMissingGTs(Pedigree filteredFamily,VariantContext variantContext) {
return filteredFamily.getMembers().values().stream().anyMatch(sample -> {
Genotype gt = variantContext.getGenotype(sample.getPerson().getIndividualId());
return gt == null || !gt.isCalled();
});
}

private void checkXl(VariantContext variantContext, Pedigree family,
Inheritance inheritance) {
if (xldChecker.check(variantContext, family)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.molgenis.vcf.inheritance.matcher;

import static java.util.Arrays.asList;
import static java.util.Collections.emptyMap;

import htsjdk.variant.variantcontext.VariantContext;
Expand All @@ -14,6 +13,7 @@
import java.util.Set;
import org.molgenis.vcf.inheritance.matcher.model.Gene;
import org.molgenis.vcf.inheritance.matcher.model.InheritanceMode;
import org.molgenis.vcf.inheritance.matcher.model.VariantContextGenes;
import org.molgenis.vcf.utils.metadata.FieldMetadataService;
import org.molgenis.vcf.utils.model.FieldMetadata;
import org.molgenis.vcf.utils.model.NestedField;
Expand Down Expand Up @@ -63,18 +63,20 @@ private void init(VCFFileReader vcfFileReader) {
throw new MissingInfoException("VEP");
}

public Map<String, Gene> getGenes(VariantContext vc) {
public VariantContextGenes getGenes(VariantContext vc) {
return getGenes(vc, emptyMap());
}

public Map<String, Gene> getGenes(VariantContext vc, Map<String, Gene> knownGenes) {
public VariantContextGenes getGenes(VariantContext vc, Map<String, Gene> knownGenes) {
VariantContextGenes.VariantContextGenesBuilder genesBuilder = VariantContextGenes.builder();
Map<String, Gene> genes = new HashMap<>();
List<String> vepValues = vc.getAttributeAsStringList(vepFieldId, "");
for (String vepValue : vepValues) {
String[] vepSplit = vepValue.split("\\|", -1);
String gene = vepSplit[geneIndex];
String source = vepSplit[geneSourceIndex];
if (gene.isEmpty() || source.isEmpty()) {
genesBuilder.containsVcWithoutGene(true);
continue;
}

Expand All @@ -94,7 +96,8 @@ public Map<String, Gene> getGenes(VariantContext vc, Map<String, Gene> knownGene
genes.put(gene, knownGenes.get(gene));
}
}
return genes;
genesBuilder.genes(genes);
return genesBuilder.build();
}

private void mapGeneInheritance(Set<InheritanceMode> modes, String[] inheritanceModes) {
Expand Down Expand Up @@ -123,7 +126,7 @@ private void mapGeneInheritance(Set<InheritanceMode> modes, String[] inheritance
}

public boolean containsIncompletePenetrance(VariantContext variantContext) {
Map<String, Gene> genes = getGenes(variantContext);
Map<String, Gene> genes = getGenes(variantContext).getGenes();
return genes.values().stream().anyMatch(Gene::isIncompletePenetrance);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public List<VariantContext> check(
VariantContext variantContext, Pedigree family) {
if (onAutosome(variantContext)) {
List<VariantContext> compounds = new ArrayList<>();
Map<String, Gene> genes = vepMapper.getGenes(variantContext);
Map<String, Gene> genes = vepMapper.getGenes(variantContext).getGenes();
for (Gene gene : genes.values()) {
checkForGene(geneVariantMap, variantContext, family, compounds, gene);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@ public class Inheritance {
Set<String> compounds = new HashSet<>();

@Builder.Default
InheritanceMatch match = InheritanceMatch.UNKNOWN;
InheritanceMatch match = InheritanceMatch.POTENTIAL;

@Builder.Default
boolean denovo = false;

@Builder.Default
boolean isFamilyWithMissingGT = false;

public void addInheritanceMode(InheritanceMode inheritanceMode) {
inheritanceModes.add(inheritanceMode);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package org.molgenis.vcf.inheritance.matcher.model;

public enum InheritanceMatch {
TRUE, FALSE, UNKNOWN
TRUE, FALSE, POTENTIAL
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.molgenis.vcf.inheritance.matcher.model;

import lombok.Builder;
import lombok.Data;
import java.util.Map;
@Data
@Builder
public class VariantContextGenes{
Map<String, Gene> genes;
@Builder.Default
boolean containsVcWithoutGene = false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ void annotateHeader() {
() -> verify(vcfHeader)
.addMetaDataLine(new VCFFormatHeaderLine(MATCHING_GENES, VCFHeaderLineCount.UNBOUNDED,
VCFHeaderLineType.String,
"Genes with an inheritance match.")),
"Genes with a (potential) inheritance match.")),
() -> verify(vcfHeader, times(2)).getInfoHeaderLines(),
() -> verify(vcfHeader, times(2)).getFormatHeaderLines(),
() -> verify(vcfHeader, times(2)).getFilterLines(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,10 @@
import static org.molgenis.vcf.inheritance.matcher.model.InheritanceMode.AR;
import static org.molgenis.vcf.inheritance.matcher.model.InheritanceMode.AD;

import java.util.Collection;
import java.util.Map;
import java.util.Set;
import org.junit.jupiter.api.Test;
import org.molgenis.vcf.inheritance.matcher.model.Annotation;
import org.molgenis.vcf.inheritance.matcher.model.Gene;
import org.molgenis.vcf.inheritance.matcher.model.Inheritance;
import org.molgenis.vcf.inheritance.matcher.model.SubInheritanceMode;
import org.molgenis.vcf.inheritance.matcher.model.*;

class InheritanceMatcherTest {

Expand All @@ -26,7 +22,7 @@ void matchInheritanceMatch() {
Set.of(AR)).subInheritanceModes(emptySet()).compounds(singleton("OTHER_VARIANT")).build();
Map<String, Inheritance> inheritanceMap = Map.of("sample1", inheritance1, "sample2",
inheritance2);
Collection<Gene> genes = Set.of(new Gene("GENE1","EntrezGene", true, Set.of(AR,AD)),new Gene("GENE2","EntrezGene", true, Set.of(AD)));
VariantContextGenes genes = VariantContextGenes.builder().genes(Map.of("GENE1", new Gene("GENE1","EntrezGene", true, Set.of(AR,AD)), "GENE2", new Gene("GENE2","EntrezGene", true, Set.of(AD)))).build();

Map<String, Annotation> actual = InheritanceMatcher
.matchInheritance(inheritanceMap, genes);
Expand All @@ -46,7 +42,7 @@ void matchInheritanceMismatch() {
Inheritance inheritance = Inheritance.builder().inheritanceModes(
Set.of(AD)).subInheritanceModes(Set.of(SubInheritanceMode.AD_IP)).build();
Map<String, Inheritance> inheritanceMap = Map.of("sample1", inheritance);
Collection<Gene> genes = Set.of(new Gene("GENE1","EntrezGene", true, Set.of(AR)));
VariantContextGenes genes = VariantContextGenes.builder().genes(Map.of("GENE1", new Gene("GENE1","EntrezGene", true, Set.of(AR)))).build();

Map<String, Annotation> actual = InheritanceMatcher
.matchInheritance(inheritanceMap, genes);
Expand All @@ -64,7 +60,7 @@ void matchInheritanceNoSuitableModes() {
Inheritance inheritance1 = Inheritance.builder().match(FALSE).inheritanceModes(
emptySet()).subInheritanceModes(emptySet()).build();
Map<String, Inheritance> inheritanceMap = Map.of("sample1", inheritance1);
Collection<Gene> genes = Set.of(new Gene("GENE1","EntrezGene", false, Set.of(AR,AD)),new Gene("GENE2","EntrezGene", false, Set.of(AD)));
VariantContextGenes genes = VariantContextGenes.builder().genes(Map.of("GENE1",new Gene("GENE1","EntrezGene", false, Set.of(AR,AD)),"GENE2",new Gene("GENE2","EntrezGene", false, Set.of(AD)))).build();

Map<String, Annotation> actual = InheritanceMatcher
.matchInheritance(inheritanceMap, genes);
Expand All @@ -81,12 +77,12 @@ void matchInheritanceUnknownGene() {
Inheritance inheritance1 = Inheritance.builder().inheritanceModes(
Set.of(AD,AR)).subInheritanceModes(Set.of(SubInheritanceMode.AD_IP, SubInheritanceMode.AR_C)).compounds(singleton("OTHER_VARIANT")).build();
Map<String, Inheritance> inheritanceMap = Map.of("sample1", inheritance1);
Collection<Gene> genes = Set.of(new Gene("GENE1","EntrezGene", true, emptySet()));
VariantContextGenes genes = VariantContextGenes.builder().genes(Map.of("GENE1",new Gene("GENE1","EntrezGene", true, emptySet()))).build();

Map<String, Annotation> actual = InheritanceMatcher
.matchInheritance(inheritanceMap, genes);

Inheritance expectedInheritance = Inheritance.builder().match(UNKNOWN).inheritanceModes(
Inheritance expectedInheritance = Inheritance.builder().match(POTENTIAL).inheritanceModes(
Set.of(AR, AD)).subInheritanceModes(Set.of(SubInheritanceMode.AD_IP, SubInheritanceMode.AR_C)).compounds(singleton("OTHER_VARIANT")).build();
Annotation expectedAnnotation = Annotation.builder().inheritance(expectedInheritance).matchingGenes(emptySet()).build();
Map<String, Annotation> expected = Map.of("sample1",expectedAnnotation);
Expand All @@ -98,7 +94,7 @@ void matchInheritanceUnknownGeneAndKnownGeneMatch() {
Inheritance inheritance1 = Inheritance.builder().inheritanceModes(
Set.of(AR)).subInheritanceModes(Set.of(SubInheritanceMode.AR_C)).compounds(singleton("OTHER_VARIANT")).build();
Map<String, Inheritance> inheritanceMap = Map.of("sample1", inheritance1);
Collection<Gene> genes = Set.of(new Gene("GENE1","EntrezGene", false, emptySet()),new Gene("GENE2","EntrezGene", false, Set.of(AR)));
VariantContextGenes genes = VariantContextGenes.builder().genes(Map.of("GENE1",new Gene("GENE1","EntrezGene", false, emptySet()),"GENE2",new Gene("GENE2","EntrezGene", false, Set.of(AR)))).build();

Map<String, Annotation> actual = InheritanceMatcher
.matchInheritance(inheritanceMap, genes);
Expand All @@ -116,12 +112,12 @@ void matchInheritanceUnknownGeneAndKnownGeneMismatch() {
Set.of(AD)).subInheritanceModes(emptySet()).compounds(emptySet()).build();

Map<String, Inheritance> inheritanceMap = Map.of("sample1", inheritance1);
Collection<Gene> genes = Set.of(new Gene("GENE1","EntrezGene", false, emptySet()),new Gene("GENE2","EntrezGene", false, Set.of(AR)));
VariantContextGenes genes = VariantContextGenes.builder().genes(Map.of("GENE1", new Gene("GENE1","EntrezGene", false, emptySet()),"GENE2", new Gene("GENE2","EntrezGene", false, Set.of(AR)))).build();

Map<String, Annotation> actual = InheritanceMatcher
.matchInheritance(inheritanceMap, genes);

Inheritance expectedInheritance = Inheritance.builder().match(UNKNOWN).inheritanceModes(
Inheritance expectedInheritance = Inheritance.builder().match(POTENTIAL).inheritanceModes(
Set.of(AD)).subInheritanceModes(emptySet()).compounds(emptySet()).build();
Annotation expectedAnnotation = Annotation.builder().inheritance(expectedInheritance).matchingGenes(emptySet()).build();
Map<String, Annotation> expected = Map.of("sample1",expectedAnnotation);
Expand Down
Loading

0 comments on commit c42e0f1

Please sign in to comment.