scout-browser 4.91.2__py3-none-any.whl → 4.93.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- scout/__version__.py +1 -1
- scout/adapter/mongo/base.py +3 -0
- scout/adapter/mongo/case.py +27 -2
- scout/adapter/mongo/ccv.py +131 -0
- scout/adapter/mongo/query.py +13 -16
- scout/adapter/mongo/variant.py +4 -3
- scout/adapter/mongo/variant_events.py +45 -1
- scout/build/ccv.py +59 -0
- scout/commands/delete/delete_command.py +27 -4
- scout/commands/serve.py +2 -1
- scout/constants/__init__.py +2 -0
- scout/constants/case_tags.py +2 -0
- scout/constants/ccv.py +244 -0
- scout/demo/643594.config.yaml +2 -2
- scout/demo/images/custom_images/1300x1000.jpg +0 -0
- scout/models/ccv_evaluation.py +26 -0
- scout/models/variant/variant.py +1 -0
- scout/parse/panelapp.py +3 -1
- scout/server/blueprints/cases/templates/cases/case_report.html +45 -0
- scout/server/blueprints/cases/templates/cases/collapsible_actionbar.html +2 -2
- scout/server/blueprints/cases/templates/cases/index.html +0 -2
- scout/server/blueprints/genes/templates/genes/gene.html +6 -0
- scout/server/blueprints/institutes/templates/overview/causatives.html +1 -1
- scout/server/blueprints/institutes/templates/overview/utils.html +12 -1
- scout/server/blueprints/institutes/templates/overview/verified.html +1 -1
- scout/server/blueprints/institutes/views.py +4 -0
- scout/server/blueprints/panels/controllers.py +5 -6
- scout/server/blueprints/panels/templates/panels/panel.html +5 -5
- scout/server/blueprints/variant/controllers.py +148 -1
- scout/server/blueprints/variant/templates/variant/cancer-variant.html +1 -1
- scout/server/blueprints/variant/templates/variant/ccv.html +183 -0
- scout/server/blueprints/variant/templates/variant/components.html +61 -3
- scout/server/blueprints/variant/templates/variant/variant.html +1 -1
- scout/server/blueprints/variant/templates/variant/variant_details.html +29 -11
- scout/server/blueprints/variant/utils.py +21 -1
- scout/server/blueprints/variant/views.py +114 -3
- scout/server/blueprints/variants/controllers.py +31 -0
- scout/server/blueprints/variants/templates/variants/cancer-variants.html +2 -1
- scout/server/blueprints/variants/templates/variants/components.html +63 -73
- scout/server/blueprints/variants/templates/variants/indicators.html +11 -0
- scout/server/extensions/panelapp_extension.py +2 -2
- scout/server/static/custom_images.js +19 -2
- scout/utils/ccv.py +201 -0
- {scout_browser-4.91.2.dist-info → scout_browser-4.93.1.dist-info}/METADATA +6 -5
- {scout_browser-4.91.2.dist-info → scout_browser-4.93.1.dist-info}/RECORD +49 -43
- {scout_browser-4.91.2.dist-info → scout_browser-4.93.1.dist-info}/WHEEL +1 -1
- scout/demo/images/custom_images/640x480_two.jpg +0 -0
- {scout_browser-4.91.2.dist-info → scout_browser-4.93.1.dist-info}/LICENSE +0 -0
- {scout_browser-4.91.2.dist-info → scout_browser-4.93.1.dist-info}/entry_points.txt +0 -0
- {scout_browser-4.91.2.dist-info → scout_browser-4.93.1.dist-info}/top_level.txt +0 -0
@@ -16,6 +16,10 @@ from scout.constants import (
|
|
16
16
|
CANCER_SPECIFIC_VARIANT_DISMISS_OPTIONS,
|
17
17
|
CANCER_TIER_OPTIONS,
|
18
18
|
CASE_TAGS,
|
19
|
+
CCV_COMPLETE_MAP,
|
20
|
+
CCV_CRITERIA,
|
21
|
+
CCV_MAP,
|
22
|
+
CCV_OPTIONS,
|
19
23
|
DISMISS_VARIANT_OPTIONS,
|
20
24
|
IGV_TRACKS,
|
21
25
|
INHERITANCE_PALETTE,
|
@@ -41,6 +45,7 @@ from scout.server.utils import (
|
|
41
45
|
from .utils import (
|
42
46
|
add_gene_info,
|
43
47
|
associate_variant_genes_with_case_panels,
|
48
|
+
ccv_evaluation,
|
44
49
|
clinsig_human,
|
45
50
|
default_panels,
|
46
51
|
end_position,
|
@@ -194,9 +199,11 @@ def variant(
|
|
194
199
|
'cancer_tier_options': CANCER_TIER_OPTIONS,
|
195
200
|
'dismiss_variant_options': DISMISS_VARIANT_OPTIONS,
|
196
201
|
'ACMG_OPTIONS': ACMG_OPTIONS,
|
202
|
+
'CCV_OPTIONS': CCV_OPTIONS,
|
197
203
|
'igv_tracks': IGV_TRACKS,
|
198
204
|
'gens_info': <dict>,
|
199
205
|
'evaluations': <list(evaluations)>,
|
206
|
+
'ccv_evaluations': <list(evaluations)>,
|
200
207
|
'rank_score_results': <list(rank_score_results)>,
|
201
208
|
}
|
202
209
|
|
@@ -340,6 +347,17 @@ def variant(
|
|
340
347
|
evaluation(store, evaluation_obj)
|
341
348
|
evaluations.append(evaluation_obj)
|
342
349
|
|
350
|
+
# Prepare classification information for visualisation
|
351
|
+
ccv_classification = variant_obj.get("ccv_classification")
|
352
|
+
if isinstance(ccv_classification, int):
|
353
|
+
ccv_code = CCV_MAP[variant_obj["ccv_classification"]]
|
354
|
+
variant_obj["ccv_classification"] = CCV_COMPLETE_MAP[ccv_code]
|
355
|
+
|
356
|
+
ccv_evaluations = []
|
357
|
+
for evaluation_obj in store.get_ccv_evaluations(variant_obj):
|
358
|
+
ccv_evaluation(store, evaluation_obj)
|
359
|
+
ccv_evaluations.append(evaluation_obj)
|
360
|
+
|
343
361
|
case_clinvars = store.case_to_clinVars(case_obj.get("display_name"))
|
344
362
|
|
345
363
|
if variant_id in case_clinvars:
|
@@ -379,12 +397,14 @@ def variant(
|
|
379
397
|
"dismiss_variant_options": dismiss_options,
|
380
398
|
"mosaic_variant_options": MOSAICISM_OPTIONS,
|
381
399
|
"ACMG_OPTIONS": ACMG_OPTIONS,
|
400
|
+
"CCV_OPTIONS": CCV_OPTIONS,
|
382
401
|
"case_tag_options": CASE_TAGS,
|
383
402
|
"inherit_palette": INHERITANCE_PALETTE,
|
384
403
|
"igv_tracks": get_igv_tracks("38" if variant_obj["is_mitochondrial"] else genome_build),
|
385
404
|
"has_rna_tracks": case_has_rna_tracks(case_obj),
|
386
405
|
"gens_info": gens.connection_settings(genome_build),
|
387
406
|
"evaluations": evaluations,
|
407
|
+
"ccv_evaluations": ccv_evaluations,
|
388
408
|
"rank_score_results": variant_rank_scores(store, case_obj, variant_obj),
|
389
409
|
}
|
390
410
|
|
@@ -442,7 +462,7 @@ def get_loqusdb_obs_cases(
|
|
442
462
|
obs_cases = []
|
443
463
|
user_institutes_ids = set([inst["_id"] for inst in user_institutes(store, current_user)])
|
444
464
|
for i, case_id in enumerate(obs_families):
|
445
|
-
if len(obs_cases) ==
|
465
|
+
if len(obs_cases) == 50:
|
446
466
|
break
|
447
467
|
if case_id == variant_obj["case_id"]:
|
448
468
|
continue
|
@@ -708,3 +728,130 @@ def variant_acmg_post(
|
|
708
728
|
criteria=criteria,
|
709
729
|
)
|
710
730
|
return classification
|
731
|
+
|
732
|
+
|
733
|
+
def variant_ccv(store: MongoAdapter, institute_id: str, case_name: str, variant_id: str):
|
734
|
+
"""Collect data relevant for rendering ClinGen-CCV-VIGG classification form.
|
735
|
+
|
736
|
+
Args:
|
737
|
+
store(scout.adapter.MongoAdapter)
|
738
|
+
institute_id(str): institute_obj['_id']
|
739
|
+
case_name(str): case_obj['display_name']
|
740
|
+
variant_id(str): variant_obj['document_id']
|
741
|
+
|
742
|
+
Returns:
|
743
|
+
data(dict): Things for the template
|
744
|
+
"""
|
745
|
+
variant_obj = store.variant(variant_id)
|
746
|
+
|
747
|
+
if not variant_obj:
|
748
|
+
return abort(404)
|
749
|
+
|
750
|
+
institute_obj, case_obj = variant_institute_and_case(
|
751
|
+
store, variant_obj, institute_id, case_name
|
752
|
+
)
|
753
|
+
|
754
|
+
return dict(
|
755
|
+
institute=institute_obj,
|
756
|
+
case=case_obj,
|
757
|
+
variant=variant_obj,
|
758
|
+
CRITERIA=CCV_CRITERIA,
|
759
|
+
CCV_OPTIONS=CCV_OPTIONS,
|
760
|
+
)
|
761
|
+
|
762
|
+
|
763
|
+
def check_reset_variant_ccv_classification(
|
764
|
+
store: MongoAdapter, evaluation_obj: dict, link: str
|
765
|
+
) -> bool:
|
766
|
+
"""Check if this was the last ClinGen-CGC-VIGG evaluation left on the variant.
|
767
|
+
If there is still a classification we want to remove the classification.
|
768
|
+
|
769
|
+
Args:
|
770
|
+
stores(cout.adapter.MongoAdapter)
|
771
|
+
evaluation_obj(dict): ClinGen-CGC-VIGG evaluation object
|
772
|
+
link(str): link for event
|
773
|
+
|
774
|
+
Returns: reset(bool) - True if classification reset was attempted
|
775
|
+
|
776
|
+
"""
|
777
|
+
|
778
|
+
if list(store.get_ccv_evaluations_case_specific(evaluation_obj["variant_specific"])):
|
779
|
+
return False
|
780
|
+
|
781
|
+
variant_obj = store.variant(document_id=evaluation_obj["variant_specific"])
|
782
|
+
|
783
|
+
if not variant_obj:
|
784
|
+
return abort(404)
|
785
|
+
|
786
|
+
ccv_classification = variant_obj.get("ccv_classification")
|
787
|
+
|
788
|
+
if not isinstance(ccv_classification, int):
|
789
|
+
return False
|
790
|
+
|
791
|
+
institute_obj, case_obj = variant_institute_and_case(
|
792
|
+
store,
|
793
|
+
variant_obj,
|
794
|
+
evaluation_obj["institute"]["_id"],
|
795
|
+
evaluation_obj["case"]["display_name"],
|
796
|
+
)
|
797
|
+
user_obj = store.user(current_user.email)
|
798
|
+
|
799
|
+
new_ccv = None
|
800
|
+
store.submit_ccv_evaluation(
|
801
|
+
variant_obj=variant_obj,
|
802
|
+
user_obj=user_obj,
|
803
|
+
institute_obj=institute_obj,
|
804
|
+
case_obj=case_obj,
|
805
|
+
link=link,
|
806
|
+
classification=new_ccv,
|
807
|
+
)
|
808
|
+
return True
|
809
|
+
|
810
|
+
|
811
|
+
def variant_ccv_post(
|
812
|
+
store: MongoAdapter,
|
813
|
+
institute_id: str,
|
814
|
+
case_name: str,
|
815
|
+
variant_id: str,
|
816
|
+
user_email: str,
|
817
|
+
criteria: list,
|
818
|
+
) -> dict:
|
819
|
+
"""Calculate an ClinGen-CGC-VICC classification based on a list of criteria.
|
820
|
+
|
821
|
+
Args:
|
822
|
+
store(scout.adapter.MongoAdapter)
|
823
|
+
institute_id(str): institute_obj['_id']
|
824
|
+
case_name(str): case_obj['display_name']
|
825
|
+
variant_id(str): variant_obj['document_id']
|
826
|
+
user_mail(str)
|
827
|
+
criteria()
|
828
|
+
|
829
|
+
Returns:
|
830
|
+
data(dict): Things for the template
|
831
|
+
|
832
|
+
"""
|
833
|
+
variant_obj = store.variant(variant_id)
|
834
|
+
|
835
|
+
if not variant_obj:
|
836
|
+
return abort(404)
|
837
|
+
|
838
|
+
institute_obj, case_obj = variant_institute_and_case(
|
839
|
+
store, variant_obj, institute_id, case_name
|
840
|
+
)
|
841
|
+
|
842
|
+
user_obj = store.user(user_email)
|
843
|
+
variant_link = url_for(
|
844
|
+
"variant.variant",
|
845
|
+
institute_id=institute_id,
|
846
|
+
case_name=case_name,
|
847
|
+
variant_id=variant_id,
|
848
|
+
)
|
849
|
+
classification = store.submit_ccv_evaluation(
|
850
|
+
institute_obj=institute_obj,
|
851
|
+
case_obj=case_obj,
|
852
|
+
variant_obj=variant_obj,
|
853
|
+
user_obj=user_obj,
|
854
|
+
link=variant_link,
|
855
|
+
criteria=criteria,
|
856
|
+
)
|
857
|
+
return classification
|
@@ -74,7 +74,7 @@
|
|
74
74
|
{{ matching_variants(managed_variant, causatives, variant.matching_ranked, variant.matching_tiered) }}
|
75
75
|
<div class="row">
|
76
76
|
<div class="col-sm-3">
|
77
|
-
{{ panel_classify(variant, institute, case, ACMG_OPTIONS, manual_rank_options, cancer_tier_options, dismiss_variant_options, mosaic_variant_options, evaluations) }}
|
77
|
+
{{ panel_classify(variant, institute, case, ACMG_OPTIONS, CCV_OPTIONS, manual_rank_options, cancer_tier_options, dismiss_variant_options, mosaic_variant_options, evaluations, ccv_evaluations) }}
|
78
78
|
</div>
|
79
79
|
<div class="col-sm-4">{{ panel_summary() }}</div>
|
80
80
|
<div class="col-sm-3">
|
@@ -0,0 +1,183 @@
|
|
1
|
+
{% extends "layout.html" %}
|
2
|
+
|
3
|
+
{% block title %}
|
4
|
+
{{ super() }} - {{ institute.display_name }} - {{ case.display_name }} - {{ variant.display_name }} - Classify
|
5
|
+
{% endblock %}
|
6
|
+
|
7
|
+
{% block top_nav %}
|
8
|
+
{{ super() }}
|
9
|
+
<li class="nav-item">
|
10
|
+
<a class="nav-link text-nowrap" href="{{ url_for('cases.index') }}">Institutes</a>
|
11
|
+
</li>
|
12
|
+
<li class="nav-item">
|
13
|
+
<a class="nav-link text-nowrap" href="{{ url_for('overview.cases', institute_id=institute._id) }}">
|
14
|
+
{{ institute.display_name }}
|
15
|
+
</a>
|
16
|
+
</li>
|
17
|
+
<li class="nav-item">
|
18
|
+
<a class="nav-link text-nowrap" href="{{ url_for('cases.case', institute_id=institute._id, case_name=case.display_name) }}">
|
19
|
+
{{ case.display_name }}
|
20
|
+
</a>
|
21
|
+
</li>
|
22
|
+
<li class="nav-item active d-flex align-items-center">
|
23
|
+
<span class="navbar-text">{{ variant.display_name }}</span>
|
24
|
+
</li>
|
25
|
+
{% endblock %}
|
26
|
+
|
27
|
+
{% block content_main %}
|
28
|
+
<div class="container mt-3 mb-5">
|
29
|
+
<form action="{{ url_for('variant.variant_ccv', institute_id=institute._id, case_name=case.display_name, variant_id=variant._id) }}" method="POST">
|
30
|
+
<div class="card panel-default mt-3">
|
31
|
+
<div class="card-body">
|
32
|
+
{% if evaluation %}
|
33
|
+
<h4>
|
34
|
+
{{ evaluation.ccv_classification.label }}
|
35
|
+
<span class="badge bg-info">{{ evaluation.ccv_classification.short|safe }}</span>
|
36
|
+
</h4>
|
37
|
+
By {{ evaluation.user_name }} on {{ evaluation.created_at.date() }}
|
38
|
+
{% if edit %}
|
39
|
+
<br><br>
|
40
|
+
<button class="btn btn-primary form-control" data-bs-toggle="tooltip" title="Editing this classification will result in a new classification">Reclassify</button>
|
41
|
+
{% endif %}
|
42
|
+
{% elif not evaluation %}
|
43
|
+
<button class="btn btn-primary form-control">Submit</button>
|
44
|
+
{% endif %}
|
45
|
+
<div id="conflicts_div" class="bg-warning"></div>
|
46
|
+
</div>
|
47
|
+
</div>
|
48
|
+
|
49
|
+
<div class="d-flex flex-row justify-content-between mt-3">
|
50
|
+
{% for category, criteria_group in CRITERIA.items() %}
|
51
|
+
<div class="flex-column {{ 'me-3' if not loop.last }}">
|
52
|
+
<h4>Evidence of {{ category }}</h4>
|
53
|
+
{% for evidence, criteria in criteria_group.items() %}
|
54
|
+
<ul class="list-group mt-3">
|
55
|
+
<li class="list-group-item">{{ evidence }}</li>
|
56
|
+
{% for criterion_code, criterion in criteria.items() %}
|
57
|
+
{% if evaluation and evaluation.ccv_criteria.get(criterion_code).comment %}
|
58
|
+
{% set comment = evaluation.ccv_criteria.get(criterion_code).comment %}
|
59
|
+
{% endif %}
|
60
|
+
{% if evaluation and evaluation.ccv_criteria.get(criterion_code).links %}
|
61
|
+
{% set link = evaluation.ccv_criteria.get(criterion_code).links[0] %}
|
62
|
+
{% endif %}
|
63
|
+
{% if evaluation and evaluation.ccv_criteria.get(criterion_code).modifier %}
|
64
|
+
{% set modifier = evaluation.ccv_criteria.get(criterion_code).modifier %}
|
65
|
+
{% endif %}
|
66
|
+
<div class="list-group-item">
|
67
|
+
<div class="d-flex justify-content-between">
|
68
|
+
<div data-bs-toggle="tooltip" data-bs-placement="top" title="{{ criterion.description|safe }}">
|
69
|
+
<span class="badge bg-info me-1">{{ criterion_code }}</span>
|
70
|
+
{{ criterion.short|safe}}
|
71
|
+
</div>
|
72
|
+
<div class="form-check form-switch">
|
73
|
+
<input type="checkbox" class="form-check-input" id="checkbox-{{ criterion_code }}" name="criteria" value="{{ criterion_code }}" {{ 'checked' if evaluation and criterion_code in evaluation.ccv_criteria }} {{ 'disabled' if evaluation and edit is false }}>
|
74
|
+
<label class="form-check-label" for="checkbox-{{ criterion_code }}"></label>
|
75
|
+
</div>
|
76
|
+
</div>
|
77
|
+
<div id="comment-{{ criterion_code }}" class="{{ 'collapse' if not (comment or link or modifier) }} mt-2">
|
78
|
+
{% if criterion.documentation %}<div class="row"><span class="me-1 fw-light text-wrap">{{ criterion.documentation | safe }}</span></div>{% endif %}
|
79
|
+
<div class="row">
|
80
|
+
<select {{ 'disabled' if evaluation and edit is false}} id="modifier-{{ criterion_code }}" name="modifier-{{ criterion_code }}" class="form-control form-select">
|
81
|
+
<option value="" {% if not modifier %}selected{% endif %}>Strength modifier...</option>
|
82
|
+
{% for level in "Strong", "Moderate", "Supporting" %}
|
83
|
+
{% if(level != evidence) %}
|
84
|
+
<option id="{{ criterion_code }}-{{ level }}" value="{{ level }}" {% if modifier == level %}selected{% endif %}>{{ level }}</option>
|
85
|
+
{% endif %}
|
86
|
+
{% endfor %}
|
87
|
+
</select>
|
88
|
+
</div>
|
89
|
+
<div class="row">
|
90
|
+
<textarea {{ 'disabled' if evaluation and edit is false }} class="form-control"
|
91
|
+
name="comment-{{ criterion_code }}" rows="3" placeholder="Comment (optional)">{{ comment }}</textarea>
|
92
|
+
</div>
|
93
|
+
<input type="url" {{ 'disabled' if evaluation and edit is false }} class="form-control" name="link-{{ criterion_code }}"
|
94
|
+
placeholder="{{ link or 'Supporting link (optional)' }}" value="">
|
95
|
+
</div>
|
96
|
+
</div>
|
97
|
+
{% endfor %}
|
98
|
+
</li>
|
99
|
+
</ul>
|
100
|
+
{% endfor %}
|
101
|
+
</div>
|
102
|
+
{% endfor %}
|
103
|
+
</div>
|
104
|
+
<!-- classification preview in the footer-->
|
105
|
+
<div class="mt-3 fixed-bottom bg-light border">
|
106
|
+
<div class="row">
|
107
|
+
<div class="col-3" style="font-size:1.5em">
|
108
|
+
<a href="https://doi.org/10.1016/j.gim.2022.01.001" data-bs-toggle="tooltip" title="Suggested classification based on Horak et al 2022." rel="noopener noreferrer" target="_blank"><span id="temperature_span" class="badge"></span></a>
|
109
|
+
</div>
|
110
|
+
<div class="col-6 text-center">
|
111
|
+
{% for option in CCV_OPTIONS %}
|
112
|
+
<a id="ccv-{{ option.code }}" href="https://doi.org/10.1016/j.gim.2022.01.001" class="btn ccv-preview" data-bs-toggle="tooltip" title="Suggested classification based on Horak et al 2022." rel="noopener noreferrer" target="_blank">{{ option.label }}</a>
|
113
|
+
{% endfor %}
|
114
|
+
</div>
|
115
|
+
</div>
|
116
|
+
</div>
|
117
|
+
</form>
|
118
|
+
</div>
|
119
|
+
{% endblock %}
|
120
|
+
|
121
|
+
{% block scripts %}
|
122
|
+
{{ super() }}
|
123
|
+
|
124
|
+
<script>
|
125
|
+
|
126
|
+
window.onload=function() {
|
127
|
+
update_classification();
|
128
|
+
}
|
129
|
+
|
130
|
+
$(function () {
|
131
|
+
$('[data-bs-toggle="tooltip"]').tooltip();
|
132
|
+
|
133
|
+
$('.form-switch').change(function(event) {
|
134
|
+
var el = $('#comment-' + event.target.value);
|
135
|
+
if (event.target.checked) {
|
136
|
+
el.collapse('show');
|
137
|
+
} else {
|
138
|
+
el.collapse('hide');
|
139
|
+
}
|
140
|
+
update_classification()
|
141
|
+
});
|
142
|
+
|
143
|
+
$('.form-select').change(function(event) {
|
144
|
+
update_classification()
|
145
|
+
});
|
146
|
+
});
|
147
|
+
|
148
|
+
|
149
|
+
function update_classification() {
|
150
|
+
var criteria = $(':checked').map(function(idx, elem) {
|
151
|
+
const modifiers = ["Strong", "Moderate", "Supporting"];
|
152
|
+
for (possible_modifier of modifiers) {
|
153
|
+
var modifier_option;
|
154
|
+
if(elem.value !== null && elem.value !== '') {
|
155
|
+
modifier_option = document.getElementById(elem.value + '-' + possible_modifier)
|
156
|
+
}
|
157
|
+
if(modifier_option) {
|
158
|
+
if (modifier_option.selected) {
|
159
|
+
return 'criterion=' + elem.value + '_' + possible_modifier
|
160
|
+
}
|
161
|
+
}
|
162
|
+
}
|
163
|
+
return 'criterion=' + elem.value
|
164
|
+
});
|
165
|
+
|
166
|
+
|
167
|
+
$.getJSON('/api/v1/ccv?' + criteria.toArray().join('&'), function(data) {
|
168
|
+
// reset the selection
|
169
|
+
$('.ccv-preview').removeClass('btn-primary');
|
170
|
+
// add new selection
|
171
|
+
$('#ccv-' + data.classification).addClass('btn-primary');
|
172
|
+
|
173
|
+
var temperature_span = document.getElementById("temperature_span");
|
174
|
+
temperature_span.innerHTML = 'Score ' + data.points + ' <span class="fa ' + data.temperature_icon + '"></span> ' + data.temperature + ' (' + data.point_classification + ')'
|
175
|
+
temperature_span.className = 'badge bg-' + data.temperature_class
|
176
|
+
|
177
|
+
// Update any classification conflicts
|
178
|
+
var conflicts_div = document.getElementById("conflicts_div");
|
179
|
+
conflicts_div.innerHTML = data.conflicts.join("<br>");
|
180
|
+
});
|
181
|
+
}
|
182
|
+
</script>
|
183
|
+
{% endblock %}
|
@@ -133,7 +133,7 @@
|
|
133
133
|
{% endmacro %}
|
134
134
|
|
135
135
|
{% macro acmg_form(institute, case, variant, ACMG_OPTIONS, selected=None) %}
|
136
|
-
<label class="mt-3">ACMG classification</label>
|
136
|
+
<label class="mt-3" data-bs-toggle="tooltip" title="Richards et al 2015"><a href="https://www.acmg.net/docs/standards_guidelines_for_the_interpretation_of_sequence_variants.pdf" rel="noopener noreferrer" target="_blank" style="color: inherit; text-decoration: inherit;">ACMG classification</a></label>
|
137
137
|
<form action="{{ url_for('variant.variant_update', institute_id=institute._id, case_name=case.display_name, variant_id=variant._id) }}" method="POST">
|
138
138
|
<div class="d-flex justify-content-between">
|
139
139
|
{% for option in ACMG_OPTIONS %}
|
@@ -145,11 +145,56 @@
|
|
145
145
|
</form>
|
146
146
|
{% endmacro %}
|
147
147
|
|
148
|
+
{% macro ccv_classification_item(variant, data) %}
|
149
|
+
{% set current_variant = (data.variant_specific == variant._id) %}
|
150
|
+
<li class="list-group-item {{ 'list-group-item-info' if current_variant }}">
|
151
|
+
<div class="d-flex">
|
152
|
+
<span>
|
153
|
+
<a href="{{ url_for('variant.ccv_evaluation', evaluation_id=data._id) }}">
|
154
|
+
{{ data.ccv_classification.label }}
|
155
|
+
</a>
|
156
|
+
<span class="badge bg-info">{{ data.ccv_classification.short }}</span>
|
157
|
+
</span>
|
158
|
+
<span>
|
159
|
+
{% if not current_variant %}
|
160
|
+
<small>{{ data.case.display_name }}</small>
|
161
|
+
{% endif %}
|
162
|
+
</span>
|
163
|
+
</div>
|
164
|
+
<span>
|
165
|
+
<small class="text-muted">
|
166
|
+
{{ data.user_name }} on {{ data.created_at.date() }}
|
167
|
+
{% if current_variant %}
|
168
|
+
<form action="{{ url_for('variant.ccv_evaluation', evaluation_id=data._id) }}" method="POST" style="display: inline-block;">
|
169
|
+
<button class="btn btn-xs btn-link" >Delete</button>
|
170
|
+
</form>
|
171
|
+
{% if data.ccv_criteria %}
|
172
|
+
<a class="btn btn-xs btn-link" href="{{ url_for('variant.ccv_evaluation', evaluation_id=data._id, edit=True) }}" data-bs-toggle="tooltip" title="Editing this classification will result in a new classification">Edit</a>
|
173
|
+
{% endif %}
|
174
|
+
{% endif %}
|
175
|
+
</small>
|
176
|
+
</span>
|
177
|
+
</li>
|
178
|
+
{% endmacro %}
|
148
179
|
|
149
|
-
|
180
|
+
|
181
|
+
{% macro ccv_form(institute, case, variant, CCV_OPTIONS, selected=None) %}
|
182
|
+
<label class="mt-3" data-bs-toggle="tooltip" title="Horak et al 2022"><a href="https://doi.org/10.1016/j.gim.2022.01.001" rel="noopener noreferrer" target="_blank" style="color: inherit; text-decoration: inherit;">ClinGen-CGC-VICC Oncogenicity classification</a></label>
|
183
|
+
<form action="{{ url_for('variant.variant_update', institute_id=institute._id, case_name=case.display_name, variant_id=variant._id) }}" method="POST">
|
184
|
+
<div class="d-flex justify-content-between">
|
185
|
+
{% for option in CCV_OPTIONS %}
|
186
|
+
<button class="btn btn-{{ option.color if (option.code == selected or not selected) else 'outline-secondary' }} form-control {{ 'me-1' if not loop.last }}" name="ccv_classification" value="{{ option.code }}" title="{{ option.label }}">
|
187
|
+
{{ option.short }}
|
188
|
+
</button>
|
189
|
+
{% endfor %}
|
190
|
+
</div>
|
191
|
+
</form>
|
192
|
+
{% endmacro %}
|
193
|
+
|
194
|
+
{% macro panel_classify(variant, institute, case, ACMG_OPTIONS, CCV_OPTIONS, manual_rank_options, cancer_tier_options, dismiss_variant_options, mosaic_variant_options, evaluations, ccv_evaluations) %}
|
150
195
|
<div class="card panel-default">
|
151
196
|
<div class="panel-heading">Classify</div>
|
152
|
-
<div class="card-body">
|
197
|
+
<div class="card-body" style="margin-top: -30px">
|
153
198
|
{{ variant_tag_button(variant, institute, case, manual_rank_options) }}
|
154
199
|
{% if case.track == "cancer" %}
|
155
200
|
{{ variant_tier_button(variant, institute, case, cancer_tier_options) }}
|
@@ -169,6 +214,19 @@
|
|
169
214
|
{% endfor %}
|
170
215
|
</div>
|
171
216
|
{% endif %}
|
217
|
+
{% if case.track == "cancer" %}
|
218
|
+
{{ ccv_form(institute, case, variant, CCV_OPTIONS, variant.ccv_classification.code if variant.ccv_classification) }}
|
219
|
+
<div class="mt-3">
|
220
|
+
<a href="{{ url_for('variant.variant_ccv', institute_id=institute._id, case_name=case.display_name, variant_id=variant._id) }}" class="btn btn-outline-secondary form-control">Classify</a>
|
221
|
+
</div>
|
222
|
+
{% if ccv_evaluations %} <!-- scrollable previous ClinGen-CGC-VICC evaluations div-->
|
223
|
+
<div class="list-group mt-3" style="max-height:200px;overflow-y: scroll;">
|
224
|
+
{% for ccv_evaluation in ccv_evaluations %}
|
225
|
+
{{ ccv_classification_item(variant, ccv_evaluation) }}
|
226
|
+
{% endfor %}
|
227
|
+
</div>
|
228
|
+
{% endif %}
|
229
|
+
{% endif %}
|
172
230
|
</div>
|
173
231
|
</div>
|
174
232
|
{% endmacro %}
|
@@ -84,7 +84,7 @@
|
|
84
84
|
|
85
85
|
<div class="row">
|
86
86
|
<div class="col-lg-3 col-md-6">
|
87
|
-
{{ panel_classify(variant, institute, case, ACMG_OPTIONS, manual_rank_options, cancer_tier_options, dismiss_variant_options, mosaic_variant_options, evaluations) }}
|
87
|
+
{{ panel_classify(variant, institute, case, ACMG_OPTIONS, CCV_OPTIONS, manual_rank_options, cancer_tier_options, dismiss_variant_options, mosaic_variant_options, evaluations, ccv_evaluations) }}
|
88
88
|
</div>
|
89
89
|
<div class="col-lg-5 col-md-6">
|
90
90
|
{{ panel_summary() }}
|
@@ -200,6 +200,20 @@
|
|
200
200
|
</div>
|
201
201
|
{% endmacro %}
|
202
202
|
|
203
|
+
{% macro observation_badge(observed_case) %}
|
204
|
+
|
205
|
+
{% if observed_case.variant and observed_case.variant.category == "snv"%}
|
206
|
+
<a class="badge rounded-pill bg-light text-dark" target="_blank" href="{{ url_for('variant.variant', institute_id=observed_case.case.owner, case_name=observed_case.case.display_name, variant_id=observed_case.variant._id) }}">{{ observed_case.case.display_name }}</a>
|
207
|
+
{% elif observed_case.variant and observed_case.variant.category == "sv"%}
|
208
|
+
<a class="badge rounded-pill bg-light text-dark" target="_blank" href="{{ url_for('variant.sv_variant', institute_id=observed_case.case.owner, case_name=observed_case.case.display_name, variant_id=observed_case.variant._id) }}">{{ observed_case.case.display_name }}</a>
|
209
|
+
{% else %}
|
210
|
+
<span data-bs-toggle="tooltip" title="Missing link, this might be caused by variants not loaded after a rerun or inexact SV matching.">
|
211
|
+
<span class="ml-3 badge rounded-pill bg-light text-dark">{{ observed_case.case.display_name }}</span>
|
212
|
+
</span>
|
213
|
+
{% endif %}
|
214
|
+
|
215
|
+
{% endmacro %}
|
216
|
+
|
203
217
|
{% macro observations_panel(variant, observations, case) %}
|
204
218
|
<div class="card panel-default">
|
205
219
|
<div class="panel-heading d-flex justify-content-between">
|
@@ -240,19 +254,23 @@
|
|
240
254
|
</span>
|
241
255
|
{% endif %}
|
242
256
|
{% endif %}
|
243
|
-
{% for
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
<a class="badge rounded-pill bg-light text-dark" target="_blank" href="{{ url_for('variant.sv_variant', institute_id=data.case.owner, case_name=data.case.display_name, variant_id=data.variant._id) }}">{{ data.case.display_name }}</a>
|
248
|
-
{% else %}
|
249
|
-
<span data-bs-toggle="tooltip" title="Missing link, this might be caused by variants not loaded after a rerun or inexact SV matching.">
|
250
|
-
<span class="ml-3 badge rounded-pill bg-light text-dark">{{ data.case.display_name }}</span>
|
251
|
-
</span>
|
252
|
-
{% endif %}
|
257
|
+
{% for observed_case in obs.cases %}
|
258
|
+
{% if loop.index <= 10 %}
|
259
|
+
{{ observation_badge(observed_case) }}
|
260
|
+
{% endif %}
|
253
261
|
{% endfor %}
|
262
|
+
|
254
263
|
{% if obs.cases|length > 10 %}
|
255
|
-
|
264
|
+
<span class="collapse" id="additionalCases_{{ loqusid }}">
|
265
|
+
{% for observed_case in obs.cases %}
|
266
|
+
{% if loop.index > 10 %}
|
267
|
+
{{ observation_badge(observed_case) }}
|
268
|
+
{% endif %}
|
269
|
+
{% endfor %}
|
270
|
+
</span>
|
271
|
+
<button class="btn btn-link p-0 toggle-button" type="button" data-bs-toggle="collapse" href="#additionalCases_{{ loqusid }}">
|
272
|
+
<span class="toggle-text">Show more/less</span>
|
273
|
+
</button>
|
256
274
|
{% endif %}
|
257
275
|
</td>
|
258
276
|
</tr>
|
@@ -2,7 +2,14 @@ import logging
|
|
2
2
|
from typing import Dict, List, Optional, Tuple
|
3
3
|
|
4
4
|
from scout.adapter import MongoAdapter
|
5
|
-
from scout.constants import
|
5
|
+
from scout.constants import (
|
6
|
+
ACMG_COMPLETE_MAP,
|
7
|
+
CALLERS,
|
8
|
+
CCV_COMPLETE_MAP,
|
9
|
+
CLINSIG_MAP,
|
10
|
+
SO_TERMS,
|
11
|
+
VARIANT_FILTERS,
|
12
|
+
)
|
6
13
|
from scout.server.links import add_gene_links, add_tx_links
|
7
14
|
|
8
15
|
LOG = logging.getLogger(__name__)
|
@@ -472,6 +479,19 @@ def evaluation(store, evaluation_obj):
|
|
472
479
|
return evaluation_obj
|
473
480
|
|
474
481
|
|
482
|
+
def ccv_evaluation(store, evaluation_obj):
|
483
|
+
"""Fetch and fill-in evaluation object."""
|
484
|
+
evaluation_obj["institute"] = store.institute(evaluation_obj["institute_id"])
|
485
|
+
evaluation_obj["case"] = store.case(evaluation_obj["case_id"])
|
486
|
+
evaluation_obj["variant"] = store.variant(evaluation_obj["variant_specific"])
|
487
|
+
evaluation_obj["ccv_criteria"] = {
|
488
|
+
criterion["term"]: criterion for criterion in evaluation_obj["ccv_criteria"]
|
489
|
+
}
|
490
|
+
evaluation_obj["ccv_classification"] = CCV_COMPLETE_MAP.get(
|
491
|
+
evaluation_obj["ccv_classification"]
|
492
|
+
)
|
493
|
+
|
494
|
+
|
475
495
|
def transcript_str(transcript_obj, gene_name=None):
|
476
496
|
"""Generate amino acid change as a string.
|
477
497
|
|