scout-browser 4.80__py3-none-any.whl → 4.82.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/disease_terms.py +5 -2
- scout/adapter/mongo/query.py +23 -11
- scout/adapter/mongo/variant.py +2 -2
- scout/build/managed_variant.py +12 -1
- scout/build/variant/genotype.py +2 -0
- scout/build/variant/variant.py +5 -0
- scout/constants/__init__.py +1 -0
- scout/constants/clinvar.py +1 -1
- scout/constants/indexes.py +10 -0
- scout/constants/query_terms.py +3 -1
- scout/models/variant/variant.py +1 -0
- scout/parse/variant/frequency.py +56 -54
- scout/parse/variant/genotype.py +89 -15
- scout/parse/variant/transcript.py +17 -9
- scout/parse/variant/variant.py +12 -0
- scout/server/app.py +6 -3
- scout/server/blueprints/alignviewers/templates/alignviewers/utils.html +1 -1
- scout/server/blueprints/cases/controllers.py +2 -57
- scout/server/blueprints/cases/templates/cases/case_report.html +212 -190
- scout/server/blueprints/cases/templates/cases/chanjo2_form.html +47 -0
- scout/server/blueprints/cases/templates/cases/collapsible_actionbar.html +4 -4
- scout/server/blueprints/cases/templates/cases/gene_panel.html +17 -23
- scout/server/blueprints/cases/templates/cases/utils.html +3 -1
- scout/server/blueprints/cases/views.py +0 -22
- scout/server/blueprints/clinvar/controllers.py +3 -3
- scout/server/blueprints/clinvar/templates/clinvar/clinvar_submissions.html +29 -2
- scout/server/blueprints/clinvar/templates/clinvar/multistep_add_variant.html +36 -18
- scout/server/blueprints/clinvar/views.py +13 -1
- scout/server/blueprints/diagnoses/controllers.py +2 -0
- scout/server/blueprints/institutes/controllers.py +76 -38
- scout/server/blueprints/institutes/templates/overview/cases.html +54 -42
- scout/server/blueprints/managed_variants/templates/managed_variants/managed_variants.html +1 -1
- scout/server/blueprints/managed_variants/views.py +2 -4
- scout/server/blueprints/panels/templates/panels/panel.html +8 -7
- scout/server/blueprints/panels/templates/panels/panel_pdf_case_hits.html +2 -2
- scout/server/blueprints/panels/templates/panels/panel_pdf_simple.html +3 -3
- scout/server/blueprints/panels/views.py +2 -11
- scout/server/blueprints/phenotypes/templates/phenotypes/hpo_terms.html +3 -2
- scout/server/blueprints/variant/controllers.py +3 -2
- scout/server/blueprints/variant/templates/variant/components.html +1 -1
- scout/server/blueprints/variant/templates/variant/utils.html +3 -1
- scout/server/blueprints/variant/templates/variant/variant.html +20 -15
- scout/server/blueprints/variant/templates/variant/variant_details.html +78 -26
- scout/server/blueprints/variant/utils.py +9 -13
- scout/server/blueprints/variants/controllers.py +32 -3
- scout/server/blueprints/variants/forms.py +15 -1
- scout/server/blueprints/variants/templates/variants/components.html +55 -0
- scout/server/blueprints/variants/templates/variants/fusion-variants.html +3 -50
- scout/server/blueprints/variants/templates/variants/str-variants.html +8 -5
- scout/server/blueprints/variants/templates/variants/utils.html +57 -31
- scout/server/blueprints/variants/templates/variants/variants.html +1 -1
- scout/server/blueprints/variants/utils.py +7 -10
- scout/server/extensions/clinvar_extension.py +10 -2
- scout/server/templates/report_base.html +3 -3
- scout/server/templates/utils.html +2 -2
- {scout_browser-4.80.dist-info → scout_browser-4.82.1.dist-info}/METADATA +6 -5
- {scout_browser-4.80.dist-info → scout_browser-4.82.1.dist-info}/RECORD +62 -61
- {scout_browser-4.80.dist-info → scout_browser-4.82.1.dist-info}/LICENSE +0 -0
- {scout_browser-4.80.dist-info → scout_browser-4.82.1.dist-info}/WHEEL +0 -0
- {scout_browser-4.80.dist-info → scout_browser-4.82.1.dist-info}/entry_points.txt +0 -0
- {scout_browser-4.80.dist-info → scout_browser-4.82.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
{% macro chanjo2_report_form(institute_obj, case_obj, panel_name, report_type, hgnc_ids, link_text) %}
|
2
|
+
|
3
|
+
{% set form_name = "chanjo2_"+panel_name+"_"+report_type %}
|
4
|
+
{% set form_action = config.CHANJO2_URL+"/"+report_type %}
|
5
|
+
{% set build = "GRCh38" if "38" in case_obj.get("genome_build", "37") else "GRCh37" %}
|
6
|
+
{% set default_level = institute_obj.coverage_cutoff %}
|
7
|
+
{% set interval_type = "genes" %} <!-- wgs analysis as default -->
|
8
|
+
{% set samples = [] %}
|
9
|
+
{% set analysis_types = [] %}
|
10
|
+
|
11
|
+
<!-- set sample dictionaries -->
|
12
|
+
|
13
|
+
{% for ind in case_obj.individuals %}
|
14
|
+
{% if ind.d4_file %}
|
15
|
+
{% set sample = {
|
16
|
+
"name" : ind.display_name,
|
17
|
+
"coverage_file_path" : ind.d4_file,
|
18
|
+
"case_name" : case_obj.display_name,
|
19
|
+
"analysis_date" : case_obj.analysis_date.strftime("%FT%T.%f")[:-3] ~ "Z" }
|
20
|
+
%}
|
21
|
+
{% do samples.append( sample ) %}
|
22
|
+
{% do analysis_types.append( ind.analysis_type ) %}
|
23
|
+
{% endif %}
|
24
|
+
{% endfor %}
|
25
|
+
|
26
|
+
{% if "wes" in analysis_types %}
|
27
|
+
{% set interval_type = "exons" %}
|
28
|
+
{% elif "wts" in analysis_types %}
|
29
|
+
{% set interval_type = "transcripts" %}
|
30
|
+
{% endif %}
|
31
|
+
|
32
|
+
<form name="{{form_name}}" method="post" action="{{form_action}}" target="_blank" rel="noopener">
|
33
|
+
<input type="hidden" id="build" name="build" value="{{build}}">
|
34
|
+
<input type="hidden" id="default_level" name="default_level" value="{{default_level}}">
|
35
|
+
<input type="hidden" id="interval_type" name="interval_type" value="{{interval_type}}">
|
36
|
+
<input type="hidden" id="panel_name" name="panel_name" value="{{panel_name}}">
|
37
|
+
<input type="hidden" id="case_display_name" name="case_display_name" value="{{case_obj.display_name}}">
|
38
|
+
<input type="hidden" id="hgnc_gene_ids" name="hgnc_gene_ids" value={{hgnc_ids}}>
|
39
|
+
<input type="hidden" id="samples" name="samples" value="{{samples|safe}}">
|
40
|
+
{% if panel_name == "HPO Panel" %}
|
41
|
+
<button type="submit" class="btn btn-secondary btn-sm text-white"> Coverage {{report_type}} (Chanjo2) </button>
|
42
|
+
{% else %}
|
43
|
+
<a class="link-primary" onclick="this.closest('form').submit();return false;">{{link_text}}</a>
|
44
|
+
{% endif %}
|
45
|
+
</form>
|
46
|
+
|
47
|
+
{% endmacro %}
|
@@ -1,3 +1,5 @@
|
|
1
|
+
{% from "cases/chanjo2_form.html" import chanjo2_report_form %}
|
2
|
+
|
1
3
|
{% macro action_bar(institute, case, causatives, collaborators, current_user, report_types, has_rna_tracks) %}
|
2
4
|
<!-- Collapsible Sidebar, Based on https://www.codeply.com/go/LFd2SEMECH -->
|
3
5
|
<div id="sidebar-container" class="sidebar-expanded d-none d-md-block"><!-- d-* hiddens the Sidebar in smaller devices. Its itens can be kept on the Navbar 'Menu' -->
|
@@ -84,13 +86,11 @@
|
|
84
86
|
</div>
|
85
87
|
|
86
88
|
<!-- If connected to a chanjo or chanjo2 instance, display coverage report -->
|
87
|
-
{% if case.chanjo2_coverage %}
|
89
|
+
{% if case.chanjo2_coverage and case.default_genes %}
|
88
90
|
<div href="#" class="bg-dark list-group-item text-white">
|
89
91
|
<div class="d-flex flex-row flex-fill bd-highlight">
|
90
92
|
<span class="menu-collapsed">Coverage (chanjo2)</span>
|
91
|
-
|
92
|
-
<span class="fa fa-link"></span>
|
93
|
-
</a>
|
93
|
+
{{ chanjo2_report_form(institute, case, case.panel_names|join(', '), 'report', case.default_genes|join(','), "<span class='fa fa-link'></span>"|safe ) }} <!--chanjo2 report-->
|
94
94
|
</div>
|
95
95
|
</div>
|
96
96
|
{% endif %}
|
@@ -1,3 +1,5 @@
|
|
1
|
+
{% from "cases/chanjo2_form.html" import chanjo2_report_form %}
|
2
|
+
|
1
3
|
{% macro genepanels_table(case, institute) %}
|
2
4
|
<div class="card panel-default">
|
3
5
|
<div class="panel-heading">Gene panels</div>
|
@@ -130,8 +132,8 @@
|
|
130
132
|
</div>
|
131
133
|
</div>
|
132
134
|
|
133
|
-
<div
|
134
|
-
<div class="row">
|
135
|
+
<div>
|
136
|
+
<div class="row"> <!-- Show variants in dynamic gene list -->
|
135
137
|
<form action="{{ url_for('cases.update_clinical_filter_hpo', institute_id=institute._id, case_name=case.display_name)+'#hpo_clinical_filter' }}" method="POST">
|
136
138
|
<div class="form-check form-switch">
|
137
139
|
<input type="checkbox" class="form-check-input" id="hpo_clinical_filter" onChange="this.form.submit()" name="hpo_clinical_filter"{% if case.hpo_clinical_filter %}checked{% endif %}>
|
@@ -199,41 +201,33 @@
|
|
199
201
|
<div class="row mt-1">
|
200
202
|
<div class="btn-group btn-group-sm">
|
201
203
|
{% if case.chanjo_coverage %}
|
202
|
-
<
|
203
|
-
<
|
204
|
-
<form id="hpo-report-form" action="{{ url_for('report.report', sample_id=case.individuals|map(attribute='individual_id')|list, panel_name="HPO panel", level=institute.coverage_cutoff) }}" method="POST" target="_blank">
|
204
|
+
<a class="btn btn-secondary btn-sm text-white" href="#section" onClick="document.getElementById('hpo-report-form').submit();" >Coverage report</a>
|
205
|
+
<form id="hpo-report-form" action="{{ url_for('report.report', sample_id=case.individuals|map(attribute='individual_id')|list, panel_name='HPO panel', level=institute.coverage_cutoff) }}" method="POST" target="_blank">
|
205
206
|
<input type="hidden" name="gene_ids" value="{{ case.dynamic_gene_list|map(attribute='hgnc_id')|join(',') }}">
|
206
207
|
</form>
|
207
208
|
|
208
|
-
<
|
209
|
-
<
|
210
|
-
<form id="hpo-overview-form" action="{{ url_for('report.genes', sample_id=case.individuals|map(attribute='individual_id')|list, panel_name="HPO panel", level=institute.coverage_cutoff) }}" method="POST" target="_blank">
|
209
|
+
<a class="btn btn-secondary btn-sm text-white" href="#section" onClick="document.getElementById('hpo-overview-form').submit();" >Coverage overview</a>
|
210
|
+
<form id="hpo-overview-form" action="{{ url_for('report.genes', sample_id=case.individuals|map(attribute='individual_id')|list, panel_name='HPO panel', level=institute.coverage_cutoff) }}" method="POST" target="_blank">
|
211
211
|
<input type="hidden" name="gene_ids" value="{{ case.dynamic_gene_list|map(attribute='hgnc_id')|join(',') }}">
|
212
212
|
</form>
|
213
213
|
{% endif %}
|
214
214
|
|
215
215
|
{% if case.chanjo2_coverage %}
|
216
|
-
|
217
|
-
|
218
|
-
case_name=case.display_name, panel_name='HPO Panel', report_type='report') }}" target="_blank" rel="noopener">
|
219
|
-
Coverage report (Chanjo2)
|
220
|
-
</a>
|
221
|
-
|
222
|
-
<a class="btn btn-secondary btn-sm text-white"
|
223
|
-
href="{{ url_for('cases.chanjo2_coverage_report', institute_id=institute._id,
|
224
|
-
case_name=case.display_name, panel_name='HPO Panel', report_type='overview') }}" target="_blank" rel="noopener">
|
225
|
-
Coverage overview (Chanjo2)
|
226
|
-
</a>
|
216
|
+
{{ chanjo2_report_form(institute, case, "HPO Panel", 'report', case.dynamic_gene_list|map(attribute='hgnc_id')|join(',')) }} <!--chanjo2 report-->
|
217
|
+
{{ chanjo2_report_form(institute, case, "HPO Panel", 'overview', case.dynamic_gene_list|map(attribute='hgnc_id')|join(',')) }} <!--chanjo2 genes overview -->
|
227
218
|
{% endif %}
|
228
219
|
|
229
220
|
</div>
|
230
221
|
</div>
|
231
222
|
{% endif %} <!-- End of if case.chanjo_coverage or case.chanjo2_coverage -->
|
232
|
-
</div> <!-- End of Show variants in dynamic gene list -->
|
233
223
|
|
234
|
-
|
235
|
-
|
236
|
-
|
224
|
+
<div class="row mt-1">
|
225
|
+
<div class="btn-group btn-group-sm"> <!-- Download genes in HPO gene panel -->
|
226
|
+
<a class="btn btn-sm btn-primary text-white" href="{{ url_for('cases.download_hpo_genes', institute_id=institute._id, case_name=case.display_name, category="clinical") }}" download><span class="fa fa-download text-white" aria-hidden="true"></span> Clinical HPO gene panel</a>
|
227
|
+
<a class="btn btn-sm btn-primary text-white" href="{{ url_for('cases.download_hpo_genes', institute_id=institute._id, case_name=case.display_name, category="research") }}" download><span class="fa fa-download text-white" aria-hidden="true"></span> Research HPO gene panel</a>
|
228
|
+
</div>
|
229
|
+
</div>
|
230
|
+
|
237
231
|
</div>
|
238
232
|
|
239
233
|
{% endif %}
|
@@ -268,7 +268,7 @@
|
|
268
268
|
|
269
269
|
<!-- show transcript info only if it's canonical, disease-associated or primary (print max 5 primary transcripts) -->
|
270
270
|
{% if transcript.refseq_identifiers and n_primary_txs.count <= 5 or transcript.is_canonical or transcript.is_disease_associated or transcript.is_primary %}
|
271
|
-
<li>{{transcript.transcript_id}}, RefSeq:[{{ transcript.refseq_identifiers|join(", ") or "-" }}], {{ (transcript.coding_sequence_name or '')|truncate(20, True) }}, {{ (transcript.protein_sequence_name or '')|url_decode|truncate(20, True) }}
|
271
|
+
<li class="mb-1">{{transcript.transcript_id}}, RefSeq:[{{ transcript.refseq_identifiers|join(", ") or "-" }}], {{ (transcript.coding_sequence_name or '')|truncate(20, True) }}, {{ (transcript.protein_sequence_name or '')|url_decode|truncate(20, True) }}
|
272
272
|
{% if transcript.is_canonical %}
|
273
273
|
<span class="badge rounded-pill bg-info text-white" title="canonical">C</span>
|
274
274
|
{% endif %}
|
@@ -602,6 +602,8 @@
|
|
602
602
|
<form id="clinvar_submit" class="d-flex justify-content-center" action="{{ url_for('clinvar.clinvar_add_variant', institute_id=institute._id, case_name=case.display_name) }}" method="POST">
|
603
603
|
{% if case.clinvar_variants and variant._id in case.clinvar_variants.keys() %}
|
604
604
|
(included in ClinVar submission)
|
605
|
+
{% elif variant.category in ('cancer', 'cancer_sv') %}
|
606
|
+
<button data-bs-toggle='tooltip' data-bs-placement="bottom" title="Submission of somatic variants from Scout is temporarily suspended. We are working to harmonize submissions with changes introduced by ClinVar for this variant category." disabled >Add to ClinVar submission</button>
|
605
607
|
{% else %}
|
606
608
|
<button type="submit" name="var_id" value="{{variant._id}}" class="btn btn-secondary btn-sm" style="float: right;">Add to ClinVar submission</button>
|
607
609
|
{% endif %}
|
@@ -313,28 +313,6 @@ def pdf_case_report(institute_id, case_name):
|
|
313
313
|
)
|
314
314
|
|
315
315
|
|
316
|
-
@cases_bp.route("/<institute_id>/<case_name>/chanjo2_report/<report_type>", methods=["GET"])
|
317
|
-
def chanjo2_coverage_report(institute_id: str, case_name: str, report_type: str):
|
318
|
-
"""Return the HTML coverage report or coverage overview created by chanjo2."""
|
319
|
-
|
320
|
-
REPORT_TYPES = ["report", "overview"]
|
321
|
-
if report_type not in REPORT_TYPES:
|
322
|
-
flash(f"Wrong value for report_type parameter. Accepted values: {REPORT_TYPES}", "warning")
|
323
|
-
return redirect(request.referrer)
|
324
|
-
|
325
|
-
institute_obj, case_obj = institute_and_case(store, institute_id, case_name)
|
326
|
-
report_html_content: str = controllers.chanjo2_coverage_report_contents(
|
327
|
-
institute_obj=institute_obj,
|
328
|
-
case_obj=case_obj,
|
329
|
-
panel_name=request.args.get("panel_name"),
|
330
|
-
panel_id=request.args.get("panel_id"),
|
331
|
-
report_type=report_type,
|
332
|
-
)
|
333
|
-
if report_html_content is None:
|
334
|
-
return redirect(request.referrer)
|
335
|
-
return report_html_content
|
336
|
-
|
337
|
-
|
338
316
|
@cases_bp.route("/<institute_id>/<case_name>/mt_report", methods=["GET"])
|
339
317
|
def mt_report(institute_id, case_name):
|
340
318
|
institute_obj, case_obj = institute_and_case(store, institute_id, case_name)
|
@@ -107,7 +107,7 @@ def _get_snv_var_form(variant_obj, case_obj):
|
|
107
107
|
var_form.variations_ids.data = var_ids.split(";")[0]
|
108
108
|
var_form.chromosome.data = variant_obj.get("chromosome")
|
109
109
|
var_form.start.data = variant_obj.get("position")
|
110
|
-
var_form.stop.data = variant_obj.get("
|
110
|
+
var_form.stop.data = variant_obj.get("end")
|
111
111
|
return var_form
|
112
112
|
|
113
113
|
|
@@ -276,7 +276,7 @@ def parse_variant_form_fields(form):
|
|
276
276
|
clinvar_var["variations_ids"] = form["dbsnp_id"]
|
277
277
|
|
278
278
|
if clinvar_var.get("ref_seq") and clinvar_var.get("hgvs"):
|
279
|
-
# Variant is described by RefSeq and HGVS already, remove
|
279
|
+
# Variant is described by RefSeq and HGVS already, remove redundant fields from submission
|
280
280
|
for item in ["chromosome", "start", "stop", "ref", "alt"]:
|
281
281
|
clinvar_var.pop(item)
|
282
282
|
|
@@ -437,7 +437,7 @@ def send_api_submission(institute_id, submission_id, key):
|
|
437
437
|
|
438
438
|
clinvar_id = store.get_clinvar_id(
|
439
439
|
submission_id
|
440
|
-
) # This is the official ID associated with this submission in Clinvar (
|
440
|
+
) # This is the official ID associated with this submission in Clinvar (ex: SUB999999)
|
441
441
|
|
442
442
|
if clinvar_id: # Check if submission object has already an associated ClinVar ID
|
443
443
|
conversion_res["submissionName"] = clinvar_id
|
@@ -95,10 +95,16 @@
|
|
95
95
|
</form>
|
96
96
|
{% if subm_obj.status == 'open' and show_submit %}
|
97
97
|
<form id="useApi_{{subm_obj._id}}" action="{{ url_for('clinvar.clinvar_update_submission', institute_id=institute._id, submission=subm_obj._id) }}" method="POST">
|
98
|
-
{{ submit_modal(
|
98
|
+
{{ submit_modal() }}
|
99
99
|
<td style="width: 20%"><button type="button" class="btn btn-sm btn-success form-control" name="update_submission" value="api_submit" data-bs-toggle="modal" data-bs-target="#submitModal">Submit to ClinVar</button></td>
|
100
100
|
</form>
|
101
101
|
{% endif %}
|
102
|
+
{% if subm_obj.status == 'submitted' %} <!--Submission status query -->
|
103
|
+
<form id="statusApi_{{subm_obj._id}}" action="{{ url_for('clinvar.clinvar_submission_status', submission_id=subm_obj.clinvar_subm_id) }}" method="POST">
|
104
|
+
{{ status_modal() }}
|
105
|
+
<td style="width: 20%"><button type="button" class="btn btn-sm btn-secondary form-control" name="status_enquiry" value="api_status" data-bs-toggle="modal" data-bs-target="#statusModal">Submission status enquiry</button></td>
|
106
|
+
</form>
|
107
|
+
{% endif %}
|
102
108
|
</tr>
|
103
109
|
</table>
|
104
110
|
</div>
|
@@ -240,7 +246,28 @@
|
|
240
246
|
</div>
|
241
247
|
{% endmacro %}
|
242
248
|
|
243
|
-
{% macro
|
249
|
+
{% macro status_modal() %}
|
250
|
+
<div class="modal fade" id="statusModal" tabindex="-1">
|
251
|
+
<div class="modal-dialog">
|
252
|
+
<div class="modal-content">
|
253
|
+
<div class="modal-header">
|
254
|
+
<h5 class="modal-title">Submission status</h5>
|
255
|
+
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
256
|
+
</div>
|
257
|
+
<div class="modal-body">
|
258
|
+
<label for="apiKey">Submitter's <a href="https://www.ncbi.nlm.nih.gov/clinvar/docs/api_http/" target="_blank" rel="noopener">API key</a></label>
|
259
|
+
<input type="password" class="form-control" name="apiKey" id="apiKey" placeholder="64 alphanumeric characters" value="{{institute.clinvar_key or ''}}" required>
|
260
|
+
</div>
|
261
|
+
<div class="modal-footer">
|
262
|
+
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
263
|
+
<button type="submit" name="show_status" value="status" class="btn btn-primary">Submission status enquiry</button>
|
264
|
+
</div>
|
265
|
+
</div>
|
266
|
+
</div>
|
267
|
+
</div>
|
268
|
+
{% endmacro %}
|
269
|
+
|
270
|
+
{% macro submit_modal() %}
|
244
271
|
<div class="modal fade" id="submitModal" tabindex="-1">
|
245
272
|
<div class="modal-dialog">
|
246
273
|
<div class="modal-content">
|
@@ -34,7 +34,7 @@
|
|
34
34
|
</ul>
|
35
35
|
<!-- fieldsets -->
|
36
36
|
<fieldset data-step="1">
|
37
|
-
<legend>ClinVar variant submission form</legend>
|
37
|
+
<legend class="text-dark">ClinVar variant submission form</legend>
|
38
38
|
<p class="text-dark">
|
39
39
|
The form present on this page mirrors the fields on the ClinVar submission spreadsheets.<br>
|
40
40
|
After collecting the required fields, this variant gets saved in an open ClinVar submission object.<br>
|
@@ -44,7 +44,7 @@
|
|
44
44
|
</fieldset>
|
45
45
|
|
46
46
|
<fieldset data-step="2">
|
47
|
-
<legend>Assertion criteria <span class="text-danger" data-bs-toggle='tooltip' title="The new ClinVar spreadsheet templates (versions L1.7 and 4.3) no longer include the following columns: Assertion method and Assertion method citation.
|
47
|
+
<legend class="text-dark">Assertion criteria <span class="text-danger" data-bs-toggle='tooltip' title="The new ClinVar spreadsheet templates (versions L1.7 and 4.3) no longer include the following columns: Assertion method and Assertion method citation.
|
48
48
|
New files for assertion criteria will be uploaded on your landing page in the ClinVar Submission Portal, independent of a submission. For this reason Scout will collect this information but will not export it as columns in the submission Variant file."><strong>?</strong></span></legend>
|
49
49
|
|
50
50
|
<!-- hidden fields -->
|
@@ -73,7 +73,7 @@
|
|
73
73
|
<br><br>
|
74
74
|
<div class="d-flex flex-column flex-lg-row justify-content-center align-items-center">
|
75
75
|
{{variant_data.var_form.assertion_method_cit_db.label(class="fw-bold text-dark my-2 mx-lg-2")}}
|
76
|
-
{{variant_data.var_form.assertion_method_cit_db(class="
|
76
|
+
{{variant_data.var_form.assertion_method_cit_db(class="btn-secondary my-2 mx-lg-2")}}
|
77
77
|
<div class="my-2 mx-lg-2">{{variant_data.var_form.assertion_method_cit_id.label(class="fw-bold text-dark")}}
|
78
78
|
<span class="text-danger" id="assertion_method_cit_id_tooltip" data-bs-toggle='tooltip' title="The Assertion method citation is now supplied as a database identifier and an id number in the corresponding format">
|
79
79
|
<strong>?</strong>
|
@@ -85,7 +85,7 @@
|
|
85
85
|
<input type="button" name="next" class="next action-button" value="Next"/>
|
86
86
|
</fieldset>
|
87
87
|
<fieldset data-step="3">
|
88
|
-
<legend>Variant Details</legend>
|
88
|
+
<legend class="text-dark">Variant Details</legend>
|
89
89
|
{{variant_data.var_form.gene_symbol.label(class="fw-bold, text-dark")}} <span class="text-danger" data-bs-toggle='tooltip' title="Gene symbol should be provided only to indicate the gene-disease relationship supporting the variant interpretation. Gene symbol is not expected for SVs, except to make a statement that a specific gene within the variant has a relationship to the interpreted condition."><strong>?</strong></span>
|
90
90
|
{{variant_data.var_form.gene_symbol(class="bg-white")}}
|
91
91
|
<br>
|
@@ -114,7 +114,7 @@
|
|
114
114
|
{% for item_row in variant_data.var_form.tx_hgvs | batch(3) %}
|
115
115
|
<tr>
|
116
116
|
{% for item in item_row %}
|
117
|
-
<td style="width: 3%; text-align: right; vertical-align: baseline;">{{item
|
117
|
+
<td style="width: 3%; text-align: right; vertical-align: baseline;">{{item}}</td>
|
118
118
|
|
119
119
|
{% if "(validated)" in item.label.text %}
|
120
120
|
{% set ns.validated = true %}
|
@@ -124,7 +124,7 @@
|
|
124
124
|
{% set ns.label = item.label.text | replace(" (validated)", "") %}
|
125
125
|
|
126
126
|
<td style="width: 30%; text-align: left; ">
|
127
|
-
<p
|
127
|
+
<p class="text-dark"
|
128
128
|
{% if ns.label|length > 25 %}
|
129
129
|
data-bs-toggle="tooltip" title="{{ns.label}}">{{ ns.label|truncate(25,true,'..') }}
|
130
130
|
{% else %}
|
@@ -196,7 +196,7 @@
|
|
196
196
|
</fieldset>
|
197
197
|
|
198
198
|
<fieldset data-step="4">
|
199
|
-
<legend>Inheritance model</legend>
|
199
|
+
<legend class="text-dark">Inheritance model</legend>
|
200
200
|
<h3 class="fs-subtitle">The mode of inheritance specific to the variant-disease pair, not generally for the disease</h3>
|
201
201
|
{{variant_data.var_form.inheritance_mode.label(class="fw-bold, text-dark")}}
|
202
202
|
{{variant_data.var_form.inheritance_mode(class="form-control, btn-secondary")}}
|
@@ -206,7 +206,7 @@
|
|
206
206
|
</fieldset>
|
207
207
|
|
208
208
|
<fieldset data-step="5">
|
209
|
-
<legend>Germline Classification</legend>
|
209
|
+
<legend class="text-dark">Germline Classification</legend>
|
210
210
|
<h3 class="fs-subtitle">Represents a variant-level classification for a disease, rather than an interpretation of the clinical significance of a variant for a specific patient.</h3>
|
211
211
|
|
212
212
|
<div class="row">
|
@@ -231,23 +231,19 @@
|
|
231
231
|
</fieldset>
|
232
232
|
|
233
233
|
<fieldset data-step="6">
|
234
|
-
<legend>Associated Conditions</legend>
|
234
|
+
<legend class="text-dark">Associated Conditions</legend>
|
235
235
|
<h3 class="fs-subtitle">The condition for which the variant is interpreted. Examples available at <a href="https://www.ncbi.nlm.nih.gov/clinvar/docs/spreadsheet/#condition" target="_blank" rel="noopener">ClinVar</a></h3>
|
236
236
|
|
237
237
|
<div class="row">
|
238
238
|
<div class="col-6" id="clinvar_condition_container">
|
239
239
|
{{variant_data.var_form.condition_type.label(class="fw-bold, text-dark")}}<span class="text-danger" data-bs-toggle='tooltip' title="Required field."><strong>*</strong></span>
|
240
|
+
|
240
241
|
<select class="form-control, btn-secondary" name="condition_type" id="condition_type">
|
241
242
|
{% for dbtype, _ in variant_data.var_form.condition_type.choices %}
|
242
|
-
{
|
243
|
-
<option value="{{dbtype}}" selected>{{dbtype}}</option>
|
244
|
-
{% elif dbtype == "HP" and variant_data.var_form.hpo_terms.choices %}
|
245
|
-
<option value="{{dbtype}}" selected>{{dbtype}}</option>
|
246
|
-
{% else %}
|
247
|
-
<option value="{{dbtype}}">{{dbtype}}</option>
|
248
|
-
{% endif %}
|
243
|
+
<option value="{{dbtype}}">{{dbtype}}</option>
|
249
244
|
{% endfor %}
|
250
245
|
</select>
|
246
|
+
|
251
247
|
<br><br>
|
252
248
|
{{variant_data.var_form.conditions.label(class="fw-bold, text-dark")}} <span class="text-danger" data-bs-toggle='tooltip' title="Required field. Include data from ONE DATABASE TYPE ONLY (i.e. only OMIM terms, only HPO terms etc). If multiple conditions are submitted for a variant, this indicates that the variant was interpreted for the combination of conditions in the same individual(s). i.e. this variant causes both condition A and condition B in the same individual. This scenario is most common for a new disease or syndrome that does not yet have a name and is described by several clinical features. If you want to indicate that the variant has been interpreted for more than one condition, please submit these as separate records."><strong>*?</strong></span>
|
253
249
|
<select class="select2" id="condition_tags" name="conditions" multiple="true" style="width:100%;">
|
@@ -313,7 +309,7 @@
|
|
313
309
|
</fieldset>
|
314
310
|
|
315
311
|
<fieldset data-step="7">
|
316
|
-
<legend>Observation Data</legend>
|
312
|
+
<legend class="text-dark">Observation Data</legend>
|
317
313
|
<h3 class="fs-subtitle">Information provided by filling in these fields will be used to create the CaseData.csv file. Observations from at least one individuals are required.</h3>
|
318
314
|
|
319
315
|
<ul class="list-group">
|
@@ -372,6 +368,7 @@ var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
|
|
372
368
|
|
373
369
|
// Validates fields for conditions associated to a variant
|
374
370
|
function validateConditions(){
|
371
|
+
|
375
372
|
if ($("#condition_tags option:selected").length == 0) {
|
376
373
|
alert("Please provide at least one condition ID");
|
377
374
|
return false;
|
@@ -387,7 +384,16 @@ function validateConditions(){
|
|
387
384
|
return false;
|
388
385
|
}
|
389
386
|
|
390
|
-
|
387
|
+
// Make sure that provided conditions are numbers, except when condition type is MeSH
|
388
|
+
var selectedConditionsValues = $('#condition_tags').val();
|
389
|
+
for (let i = 0; i < selectedConditionsValues.length; i++) {
|
390
|
+
if (isNaN(selectedConditionsValues[i]) && $('#condition_type').val() != 'MeSH'){
|
391
|
+
alert(`Condition ID "${selectedConditionsValues[i]}" has an invalid format.`);
|
392
|
+
return false;
|
393
|
+
}
|
394
|
+
}
|
395
|
+
|
396
|
+
return true;
|
391
397
|
}
|
392
398
|
|
393
399
|
var current_fs, next_fs, previous_fs; //fieldsets
|
@@ -526,6 +532,18 @@ $('#condition_tags').select2({
|
|
526
532
|
allowClear: true,
|
527
533
|
});
|
528
534
|
|
535
|
+
// Set selected condition type on page load
|
536
|
+
window.onload = function() {
|
537
|
+
const selectedCondId = document.getElementById('condition_type');
|
538
|
+
{% if variant_data.var_form.omim_terms.choices %}
|
539
|
+
selectedCondId.options.selectedIndex = 4;
|
540
|
+
{% elif variant_data.var_form.orpha_terms.choices %}
|
541
|
+
selectedCondId.options.selectedIndex = 5;
|
542
|
+
{% elif variant_data.var_form.hpo_terms.choices %}
|
543
|
+
selectedCondId.options.selectedIndex = 0;
|
544
|
+
{% endif %}
|
545
|
+
};
|
546
|
+
|
529
547
|
// reset and modify conditions field's placeholder when condition ID type changes
|
530
548
|
$(function(){
|
531
549
|
$("#condition_type").change(function(){
|
@@ -8,7 +8,7 @@ from flask import Blueprint, flash, redirect, render_template, request, send_fil
|
|
8
8
|
from flask_login import current_user
|
9
9
|
|
10
10
|
from scout.constants.clinvar import CASEDATA_HEADER, CLINVAR_HEADER, GERMLINE_CLASSIF_TERMS
|
11
|
-
from scout.server.extensions import store
|
11
|
+
from scout.server.extensions import clinvar_api, store
|
12
12
|
from scout.server.utils import institute_and_case
|
13
13
|
|
14
14
|
from . import controllers
|
@@ -24,6 +24,18 @@ clinvar_bp = Blueprint(
|
|
24
24
|
)
|
25
25
|
|
26
26
|
|
27
|
+
@clinvar_bp.route("/clinvar/status-enquiry/<submission_id>", methods=["POST"])
|
28
|
+
def clinvar_submission_status(submission_id):
|
29
|
+
"""Sends a request to ClinVar to retrieve and display the status of a submission."""
|
30
|
+
|
31
|
+
# flash a message with current submission status for a ClinVar submission
|
32
|
+
clinvar_api.show_submission_status(
|
33
|
+
submission_id=submission_id, api_key=request.form.get("apiKey")
|
34
|
+
)
|
35
|
+
|
36
|
+
return redirect(request.referrer)
|
37
|
+
|
38
|
+
|
27
39
|
@clinvar_bp.route("/<institute_id>/<case_name>/clinvar/add_variant", methods=["POST"])
|
28
40
|
def clinvar_add_variant(institute_id, case_name):
|
29
41
|
"""Create a ClinVar submission document in database for one or more variants from a case."""
|
@@ -36,6 +36,8 @@ def disease_terms(store: MongoAdapter, query: str, source: str) -> dict:
|
|
36
36
|
|
37
37
|
for gene in gene_ids:
|
38
38
|
gene_caption = store.hgnc_gene_caption(hgnc_identifier=gene)
|
39
|
+
if not gene_caption:
|
40
|
+
continue
|
39
41
|
gene_ids_symbols.append(
|
40
42
|
{"hgnc_id": gene_caption["hgnc_id"], "hgnc_symbol": gene_caption["hgnc_symbol"]}
|
41
43
|
)
|
@@ -469,7 +469,12 @@ def cases(store, request, institute_id):
|
|
469
469
|
|
470
470
|
data["status_ncases"] = store.nr_cases_by_status(institute_id=institute_id)
|
471
471
|
data["nr_cases"] = sum(data["status_ncases"].values())
|
472
|
-
|
472
|
+
|
473
|
+
sanger_ordered_not_validated: Tuple[Dict[str, list]] = get_sanger_unevaluated(
|
474
|
+
store, institute_id, current_user.email
|
475
|
+
)
|
476
|
+
data["sanger_unevaluated"]: Dict[str, list] = sanger_ordered_not_validated[0]
|
477
|
+
data["sanger_validated_by_others"]: Dict[str, list] = sanger_ordered_not_validated[1]
|
473
478
|
|
474
479
|
# local function to add info to case obj
|
475
480
|
def populate_case_obj(case_obj):
|
@@ -559,27 +564,76 @@ def populate_case_filter_form(params):
|
|
559
564
|
return form
|
560
565
|
|
561
566
|
|
562
|
-
def
|
563
|
-
|
567
|
+
def _get_unevaluated_variants_for_case(
|
568
|
+
case_obj: dict, var_ids_list: List[str], sanger_validated_by_user_by_case: Dict[str, List[str]]
|
569
|
+
) -> Tuple[Dict[str, list]]:
|
570
|
+
"""Returns the variants with Sanger ordered by a user that need validation or are validated by another user."""
|
564
571
|
|
565
|
-
|
566
|
-
|
567
|
-
|
572
|
+
case_display_name: str = case_obj["display_name"]
|
573
|
+
case_id: str = case_obj["_id"]
|
574
|
+
|
575
|
+
def _variant_has_sanger_ordered(variant_obj: dict) -> bool:
|
576
|
+
"""Returns True if the sanger_ordered status of a variant is True, else False."""
|
577
|
+
|
578
|
+
if (
|
579
|
+
variant_obj is None
|
580
|
+
or variant_obj.get("sanger_ordered") is None
|
581
|
+
or variant_obj.get("sanger_ordered") is False
|
582
|
+
):
|
583
|
+
return False
|
584
|
+
return True
|
585
|
+
|
586
|
+
unevaluated_by_case = {case_display_name: []}
|
587
|
+
evaluated_by_others_by_case = {case_display_name: []}
|
588
|
+
for var_id in var_ids_list:
|
589
|
+
# For each variant with sanger validation ordered
|
590
|
+
variant_obj = store.variant(document_id=var_id, case_id=case_id)
|
591
|
+
|
592
|
+
# Double check that Sanger was ordered (and not canceled) for the variant
|
593
|
+
if _variant_has_sanger_ordered(variant_obj) is False:
|
594
|
+
continue
|
595
|
+
|
596
|
+
validation = variant_obj.get("validation", "not_evaluated")
|
597
|
+
|
598
|
+
# Check that the variant is not evaluated
|
599
|
+
if validation in ["True positive", "False positive"]:
|
600
|
+
if var_id in sanger_validated_by_user_by_case.get(
|
601
|
+
case_id, []
|
602
|
+
): # User had validated this variant
|
603
|
+
continue
|
604
|
+
|
605
|
+
# Another user has validated the variant
|
606
|
+
evaluated_by_others_by_case[case_display_name].append(variant_obj["_id"])
|
607
|
+
else:
|
608
|
+
unevaluated_by_case[case_display_name].append(variant_obj["_id"])
|
609
|
+
|
610
|
+
return unevaluated_by_case, evaluated_by_others_by_case
|
611
|
+
|
612
|
+
|
613
|
+
def get_sanger_unevaluated(
|
614
|
+
store: MongoAdapter, institute_id: str, user_id: str
|
615
|
+
) -> Tuple[List[Dict[str, list]]]:
|
616
|
+
"""Return all variant with Sanger sequencing ordered by a user with validation missing or validated by another user.
|
568
617
|
|
569
618
|
Returns:
|
570
|
-
unevaluated: a list that looks like this: [ {'case1': [varID_1, varID_2, .., varID_n]},
|
619
|
+
unevaluated: a list that looks like this: [ {'case1': [varID_1, varID_2, .., varID_n]}, .. ],
|
571
620
|
where the keys are case_ids and the values are lists of variants with Sanger ordered but not yet validated
|
621
|
+
evaluated_by_others: a list that looks like the one above where varID_1, varID_2 etc are variants validated by some other user
|
572
622
|
|
573
623
|
"""
|
624
|
+
sanger_ordered_by_user_by_case: Dict[str, List[str]] = {
|
625
|
+
case_variants["_id"]: case_variants["vars"]
|
626
|
+
for case_variants in store.sanger_ordered(institute_id=institute_id, user_id=user_id)
|
627
|
+
}
|
628
|
+
sanger_validated_by_user_by_case: Dict[str, List[str]] = {
|
629
|
+
case_variants["_id"]: case_variants["vars"]
|
630
|
+
for case_variants in store.validated(institute_id=institute_id, user_id=user_id)
|
631
|
+
}
|
574
632
|
|
575
|
-
# Retrieve a list of ids for variants with Sanger ordered grouped by case from the 'event' collection
|
576
|
-
# This way is much faster than querying over all variants in all cases of an institute
|
577
|
-
sanger_ordered_by_case = store.sanger_ordered(institute_id, user_id)
|
578
633
|
unevaluated = []
|
634
|
+
evaluated_by_others = []
|
579
635
|
|
580
|
-
|
581
|
-
for item in sanger_ordered_by_case:
|
582
|
-
case_id = item["_id"]
|
636
|
+
for case_id, var_ids_list in sanger_ordered_by_user_by_case.items():
|
583
637
|
# Get the case to collect display name
|
584
638
|
CASE_SANGER_UNEVALUATED_PROJECTION = {"display_name": 1}
|
585
639
|
case_obj = store.case(case_id=case_id, projection=CASE_SANGER_UNEVALUATED_PROJECTION)
|
@@ -588,36 +642,20 @@ def get_sanger_unevaluated(store, institute_id, user_id):
|
|
588
642
|
continue
|
589
643
|
|
590
644
|
case_display_name = case_obj.get("display_name")
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
for var_id in varid_list:
|
597
|
-
# For each variant with sanger validation ordered
|
598
|
-
variant_obj = store.variant(document_id=var_id, case_id=case_id)
|
599
|
-
|
600
|
-
# Double check that Sanger was ordered (and not canceled) for the variant
|
601
|
-
if (
|
602
|
-
variant_obj is None
|
603
|
-
or variant_obj.get("sanger_ordered") is None
|
604
|
-
or variant_obj.get("sanger_ordered") is False
|
605
|
-
):
|
606
|
-
continue
|
607
|
-
|
608
|
-
validation = variant_obj.get("validation", "not_evaluated")
|
609
|
-
|
610
|
-
# Check that the variant is not evaluated
|
611
|
-
if validation in ["True positive", "False positive"]:
|
612
|
-
continue
|
613
|
-
|
614
|
-
unevaluated_by_case[case_display_name].append(variant_obj["_id"])
|
645
|
+
unevaluated_by_case, evaluated_by_others_by_case = _get_unevaluated_variants_for_case(
|
646
|
+
case_obj=case_obj,
|
647
|
+
var_ids_list=var_ids_list,
|
648
|
+
sanger_validated_by_user_by_case=sanger_validated_by_user_by_case,
|
649
|
+
)
|
615
650
|
|
616
651
|
# If for a case there is at least one Sanger validation to evaluate add the object to the unevaluated objects list
|
617
652
|
if len(unevaluated_by_case[case_display_name]) > 0:
|
618
653
|
unevaluated.append(unevaluated_by_case)
|
619
654
|
|
620
|
-
|
655
|
+
if len(evaluated_by_others_by_case[case_display_name]) > 0:
|
656
|
+
evaluated_by_others.append(evaluated_by_others_by_case)
|
657
|
+
|
658
|
+
return unevaluated, evaluated_by_others
|
621
659
|
|
622
660
|
|
623
661
|
def export_gene_variants(
|