Skip to content

Commit

Permalink
Merge pull request #52 from monarch-initiative/51-add-acmg-check-for-…
Browse files Browse the repository at this point in the history
…variant-results

51 add acmg check for variant results
  • Loading branch information
julesjacobsen authored Mar 18, 2024
2 parents bf29309 + 7384015 commit 0e27bf0
Show file tree
Hide file tree
Showing 2 changed files with 264 additions and 15 deletions.
61 changes: 49 additions & 12 deletions src/pheval_exomiser/post_process/post_process_results_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def extract_pheval_gene_requirements(self) -> [PhEvalGeneResult]:


class PhEvalVariantResultFromExomiserJsonCreator:

def __init__(self, exomiser_json_result: [dict], score_name: str):
self.exomiser_json_result = exomiser_json_result
self.score_name = score_name
Expand Down Expand Up @@ -97,25 +98,51 @@ def _find_relevant_score(self, result_entry) -> float:
"""Return score from Exomiser result entry."""
return round(result_entry[self.score_name], 4)

def extract_pheval_variant_requirements(self) -> [PhEvalVariantResult]:
def _filter_for_acmg_assignments(
self, variant: PhEvalVariantResult, score: float, variant_acmg_assignments: dict
) -> bool:
"""Filter variants if they meet the PATHOGENIC or LIKELY_PATHOGENIC ACMG classification."""
for assignment in variant_acmg_assignments:
if variant == PhEvalVariantResult(
chromosome=self._find_chromosome(assignment["variantEvaluation"]),
start=self._find_start_pos(assignment["variantEvaluation"]),
end=self._find_end_pos(assignment["variantEvaluation"]),
ref=self._find_ref(assignment["variantEvaluation"]),
alt=self._find_alt(assignment["variantEvaluation"]),
score=score,
) and (
assignment["acmgClassification"] == "PATHOGENIC"
or assignment["acmgClassification"] == "LIKELY_PATHOGENIC"
):
return True

def extract_pheval_variant_requirements(
self, use_acmg_filter: bool = False
) -> [PhEvalVariantResult]:
"""Extract data required to produce PhEval variant output."""
simplified_exomiser_result = []
for result_entry in self.exomiser_json_result:
for gene_hit in result_entry["geneScores"]:
if self.score_name in result_entry:
if "contributingVariants" in gene_hit:
score = self._find_relevant_score(result_entry)
for cv in gene_hit["contributingVariants"]:
simplified_exomiser_result.append(
PhEvalVariantResult(
chromosome=self._find_chromosome(cv),
start=self._find_start_pos(cv),
end=self._find_end_pos(cv),
ref=self._find_ref(cv),
alt=self._find_alt(cv),
score=score,
)
contributing_variants = gene_hit["contributingVariants"]
variant_acmg_assignments = gene_hit["acmgAssignments"]
for cv in contributing_variants:
variant = PhEvalVariantResult(
chromosome=self._find_chromosome(cv),
start=self._find_start_pos(cv),
end=self._find_end_pos(cv),
ref=self._find_ref(cv),
alt=self._find_alt(cv),
score=score,
)
if use_acmg_filter and self._filter_for_acmg_assignments(
variant, score, variant_acmg_assignments
):
simplified_exomiser_result.append(variant)
if not use_acmg_filter:
simplified_exomiser_result.append(variant)
return simplified_exomiser_result


Expand Down Expand Up @@ -166,6 +193,7 @@ def create_standardised_results(
variant_analysis: bool,
gene_analysis: bool,
disease_analysis: bool,
include_acmg: bool = False,
) -> None:
"""Write standardised gene/variant/disease results from default Exomiser json output."""
for exomiser_json_result in files_with_suffix(results_dir, ".json"):
Expand All @@ -183,7 +211,7 @@ def create_standardised_results(
if variant_analysis:
pheval_variant_requirements = PhEvalVariantResultFromExomiserJsonCreator(
exomiser_result, score_name
).extract_pheval_variant_requirements()
).extract_pheval_variant_requirements(include_acmg)
generate_pheval_result(
pheval_result=pheval_variant_requirements,
sort_order_str=sort_order,
Expand Down Expand Up @@ -255,6 +283,13 @@ def create_standardised_results(
default=False,
help="Specify whether to create PhEval disease results.",
)
@click.option(
"--include-acmg",
is_flag=True,
type=bool,
default=False,
help="Specify whether to include ACMG filter for PATHOGENIC or LIKELY_PATHOGENIC classifications.",
)
def post_process_exomiser_results(
output_dir: Path,
results_dir: Path,
Expand All @@ -263,6 +298,7 @@ def post_process_exomiser_results(
gene_analysis: bool,
variant_analysis: bool,
disease_analysis: bool,
include_acmg: bool,
):
"""Post-process Exomiser json results into PhEval gene and variant outputs."""
(
Expand All @@ -288,4 +324,5 @@ def post_process_exomiser_results(
variant_analysis,
gene_analysis,
disease_analysis,
include_acmg,
)
218 changes: 215 additions & 3 deletions tests/test_post_process_results_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@
"modeOfInheritance": "AUTOSOMAL_DOMINANT",
"disease": {"diseaseType": "UNCONFIRMED", "inheritanceMode": "UNKNOWN"},
"acmgEvidence": {"empty": True},
"acmgClassification": "UNCERTAIN_SIGNIFICANCE",
"acmgClassification": "PATHOGENIC",
}
],
},
Expand Down Expand Up @@ -834,7 +834,7 @@
"modeOfInheritance": "AUTOSOMAL_RECESSIVE",
"disease": {"diseaseType": "UNCONFIRMED", "inheritanceMode": "UNKNOWN"},
"acmgEvidence": {"empty": True},
"acmgClassification": "UNCERTAIN_SIGNIFICANCE",
"acmgClassification": "PATHOGENIC",
},
],
},
Expand Down Expand Up @@ -1307,7 +1307,7 @@
"modeOfInheritance": "AUTOSOMAL_DOMINANT",
"disease": {"diseaseType": "UNCONFIRMED", "inheritanceMode": "UNKNOWN"},
"acmgEvidence": {"empty": True},
"acmgClassification": "UNCERTAIN_SIGNIFICANCE",
"acmgClassification": "LIKELY_PATHOGENIC",
}
],
},
Expand Down Expand Up @@ -2388,6 +2388,183 @@
}
]

variant_acmg_pathogenic = [
{
"variantEvaluation": {
"genomeAssembly": "HG19",
"contigName": "3",
"start": 126730873,
"end": 126730873,
"ref": "G",
"alt": "A",
"id": "rs78052417",
"type": "SNV",
"length": 1,
"phredScore": 2970.4399999999996,
"variantEffect": "MISSENSE_VARIANT",
"filterStatus": "PASSED",
"contributesToGeneScore": True,
"variantScore": 0.55660325,
"frequencyScore": 0.9972702,
"pathogenicityScore": 0.5581268,
"predictedPathogenic": True,
"passedFilterTypes": [
"FAILED_VARIANT_FILTER",
"PATHOGENICITY_FILTER",
"FREQUENCY_FILTER",
"VARIANT_EFFECT_FILTER",
"INHERITANCE_FILTER",
],
"frequencyData": {
"rsId": "rs78052417",
"knownFrequencies": [
{"source": "THOUSAND_GENOMES", "frequency": 0.01997},
{"source": "TOPMED", "frequency": 0.001133},
{"source": "EXAC_NON_FINNISH_EUROPEAN", "frequency": 0.004534462},
{"source": "GNOMAD_E_NFE", "frequency": 0.0035905354},
],
"score": 0.9972702,
},
"pathogenicityData": {
"clinVarData": {"primaryInterpretation": "NOT_PROVIDED"},
"mostPathogenicScore": {"source": "MVP", "score": 0.5581268},
"score": 0.5581268,
"predictedPathogenicityScores": [
{"source": "REVEL", "score": 0.348},
{"source": "MVP", "score": 0.5581268},
],
},
"compatibleInheritanceModes": ["AUTOSOMAL_DOMINANT", "AUTOSOMAL_RECESSIVE"],
"contributingInheritanceModes": ["AUTOSOMAL_DOMINANT", "AUTOSOMAL_RECESSIVE"],
"transcriptAnnotations": [
{
"variantEffect": "MISSENSE_VARIANT",
"geneSymbol": "PLXNA1",
"accession": "ENST00000251772.4",
"hgvsGenomic": "g.126730873G>A",
"hgvsCdna": "c.2116G>A",
"hgvsProtein": "p.(Ala706Thr)",
"rankType": "EXON",
"rank": 9,
"rankTotal": 31,
},
{
"variantEffect": "MISSENSE_VARIANT",
"geneSymbol": "PLXNA1",
"accession": "ENST00000393409.2",
"hgvsGenomic": "g.126730873G>A",
"hgvsCdna": "c.2185G>A",
"hgvsProtein": "p.(Ala729Thr)",
"rankType": "EXON",
"rank": 9,
"rankTotal": 31,
},
],
},
"geneIdentifier": {
"geneId": "ENSG00000114554",
"geneSymbol": "PLXNA1",
"hgncId": "HGNC:9099",
"hgncSymbol": "PLXNA1",
"entrezId": "5361",
"ensemblId": "ENSG00000114554",
"ucscId": "uc003ejg.3",
},
"modeOfInheritance": "AUTOSOMAL_DOMINANT",
"disease": {"diseaseType": "UNCONFIRMED", "inheritanceMode": "UNKNOWN"},
"acmgEvidence": {"empty": True},
"acmgClassification": "PATHOGENIC",
}
]
variant_acmg_uncertain_significance = [
{
"variantEvaluation": {
"genomeAssembly": "HG19",
"contigName": "3",
"start": 126730873,
"end": 126730873,
"ref": "G",
"alt": "A",
"id": "rs78052417",
"type": "SNV",
"length": 1,
"phredScore": 2970.4399999999996,
"variantEffect": "MISSENSE_VARIANT",
"filterStatus": "PASSED",
"contributesToGeneScore": True,
"variantScore": 0.55660325,
"frequencyScore": 0.9972702,
"pathogenicityScore": 0.5581268,
"predictedPathogenic": True,
"passedFilterTypes": [
"FAILED_VARIANT_FILTER",
"PATHOGENICITY_FILTER",
"FREQUENCY_FILTER",
"VARIANT_EFFECT_FILTER",
"INHERITANCE_FILTER",
],
"frequencyData": {
"rsId": "rs78052417",
"knownFrequencies": [
{"source": "THOUSAND_GENOMES", "frequency": 0.01997},
{"source": "TOPMED", "frequency": 0.001133},
{"source": "EXAC_NON_FINNISH_EUROPEAN", "frequency": 0.004534462},
{"source": "GNOMAD_E_NFE", "frequency": 0.0035905354},
],
"score": 0.9972702,
},
"pathogenicityData": {
"clinVarData": {"primaryInterpretation": "NOT_PROVIDED"},
"mostPathogenicScore": {"source": "MVP", "score": 0.5581268},
"score": 0.5581268,
"predictedPathogenicityScores": [
{"source": "REVEL", "score": 0.348},
{"source": "MVP", "score": 0.5581268},
],
},
"compatibleInheritanceModes": ["AUTOSOMAL_DOMINANT", "AUTOSOMAL_RECESSIVE"],
"contributingInheritanceModes": ["AUTOSOMAL_DOMINANT", "AUTOSOMAL_RECESSIVE"],
"transcriptAnnotations": [
{
"variantEffect": "MISSENSE_VARIANT",
"geneSymbol": "PLXNA1",
"accession": "ENST00000251772.4",
"hgvsGenomic": "g.126730873G>A",
"hgvsCdna": "c.2116G>A",
"hgvsProtein": "p.(Ala706Thr)",
"rankType": "EXON",
"rank": 9,
"rankTotal": 31,
},
{
"variantEffect": "MISSENSE_VARIANT",
"geneSymbol": "PLXNA1",
"accession": "ENST00000393409.2",
"hgvsGenomic": "g.126730873G>A",
"hgvsCdna": "c.2185G>A",
"hgvsProtein": "p.(Ala729Thr)",
"rankType": "EXON",
"rank": 9,
"rankTotal": 31,
},
],
},
"geneIdentifier": {
"geneId": "ENSG00000114554",
"geneSymbol": "PLXNA1",
"hgncId": "HGNC:9099",
"hgncSymbol": "PLXNA1",
"entrezId": "5361",
"ensemblId": "ENSG00000114554",
"ucscId": "uc003ejg.3",
},
"modeOfInheritance": "AUTOSOMAL_DOMINANT",
"disease": {"diseaseType": "UNCONFIRMED", "inheritanceMode": "UNKNOWN"},
"acmgEvidence": {"empty": True},
"acmgClassification": "UNCERTAIN_SIGNIFICANCE",
}
]


class TestPhEvalGeneResultFromExomiserJsonCreator(unittest.TestCase):
@classmethod
Expand Down Expand Up @@ -2466,6 +2643,28 @@ def test_find_relevant_score(self):
0.0484,
)

def test__filter_for_acmg_assignments_pathogenic(self):
self.assertTrue(
self.json_result._filter_for_acmg_assignments(
PhEvalVariantResult(
chromosome="3", start=126730873, end=126730873, ref="G", alt="A", score=0.0484
),
score=0.0484,
variant_acmg_assignments=variant_acmg_pathogenic,
)
)

def test__filter_for_acmg_assignments_uncertain_significance(self):
self.assertFalse(
self.json_result._filter_for_acmg_assignments(
PhEvalVariantResult(
chromosome="3", start=126730873, end=126730873, ref="G", alt="A", score=0.0484
),
score=0.0484,
variant_acmg_assignments=variant_acmg_uncertain_significance,
)
)

def test_extract_pheval_variant_requirements(self):
self.assertEqual(
self.json_result.extract_pheval_variant_requirements(),
Expand All @@ -2482,6 +2681,19 @@ def test_extract_pheval_variant_requirements(self):
],
)

def test_extract_pheval_variant_requirements_filter_acmg(self):
self.assertEqual(
self.json_result.extract_pheval_variant_requirements(True),
[
PhEvalVariantResult(
chromosome="3", start=126730873, end=126730873, ref="G", alt="A", score=0.0484
),
PhEvalVariantResult(
chromosome="3", start=126741108, end=126741108, ref="G", alt="A", score=0.0484
),
],
)


class TestPhEvalDiseaseResultFromExomiserJsonCreator(unittest.TestCase):
@classmethod
Expand Down

0 comments on commit 0e27bf0

Please sign in to comment.