scout-browser 4.92__py3-none-any.whl → 4.95.0__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/adapter/mongo/base.py +3 -0
- scout/adapter/mongo/case.py +27 -2
- scout/adapter/mongo/ccv.py +131 -0
- scout/adapter/mongo/hgnc.py +5 -1
- scout/adapter/mongo/managed_variant.py +4 -2
- scout/adapter/mongo/query.py +91 -54
- scout/adapter/mongo/variant.py +17 -11
- scout/adapter/mongo/variant_events.py +45 -1
- scout/build/ccv.py +59 -0
- scout/build/panel.py +1 -1
- scout/commands/export/export_command.py +0 -0
- scout/commands/load/base.py +0 -0
- scout/commands/load/user.py +0 -0
- scout/commands/serve.py +2 -1
- scout/commands/update/disease.py +0 -0
- scout/commands/update/genes.py +0 -0
- scout/commands/wipe_database.py +0 -0
- scout/constants/__init__.py +2 -0
- scout/constants/case_tags.py +2 -0
- scout/constants/ccv.py +244 -0
- scout/constants/gene_tags.py +22 -12
- scout/demo/643594.config.yaml +2 -2
- scout/demo/643594.research.mei.vcf.gz +0 -0
- scout/demo/643594.research.mei.vcf.gz.tbi +0 -0
- scout/demo/images/custom_images/1300x1000.jpg +0 -0
- scout/load/panelapp.py +8 -12
- scout/models/ccv_evaluation.py +26 -0
- scout/models/variant/variant.py +1 -0
- scout/parse/omim.py +5 -6
- scout/parse/panelapp.py +16 -42
- scout/parse/variant/compound.py +20 -21
- scout/parse/variant/gene.py +0 -0
- scout/parse/variant/genotype.py +0 -0
- scout/resources/custom_igv_tracks/mane.bb +0 -0
- scout/server/blueprints/cases/controllers.py +48 -0
- scout/server/blueprints/cases/templates/cases/case_report.html +61 -1
- scout/server/blueprints/cases/templates/cases/collapsible_actionbar.html +2 -2
- scout/server/blueprints/cases/templates/cases/index.html +0 -2
- scout/server/blueprints/cases/views.py +5 -5
- scout/server/blueprints/clinvar/controllers.py +4 -5
- scout/server/blueprints/institutes/controllers.py +129 -67
- scout/server/blueprints/institutes/forms.py +5 -2
- scout/server/blueprints/institutes/templates/overview/cases.html +6 -0
- scout/server/blueprints/institutes/templates/overview/causatives.html +1 -1
- scout/server/blueprints/institutes/templates/overview/utils.html +18 -6
- scout/server/blueprints/institutes/templates/overview/verified.html +1 -1
- scout/server/blueprints/institutes/views.py +4 -0
- scout/server/blueprints/managed_variants/forms.py +17 -2
- scout/server/blueprints/managed_variants/templates/managed_variants/managed_variants.html +2 -2
- 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 +86 -5
- scout/server/blueprints/variant/templates/variant/sv-variant.html +2 -2
- scout/server/blueprints/variant/templates/variant/tx_overview.html +3 -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 +115 -5
- scout/server/blueprints/variants/controllers.py +31 -0
- scout/server/blueprints/variants/forms.py +33 -5
- scout/server/blueprints/variants/templates/variants/cancer-sv-variants.html +4 -18
- scout/server/blueprints/variants/templates/variants/cancer-variants.html +4 -13
- scout/server/blueprints/variants/templates/variants/components.html +77 -73
- scout/server/blueprints/variants/templates/variants/indicators.html +11 -0
- scout/server/blueprints/variants/templates/variants/sv-variants.html +2 -2
- scout/server/links.py +1 -1
- scout/server/static/custom_images.js +19 -2
- scout/utils/acmg.py +0 -1
- scout/utils/ccv.py +193 -0
- scout/utils/link.py +4 -3
- scout/utils/md5.py +0 -0
- {scout_browser-4.92.dist-info → scout_browser-4.95.0.dist-info}/METADATA +67 -45
- {scout_browser-4.92.dist-info → scout_browser-4.95.0.dist-info}/RECORD +70 -65
- {scout_browser-4.92.dist-info → scout_browser-4.95.0.dist-info}/WHEEL +1 -2
- scout/__version__.py +0 -1
- scout/demo/images/custom_images/640x480_two.jpg +0 -0
- scout_browser-4.92.dist-info/top_level.txt +0 -1
- {scout_browser-4.92.dist-info → scout_browser-4.95.0.dist-info}/entry_points.txt +0 -0
- {scout_browser-4.92.dist-info → scout_browser-4.95.0.dist-info/licenses}/LICENSE +0 -0
@@ -10,6 +10,8 @@ from scout.constants import (
|
|
10
10
|
ACMG_COMPLETE_MAP,
|
11
11
|
ACMG_MAP,
|
12
12
|
CALLERS,
|
13
|
+
CCV_COMPLETE_MAP,
|
14
|
+
CCV_MAP,
|
13
15
|
INHERITANCE_PALETTE,
|
14
16
|
VERBS_ICONS_MAP,
|
15
17
|
VERBS_MAP,
|
@@ -72,6 +74,7 @@ def verified(institute_id):
|
|
72
74
|
return dict(
|
73
75
|
acmg_map={key: ACMG_COMPLETE_MAP[value] for key, value in ACMG_MAP.items()},
|
74
76
|
callers=CALLERS,
|
77
|
+
ccv_map={key: CCV_COMPLETE_MAP[value] for key, value in CCV_MAP.items()},
|
75
78
|
inherit_palette=INHERITANCE_PALETTE,
|
76
79
|
institute=institute_obj,
|
77
80
|
verified=verified_vars,
|
@@ -87,6 +90,7 @@ def causatives(institute_id):
|
|
87
90
|
acmg_map={key: ACMG_COMPLETE_MAP[value] for key, value in ACMG_MAP.items()},
|
88
91
|
callers=CALLERS,
|
89
92
|
causatives=controllers.causatives(institute_obj, request),
|
93
|
+
ccv_map={key: CCV_COMPLETE_MAP[value] for key, value in CCV_MAP.items()},
|
90
94
|
institute=institute_obj,
|
91
95
|
inherit_palette=INHERITANCE_PALETTE,
|
92
96
|
)
|
@@ -10,6 +10,7 @@ from wtforms import (
|
|
10
10
|
SubmitField,
|
11
11
|
validators,
|
12
12
|
)
|
13
|
+
from wtforms.widgets import NumberInput
|
13
14
|
|
14
15
|
from scout.constants import CHROMOSOMES, SV_TYPES
|
15
16
|
|
@@ -24,8 +25,22 @@ CATEGORY_CHOICES = [
|
|
24
25
|
|
25
26
|
|
26
27
|
class ManagedVariantForm(FlaskForm):
|
27
|
-
position = IntegerField(
|
28
|
-
|
28
|
+
position = IntegerField(
|
29
|
+
"Start position",
|
30
|
+
[
|
31
|
+
validators.Optional(),
|
32
|
+
validators.NumberRange(min=0, message="Start position must be 1 or greater."),
|
33
|
+
],
|
34
|
+
widget=NumberInput(min=1),
|
35
|
+
)
|
36
|
+
end = IntegerField(
|
37
|
+
"End position",
|
38
|
+
[
|
39
|
+
validators.Optional(),
|
40
|
+
validators.NumberRange(min=0, message="End position must be 1 or greater."),
|
41
|
+
],
|
42
|
+
widget=NumberInput(min=1),
|
43
|
+
)
|
29
44
|
cytoband_start = SelectField("Cytoband start", choices=[])
|
30
45
|
cytoband_end = SelectField("Cytoband end", choices=[])
|
31
46
|
description = StringField(label="Description")
|
@@ -212,8 +212,8 @@
|
|
212
212
|
<tbody>
|
213
213
|
<tr>
|
214
214
|
<td>{{ add_form.chromosome(class_="form-control") }}</td>
|
215
|
-
<td><input type="number" name="position" id="position" class="form-control" required></td>
|
216
|
-
<td><input type="number" name="end" id="end" class="form-control"></td>
|
215
|
+
<td><input type="number" name="position" id="position" class="form-control" required min="1"></td>
|
216
|
+
<td><input type="number" name="end" id="end" class="form-control" min="1"></td>
|
217
217
|
<td><input type="text" name="reference" id="reference" class="form-control" required></td>
|
218
218
|
<td><input type="text" name="alternative" id="alternative" class="form-control" required></td>
|
219
219
|
<td>{{ add_form.category(class_="form-control", onchange="populateSubTypeSelect('add_variant')") }}</td>
|
@@ -160,7 +160,6 @@ def update_panel(store, panel_name, csv_lines, option):
|
|
160
160
|
Returns:
|
161
161
|
panel_obj(dict)
|
162
162
|
"""
|
163
|
-
new_genes = []
|
164
163
|
panel_obj = store.gene_panel(panel_name)
|
165
164
|
if panel_obj is None:
|
166
165
|
return None
|
@@ -202,11 +201,11 @@ def update_panel(store, panel_name, csv_lines, option):
|
|
202
201
|
)
|
203
202
|
|
204
203
|
info_data = {
|
205
|
-
"disease_associated_transcripts": new_gene
|
206
|
-
"reduced_penetrance": new_gene
|
207
|
-
"mosaicism": new_gene
|
208
|
-
"inheritance_models": new_gene
|
209
|
-
"database_entry_version": new_gene
|
204
|
+
"disease_associated_transcripts": new_gene.get("transcripts", []),
|
205
|
+
"reduced_penetrance": new_gene.get("reduced_penetrance", ""),
|
206
|
+
"mosaicism": new_gene.get("mosaicism", ""),
|
207
|
+
"inheritance_models": new_gene.get("inheritance_models", []),
|
208
|
+
"database_entry_version": new_gene.get("database_entry_version", ""),
|
210
209
|
}
|
211
210
|
if (
|
212
211
|
option == "replace"
|
@@ -223,15 +223,15 @@
|
|
223
223
|
<span data-bs-toggle="tooltip" data-bs-placement="right" data-bs-html="true" title="
|
224
224
|
<div class='text-left'>
|
225
225
|
<strong>Transcripts</strong>:
|
226
|
-
{{ gene.info.disease_associated_transcripts|join(',') }} <br>
|
226
|
+
{{ gene.info.disease_associated_transcripts|join(',') if gene.info.disease_associated_transcripts }} <br>
|
227
227
|
<strong>Reduced penetrance</strong>:
|
228
|
-
{{
|
228
|
+
{{ gene.info.reduced_penetrance if gene.info.reduced_penetrance }} <br>
|
229
229
|
<strong>Mosaicism</strong>:
|
230
|
-
{{
|
230
|
+
{{ gene.info.mosaicism if gene.info.mosaicism }} <br>
|
231
231
|
<strong>Inheritance models</strong>:
|
232
|
-
{{ gene.info.inheritance_models|join(',') }} <br>
|
232
|
+
{{ gene.info.inheritance_models|join(',') if gene.info.inheritance_models }} <br>
|
233
233
|
<strong>Entry version</strong>:
|
234
|
-
{{ gene.info.database_entry_version }} <br>
|
234
|
+
{{ gene.info.database_entry_version if gene.info.database_entry_version }} <br>
|
235
235
|
</div>
|
236
236
|
">
|
237
237
|
{{ gene.symbol }}
|
@@ -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 %}
|
@@ -38,9 +38,13 @@
|
|
38
38
|
<li class="list-group-item {{ 'list-group-item-info' if current_variant }}">
|
39
39
|
<div class="d-flex">
|
40
40
|
<span>
|
41
|
-
|
41
|
+
{% if variant.category in ["snv", "cancer_snv"] %}
|
42
|
+
<a href="{{ url_for('variant.evaluation', evaluation_id=data._id) }}">
|
43
|
+
{{ data.classification.label }}
|
44
|
+
</a>
|
45
|
+
{% else %}
|
42
46
|
{{ data.classification.label }}
|
43
|
-
|
47
|
+
{% endif %}
|
44
48
|
<span class="badge bg-info">{{ data.classification.short }}</span>
|
45
49
|
</span>
|
46
50
|
<span>
|
@@ -133,7 +137,6 @@
|
|
133
137
|
{% endmacro %}
|
134
138
|
|
135
139
|
{% macro acmg_form(institute, case, variant, ACMG_OPTIONS, selected=None) %}
|
136
|
-
<label class="mt-3">ACMG classification</label>
|
137
140
|
<form action="{{ url_for('variant.variant_update', institute_id=institute._id, case_name=case.display_name, variant_id=variant._id) }}" method="POST">
|
138
141
|
<div class="d-flex justify-content-between">
|
139
142
|
{% for option in ACMG_OPTIONS %}
|
@@ -145,11 +148,75 @@
|
|
145
148
|
</form>
|
146
149
|
{% endmacro %}
|
147
150
|
|
151
|
+
{% macro ccv_classification_item(variant, data) %}
|
152
|
+
{% set current_variant = (data.variant_specific == variant._id) %}
|
153
|
+
<li class="list-group-item {{ 'list-group-item-info' if current_variant }}">
|
154
|
+
<div class="d-flex">
|
155
|
+
<span>
|
156
|
+
<a href="{{ url_for('variant.ccv_evaluation', evaluation_id=data._id) }}">
|
157
|
+
{{ data.ccv_classification.label }}
|
158
|
+
</a>
|
159
|
+
<span class="badge bg-info">{{ data.ccv_classification.short }}</span>
|
160
|
+
</span>
|
161
|
+
<span>
|
162
|
+
{% if not current_variant %}
|
163
|
+
<small>{{ data.case.display_name }}</small>
|
164
|
+
{% endif %}
|
165
|
+
</span>
|
166
|
+
</div>
|
167
|
+
<span>
|
168
|
+
<small class="text-muted">
|
169
|
+
{{ data.user_name }} on {{ data.created_at.date() }}
|
170
|
+
{% if current_variant %}
|
171
|
+
<form action="{{ url_for('variant.ccv_evaluation', evaluation_id=data._id) }}" method="POST" style="display: inline-block;">
|
172
|
+
<button class="btn btn-xs btn-link" >Delete</button>
|
173
|
+
</form>
|
174
|
+
{% if data.ccv_criteria %}
|
175
|
+
<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>
|
176
|
+
{% endif %}
|
177
|
+
{% endif %}
|
178
|
+
</small>
|
179
|
+
</span>
|
180
|
+
</li>
|
181
|
+
{% endmacro %}
|
182
|
+
|
183
|
+
|
184
|
+
{% macro ccv_form(institute, case, variant, CCV_OPTIONS, selected=None) %}
|
185
|
+
<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>
|
186
|
+
<form action="{{ url_for('variant.variant_update', institute_id=institute._id, case_name=case.display_name, variant_id=variant._id) }}" method="POST">
|
187
|
+
<div class="d-flex justify-content-between">
|
188
|
+
{% for option in CCV_OPTIONS %}
|
189
|
+
<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 }}">
|
190
|
+
{{ option.short }}
|
191
|
+
</button>
|
192
|
+
{% endfor %}
|
193
|
+
</div>
|
194
|
+
</form>
|
195
|
+
{% endmacro %}
|
196
|
+
|
197
|
+
{% macro panel_classify_sv(variant, institute, case, ACMG_OPTIONS, evaluations) %}
|
198
|
+
<div class="mt-3">
|
199
|
+
ACMG (INDEL) <a href="https://www.acmg.net/docs/standards_guidelines_for_the_interpretation_of_sequence_variants.pdf" rel="noopener noreferrer" target="_blank" style="text-decoration: inherit;" data-bs-toggle="tooltip" title="Richards et al 2015">classification</a>
|
200
|
+
</div>
|
201
|
+
<div>
|
202
|
+
{{ acmg_form(institute, case, variant, ACMG_OPTIONS, variant.acmg_classification.code if variant.acmg_classification) }}
|
203
|
+
</div>
|
204
|
+
<div class="mt-3">
|
205
|
+
ACMG SV classification <a href="https://pubmed.ncbi.nlm.nih.gov/31690835/" target="_blank" rel="noopener noreferrer" referrerpolicy="no-referrer">guidelines</a> & <a href="https://cnvcalc.clinicalgenome.org/cnvcalc/" target="_blank" rel="noopener noreferrer" referrerpolicy="no-referrer">guide</a>.
|
206
|
+
</div>
|
207
|
+
{% if evaluations %} <!-- scrollable previous ACMG evaluations div-->
|
208
|
+
<div class="list-group mt-3" style="max-height:200px;overflow-y: scroll;">
|
209
|
+
{% for evaluation in evaluations %}
|
210
|
+
{{ acmg_classification_item(variant, evaluation) }}
|
211
|
+
{% endfor %}
|
212
|
+
</div>
|
213
|
+
{% endif %}
|
214
|
+
{% endmacro %}
|
148
215
|
|
149
|
-
{% macro panel_classify(variant, institute, case, ACMG_OPTIONS, manual_rank_options, cancer_tier_options, dismiss_variant_options, mosaic_variant_options, evaluations) %}
|
216
|
+
{% 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
217
|
<div class="card panel-default">
|
151
218
|
<div class="panel-heading">Classify</div>
|
152
|
-
<div class="card-body">
|
219
|
+
<div class="card-body" style="margin-top: -30px">
|
153
220
|
{{ variant_tag_button(variant, institute, case, manual_rank_options) }}
|
154
221
|
{% if case.track == "cancer" %}
|
155
222
|
{{ variant_tier_button(variant, institute, case, cancer_tier_options) }}
|
@@ -158,6 +225,7 @@
|
|
158
225
|
{% if case.track != "cancer" %}
|
159
226
|
{{ mosaic_variant_button(variant, institute, case, mosaic_variant_options) }}
|
160
227
|
{% endif %}
|
228
|
+
ACMG <a href="https://www.acmg.net/docs/standards_guidelines_for_the_interpretation_of_sequence_variants.pdf" rel="noopener noreferrer" target="_blank" style="text-decoration: inherit;" data-bs-toggle="tooltip" title="Richards et al 2015">classification</a>
|
161
229
|
{{ acmg_form(institute, case, variant, ACMG_OPTIONS, variant.acmg_classification.code if variant.acmg_classification) }}
|
162
230
|
<div class="mt-3">
|
163
231
|
<a href="{{ url_for('variant.variant_acmg', institute_id=institute._id, case_name=case.display_name, variant_id=variant._id) }}" class="btn btn-outline-secondary form-control">Classify</a>
|
@@ -169,6 +237,19 @@
|
|
169
237
|
{% endfor %}
|
170
238
|
</div>
|
171
239
|
{% endif %}
|
240
|
+
{% if case.track == "cancer" %}
|
241
|
+
{{ ccv_form(institute, case, variant, CCV_OPTIONS, variant.ccv_classification.code if variant.ccv_classification) }}
|
242
|
+
<div class="mt-3">
|
243
|
+
<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>
|
244
|
+
</div>
|
245
|
+
{% if ccv_evaluations %} <!-- scrollable previous ClinGen-CGC-VICC evaluations div-->
|
246
|
+
<div class="list-group mt-3" style="max-height:200px;overflow-y: scroll;">
|
247
|
+
{% for ccv_evaluation in ccv_evaluations %}
|
248
|
+
{{ ccv_classification_item(variant, ccv_evaluation) }}
|
249
|
+
{% endfor %}
|
250
|
+
</div>
|
251
|
+
{% endif %}
|
252
|
+
{% endif %}
|
172
253
|
</div>
|
173
254
|
</div>
|
174
255
|
{% endmacro %}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
{% extends "layout.html" %}
|
2
2
|
{% from "utils.html" import activity_panel, comments_panel, pedigree_panel %}
|
3
3
|
{% from "variant/variant_details.html" import old_observations %}
|
4
|
-
{% from "variant/components.html" import external_scripts, external_stylesheets, matching_variants, variant_scripts %}
|
4
|
+
{% from "variant/components.html" import external_scripts, external_stylesheets, matching_variants, panel_classify_sv, variant_scripts %}
|
5
5
|
{% from "variant/utils.html" import causative_button, genes_panel, igv_track_selection, modal_causative, overlapping_panel, sv_alignments, pin_button, transcripts_panel, custom_annotations, gene_panels %}
|
6
6
|
{% from "variant/rank_score_results.html" import rankscore_panel %}
|
7
7
|
{% from "variant/gene_disease_relations.html" import orpha_omim_phenotypes %}
|
@@ -196,7 +196,7 @@
|
|
196
196
|
{{ variant_tag_button(variant, institute, case, manual_rank_options) }}
|
197
197
|
</div>
|
198
198
|
<div>
|
199
|
-
|
199
|
+
{{ panel_classify_sv(variant, institute, case, ACMG_OPTIONS, evaluations) }}
|
200
200
|
</div>
|
201
201
|
</div>
|
202
202
|
<div class="list-group mt-3">
|