scout-browser 4.99.0__py3-none-any.whl → 4.100.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.
Files changed (64) hide show
  1. scout/adapter/mongo/case.py +30 -15
  2. scout/adapter/mongo/clinvar.py +23 -31
  3. scout/adapter/mongo/event.py +14 -4
  4. scout/adapter/mongo/omics_variant.py +14 -1
  5. scout/adapter/mongo/query.py +24 -1
  6. scout/adapter/mongo/variant.py +37 -19
  7. scout/adapter/mongo/variant_loader.py +159 -176
  8. scout/build/individual.py +3 -1
  9. scout/commands/download/ensembl.py +1 -2
  10. scout/commands/load/research.py +2 -3
  11. scout/commands/update/individual.py +1 -0
  12. scout/constants/__init__.py +7 -2
  13. scout/constants/igv_tracks.py +4 -3
  14. scout/constants/indexes.py +5 -4
  15. scout/constants/query_terms.py +1 -0
  16. scout/models/case/case.py +1 -0
  17. scout/models/case/case_loading_models.py +3 -1
  18. scout/parse/ensembl.py +8 -3
  19. scout/server/app.py +6 -0
  20. scout/server/blueprints/alignviewers/templates/alignviewers/igv_viewer.html +10 -0
  21. scout/server/blueprints/cases/controllers.py +9 -3
  22. scout/server/blueprints/cases/templates/cases/case_report.html +25 -13
  23. scout/server/blueprints/cases/templates/cases/chanjo2_form.html +1 -1
  24. scout/server/blueprints/cases/templates/cases/collapsible_actionbar.html +1 -1
  25. scout/server/blueprints/cases/templates/cases/gene_panel.html +1 -1
  26. scout/server/blueprints/cases/templates/cases/utils.html +19 -0
  27. scout/server/blueprints/clinvar/controllers.py +5 -1
  28. scout/server/blueprints/clinvar/templates/clinvar/clinvar_submissions.html +34 -12
  29. scout/server/blueprints/clinvar/templates/clinvar/multistep_add_variant.html +1 -1
  30. scout/server/blueprints/diagnoses/static/diagnoses.js +8 -1
  31. scout/server/blueprints/institutes/static/variants_list_scripts.js +9 -1
  32. scout/server/blueprints/institutes/templates/overview/institute_sidebar.html +9 -1
  33. scout/server/blueprints/mme/__init__.py +1 -0
  34. scout/server/blueprints/mme/controllers.py +18 -0
  35. scout/server/blueprints/mme/templates/mme/mme_submissions.html +153 -0
  36. scout/server/blueprints/mme/views.py +34 -0
  37. scout/server/blueprints/panels/templates/panels/panel.html +19 -6
  38. scout/server/blueprints/phenotypes/templates/phenotypes/hpo_terms.html +8 -1
  39. scout/server/blueprints/variant/controllers.py +19 -10
  40. scout/server/blueprints/variant/templates/variant/acmg.html +9 -0
  41. scout/server/blueprints/variant/templates/variant/cancer-variant.html +1 -1
  42. scout/server/blueprints/variant/templates/variant/components.html +19 -16
  43. scout/server/blueprints/variant/templates/variant/sv-variant.html +2 -2
  44. scout/server/blueprints/variant/templates/variant/utils.html +20 -8
  45. scout/server/blueprints/variant/templates/variant/variant.html +42 -1
  46. scout/server/blueprints/variant/views.py +12 -0
  47. scout/server/blueprints/variants/controllers.py +17 -9
  48. scout/server/blueprints/variants/forms.py +8 -3
  49. scout/server/blueprints/variants/templates/variants/components.html +8 -2
  50. scout/server/blueprints/variants/templates/variants/indicators.html +11 -13
  51. scout/server/blueprints/variants/templates/variants/utils.html +27 -22
  52. scout/server/extensions/bionano_extension.py +0 -1
  53. scout/server/extensions/chanjo2_extension.py +54 -13
  54. scout/server/links.py +15 -0
  55. scout/server/static/bs_styles.css +34 -6
  56. scout/server/templates/utils.html +9 -10
  57. scout/server/utils.py +18 -0
  58. scout/utils/ensembl_biomart_clients.py +1 -0
  59. scout/utils/scout_requests.py +1 -3
  60. {scout_browser-4.99.0.dist-info → scout_browser-4.100.1.dist-info}/METADATA +1 -1
  61. {scout_browser-4.99.0.dist-info → scout_browser-4.100.1.dist-info}/RECORD +64 -60
  62. {scout_browser-4.99.0.dist-info → scout_browser-4.100.1.dist-info}/WHEEL +0 -0
  63. {scout_browser-4.99.0.dist-info → scout_browser-4.100.1.dist-info}/entry_points.txt +0 -0
  64. {scout_browser-4.99.0.dist-info → scout_browser-4.100.1.dist-info}/licenses/LICENSE +0 -0
@@ -10,12 +10,25 @@
10
10
  <li class="nav-item">
11
11
  <a class="nav-link" href="{{ url_for('cases.index') }}">Institutes</a>
12
12
  </li>
13
- <li class="nav-item">
14
- <a class="nav-link" href="{{ url_for('panels.panels') }}">Gene Panels</a>
15
- </li>
16
- <li class="nav-item active d-flex align-items-center">
17
- <span class="navbar-text">{{ panel.display_name }} {{ panel.version }}</span>
18
- </li>
13
+ {% if case %}
14
+ <li class="nav-item">
15
+ <a class="nav-link" href="{{ url_for('overview.cases', institute_id=institute._id) }}">
16
+ {{ institute.display_name }}
17
+ </a>
18
+ </li>
19
+ <li class="nav-item d-flex align-items-center">
20
+ <a class="nav-link" href="{{ url_for('cases.case', institute_id=institute._id, case_name=case.display_name) }}">
21
+ {{ case.display_name }}
22
+ </a>
23
+ </li>
24
+ {% else %}
25
+ <li class="nav-item">
26
+ <a class="nav-link" href="{{ url_for('panels.panels') }}">Gene Panels</a>
27
+ </li>
28
+ {% endif %}
29
+ <li class="nav-item active d-flex align-items-center">
30
+ <span class="navbar-text">{{ panel.display_name }} {{ panel.version }}</span>
31
+ </li>
19
32
  {% endblock %}
20
33
 
21
34
  {% block content_main %}
@@ -56,7 +56,14 @@
56
56
  $('#phenotypes_table').DataTable( {
57
57
  paging: true,
58
58
  pageLength: 50,
59
- dom: 'fBrtip',
59
+ layout: {
60
+ topStart: 'buttons',
61
+ topEnd: {
62
+ search: {
63
+ placeholder: 'Filter...'
64
+ }
65
+ }
66
+ },
60
67
  buttons: [
61
68
  {
62
69
  extend: 'excelHtml5',
@@ -367,11 +367,13 @@ def variant(
367
367
  if variant_id in case_clinvars:
368
368
  variant_obj["clinvar_clinsig"] = case_clinvars.get(variant_id)["clinsig"]
369
369
 
370
- overlapping_vars = []
370
+ overlapping_variants, overlapping_outliers = [], []
371
371
  if get_overlapping:
372
- for var in store.hgnc_overlapping(variant_obj):
372
+ overlapping_variants, overlapping_outliers = map(list, store.hgnc_overlapping(variant_obj))
373
+
374
+ for var in overlapping_variants:
373
375
  var.update(predictions(var.get("genes", [])))
374
- overlapping_vars.append(var)
376
+
375
377
  variant_obj["end_chrom"] = variant_obj.get("end_chrom", variant_obj["chromosome"])
376
378
 
377
379
  dismiss_options = DISMISS_VARIANT_OPTIONS
@@ -395,7 +397,8 @@ def variant(
395
397
  "causatives": other_causatives,
396
398
  "managed_variant": managed_variant,
397
399
  "events": events,
398
- "overlapping_vars": overlapping_vars,
400
+ "overlapping_vars": overlapping_variants,
401
+ "overlapping_outliers": overlapping_outliers,
399
402
  "manual_rank_options": MANUAL_RANK_OPTIONS,
400
403
  "cancer_tier_options": CANCER_TIER_OPTIONS,
401
404
  "dismiss_variant_options": dismiss_options,
@@ -406,9 +409,6 @@ def variant(
406
409
  "inherit_palette": INHERITANCE_PALETTE,
407
410
  "igv_tracks": get_igv_tracks("38" if variant_obj["is_mitochondrial"] else genome_build),
408
411
  "has_rna_tracks": case_has_rna_tracks(case_obj),
409
- "gene_has_full_coverage": get_gene_has_full_coverage(
410
- institute_obj, case_obj, variant_obj, genome_build
411
- ),
412
412
  "gens_info": gens.connection_settings(genome_build),
413
413
  "evaluations": evaluations,
414
414
  "ccv_evaluations": ccv_evaluations,
@@ -416,16 +416,19 @@ def variant(
416
416
  }
417
417
 
418
418
 
419
- def get_gene_has_full_coverage(
420
- institute_obj, case_obj, variant_obj, genome_build
421
- ) -> Dict[int, bool]:
419
+ def get_gene_has_full_coverage(institute_obj, case_obj, variant_obj) -> Dict[int, bool]:
422
420
  """
423
421
  Query chanjo2, if configured and d4 files are available for this case,
424
422
  for coverage completeness on the genes touching this variant.
425
423
  """
424
+ case_has_chanjo2_coverage(case_obj)
426
425
  if not case_obj.get("chanjo2_coverage"):
427
426
  return {}
428
427
 
428
+ genome_build = str(case_obj.get("genome_build", "37"))
429
+ if genome_build not in ["37", "38"]:
430
+ genome_build = "37"
431
+
429
432
  gene_has_full_coverage: dict = {
430
433
  hgnc_id: chanjo2.get_gene_complete_coverage(
431
434
  hgnc_id=hgnc_id,
@@ -653,6 +656,12 @@ def variant_acmg(store: MongoAdapter, institute_id: str, case_name: str, variant
653
656
  store, variant_obj, institute_id, case_name
654
657
  )
655
658
 
659
+ genome_build = str(case_obj.get("genome_build", "37"))
660
+ if genome_build not in ["37", "38"]:
661
+ genome_build = "37"
662
+
663
+ add_gene_info(store, variant_obj, genome_build=genome_build)
664
+
656
665
  return dict(
657
666
  institute=institute_obj,
658
667
  case=case_obj,
@@ -105,6 +105,15 @@
105
105
  </div>
106
106
  {% endfor %}
107
107
  </div>
108
+ <!-- external links -->
109
+ <div class="card panel-default mt-3">
110
+ <div class="card-body">
111
+ Search ClinGen Criteria Specifications (CSPEC):
112
+ {% for gene in variant.genes %}
113
+ <a href="{{ gene.cspec_link }}" class="btn btn-secondary text-white" rel="noopener" referrerpolicy="no-referrer" target="_blank">{{ gene.common.hgnc_symbol if gene.common else gene.hgnc_id }}</a>
114
+ {% endfor %}
115
+ </div>
116
+ </div>
108
117
  <!-- classification preview in the footer-->
109
118
  <div class="mt-3 fixed-bottom bg-light border">
110
119
  <div class="row">
@@ -104,7 +104,7 @@
104
104
  </div>
105
105
 
106
106
  <div class="row">
107
- <div class="col-12">{{ overlapping_panel(variant, overlapping_vars, case, institute) }}</div>
107
+ <div class="col-12">{{ overlapping_panel(variant, overlapping_vars, overlapping_outliers, case, institute) }}</div>
108
108
  {% if rank_score_results %}
109
109
  <div class="col-12">{{ rankscore_panel(rank_score_results) }}</div>
110
110
  {% endif %}
@@ -132,27 +132,31 @@
132
132
  </div>
133
133
  {% endif %}
134
134
  {% for gene in variant.genes %}
135
- <div class="d-flex flex-wrap ms-1">
135
+ <div class="ms-1">
136
136
  {% if gene.alamut_link %}
137
137
  <a href="{{ gene.alamut_link }}" class="btn btn-sm btn-secondary text-white" rel="noopener" referrerpolicy="no-referrer" target="_blank" data-bs-toggle="tooltip" title="Alamut Visual (Plus) - Open variant - with gene transcript c. coordinate">Alamut {{ gene.common.hgnc_symbol if gene.common else gene.hgnc_id }} c.</a>
138
138
  {% endif %}
139
139
  </div>
140
140
  {% endfor %}
141
- {{ gene_coverage(institute, variant, case, config) }}
142
141
  </li>
143
142
  <li class="list-group-item">
144
143
  <div>
145
144
  {{ igv_track_selection(igv_tracks, current_user) }}
146
145
  </div>
147
146
  </li>
147
+ {% if (case.chanjo_coverage and config.chanjo_report) or case.chanjo2_coverage %}
148
+ <li class="list-group-item d-flex justify-content-between">
149
+ {{ gene_coverage(institute, variant, case, config) }}
150
+ </li>
151
+ {% endif %}
148
152
  </ul>
149
153
  {% endmacro %}
150
154
 
151
155
  {% macro gene_coverage(institute, variant, case, config) %}
152
156
  {% if case.chanjo_coverage and config.chanjo_report %}
153
- <div class="d-flex flex-wrap ms-1">
157
+ <div class="d-flex flex-wrap ms-1" data-bs-toggle="tooltip" title="Chanjo coverage reports">
154
158
  {% for gene in variant.genes %}
155
- <a class="btn btn-sm btn-secondary text-white" rel="noopener noreferrer" target="_blank" href="{{ url_for('report.gene', gene_id=gene.hgnc_id, sample_id=variant.samples|map(attribute='sample_id')|list) }}" data-bs-toggle="tooltip" title="Chanjo coverage report">
159
+ <a class="btn btn-sm btn-secondary text-white" rel="noopener noreferrer" target="_blank" href="{{ url_for('report.gene', gene_id=gene.hgnc_id, sample_id=variant.samples|map(attribute='sample_id')|list) }}">
156
160
  Gene coverage: {{ gene.common.hgnc_symbol if gene.common else gene.hgnc_id }}
157
161
  </a>
158
162
  {% endfor %}
@@ -160,14 +164,12 @@
160
164
  {% endif %}
161
165
  {% if case.chanjo2_coverage %}
162
166
  <div class="d-flex flex-wrap ms-1" data-bs-toggle="tooltip" title="Chanjo2 coverage reports">
163
- {% for gene in variant.genes %}
164
- {{ chanjo2_report_form(institute, case, gene.hgnc_symbol, 'overview', gene.hgnc_id, "Gene coverage " + (gene.common.hgnc_symbol if gene.common else gene.hgnc_id), "btn btn-sm btn-secondary text-white") }} <!--chanjo2 genes overview -->
165
- {% if gene.common.hgnc_id in gene_has_full_coverage and gene.common.hgnc_id[gene.common.hgnc_id] %}
166
- <span class="bg-success fa-solid fa-circle-check" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Chanjo2 coverage is at 100% completeness."></span>
167
- {% else %}
168
- <span class="bg-warning fa-solid fa-triangle-exclamation" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Note that Chanjo2 coverage is below 100% completeness."></span>
169
- {% endif %}
170
- {% endfor %}
167
+ {% for gene in variant.genes %}
168
+ <div class="btn-group" style="display:flex">
169
+ {{ chanjo2_report_form(institute, case, gene.hgnc_symbol if gene.hgnc_symbol else gene.hgnc_id, 'overview', gene.hgnc_id, "Gene coverage " ~ (gene.hgnc_symbol if gene.hgnc_symbol else gene.hgnc_id), "btn btn-sm btn-secondary text-white") }} <!--chanjo2 genes overview -->
170
+ <span class="btn complete-coverage-indicator align-items-center btn-info text-white btn-sm" style="display:flex" id="coverage-indicator-{{gene.hgnc_id}}-button" data-bs-toggle="tooltip" data-bs-placement="bottom" data-loading-text="Checking completeness..." title="Checking completeness..."><span style="display:flex" id="coverage-indicator-{{gene.hgnc_id}}-icon" class='align-self-center blink_me fa-solid fa-circle-question'></span><span style="display:flex" id="coverage-indicator-{{gene.hgnc_id}}-text" class='align-self-center'>Checking</span></span>
171
+ </div>
172
+ {% endfor %}
171
173
  </div>
172
174
  {% endif %}
173
175
  {% endmacro %}
@@ -338,8 +340,8 @@
338
340
  <div class="card-body mt-1 ms-3 mb-1" style="padding: 0;">
339
341
  Matching manually ranked variants:&nbsp;
340
342
  {% for manual_rank, manual_rank_info in matching_manual_ranked.items() %}
341
- <a style="padding: 0;" class="btn btn-{{manual_rank_info.label_class}} btn-small" data-bs-toggle="collapse" href="#collapse_mr{{manual_rank}}" role="button" aria-expanded="false" aria-controls="collapseExample">
342
- {{manual_rank_info.label}} ({{manual_rank_info.links|length}}x)
343
+ <a style="padding: 0;" class="btn btn-{{manual_rank_info.label_class}} btn-small" data-bs-toggle="collapse" href="#collapse_mr{{manual_rank}}" role="button" aria-expanded="false" aria-controls="#collapse_mr{{manual_rank}}">
344
+ <span class="collapse-button-icon me-1"></span>{{manual_rank_info.label}} ({{manual_rank_info.links|length}}x)
343
345
  </a>
344
346
  <div class="collapse" id="collapse_mr{{manual_rank}}">
345
347
  <div>
@@ -360,8 +362,8 @@
360
362
  <div class="card-body mt-1 ms-3 mb-1" style="padding: 0;">
361
363
  Matching tiered:&nbsp;
362
364
  {% for tier, tiered_info in matching_tiered.items() %}
363
- <a style="padding: 0;" class="btn btn-{{tiered_info.label}} btn-xs" data-bs-toggle="collapse" href="#collapse_{{tier}}" aria-expanded="false" aria-controls="collapseExample">
364
- {{tier}} ({{tiered_info.links|length}}x)
365
+ <a style="padding: 0;" class="btn btn-{{tiered_info.label_class}} btn-xs" data-bs-toggle="collapse" href="#collapse_{{tier}}" aria-expanded="false" aria-controls="collapse_{{tier}}">
366
+ <span class="collapse-button-icon me-1"></span>{{tier}} ({{tiered_info.links|length}}x)
365
367
  </a>
366
368
  <div class="collapse" id="collapse_{{tier}}">
367
369
  <div>
@@ -431,6 +433,7 @@
431
433
  <a href="{{ gene.oncokb_link }}" class="btn btn-secondary text-white" rel="noopener" referrerpolicy="no-referrer" target="_blank">OncoKB</a>
432
434
  <a href="{{ gene.civic_link }}" class="btn btn-secondary text-white" rel="noopener" referrerpolicy="no-referrer" target="_blank">CIViC</a>
433
435
  <a href="{{ gene.ckb_link }}" class="btn btn-secondary text-white" rel="noopener" referrerpolicy="no-referrer" target="_blank">CKB</a>
436
+ <a href="{{ gene.cancer_hotspots_link }}" class="btn btn-secondary text-white" rel="noopener" referrerpolicy="no-referrer" target="_blank">Cancer Hotspots</a>
434
437
  {% endif %}
435
438
  {% if str %}
436
439
  <a href="{{ gene.stripy_link }}" class="btn btn-secondary text-white" rel="noopener" referrerpolicy="no-referrer" target="_blank">STRipy</a>
@@ -74,7 +74,7 @@
74
74
  {% if variant.category == "cancer_sv" %}
75
75
  {{matching_variants(managed_variant, causatives, variant.matching_tiered) }}
76
76
  {% else %}
77
- {{matching_variants(managed_variant, causatives) }}
77
+ {{matching_variants(managed_variant, causatives, variant.matching_ranked) }}
78
78
  {% endif %}
79
79
  </div>
80
80
  </div>
@@ -122,7 +122,7 @@
122
122
  </div>
123
123
 
124
124
  <div class="row">
125
- <div class="col-12">{{ overlapping_panel(variant, overlapping_vars, case, institute) }}</div>
125
+ <div class="col-12">{{ overlapping_panel(variant, overlapping_vars, overlapping_outliers, case, institute) }}</div>
126
126
  </div>
127
127
 
128
128
  <div class="mt-3 row">
@@ -116,7 +116,7 @@
116
116
  </div>
117
117
  {% endmacro %}
118
118
 
119
- {% macro overlapping_panel(variant, overlapping_vars, case, institute) %}
119
+ {% macro overlapping_panel(variant, overlapping_vars, overlapping_outliers, case, institute) %}
120
120
  <div class="card panel-default">
121
121
  {% if variant.category != "snv" %}
122
122
  <div class="panel-heading">Gene overlapping variants</div>
@@ -141,27 +141,39 @@
141
141
  </tr>
142
142
  </thead>
143
143
  <tbody>
144
- {% for overlapping_variant in overlapping_vars %}
144
+ {% for overlapping_variant in overlapping_vars + overlapping_outliers %}
145
145
  <tr>
146
146
  <td>
147
147
  {% if overlapping_variant.category in ("sv", "cancer_sv") %}
148
148
  <a href="{{url_for('variant.sv_variant', institute_id=institute._id,
149
149
  case_name=case.display_name, variant_id=overlapping_variant._id)}}" target="_blank">
150
- {{ overlapping_variant.display_name|truncate(20, True) }}
150
+ {{ overlapping_variant.display_name|truncate(50, True) }}
151
151
  </a>
152
- {% else %}
152
+ {% elif overlapping_variant.category == "outlier" %}
153
+ {{ overlapping_variant.display_name|truncate(50, True) }}
154
+ {% else %}
153
155
  <a href="{{url_for('variant.variant', institute_id=institute._id,
154
156
  case_name=case.display_name, variant_id=overlapping_variant._id)}}" target="_blank">
155
- {{ overlapping_variant.display_name|truncate(20, True) }}
157
+ {{ overlapping_variant.display_name|truncate(50, True) }}
156
158
  </a>
157
159
  {% endif %}
158
160
  </td>
159
161
  <td>{{ overlapping_variant.hgnc_symbols|join(', ')|truncate(40, True) }}</td>
160
162
  <td>{{ overlapping_variant.sub_category|upper }}</td>
161
- <td class="text-end">{{ variant.rank_score + overlapping_variant.rank_score }}</td>
162
- <td class="text-end">{{ overlapping_variant.rank_score }}</td>
163
+ {% if overlapping_variant.rank_score %}
164
+ <td class="text-end">{{ variant.rank_score + overlapping_variant.rank_score }}</td>
165
+ <td class="text-end">{{ overlapping_variant.rank_score }}</td>
166
+ {% else %}
167
+ <td class="text-end">-</td><td class="text-end">-</td>
168
+ {% endif %}
169
+
163
170
  <td class="text-end">{{ overlapping_variant.length }}</td>
164
- <td>{{ overlapping_variant.region_annotations|join(', ')|truncate(40, True) }}</td>
171
+ <td>
172
+ {{ overlapping_variant.region_annotations|join(', ')|truncate(40, True) }}
173
+ {% if overlapping_variant.sub_category == "splicing" %}
174
+ {{ overlapping_variant.potential_impact }} - fs {{ overlapping_variant.causes_frameshift }}
175
+ {% endif %}
176
+ </td>
165
177
  <td>{{ overlapping_variant.functional_annotations|join(', ')|truncate(40, True) }}</td>
166
178
  </tr>
167
179
  {% else %}
@@ -152,7 +152,7 @@
152
152
  {% endif %}
153
153
  {{ rankscore_panel(rank_score_results) }}
154
154
  <div class="row">
155
- <div class="col-12">{{ overlapping_panel(variant, overlapping_vars, case, institute) }}</div>
155
+ <div class="col-12">{{ overlapping_panel(variant, overlapping_vars, overlapping_outliers, case, institute) }}</div>
156
156
  </div>
157
157
  <div class="mt-3 row">
158
158
  <div class="col-12">
@@ -432,5 +432,46 @@
432
432
  set_scrolly_table('proteins_panel_table')
433
433
  set_scrolly_table('transcripts_panel_table')
434
434
 
435
+ function update_gene_has_full_coverage() {
436
+ $.getJSON('{{ url_for("variant.gene_has_full_coverage", institute_id=institute._id, case_name=case.display_name, variant_id=variant._id) }}', function (data) {
437
+ if($.isEmptyObject(data.gene_has_full_coverage)) {
438
+ const complete_coverage_indicator_elements = document.getElementsByClassName("complete-coverage-indicator");
439
+ for(let complete_coverage_indicator of complete_coverage_indicator_elements) {
440
+ complete_coverage_indicator.style.display = "none"
441
+ }
442
+ }
443
+ for (const [hgnc_id, has_complete_coverage] of Object.entries(data.gene_has_full_coverage)) {
444
+ // reset the temp color for the outer span and icon of the inner span
445
+ console.log()
446
+ var coverage_indicator_button = document.getElementById('coverage-indicator-'+hgnc_id+'-button');
447
+ var coverage_indicator_icon = document.getElementById('coverage-indicator-'+hgnc_id+'-icon');
448
+ var coverage_indicator_text = document.getElementById('coverage-indicator-'+hgnc_id+'-text');
449
+
450
+ // this is the outer, button span
451
+ coverage_indicator_button.classList.remove('btn-info');
452
+ // this is the inner, icon span
453
+ coverage_indicator_icon.classList.remove('blink_me','fa-circle-question');
454
+
455
+ if (has_complete_coverage) {
456
+ coverage_indicator_button.classList.add('btn-success');
457
+ coverage_indicator_button.setAttribute('data-bs-original-title', "Chanjo2 coverage is at 100% completeness.");
458
+ coverage_indicator_icon.classList.add('fa-circle-check');
459
+ coverage_indicator_text.textContent = "Complete"
460
+ } else {
461
+ coverage_indicator_button.classList.add('btn-warning');
462
+ coverage_indicator_button.setAttribute('data-bs-original-title', "Note that Chanjo2 coverage is below 100% completeness.");
463
+ coverage_indicator_icon.classList.add('fa-triangle-exclamation');
464
+ coverage_indicator_text.textContent = "Incomplete"
465
+ }
466
+ }
467
+ }).fail(function() {
468
+ const complete_coverage_indicator_elements = document.getElementsByClassName("complete-coverage-indicator");
469
+ for(let complete_coverage_indicator of complete_coverage_indicator_elements) {
470
+ complete_coverage_indicator.style.display = "none"
471
+ }
472
+ });
473
+ };
474
+
475
+ $( window ).on( "load", function() { update_gene_has_full_coverage(); })
435
476
  </script>
436
477
  {% endblock %}
@@ -28,6 +28,7 @@ from scout.server.blueprints.variant.controllers import (
28
28
  )
29
29
  from scout.server.blueprints.variant.controllers import evaluation as evaluation_controller
30
30
  from scout.server.blueprints.variant.controllers import (
31
+ get_gene_has_full_coverage,
31
32
  observations,
32
33
  str_variant_reviewer,
33
34
  )
@@ -423,6 +424,17 @@ def acmg():
423
424
  return jsonify({"classification": classification, "conflicts": acmg_conflicts, **acmg_bayesian})
424
425
 
425
426
 
427
+ @variant_bp.route("/api/v1/gene_has_full_coverage/<institute_id>/<case_name>/<variant_id>/")
428
+ def gene_has_full_coverage(institute_id, case_name, variant_id):
429
+ """Check if gene has full coverage using chanjo2 endpoint"""
430
+ institute_obj, case_obj = institute_and_case(store, institute_id, case_name)
431
+ variant_obj = store.variant(variant_id)
432
+
433
+ return jsonify(
434
+ {"gene_has_full_coverage": get_gene_has_full_coverage(institute_obj, case_obj, variant_obj)}
435
+ )
436
+
437
+
426
438
  @variant_bp.route("/ccv_evaluations/<evaluation_id>", methods=["GET", "POST"])
427
439
  @templated("variant/ccv.html")
428
440
  def ccv_evaluation(evaluation_id):
@@ -49,7 +49,12 @@ from scout.server.utils import (
49
49
  user_institutes,
50
50
  )
51
51
 
52
- from .forms import FILTERSFORMCLASS, CancerSvFiltersForm, FusionFiltersForm, SvFiltersForm
52
+ from .forms import (
53
+ FILTERSFORMCLASS,
54
+ CancerSvFiltersForm,
55
+ FusionFiltersForm,
56
+ SvFiltersForm,
57
+ )
53
58
  from .utils import update_case_panels
54
59
 
55
60
  NUM = re.compile(r"\d+")
@@ -111,6 +116,13 @@ def populate_institute_soft_filters(form, institute_obj):
111
116
  form.institute_soft_filters.data = ",".join(institute_obj["soft_filters"])
112
117
 
113
118
 
119
+ def set_overlapping_variants(variant_obj: dict):
120
+ """Define DNA or WTS variants that are overlapping with a gene of a variant."""
121
+ overlapping_variants, overlapping_outliers = store.hgnc_overlapping(variant_obj)
122
+ variant_obj["overlapping"] = list(overlapping_variants) or None
123
+ variant_obj["overlapping_outliers"] = list(overlapping_outliers) or None
124
+
125
+
114
126
  def variants(
115
127
  store,
116
128
  institute_obj,
@@ -137,8 +149,7 @@ def variants(
137
149
 
138
150
  variants = []
139
151
  for variant_obj in variant_res:
140
- overlapping_svs = list(store.hgnc_overlapping(variant_obj))
141
- variant_obj["overlapping"] = overlapping_svs or None
152
+ set_overlapping_variants(variant_obj)
142
153
 
143
154
  evaluations = []
144
155
  is_research = variant_obj["variant_type"] == "research"
@@ -233,8 +244,7 @@ def sv_variants(store, institute_obj, case_obj, variants_query, variant_count, p
233
244
  case_dismissed_vars = store.case_dismissed_variants(institute_obj, case_obj)
234
245
 
235
246
  for variant_obj in variants_query.skip(skip_count).limit(per_page):
236
- overlapping_svs = list(store.hgnc_overlapping(variant_obj))
237
- variant_obj["overlapping"] = overlapping_svs or None
247
+ set_overlapping_variants(variant_obj)
238
248
 
239
249
  # show previous classifications for research variants
240
250
  clinical_var_obj = variant_obj
@@ -282,8 +292,7 @@ def mei_variants(
282
292
  case_dismissed_vars = store.case_dismissed_variants(institute_obj, case_obj)
283
293
 
284
294
  for variant_obj in variants_query.skip(skip_count).limit(per_page):
285
- overlapping = list(store.hgnc_overlapping(variant_obj))
286
- variant_obj["overlapping"] = overlapping or None
295
+ set_overlapping_variants(variant_obj)
287
296
 
288
297
  # show previous classifications for research variants
289
298
  clinical_var_obj = variant_obj
@@ -1454,8 +1463,7 @@ def cancer_variants(store, institute_id, case_name, variants_query, variant_coun
1454
1463
  variant_obj["second_rep_gene"] = secondary_gene
1455
1464
  variant_obj["clinical_assessments"] = get_manual_assessments(variant_obj)
1456
1465
 
1457
- overlapping = list(store.hgnc_overlapping(variant_obj))
1458
- variant_obj["overlapping"] = overlapping or None
1466
+ set_overlapping_variants(variant_obj)
1459
1467
 
1460
1468
  evaluations = []
1461
1469
  # Get previous ClinGen-CGC-VIGG evaluations of the variant from other cases
@@ -28,6 +28,7 @@ from scout.constants import (
28
28
  CLINSIG_MAP,
29
29
  FEATURE_TYPES,
30
30
  GENETIC_MODELS,
31
+ ONC_CLNSIG,
31
32
  OUTLIER_TYPES,
32
33
  SO_TERMS,
33
34
  SPIDEX_LEVELS,
@@ -38,6 +39,7 @@ from scout.constants import (
38
39
  LOG = logging.getLogger(__name__)
39
40
 
40
41
  CLINSIG_OPTIONS = list(CLINSIG_MAP.items())
42
+ ONC_CLNSIG_OPTIONS = [(term.lower().replace(" ", "_"), term) for term in ONC_CLNSIG]
41
43
  FUNC_ANNOTATIONS = [(term, term.replace("_", " ")) for term in SO_TERMS]
42
44
  REGION_ANNOTATIONS = [(term, term.replace("_", " ")) for term in FEATURE_TYPES]
43
45
  SV_TYPE_CHOICES = [(term, term.replace("_", " ").upper()) for term in SV_TYPES]
@@ -112,8 +114,9 @@ class VariantFiltersForm(FlaskForm):
112
114
  compound_rank_score = IntegerField("Compound rank score")
113
115
  compound_follow_filter = BooleanField("Compounds follow filter")
114
116
  cadd_inclusive = BooleanField("CADD inclusive")
115
- clinsig = NonValidatingSelectMultipleField("ClinVar CLINSIG", choices=CLINSIG_OPTIONS)
117
+ clinsig = NonValidatingSelectMultipleField("ClinVar significance", choices=CLINSIG_OPTIONS)
116
118
  clinsig_exclude = BooleanField("Exclude")
119
+ clinvar_tag = BooleanField("ClinVar hits only")
117
120
  prioritise_clinvar = BooleanField("Prioritise ClinVar")
118
121
 
119
122
  gnomad_frequency = BetterDecimalField("gnomadAF", validators=[validators.Optional()])
@@ -183,7 +186,6 @@ class FiltersForm(VariantFiltersForm):
183
186
  spidex_human = SelectMultipleField("SPIDEX", choices=SPIDEX_CHOICES)
184
187
 
185
188
  clinical_filter = SubmitField(label="Clinical filter")
186
- clinvar_tag = BooleanField("ClinVar hits only")
187
189
 
188
190
  # polymorphic constant base for clinical filter
189
191
  clinical_filter_base = CLINICAL_FILTER_BASE
@@ -196,8 +198,11 @@ class CancerFiltersForm(VariantFiltersForm):
196
198
  alt_count = IntegerField("Min alt count", validators=[validators.Optional()])
197
199
  control_frequency = BetterDecimalField("Normal alt AF <", validators=[validators.Optional()])
198
200
  tumor_frequency = BetterDecimalField("Tumor alt AF >", validators=[validators.Optional()])
199
- clinvar_tag = BooleanField("ClinVar hits only")
200
201
  cosmic_tag = BooleanField("Cosmic hits")
202
+ clinsig_onc = NonValidatingSelectMultipleField(
203
+ "ClinVar oncogenicity", choices=ONC_CLNSIG_OPTIONS
204
+ )
205
+ clinsig_onc_exclude = BooleanField("Exclude")
201
206
  mvl_tag = BooleanField("Managed Variants hits")
202
207
  local_obs_cancer_somatic_old = IntegerField(
203
208
  "Local somatic obs. (archive)", validators=[validators.Optional()]
@@ -440,10 +440,16 @@
440
440
  data-bs-html="true" data-bs-trigger="hover click"
441
441
  {% if variant.category == "SNV" %}
442
442
  data-bs-content="<div>Gene overlapping non-SNVs</div>
443
- {{ overlapping_tooltip_table(institute, case, variant.overlapping[:20]) }}">Gene overlapping</a>
443
+ {{ overlapping_tooltip_table(institute, case, variant.overlapping[:20]) }}">Gene overlapping (DNA)</a>
444
444
  {% else %}
445
445
  data-bs-content="<div>Gene overlapping variants</div>
446
- {{ overlapping_tooltip_table(institute, case, variant.overlapping[:40]) }}">Gene overlapping</a>
446
+ {{ overlapping_tooltip_table(institute, case, variant.overlapping[:40]) }}">Gene overlapping (DNA)</a>
447
447
  {% endif %}
448
448
  {% endif %}
449
+
450
+ {% if variant.overlapping_outliers %}
451
+ <a href="#" class="badge bg-success text-white" data-bs-toggle="popover" data-bs-placement="left"
452
+ data-bs-html="true" data-bs-trigger="hover click" data-bs-content="<div>Gene overlapping WTS outliers</div>
453
+ {{ overlapping_tooltip_table(institute, case, variant.overlapping_outliers[:40]) }}">Gene overlapping (WTS)</a>
454
+ {% endif %}
449
455
  {% endmacro %}
@@ -41,25 +41,23 @@
41
41
 
42
42
  {% macro other_tiered_variants(variant) %}
43
43
  {% if variant.matching_tiered %}
44
- <span class="popovers badge bg-dark" data-bs-toggle="popover" data-bs-html="true" title=""
45
- data-bs-content="
44
+ <span class="badge bg-dark" data-bs-toggle="popover" data-bs-html="true" data-bs-trigger="hover click"
45
+ data-bs-title="Previously <b>T</b>iered as"
46
+ data-bs-content="
46
47
  {% for tier, tiered_info in variant.matching_tiered.items() %}
47
- <span class='badge bg-{{tiered_info.label}}'>{{tier}} ({{tiered_info.links|length}}x)</span>
48
- {% endfor %}
49
- "
50
- data-original-title="Previously tiered as">T</span>
48
+ <span class='badge bg-{{tiered_info.label_class}}'>{{tier}} ({{tiered_info.links|length}}x)</span>
49
+ {% endfor %}">T</span>
51
50
  {% endif %} <!-- end of if variant.matching_tiered -->
52
51
  {% endmacro %}
53
52
 
54
53
  {% macro matching_manual_rank(variant) %}
55
54
  {% if variant.matching_ranked %}
56
- <span class="popovers badge bg-dark" data-bs-toggle="popover" data-bs-html="true"
57
- data-bs-content="
55
+ <span class="badge bg-dark" data-bs-toggle="popover" data-bs-html="true" data-bs-trigger="hover click"
56
+ data-bs-title="Previously <b>M</b>anually ranked as"
57
+ data-bs-content="
58
58
  {% for manual_rank, manual_rank_info in variant.matching_ranked.items() %}
59
- <div>{{manual_rank_info.label}} - {{manual_rank_info.description}} ({{manual_rank_info.links|length}}x)</div>
60
- {% endfor %}
61
- "
62
- data-original-title="Previously ranked as">M</span>
59
+ <div><span class='badge bg-{{ manual_rank_info.label_class }}'>{{manual_rank_info.label}}</span> - {{manual_rank_info.description}} ({{manual_rank_info.links|length}}x)</div>
60
+ {% endfor %}">M</span>
63
61
  {% endif %}
64
62
  {% endmacro %}
65
63
 
@@ -120,7 +118,7 @@
120
118
  {% macro group_assessments_badge(variant) %}
121
119
  {% if variant.group_assessments %}
122
120
  {% for assessment in (variant.group_assessments or []) %}
123
- <span class="badge bg-{{ assessment.display_class }}" data-bs-html="true" data-bs-toggle="tooltip" data-bs-placement="right"
121
+ <span class="badge bg-{{ assessment.display_class }}<b>" data-bs-html="true" data-bs-toggle="tooltip" data-bs-placement="right"
124
122
  title="Cohort {{ assessment.title }}">
125
123
  {{ assessment.label }}</span>
126
124
  {% endfor %}