scout-browser 4.102.0__py3-none-any.whl → 4.103.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/case.py +26 -122
- scout/adapter/mongo/clinvar.py +91 -25
- scout/adapter/mongo/event.py +0 -47
- scout/adapter/mongo/variant_loader.py +7 -3
- scout/build/variant/variant.py +1 -0
- scout/commands/load/variants.py +1 -1
- scout/commands/update/user.py +87 -49
- scout/constants/__init__.py +3 -0
- scout/constants/clinvar.py +10 -0
- scout/constants/variant_tags.py +18 -0
- scout/demo/NIST.trgt.stranger.vcf.gz +0 -0
- scout/demo/NIST.trgt.stranger.vcf.gz.tbi +0 -0
- scout/demo/__init__.py +1 -0
- scout/models/clinvar.py +86 -0
- scout/parse/variant/coordinates.py +5 -1
- scout/parse/variant/gene.py +5 -9
- scout/parse/variant/genotype.py +66 -42
- scout/parse/variant/variant.py +2 -0
- scout/server/app.py +71 -2
- scout/server/blueprints/alignviewers/templates/alignviewers/igv_viewer.html +2 -0
- scout/server/blueprints/cases/controllers.py +1 -1
- scout/server/blueprints/cases/templates/cases/case_report.html +19 -2
- scout/server/blueprints/cases/templates/cases/utils.html +8 -29
- scout/server/blueprints/clinvar/controllers.py +233 -53
- scout/server/blueprints/clinvar/form.py +38 -1
- scout/server/blueprints/clinvar/static/form_style.css +8 -1
- scout/server/blueprints/clinvar/templates/clinvar/clinvar_onc_submissions.html +200 -0
- scout/server/blueprints/clinvar/templates/clinvar/clinvar_submissions.html +3 -2
- scout/server/blueprints/clinvar/templates/clinvar/components.html +198 -0
- scout/server/blueprints/clinvar/templates/clinvar/multistep_add_onc_variant.html +187 -0
- scout/server/blueprints/clinvar/templates/clinvar/multistep_add_variant.html +9 -348
- scout/server/blueprints/clinvar/templates/clinvar/scripts.html +193 -0
- scout/server/blueprints/clinvar/views.py +90 -13
- scout/server/blueprints/institutes/controllers.py +44 -5
- scout/server/blueprints/institutes/forms.py +1 -0
- scout/server/blueprints/institutes/templates/overview/gene_variants.html +15 -6
- scout/server/blueprints/institutes/templates/overview/institute_sidebar.html +28 -2
- scout/server/blueprints/institutes/templates/overview/utils.html +1 -1
- scout/server/blueprints/institutes/views.py +17 -4
- scout/server/blueprints/mme/templates/mme/mme_submissions.html +2 -2
- scout/server/blueprints/omics_variants/templates/omics_variants/outliers.html +2 -2
- scout/server/blueprints/variant/controllers.py +1 -1
- scout/server/blueprints/variant/templates/variant/cancer-variant.html +2 -1
- scout/server/blueprints/variant/templates/variant/components.html +0 -1
- scout/server/blueprints/variant/templates/variant/sv-variant.html +2 -1
- scout/server/blueprints/variant/templates/variant/variant.html +2 -2
- scout/server/blueprints/variant/templates/variant/variant_details.html +32 -24
- scout/server/blueprints/variants/templates/variants/cancer-variants.html +5 -3
- scout/server/blueprints/variants/templates/variants/str-variants.html +4 -1
- scout/server/blueprints/variants/templates/variants/sv-variants.html +3 -3
- scout/server/blueprints/variants/templates/variants/utils.html +4 -0
- scout/server/blueprints/variants/templates/variants/variants.html +4 -4
- scout/server/extensions/clinvar_extension.py +2 -2
- scout/server/templates/layout.html +1 -1
- {scout_browser-4.102.0.dist-info → scout_browser-4.103.0.dist-info}/METADATA +1 -1
- {scout_browser-4.102.0.dist-info → scout_browser-4.103.0.dist-info}/RECORD +59 -53
- {scout_browser-4.102.0.dist-info → scout_browser-4.103.0.dist-info}/WHEEL +0 -0
- {scout_browser-4.102.0.dist-info → scout_browser-4.103.0.dist-info}/entry_points.txt +0 -0
- {scout_browser-4.102.0.dist-info → scout_browser-4.103.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,10 +1,11 @@
|
|
1
1
|
import logging
|
2
2
|
from json import dumps
|
3
3
|
from tempfile import NamedTemporaryFile
|
4
|
-
from typing import List, Tuple
|
4
|
+
from typing import List, Optional, Tuple
|
5
5
|
|
6
6
|
from flask import (
|
7
7
|
Blueprint,
|
8
|
+
Response,
|
8
9
|
flash,
|
9
10
|
redirect,
|
10
11
|
render_template,
|
@@ -18,9 +19,10 @@ from scout.constants.clinvar import (
|
|
18
19
|
CASEDATA_HEADER,
|
19
20
|
CLINVAR_HEADER,
|
20
21
|
GERMLINE_CLASSIF_TERMS,
|
22
|
+
ONCOGENIC_CLASSIF_TERMS,
|
21
23
|
)
|
22
24
|
from scout.server.extensions import clinvar_api, store
|
23
|
-
from scout.server.utils import institute_and_case
|
25
|
+
from scout.server.utils import institute_and_case, safe_redirect_back
|
24
26
|
|
25
27
|
from . import controllers
|
26
28
|
|
@@ -40,8 +42,13 @@ def clinvar_submission_status(submission_id):
|
|
40
42
|
"""Sends a request to ClinVar to retrieve and display the status of a submission."""
|
41
43
|
|
42
44
|
# flash a message with current submission status for a ClinVar submission
|
45
|
+
clinvar_resp_status = dict(
|
46
|
+
clinvar_api.json_submission_status(
|
47
|
+
submission_id=submission_id, api_key=request.form.get("apiKey")
|
48
|
+
)
|
49
|
+
)
|
43
50
|
flash(
|
44
|
-
f
|
51
|
+
f"Response from ClinVar: {clinvar_resp_status}",
|
45
52
|
"primary",
|
46
53
|
)
|
47
54
|
return redirect(request.referrer)
|
@@ -76,8 +83,8 @@ def clinvar_add_variant(institute_id, case_name):
|
|
76
83
|
|
77
84
|
|
78
85
|
@clinvar_bp.route("/<institute_id>/<case_name>/clinvar/save", methods=["POST"])
|
79
|
-
def clinvar_save(institute_id, case_name):
|
80
|
-
"""Adds one variant with eventual CaseData observations to an open (or new) ClinVar submission"""
|
86
|
+
def clinvar_save(institute_id: str, case_name: str):
|
87
|
+
"""Adds one germline variant with eventual CaseData observations to an open (or new) ClinVar submission."""
|
81
88
|
institute_obj, case_obj = institute_and_case(store, institute_id, case_name)
|
82
89
|
controllers.add_variant_to_submission(
|
83
90
|
institute_obj=institute_obj, case_obj=case_obj, form=request.form
|
@@ -85,14 +92,14 @@ def clinvar_save(institute_id, case_name):
|
|
85
92
|
return redirect(url_for("cases.case", institute_id=institute_id, case_name=case_name))
|
86
93
|
|
87
94
|
|
88
|
-
@clinvar_bp.route("/<institute_id>/
|
89
|
-
def
|
95
|
+
@clinvar_bp.route("/<institute_id>/clinvar_germline_submissions", methods=["GET"])
|
96
|
+
def clinvar_germline_submissions(institute_id):
|
90
97
|
"""Handle clinVar submission objects and files"""
|
91
98
|
|
92
99
|
institute_obj = institute_and_case(store, institute_id)
|
93
100
|
institute_clinvar_submitters: List[str] = institute_obj.get("clinvar_submitters", [])
|
94
101
|
data = {
|
95
|
-
"submissions": store.
|
102
|
+
"submissions": store.get_clinvar_germline_submissions(institute_id),
|
96
103
|
"institute": institute_obj,
|
97
104
|
"variant_header_fields": CLINVAR_HEADER,
|
98
105
|
"casedata_header_fields": CASEDATA_HEADER,
|
@@ -131,24 +138,94 @@ def clinvar_update_submission(institute_id, submission):
|
|
131
138
|
|
132
139
|
|
133
140
|
@clinvar_bp.route("/<submission>/download/json/<clinvar_id>", methods=["GET"])
|
134
|
-
def clinvar_download_json(submission, clinvar_id):
|
135
|
-
"""Download a json for a clinVar submission
|
141
|
+
def clinvar_download_json(submission: str, clinvar_id: Optional[str]) -> Response:
|
142
|
+
"""Download a json for a clinVar submission.
|
143
|
+
|
144
|
+
Accepts:
|
145
|
+
submission:. It's the _id of the submission in the database
|
146
|
+
clinvar_id: It's the submission number (i.e. SUB123456). Might be available or not in the submission dictionary
|
147
|
+
|
148
|
+
"""
|
149
|
+
filename = clinvar_id if clinvar_id != "None" else submission
|
136
150
|
|
137
151
|
code, conversion_res = controllers.json_api_submission(submission_id=submission)
|
138
152
|
|
139
153
|
if code in [200, 201]:
|
140
154
|
# Write temp CSV file and serve it in response
|
141
|
-
tmp_json = NamedTemporaryFile(mode="a+", prefix=
|
155
|
+
tmp_json = NamedTemporaryFile(mode="a+", prefix=filename, suffix=".json")
|
142
156
|
tmp_json.write(dumps(conversion_res, indent=4))
|
143
157
|
|
144
158
|
tmp_json.flush()
|
145
159
|
tmp_json.seek(0)
|
146
160
|
return send_file(
|
147
161
|
tmp_json.name,
|
148
|
-
download_name=f"{
|
162
|
+
download_name=f"{filename}.json",
|
149
163
|
mimetype="application/json",
|
150
164
|
as_attachment=True,
|
151
165
|
)
|
152
166
|
else:
|
153
|
-
flash(
|
167
|
+
flash(
|
168
|
+
f"JSON file could not be crated for ClinVar submission: {filename}: {conversion_res}",
|
169
|
+
"warning",
|
170
|
+
)
|
154
171
|
return redirect(request.referrer)
|
172
|
+
|
173
|
+
|
174
|
+
### ClinVar oncogenicity variants submissions views
|
175
|
+
|
176
|
+
|
177
|
+
@clinvar_bp.route("/<institute_id>/clinvar_onc_submissions", methods=["GET"])
|
178
|
+
def clinvar_onc_submissions(institute_id):
|
179
|
+
"""Handle clinVar submission objects and files"""
|
180
|
+
|
181
|
+
institute_obj = institute_and_case(store, institute_id)
|
182
|
+
institute_clinvar_submitters: List[str] = institute_obj.get("clinvar_submitters", [])
|
183
|
+
data = {
|
184
|
+
"submissions": list(store.get_clinvar_onc_submissions(institute_id)),
|
185
|
+
"institute": institute_obj,
|
186
|
+
"show_submit": current_user.email in institute_clinvar_submitters
|
187
|
+
or not institute_clinvar_submitters,
|
188
|
+
}
|
189
|
+
return render_template("clinvar/clinvar_onc_submissions.html", **data)
|
190
|
+
|
191
|
+
|
192
|
+
@clinvar_bp.route("/<institute_id>/<case_name>/clinvar/clinvar_add_onc_variant", methods=["POST"])
|
193
|
+
def clinvar_add_onc_variant(institute_id: str, case_name: str):
|
194
|
+
"""Create a ClinVar submission document in database for one or more variants from a case."""
|
195
|
+
institute_obj, case_obj = institute_and_case(store, institute_id, case_name)
|
196
|
+
data = {
|
197
|
+
"institute": institute_obj,
|
198
|
+
"case": case_obj,
|
199
|
+
"onc_classif_terms": ONCOGENIC_CLASSIF_TERMS,
|
200
|
+
}
|
201
|
+
controllers.set_onc_clinvar_form(request.form.get("var_id"), data)
|
202
|
+
return render_template("clinvar/multistep_add_onc_variant.html", **data)
|
203
|
+
|
204
|
+
|
205
|
+
@clinvar_bp.route(
|
206
|
+
"/<institute_id>/<case_name>/clinvar_onc/clinvar_save_onc_variant", methods=["POST"]
|
207
|
+
)
|
208
|
+
def clinvar_onc_save(institute_id: str, case_name: str):
|
209
|
+
"""Adds one somatic variant with eventual CaseData observations to an open (or new) ClinVar congenicity submission"""
|
210
|
+
institute_obj, case_obj = institute_and_case(store, institute_id, case_name)
|
211
|
+
controllers.add_onc_variant_to_submission(
|
212
|
+
institute_obj=institute_obj, case_obj=case_obj, form=request.form
|
213
|
+
)
|
214
|
+
return redirect(url_for("cases.case", institute_id=institute_id, case_name=case_name))
|
215
|
+
|
216
|
+
|
217
|
+
@clinvar_bp.route("/<submission>/clinvar_onc/delete_variant", methods=["POST"])
|
218
|
+
def clinvar_delete_onc_variant(submission: str):
|
219
|
+
"""Delete a single variant (oncogenicitySubmission) from the ClinVar submissions collection."""
|
220
|
+
store.delete_clinvar_onc_var(
|
221
|
+
submission=submission,
|
222
|
+
variant_id=request.form.get("delete_object"),
|
223
|
+
)
|
224
|
+
return safe_redirect_back(request)
|
225
|
+
|
226
|
+
|
227
|
+
@clinvar_bp.route("/<submission>/download", methods=["GET"])
|
228
|
+
def clinvar_download(submission):
|
229
|
+
"""Download a json file for a clinVar submission. This function is only used for oncogenocity submissions for the time being"""
|
230
|
+
|
231
|
+
return store.get_onc_submission_json(submission)
|
@@ -51,6 +51,11 @@ VAR_SPECIFIC_EVENTS = [
|
|
51
51
|
"cancel_sanger",
|
52
52
|
]
|
53
53
|
|
54
|
+
# Query terms in default, non-specific queries for cases
|
55
|
+
NONSPECIFIC_QUERY_TERMS = [
|
56
|
+
"collaborators",
|
57
|
+
]
|
58
|
+
|
54
59
|
# Projection for fetching cases
|
55
60
|
ALL_CASES_PROJECTION = {
|
56
61
|
"analysis_date": 1,
|
@@ -566,6 +571,7 @@ def get_cases_by_query(
|
|
566
571
|
has_clinvar_submission=request.form.get("clinvar_submitted"),
|
567
572
|
projection=ALL_CASES_PROJECTION,
|
568
573
|
)
|
574
|
+
|
569
575
|
return all_cases
|
570
576
|
|
571
577
|
|
@@ -598,13 +604,42 @@ def get_and_set_cases_by_status(
|
|
598
604
|
case_groups[status].append(case_obj)
|
599
605
|
nr_cases_showall_statuses += 1
|
600
606
|
|
607
|
+
def get_specific_query(request: request) -> bool:
|
608
|
+
"""Check if only non-specific query terms were used in query,
|
609
|
+
by yielding the query without actually executing it.
|
610
|
+
|
611
|
+
If so we assume this is a default query, and dim all cases
|
612
|
+
that match the "show_all_cases_status", highlighting the
|
613
|
+
(max limit number) other cases that were returned.
|
614
|
+
|
615
|
+
If this is a specific query, cases returned by this query part will be explicitly
|
616
|
+
highlighted even if they have a status that matches "show_all_cases_status".
|
617
|
+
"""
|
618
|
+
cases_query: dict = store.cases(
|
619
|
+
collaborator=institute_obj["_id"],
|
620
|
+
name_query=request.form,
|
621
|
+
skip_assigned=request.form.get("skip_assigned"),
|
622
|
+
is_research=request.form.get("is_research"),
|
623
|
+
has_rna_data=request.form.get("has_rna"),
|
624
|
+
verification_pending=request.form.get("validation_ordered"),
|
625
|
+
has_clinvar_submission=request.form.get("clinvar_submitted"),
|
626
|
+
yield_query=True,
|
627
|
+
)
|
628
|
+
for key, value in cases_query.items():
|
629
|
+
if key not in NONSPECIFIC_QUERY_TERMS and value not in [None, ""]:
|
630
|
+
return True
|
631
|
+
return False
|
632
|
+
|
633
|
+
specific_query_asked = get_specific_query(request)
|
634
|
+
|
601
635
|
nr_name_query_matching_displayed_cases = 0
|
602
636
|
limit = int(request.form.get("search_limit", 100))
|
603
637
|
for case_obj in previous_query_result_cases:
|
604
638
|
if case_obj["status"] in status_show_all_cases:
|
605
|
-
|
606
|
-
|
607
|
-
group_case["
|
639
|
+
if specific_query_asked:
|
640
|
+
for group_case in case_groups[status]:
|
641
|
+
if group_case["_id"] == case_obj["_id"]:
|
642
|
+
group_case["dimmed_in_search"] = False
|
608
643
|
elif nr_name_query_matching_displayed_cases == limit:
|
609
644
|
break
|
610
645
|
else:
|
@@ -668,7 +703,7 @@ def populate_case_obj(case_obj: dict, store: MongoAdapter):
|
|
668
703
|
all_analyses_dates
|
669
704
|
)
|
670
705
|
|
671
|
-
case_obj["clinvar_variants"] = store.
|
706
|
+
case_obj["clinvar_variants"] = store.case_to_clinvars(case_obj["_id"])
|
672
707
|
case_obj["display_track"] = TRACKS.get(case_obj.get("track", "rare"))
|
673
708
|
|
674
709
|
|
@@ -830,7 +865,9 @@ def export_gene_variants(
|
|
830
865
|
) # CADD score
|
831
866
|
variant_line.append(" | ".join(variant.get("region_annotations", []))) # Region
|
832
867
|
variant_line.append(" | ".join(variant.get("functional_annotations", []))) # Function
|
833
|
-
variant_line.append(
|
868
|
+
variant_line.append(
|
869
|
+
" | ".join(current_app.custom_filters.format_variant_canonical_transcripts(variant))
|
870
|
+
)
|
834
871
|
|
835
872
|
export_lines.append(",".join(variant_line))
|
836
873
|
|
@@ -860,6 +897,8 @@ def gene_variants(store, pymongo_cursor, variant_count, page=1, per_page=50):
|
|
860
897
|
for variant_obj in variant_res:
|
861
898
|
# Populate variant case_display_name
|
862
899
|
variant_case_obj = store.case(case_id=variant_obj["case_id"])
|
900
|
+
if variant_case_obj is None:
|
901
|
+
continue
|
863
902
|
case_display_name = variant_case_obj.get("display_name")
|
864
903
|
variant_obj["case_display_name"] = case_display_name
|
865
904
|
|
@@ -152,6 +152,7 @@ class GeneVariantFiltersForm(FlaskForm):
|
|
152
152
|
"HGNC Symbols (comma-separated, case sensitive)",
|
153
153
|
validators=[validators.InputRequired()],
|
154
154
|
)
|
155
|
+
institute = SelectMultipleField(choices=[])
|
155
156
|
rank_score = IntegerField(default=15)
|
156
157
|
phenotype_terms = TagListField("HPO terms (comma-separated)")
|
157
158
|
phenotype_groups = TagListField("Phenotype groups")
|
@@ -2,7 +2,7 @@
|
|
2
2
|
{% from "variants/components.html" import frequency_cell_general, variant_funct_anno_cell, variant_gene_symbols_cell %}
|
3
3
|
{% from "utils.html" import comments_table %}
|
4
4
|
{% from "overview/institute_sidebar.html" import institute_actionbar %}
|
5
|
-
{% from "variants/utils.html" import pagination_footer, pagination_hidden_div %}
|
5
|
+
{% from "variants/utils.html" import pagination_footer, pagination_hidden_div, variant_rank_score %}
|
6
6
|
|
7
7
|
{% block title %}
|
8
8
|
{{ super() }} - {{ institute.display_name }} - All SNVs and INDELs
|
@@ -96,17 +96,22 @@
|
|
96
96
|
{{ variant.sub_category|upper }}({{ variant.chromosome }}{{ variant.cytoband_start }}-{{ variant.end_chrom }}{{ variant.cytoband_end }})
|
97
97
|
{% endif %}
|
98
98
|
{% else %}
|
99
|
-
|
99
|
+
<a href="{{ url_for('variant.variant', institute_id=variant.institute,
|
100
100
|
case_name=variant.case_display_name, variant_id=variant._id) }}" target="_blank">
|
101
|
-
|
102
|
-
|
103
|
-
|
101
|
+
{% set lines = variant | format_variant_canonical_transcripts %}
|
102
|
+
{% if lines | length > 1 %}
|
103
|
+
{{ lines | join('<br>') | safe }}
|
104
|
+
{% elif lines %}
|
105
|
+
{{ lines[0] }}
|
106
|
+
{% endif %}
|
107
|
+
{% endif %}
|
108
|
+
</a>
|
104
109
|
{% endmacro %}
|
105
110
|
|
106
111
|
{% macro cell_rank(variant) %}
|
107
112
|
{{ variant.case_display_name }}
|
108
113
|
:
|
109
|
-
<span class="badge bg-info">{{ variant
|
114
|
+
<span class="badge bg-info">{{ variant_rank_score(variant) }}</span>
|
110
115
|
{% endmacro %}
|
111
116
|
|
112
117
|
{% macro cell_cadd(variant) %}
|
@@ -130,6 +135,10 @@
|
|
130
135
|
{{ form.hgnc_symbols.label(class="control-label") }}
|
131
136
|
{{ form.hgnc_symbols(class="form-control") }}
|
132
137
|
</div>
|
138
|
+
<div class="col col-md-2">
|
139
|
+
{{ form.institute.label(class="control-label") }}
|
140
|
+
{{ form.institute(class="form-control", class="selectpicker", data_style="btn-secondary") }}
|
141
|
+
</div>
|
133
142
|
<div class="col col-md-1">
|
134
143
|
<label class="control-label" for="rank_score">Rank Score</label>
|
135
144
|
<input type="number" class="form-control" id="rank_score" name="rank_score" min="5" value={{form.rank_score.data}}>
|
@@ -44,12 +44,38 @@
|
|
44
44
|
</a>
|
45
45
|
|
46
46
|
<!-- ClinVar data menu item -->
|
47
|
-
<a href="
|
47
|
+
<a href="#submenu1" aria-controls="submenu1" data-bs-toggle="collapse" aria-expanded="false" class="bg-dark list-group-item list-group-item-action flex-column align-items-start">
|
48
48
|
<div class="d-flex w-100 justify-content-start align-items-center">
|
49
49
|
<span class="fas fa-file-medical me-3"></span>
|
50
|
-
<span class="menu-collapsed">ClinVar submissions</span>
|
50
|
+
<span class="menu-collapsed text-nowrap flex-grow-1">ClinVar submissions</span>
|
51
|
+
<span class="submenu-icon ms-auto"></span>
|
51
52
|
</div>
|
52
53
|
</a>
|
54
|
+
<div id='submenu1' class="collapse sidebar-submenu">
|
55
|
+
<div href="#" class="bg-dark list-group-item text-white">
|
56
|
+
|
57
|
+
<div class="d-flex flex-row flex-fill bd-highlight">
|
58
|
+
<div>
|
59
|
+
<span class="menu-collapsed">Germline</span>
|
60
|
+
</div>
|
61
|
+
<div>
|
62
|
+
<a href="{{ url_for('clinvar.clinvar_germline_submissions', institute_id=institute._id) }}" target="_blank" rel="noopener">
|
63
|
+
<span class="fa fa-link"></span></a>
|
64
|
+
</div>
|
65
|
+
</div>
|
66
|
+
|
67
|
+
<div class="d-flex flex-row flex-fill bd-highlight">
|
68
|
+
<div>
|
69
|
+
<span class="menu-collapsed">Oncogenic</span>
|
70
|
+
</div>
|
71
|
+
<div>
|
72
|
+
<a href="{{ url_for('clinvar.clinvar_onc_submissions', institute_id=institute._id) }}" target="_blank" rel="noopener">
|
73
|
+
<span class="fa fa-link"></span></a>
|
74
|
+
</div>
|
75
|
+
</div>
|
76
|
+
|
77
|
+
</div>
|
78
|
+
</div>
|
53
79
|
|
54
80
|
<!-- MME data menu item -->
|
55
81
|
<a href="{{ url_for('mme.mme_submissions', institute_id=institute._id) }}" class="bg-dark list-group-item list-group-item-action flex-column align-items-start">
|
@@ -25,7 +25,7 @@
|
|
25
25
|
</div>
|
26
26
|
<div class="col-md-1 mb-3">
|
27
27
|
{{ form.search_limit.label(class="form-label") }}
|
28
|
-
{{ form.search_limit(class="form-control") }}
|
28
|
+
{{ form.search_limit(class="form-control", type="number", min="1", step="1", required=True) }}
|
29
29
|
</div>
|
30
30
|
<div class="btn-sm mb-2 col-md-3 mx-auto">
|
31
31
|
{{ form.search(class="btn btn-primary mt-4") }}
|
@@ -18,7 +18,12 @@ from scout.constants import (
|
|
18
18
|
)
|
19
19
|
from scout.server.blueprints.variants.controllers import update_form_hgnc_symbols
|
20
20
|
from scout.server.extensions import beacon, loqusdb, store
|
21
|
-
from scout.server.utils import
|
21
|
+
from scout.server.utils import (
|
22
|
+
institute_and_case,
|
23
|
+
jsonconverter,
|
24
|
+
templated,
|
25
|
+
user_institutes,
|
26
|
+
)
|
22
27
|
|
23
28
|
from . import controllers
|
24
29
|
from .forms import GeneVariantFiltersForm, InstituteForm
|
@@ -138,10 +143,18 @@ def gene_variants(institute_id):
|
|
138
143
|
|
139
144
|
data = {}
|
140
145
|
|
146
|
+
institute_choices = [
|
147
|
+
(inst["_id"], f"{inst['display_name']} ({inst['_id']})")
|
148
|
+
for inst in user_institutes(store, current_user)
|
149
|
+
]
|
150
|
+
form = GeneVariantFiltersForm()
|
151
|
+
form.institute.choices = institute_choices
|
152
|
+
users_institute_ids = [choice[0] for choice in institute_choices]
|
153
|
+
|
141
154
|
if request.method == "GET":
|
142
|
-
form
|
155
|
+
form.process(request.args)
|
143
156
|
else: # POST
|
144
|
-
form
|
157
|
+
form.process(request.form)
|
145
158
|
|
146
159
|
if form.variant_type.data == []:
|
147
160
|
form.variant_type.data = ["clinical"]
|
@@ -158,7 +171,7 @@ def gene_variants(institute_id):
|
|
158
171
|
|
159
172
|
variants_query = store.build_variant_query(
|
160
173
|
query=form.data,
|
161
|
-
institute_ids=[inst
|
174
|
+
institute_ids=[inst for inst in form.institute.data if inst in users_institute_ids],
|
162
175
|
category=category,
|
163
176
|
variant_type=variant_type,
|
164
177
|
) # This is the actual query dictionary, not the cursor with results
|
@@ -60,7 +60,7 @@
|
|
60
60
|
{% set collapse_id = 'collapse-' + case._id %}
|
61
61
|
{% set max_chars = 300 %}
|
62
62
|
|
63
|
-
{% if case.synopsis|length > max_chars %}
|
63
|
+
{% if case.synopsis and case.synopsis|length > max_chars %}
|
64
64
|
<div>
|
65
65
|
{{ case.synopsis[:max_chars] }}…
|
66
66
|
</div>
|
@@ -80,7 +80,7 @@
|
|
80
80
|
</div>
|
81
81
|
</div>
|
82
82
|
{% else %}
|
83
|
-
{{ case.synopsis }}
|
83
|
+
{{ case.synopsis or 'NA' }}
|
84
84
|
{% endif %}
|
85
85
|
</td>
|
86
86
|
<td>{{ case.status }}</td>
|
@@ -100,8 +100,8 @@
|
|
100
100
|
<span data-bs-toggle="tooltip" data-bs-html="true" title='The ∆ψ-value, which is the difference between the actual observed ψ (intron Jaccard Index splice metric) and the expected ψ - see FRASER vignette for details.'>
|
101
101
|
{{ variant.delta_psi }} <a target="_blank" href="https://www.bioconductor.org/packages/devel/bioc/vignettes/FRASER/inst/doc/FRASER.pdf" rel="noopener noreferrer">Δψ</a></span>
|
102
102
|
{% else %}
|
103
|
-
<span data-bs-toggle="tooltip" data-bs-html="true" title='The log2 fold change - click to see OUTRIDER vignette for details.'>
|
104
|
-
{{ variant.l2fc }} <a target="_blank" href="https://www.bioconductor.org/packages/devel/bioc/vignettes/OUTRIDER/inst/doc/OUTRIDER.pdf" rel="noopener noreferrer">{% if variant.l2fc > 0 %}↑{% elif variant.l2fc < 0 %}↓{% endif %}</a></span>
|
103
|
+
<span data-bs-toggle="tooltip" data-bs-html="true" title='The log2 fold change (fold change) - click to see OUTRIDER vignette for details.'>
|
104
|
+
{{ variant.l2fc }} ({{variant.l2fc|l2fc_2_fc|round(2)}}x) <a target="_blank" href="https://www.bioconductor.org/packages/devel/bioc/vignettes/OUTRIDER/inst/doc/OUTRIDER.pdf" rel="noopener noreferrer">{% if variant.l2fc > 0 %}↑{% elif variant.l2fc < 0 %}↓{% endif %}</a></span>
|
105
105
|
{% endif %}
|
106
106
|
</td>
|
107
107
|
<td>
|
@@ -365,7 +365,7 @@ def variant(
|
|
365
365
|
ccv_evaluation(store, evaluation_obj)
|
366
366
|
ccv_evaluations.append(evaluation_obj)
|
367
367
|
|
368
|
-
case_clinvars = store.
|
368
|
+
case_clinvars = store.case_to_clinvars(case_obj.get("display_name"))
|
369
369
|
|
370
370
|
if variant_id in case_clinvars:
|
371
371
|
variant_obj["clinvar_clinsig"] = case_clinvars.get(variant_id)["clinsig"]
|
@@ -8,6 +8,7 @@
|
|
8
8
|
{% from "variant/sanger.html" import modal_cancel_sanger, modal_sanger, sanger_button %}
|
9
9
|
{% from "variant/gene_disease_relations.html" import orpha_omim_phenotypes %}
|
10
10
|
{% from "variant/rank_score_results.html" import rankscore_panel %}
|
11
|
+
{% from "variants/utils.html" import variant_rank_score %}
|
11
12
|
|
12
13
|
{% block title %}
|
13
14
|
{{ super() }} - {{ institute.display_name }} - {{ case.display_name }} - {{ variant.display_name }}
|
@@ -282,7 +283,7 @@
|
|
282
283
|
<strong>{{ variant.alternative }}</strong>
|
283
284
|
{%- endif -%}
|
284
285
|
</li>
|
285
|
-
<li class="list-group-item">Rank score: <span class="font-weight-bold">{{ variant
|
286
|
+
<li class="list-group-item">Rank score: <span class="font-weight-bold">{{ variant_rank_score(variant) }}</span>
|
286
287
|
</li>
|
287
288
|
<li class="list-group-item">
|
288
289
|
{{ clinsig_table(variant) }}
|
@@ -1,7 +1,6 @@
|
|
1
1
|
{% from "cases/chanjo2_form.html" import chanjo2_report_form %}
|
2
2
|
{% from "variant/buttons.html" import variant_tag_button, variant_tier_button, dismiss_variant_button, mosaic_variant_button %}
|
3
3
|
{% from "variants/utils.html" import compounds_table %}
|
4
|
-
{% from "variant/variant_details.html" import severity_list %}
|
5
4
|
{% from "variant/buttons.html" import reviewer_button, splice_junctions_button %}
|
6
5
|
{% from "variant/utils.html" import igv_track_selection %}
|
7
6
|
|
@@ -7,6 +7,7 @@
|
|
7
7
|
{% from "variant/gene_disease_relations.html" import orpha_omim_phenotypes %}
|
8
8
|
{% from "variant/variant_details.html" import frequencies, gtcall_panel, observations_panel %}
|
9
9
|
{% from "variant/buttons.html" import dismiss_variant_button, splice_junctions_button, variant_tag_button %}
|
10
|
+
{% from "variants/utils.html" import variant_rank_score %}
|
10
11
|
|
11
12
|
{% block title %}
|
12
13
|
{{ super() }} - {{ institute.display_name }} - {{ case.display_name }} - {{ variant.display_name }}
|
@@ -174,7 +175,7 @@
|
|
174
175
|
<li class="list-group-item">Rank <span class="badge rounded-pill bg-secondary float-end">{{ variant.variant_rank }}</span></li>
|
175
176
|
<li class="list-group-item">
|
176
177
|
Rank score
|
177
|
-
<span class="badge rounded-pill bg-secondary float-end">{{
|
178
|
+
<span class="badge rounded-pill bg-secondary float-end">{{variant_rank_score(variant)}}</span>
|
178
179
|
</li>
|
179
180
|
|
180
181
|
<li class="list-group-item">
|
@@ -1,7 +1,7 @@
|
|
1
1
|
{% extends "layout.html" %}
|
2
2
|
{% from "variant/buttons.html" import database_buttons %}
|
3
3
|
{% from "utils.html" import activity_panel, comments_panel, pedigree_panel %}
|
4
|
-
{% from "variants/utils.html" import compounds_table %}
|
4
|
+
{% from "variants/utils.html" import compounds_table, variant_rank_score %}
|
5
5
|
{% from "variant/utils.html" import causative_button, genes_panel, modal_causative, overlapping_panel, pin_button, proteins_panel, transcripts_panel, custom_annotations, gene_panels %}
|
6
6
|
{% from "variant/tx_overview.html" import disease_associated, transcripts_overview %}
|
7
7
|
{% from "variant/gene_disease_relations.html" import autozygosity_panel, genemodels_panel, inheritance_panel, orpha_omim_phenotypes %}
|
@@ -263,7 +263,7 @@
|
|
263
263
|
</td>
|
264
264
|
<td>
|
265
265
|
Rank score
|
266
|
-
<span><strong>{{
|
266
|
+
<span><strong>{{variant_rank_score(variant)}}</strong></span>
|
267
267
|
</td>
|
268
268
|
<td>
|
269
269
|
CADD score
|
@@ -19,7 +19,7 @@
|
|
19
19
|
{% elif variant.category == "sv" %}
|
20
20
|
<th rowspan="2" colspan="1" title="SV caller specific quality score. Note different scales for different callers.">SV quality</th>
|
21
21
|
{% elif variant.category == "str" %}
|
22
|
-
<th rowspan="2" colspan="1">
|
22
|
+
<th rowspan="2" colspan="1">Expansion support</th>
|
23
23
|
{% else %}
|
24
24
|
{% if variant.chromosome in ["MT","M"] %}
|
25
25
|
<th rowspan="2" colspan="1" title="Variant Allele Frequency.">Variant Allele Frequency (VAF)</th>
|
@@ -54,7 +54,8 @@
|
|
54
54
|
|
55
55
|
{% if variant.category == "snv" and variant.chromosome in ["MT","M"] %}
|
56
56
|
<td>
|
57
|
-
{
|
57
|
+
{# Using number == number as a test for NaN value numbers here. Given that they exist, NaN values are the only time a number is not considered equal to itself. #}
|
58
|
+
{% if sample.alt_frequency and sample.alt_frequency != -1 and sample.alt_frequency == sample.alt_frequency %}
|
58
59
|
{{ (100*sample.alt_frequency)|round(2) }}%
|
59
60
|
{% else %}
|
60
61
|
N/A
|
@@ -80,7 +81,7 @@
|
|
80
81
|
<small>N/A</small>
|
81
82
|
{% endif %} (<small>VQ</small>
|
82
83
|
{% if variant.quality not in ["None", None, "-1", -1] %}
|
83
|
-
{{variant.quality}}
|
84
|
+
{{variant.quality|round(1)}}
|
84
85
|
{% else %}
|
85
86
|
<small>N/A</small>
|
86
87
|
{% endif%})
|
@@ -352,13 +353,15 @@
|
|
352
353
|
<li class="list-group-item">
|
353
354
|
<a href="https://sites.google.com/site/revelgenomics/about" target="_blank" data-bs-toggle="tooltip"
|
354
355
|
title="An ensemble score based on 13 individual scores for predicting the pathogenicity of missense variants. Scores range from 0 to 1. The larger the score the more likely the SNP has damaging effect">REVEL score</a>
|
355
|
-
|
356
|
-
|
357
|
-
|
356
|
+
{% if variant.revel and variant.revel != "-" %}
|
357
|
+
<span class="badge float-end bg-{{variant.revel|get_label_or_color_by_score('revel', 'color')}}" data-bs-toggle="tooltip" title="{{variant.revel|get_label_or_color_by_score('revel', 'label')}}">
|
358
|
+
{{ variant.revel }}
|
359
|
+
</span>
|
358
360
|
{% else %}
|
359
|
-
|
361
|
+
<span class="float-end">
|
362
|
+
{{ "-" }}
|
363
|
+
</span>
|
360
364
|
{% endif %}
|
361
|
-
</span>
|
362
365
|
</li>
|
363
366
|
<li class="list-group-item">
|
364
367
|
<a href="http://database.liulab.science/dbNSFP" target="_blank" data-bs-toggle="tooltip"
|
@@ -386,23 +389,28 @@
|
|
386
389
|
<span class="float-end">{{ variant.spidex|spidex_human if variant.spidex else none|spidex_human }}</span>
|
387
390
|
</li>
|
388
391
|
<li class="list-group-item">
|
392
|
+
{% set spliceai_highest = variant.spliceai_scores | spliceai_max %}
|
389
393
|
<a href="{{ variant.spliceai_link }}" target="_blank" rel="noopener">SpliceAI</a> <a href="https://github.com/Illumina/SpliceAI" target="_blank" rel="noopener">DS max</a>
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
{%
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
394
|
+
{% if spliceai_highest %}
|
395
|
+
<span class="badge bg-{{ spliceai_highest | get_label_or_color_by_score('spliceai', 'color') }} float-end" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom"
|
396
|
+
title="<strong>
|
397
|
+
{% for entry in variant.spliceai_scores %}
|
398
|
+
{% if entry is not none %}
|
399
|
+
SpliceAI highest delta score {{ entry }} </strong> at position {{ variant.spliceai_positions[loop.index0]}} relative to this variant. {{ spliceai_highest | get_label_or_color_by_score('spliceai', 'label')}} according to Walker et al 2023.
|
400
|
+
{% if variant.spliceai_predictions[loop.index0] %}
|
401
|
+
<br>All scores and positions(relative to variant):<br>
|
402
|
+
{{ variant.spliceai_predictions[loop.index0] }} <br>
|
403
|
+
{% endif %}
|
404
|
+
<br>
|
405
|
+
{% else %}
|
406
|
+
No SpliceAI positions annotated for this variant.
|
407
|
+
{% endif %}
|
408
|
+
{% endfor %}
|
409
|
+
">
|
410
|
+
{{ variant.spliceai_scores|join(', ') }}
|
411
|
+
{% else %}
|
412
|
+
<span class="float-end">{{ "-" }}
|
413
|
+
{% endif %}
|
406
414
|
</span>
|
407
415
|
</li>
|
408
416
|
</ul>
|
@@ -1,7 +1,7 @@
|
|
1
1
|
{% extends "layout.html" %}
|
2
2
|
|
3
3
|
{% from "variants/components.html" import allele_cell, external_scripts, external_stylesheets, gene_cell, frequency_cell_general, observed_cell_general, variant_funct_anno_cell %}
|
4
|
-
{% from "variants/utils.html" import cancer_filters, cell_rank, pagination_footer, pagination_hidden_div, dismiss_variants_block, filter_form_footer, filter_script_main, update_stash_filter_button_status, callers_cell %}
|
4
|
+
{% from "variants/utils.html" import cancer_filters, cell_rank, pagination_footer, pagination_hidden_div, dismiss_variants_block, filter_form_footer, filter_script_main, update_stash_filter_button_status, callers_cell, variant_rank_score %}
|
5
5
|
{% from "variants/indicators.html" import pin_indicator, causative_badge, clinical_assessments_badge, comments_badge, dismissals_badge, evaluations_badge, group_assessments_badge, matching_manual_rank, other_tiered_variants, research_assessments_badge %}
|
6
6
|
|
7
7
|
{% block title %}
|
@@ -56,7 +56,7 @@
|
|
56
56
|
<th title="Gene">Gene</th>
|
57
57
|
<th title="Variant" style="width:12%">HGVS[c/p]</th>
|
58
58
|
<th title="Assessments including variant tier" style="width:8%">Assessment</th>
|
59
|
-
<th title="Rank
|
59
|
+
<th data-bs-toggle="tooltip" title="Rank score (normalized rank score in the range 0-1)" style="width:5%">Rank</th>
|
60
60
|
<th title="CADD scores" style="width:4%">CADD</th>
|
61
61
|
<th title="Genomic coordinate" style="width:8%">Chr pos</th>
|
62
62
|
<th title="Population frequency">Pop Freq</th>
|
@@ -156,7 +156,9 @@
|
|
156
156
|
{% elif variant.rank_score > 8 %}
|
157
157
|
{% set label_class = 'danger' %}
|
158
158
|
{% endif %}
|
159
|
-
<div class="badge bg-{{ label_class }}" data-bs-toggle="tooltip" data-bs-placement="top" title="Rank score">
|
159
|
+
<div class="badge bg-{{ label_class }}" data-bs-toggle="tooltip" data-bs-placement="top" title="Rank score">
|
160
|
+
{{ variant_rank_score(variant) }}
|
161
|
+
</div>
|
160
162
|
{% endif %}
|
161
163
|
{% endmacro %}
|
162
164
|
|