-
Notifications
You must be signed in to change notification settings - Fork 46
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
Fix #4909 - Tavtigian Bayesian point sums #4920
Open
dnil
wants to merge
23
commits into
main
Choose a base branch
from
tavtigian_heat_scale
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+174
−48
Open
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
cb2055b
Fix #4909 - Tavtigian Bayesian point sums
dnil ea4771d
change return type
dnil fd829a0
typo
dnil 8316bb6
typehint
dnil 48bf931
testing output...
dnil 99b95c9
Use constant to store color and icons, fix alignment
dnil 3d15f0a
Link with hover
dnil bfeda6b
add link and tooltip to Richards classification
dnil 55f08a4
Merge branch 'main' into tavtigian_heat_scale
dnil bb96e2f
add tests
dnil 479d381
Add some icons and color for B/LB, P/LP.
dnil a2c4667
fix tests
dnil a389430
Merge with main
dnil b2b1f64
distinct warm color
dnil 6cc8f54
Merge branch 'main' into tavtigian_heat_scale
dnil fd691b7
Merge branch 'main' into tavtigian_heat_scale
dnil e9ced70
Fix code style issues with Black
lint-action 04ae44c
add a couple of test conditions for temp
dnil 4de8ce3
Merge branch 'main' into tavtigian_heat_scale
northwestwitch 88d7fb1
Merge branch 'main' into tavtigian_heat_scale
dnil f1895ec
Fix #4906 - warn on potentially conflicting ACMG terms. (#4932)
dnil 39a4158
Merge again
dnil 6d35c74
One more missed merge
dnil File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,9 @@ | ||
# coding=UTF-8 | ||
|
||
|
||
from typing import Optional | ||
|
||
from scout.constants import ACMG_COMPLETE_MAP | ||
from scout.constants.acmg import ACMG_POTENTIAL_CONFLICTS | ||
|
||
|
||
|
@@ -161,38 +165,31 @@ def is_likely_benign(bs_terms, bp_terms): | |
return False | ||
|
||
|
||
def get_acmg(acmg_terms): | ||
"""Use the algorithm described in ACMG paper to get a ACMG calssification | ||
|
||
Modifying strength of a term is possible by adding a string describing its new level: "PP1_Strong" or | ||
"PVS1_Moderate". | ||
|
||
If no terms return None | ||
|
||
Args: | ||
acmg_terms(set(str)): A collection of prediction terms | ||
|
||
Returns: | ||
prediction(str): in ['uncertain_significance','benign','likely_benign', | ||
'likely_pathogenic','pathogenic'] | ||
|
||
def get_acmg_criteria(acmg_terms: set) -> tuple: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Refactored slightly to have one function to sort the terms, that can be reused by both the Richards and the Tavtigian classifier. |
||
""" | ||
if not acmg_terms: | ||
return None | ||
prediction = "uncertain_significance" | ||
# This variable indicates if Pathogenecity Very Strong exists | ||
Given a set of ACMG evidence criteria terms, that may be strength modified with suffixes. | ||
For each term, | ||
first, Strength modified criteria suffixes should count towards their modified score. | ||
then, we need to see if we match any of the two stand-alone terms. If so, set their respective booleans. | ||
finally, check remaining prefixes if no suffix match or stand-alone criteria match | ||
|
||
Return a tuple with | ||
pvs: This variable indicates if Pathogenicity Very Strong exists | ||
ps_terms: Collection of terms with Pathogenicity Strong | ||
pm_terms: Collection of terms with Pathogenicity moderate | ||
pp_terms: Collection of terms with Pathogenicity supporting | ||
ba: This variable indicates if Benign impact stand-alone exists | ||
bs_terms: Collection of terms with Benign evidence Strong | ||
bp_terms: Collection of terms with supporting Benign evidence | ||
""" | ||
|
||
pvs = False | ||
# Collection of terms with Pathogenecity Strong | ||
ps_terms = [] | ||
# Collection of terms with Pathogenecity moderate | ||
pm_terms = [] | ||
# Collection of terms with Pathogenecity supporting | ||
pp_terms = [] | ||
# This variable indicates if Benign impact stand-alone exists | ||
|
||
ba = False | ||
# Collection of terms with Benign evidence Strong | ||
bs_terms = [] | ||
# Collection of terms with supporting Benign evidence | ||
bp_terms = [] | ||
|
||
suffix_map = { | ||
|
@@ -220,20 +217,47 @@ def get_acmg(acmg_terms): | |
continue | ||
break | ||
else: | ||
# Do we match any of the two standalone terms | ||
if term.startswith("PVS"): | ||
pvs = True | ||
elif term.startswith("BA"): | ||
ba = True | ||
else: # Check remaining prefixes if no suffix match or standalone criteria match | ||
else: | ||
for prefix, term_list in prefix_map.items(): | ||
if term.startswith(prefix): | ||
term_list.append(term) | ||
break | ||
|
||
return (pvs, ps_terms, pm_terms, pp_terms, ba, bs_terms, bp_terms) | ||
|
||
|
||
def get_acmg(acmg_terms: set) -> Optional[str]: | ||
"""Use the algorithm described in ACMG paper (Richards 2015) to get a ACMG classification | ||
|
||
Modifying strength of a term is possible by adding a string describing its new level: "PP1_Strong" or | ||
"PVS1_Moderate". | ||
|
||
BA is considered fully Stand Alone. | ||
|
||
If no terms return None | ||
|
||
Args: | ||
acmg_terms(set(str)): A collection of prediction terms | ||
|
||
Returns: | ||
prediction(str): in ['uncertain_significance','benign','likely_benign', | ||
'likely_pathogenic','pathogenic'] | ||
|
||
""" | ||
if not acmg_terms: | ||
return None | ||
|
||
(pvs, ps_terms, pm_terms, pp_terms, ba, bs_terms, bp_terms) = get_acmg_criteria(acmg_terms) | ||
|
||
if ba: | ||
return "benign" | ||
|
||
prediction = "uncertain_significance" | ||
|
||
pathogenic = is_pathogenic(pvs, ps_terms, pm_terms, pp_terms) | ||
likely_pathogenic = is_likely_pathogenic(pvs, ps_terms, pm_terms, pp_terms) | ||
benign = is_benign(ba, bs_terms) | ||
|
@@ -255,6 +279,90 @@ def get_acmg(acmg_terms): | |
return prediction | ||
|
||
|
||
def get_acmg_temperature(acmg_terms: set) -> Optional[dict]: | ||
""" | ||
Use the algorithm described in Tavtigian 2020 to classifiy variants. | ||
|
||
PVS 8 points, S 4, M 2, P 1. | ||
This gives: | ||
|
||
P > 10 | ||
LP 6 < p < 9 | ||
VUS 0 < p < 5 | ||
LB -1 < p < -6 | ||
B < -7 | ||
|
||
If no terms return None | ||
|
||
Args: | ||
acmg_terms(set(str)): A collection of prediction terms | ||
|
||
Returns: | ||
dict: | ||
temperature: | ||
(points, temperature, point_classification) | ||
|
||
""" | ||
TEMPERATURE_STRINGS = { | ||
-1: {"label": "B/LB", "color": "success", "icon": "fa-times"}, | ||
0: {"label": "Ice cold", "color": "info", "icon": "fa-icicles"}, | ||
1: {"label": "Cold", "color": "info", "icon": "fa-snowman"}, | ||
2: {"label": "Cold", "color": "info", "icon": "fa-snowflake"}, | ||
3: {"label": "Tepid", "color": "yellow", "icon": "fa-temperature-half"}, | ||
4: {"label": "Warm", "color": "orange", "icon": "fa-mug-hot"}, | ||
5: {"label": "Hot", "color": "red", "icon": "fa-pepper-hot"}, | ||
6: {"label": "LP/P", "color": "danger", "icon": "fa-stethoscope"}, | ||
} | ||
|
||
if not acmg_terms: | ||
return {} | ||
|
||
(pvs, ps_terms, pm_terms, pp_terms, ba, bs_terms, bp_terms) = get_acmg_criteria(acmg_terms) | ||
|
||
if ba: | ||
points = -8 | ||
else: | ||
points = ( | ||
8 * pvs | ||
+ 4 * len(ps_terms) | ||
+ 2 * len(pm_terms) | ||
+ len(pp_terms) | ||
- 4 * len(bs_terms) | ||
- len(bp_terms) | ||
) | ||
|
||
if points <= -7: | ||
point_classification = "benign" | ||
temperature_icon = TEMPERATURE_STRINGS[-1].get("icon") | ||
elif points <= -1: | ||
point_classification = "likely_benign" | ||
temperature_icon = TEMPERATURE_STRINGS[-1].get("icon") | ||
elif points <= 5: | ||
point_classification = "uncertain_significance" | ||
elif points <= 9: | ||
point_classification = "likely_pathogenic" | ||
temperature_icon = TEMPERATURE_STRINGS[6].get("icon") | ||
elif points >= 10: | ||
point_classification = "pathogenic" | ||
temperature_icon = TEMPERATURE_STRINGS[6].get("icon") | ||
|
||
temperature_class = ACMG_COMPLETE_MAP[point_classification].get("color") | ||
temperature = ACMG_COMPLETE_MAP[point_classification].get("label") | ||
|
||
if point_classification == "uncertain_significance": | ||
temperature_class = TEMPERATURE_STRINGS[points].get("color") | ||
temperature = TEMPERATURE_STRINGS[points].get("label") | ||
temperature_icon = TEMPERATURE_STRINGS[points].get("icon") | ||
|
||
return { | ||
"points": points, | ||
"temperature": temperature, | ||
"temperature_class": temperature_class, | ||
"temperature_icon": temperature_icon, | ||
"point_classification": ACMG_COMPLETE_MAP[point_classification].get("short"), | ||
} | ||
|
||
|
||
def get_acmg_conflicts(acmg_terms: set) -> list: | ||
"""Check potential conflict paris, return list of reference strings.""" | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unused...