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.
Files changed (59) hide show
  1. scout/adapter/mongo/case.py +26 -122
  2. scout/adapter/mongo/clinvar.py +91 -25
  3. scout/adapter/mongo/event.py +0 -47
  4. scout/adapter/mongo/variant_loader.py +7 -3
  5. scout/build/variant/variant.py +1 -0
  6. scout/commands/load/variants.py +1 -1
  7. scout/commands/update/user.py +87 -49
  8. scout/constants/__init__.py +3 -0
  9. scout/constants/clinvar.py +10 -0
  10. scout/constants/variant_tags.py +18 -0
  11. scout/demo/NIST.trgt.stranger.vcf.gz +0 -0
  12. scout/demo/NIST.trgt.stranger.vcf.gz.tbi +0 -0
  13. scout/demo/__init__.py +1 -0
  14. scout/models/clinvar.py +86 -0
  15. scout/parse/variant/coordinates.py +5 -1
  16. scout/parse/variant/gene.py +5 -9
  17. scout/parse/variant/genotype.py +66 -42
  18. scout/parse/variant/variant.py +2 -0
  19. scout/server/app.py +71 -2
  20. scout/server/blueprints/alignviewers/templates/alignviewers/igv_viewer.html +2 -0
  21. scout/server/blueprints/cases/controllers.py +1 -1
  22. scout/server/blueprints/cases/templates/cases/case_report.html +19 -2
  23. scout/server/blueprints/cases/templates/cases/utils.html +8 -29
  24. scout/server/blueprints/clinvar/controllers.py +233 -53
  25. scout/server/blueprints/clinvar/form.py +38 -1
  26. scout/server/blueprints/clinvar/static/form_style.css +8 -1
  27. scout/server/blueprints/clinvar/templates/clinvar/clinvar_onc_submissions.html +200 -0
  28. scout/server/blueprints/clinvar/templates/clinvar/clinvar_submissions.html +3 -2
  29. scout/server/blueprints/clinvar/templates/clinvar/components.html +198 -0
  30. scout/server/blueprints/clinvar/templates/clinvar/multistep_add_onc_variant.html +187 -0
  31. scout/server/blueprints/clinvar/templates/clinvar/multistep_add_variant.html +9 -348
  32. scout/server/blueprints/clinvar/templates/clinvar/scripts.html +193 -0
  33. scout/server/blueprints/clinvar/views.py +90 -13
  34. scout/server/blueprints/institutes/controllers.py +44 -5
  35. scout/server/blueprints/institutes/forms.py +1 -0
  36. scout/server/blueprints/institutes/templates/overview/gene_variants.html +15 -6
  37. scout/server/blueprints/institutes/templates/overview/institute_sidebar.html +28 -2
  38. scout/server/blueprints/institutes/templates/overview/utils.html +1 -1
  39. scout/server/blueprints/institutes/views.py +17 -4
  40. scout/server/blueprints/mme/templates/mme/mme_submissions.html +2 -2
  41. scout/server/blueprints/omics_variants/templates/omics_variants/outliers.html +2 -2
  42. scout/server/blueprints/variant/controllers.py +1 -1
  43. scout/server/blueprints/variant/templates/variant/cancer-variant.html +2 -1
  44. scout/server/blueprints/variant/templates/variant/components.html +0 -1
  45. scout/server/blueprints/variant/templates/variant/sv-variant.html +2 -1
  46. scout/server/blueprints/variant/templates/variant/variant.html +2 -2
  47. scout/server/blueprints/variant/templates/variant/variant_details.html +32 -24
  48. scout/server/blueprints/variants/templates/variants/cancer-variants.html +5 -3
  49. scout/server/blueprints/variants/templates/variants/str-variants.html +4 -1
  50. scout/server/blueprints/variants/templates/variants/sv-variants.html +3 -3
  51. scout/server/blueprints/variants/templates/variants/utils.html +4 -0
  52. scout/server/blueprints/variants/templates/variants/variants.html +4 -4
  53. scout/server/extensions/clinvar_extension.py +2 -2
  54. scout/server/templates/layout.html +1 -1
  55. {scout_browser-4.102.0.dist-info → scout_browser-4.103.0.dist-info}/METADATA +1 -1
  56. {scout_browser-4.102.0.dist-info → scout_browser-4.103.0.dist-info}/RECORD +59 -53
  57. {scout_browser-4.102.0.dist-info → scout_browser-4.103.0.dist-info}/WHEEL +0 -0
  58. {scout_browser-4.102.0.dist-info → scout_browser-4.103.0.dist-info}/entry_points.txt +0 -0
  59. {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'Response from ClinVar: {clinvar_api.json_submission_status( submission_id=submission_id, api_key=request.form.get("apiKey"))}',
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>/clinvar_submissions", methods=["GET"])
89
- def clinvar_submissions(institute_id):
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.clinvar_submissions(institute_id),
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=clinvar_id, suffix=".json")
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"{clinvar_id}.json",
162
+ download_name=f"{filename}.json",
149
163
  mimetype="application/json",
150
164
  as_attachment=True,
151
165
  )
152
166
  else:
153
- flash(f"JSON file could not be crated for ClinVar submission: {clinvar_id} ", "warning")
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
- for group_case in case_groups[status]:
606
- if group_case["_id"] == case_obj["_id"]:
607
- group_case["dimmed_in_search"] = False
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.case_to_clinVars(case_obj["_id"])
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(variant.get("hgvs", "-")) # HGVS
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
- <a href="{{ url_for('variant.variant', institute_id=variant.institute,
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
- {{ (variant.hgvs or '')|url_decode }}
102
- {% endif %}
103
- </a>
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.rank_score|int }}</span>
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="{{ url_for('clinvar.clinvar_submissions', institute_id=institute._id) }}" class="bg-dark list-group-item list-group-item-action flex-column align-items-start">
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 institute_and_case, jsonconverter, templated, user_institutes
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 = GeneVariantFiltersForm(request.args)
155
+ form.process(request.args)
143
156
  else: # POST
144
- form = GeneVariantFiltersForm(request.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["_id"] for inst in user_institutes(store, current_user)],
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 }}&nbsp;<a target="_blank" href="https://www.bioconductor.org/packages/devel/bioc/vignettes/FRASER/inst/doc/FRASER.pdf" rel="noopener noreferrer">&Delta;&psi;</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 }}&nbsp;&nbsp;<a target="_blank" href="https://www.bioconductor.org/packages/devel/bioc/vignettes/OUTRIDER/inst/doc/OUTRIDER.pdf" rel="noopener noreferrer">{% if variant.l2fc > 0 %}&uarr;{% elif variant.l2fc < 0 %}&darr;{% 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) &nbsp;&nbsp;<a target="_blank" href="https://www.bioconductor.org/packages/devel/bioc/vignettes/OUTRIDER/inst/doc/OUTRIDER.pdf" rel="noopener noreferrer">{% if variant.l2fc > 0 %}&uarr;{% elif variant.l2fc < 0 %}&darr;{% 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.case_to_clinVars(case_obj.get("display_name"))
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.rank_score }}</span>
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">{{ variant.rank_score }}</span>
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>{{ variant.rank_score }}</strong></span>
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">ExpansionHunter support</th>
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
- {% if sample.alt_frequency and sample.alt_frequency != -1 %}
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
- <span class="float-end">
356
- {% if variant.revel %}
357
- {{ variant.revel }}
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
- <span class="float-end control-label" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom"
391
- title="<strong>
392
- {% for entry in variant.spliceai_scores %}
393
- {% if entry is not none %}
394
- SpliceAI highest delta score {{ entry }} </strong> at position {{ variant.spliceai_positions[loop.index0]}} relative to this variant.
395
- {% if variant.spliceai_predictions[loop.index0] %}
396
- <br>All scores and positions(relative to variant):<br>
397
- {{ variant.spliceai_predictions[loop.index0] }} <br>
398
- {% endif %}
399
- <br>
400
- {% else %}
401
- No SpliceAI positions annotated for this variant.
402
- {% endif %}
403
- {% endfor %}
404
- ">
405
- {{ variant.spliceai_scores|join(', ') or "-"}}
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 scores" style="width:4%">Rank</th>
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">{{ variant.rank_score }}</div>
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