scout-browser 4.98.0__py3-none-any.whl → 4.100.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 (91) 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/institute.py +42 -55
  5. scout/adapter/mongo/omics_variant.py +14 -1
  6. scout/adapter/mongo/query.py +24 -1
  7. scout/adapter/mongo/variant.py +44 -22
  8. scout/adapter/mongo/variant_loader.py +169 -186
  9. scout/build/individual.py +5 -1
  10. scout/build/variant/variant.py +8 -0
  11. scout/commands/download/ensembl.py +18 -3
  12. scout/commands/load/research.py +2 -3
  13. scout/commands/update/individual.py +3 -0
  14. scout/commands/update/panelapp.py +15 -2
  15. scout/constants/__init__.py +6 -2
  16. scout/constants/clnsig.py +2 -0
  17. scout/constants/file_types.py +12 -0
  18. scout/constants/igv_tracks.py +9 -6
  19. scout/constants/indexes.py +5 -4
  20. scout/constants/panels.py +3 -0
  21. scout/constants/query_terms.py +1 -0
  22. scout/constants/variant_tags.py +6 -6
  23. scout/demo/643594.config.yaml +1 -0
  24. scout/load/panelapp.py +11 -5
  25. scout/models/case/case.py +1 -0
  26. scout/models/case/case_loading_models.py +7 -1
  27. scout/parse/ensembl.py +8 -3
  28. scout/parse/variant/clnsig.py +38 -0
  29. scout/parse/variant/genotype.py +4 -10
  30. scout/parse/variant/models.py +5 -11
  31. scout/parse/variant/rank_score.py +5 -13
  32. scout/parse/variant/variant.py +90 -111
  33. scout/server/app.py +39 -22
  34. scout/server/blueprints/alignviewers/controllers.py +29 -10
  35. scout/server/blueprints/alignviewers/templates/alignviewers/igv_viewer.html +51 -11
  36. scout/server/blueprints/cases/controllers.py +9 -3
  37. scout/server/blueprints/cases/templates/cases/case_report.html +25 -13
  38. scout/server/blueprints/cases/templates/cases/chanjo2_form.html +1 -1
  39. scout/server/blueprints/cases/templates/cases/collapsible_actionbar.html +1 -1
  40. scout/server/blueprints/cases/templates/cases/gene_panel.html +1 -1
  41. scout/server/blueprints/cases/templates/cases/utils.html +25 -6
  42. scout/server/blueprints/clinvar/controllers.py +34 -15
  43. scout/server/blueprints/clinvar/templates/clinvar/clinvar_submissions.html +34 -12
  44. scout/server/blueprints/clinvar/templates/clinvar/multistep_add_variant.html +14 -5
  45. scout/server/blueprints/clinvar/views.py +14 -2
  46. scout/server/blueprints/diagnoses/static/diagnoses.js +8 -1
  47. scout/server/blueprints/institutes/controllers.py +10 -2
  48. scout/server/blueprints/institutes/static/variants_list_scripts.js +9 -1
  49. scout/server/blueprints/institutes/templates/overview/institute_sidebar.html +9 -1
  50. scout/server/blueprints/login/controllers.py +112 -12
  51. scout/server/blueprints/login/views.py +38 -60
  52. scout/server/blueprints/mme/__init__.py +1 -0
  53. scout/server/blueprints/mme/controllers.py +18 -0
  54. scout/server/blueprints/mme/templates/mme/mme_submissions.html +153 -0
  55. scout/server/blueprints/mme/views.py +34 -0
  56. scout/server/blueprints/panels/templates/panels/panel.html +19 -6
  57. scout/server/blueprints/phenotypes/templates/phenotypes/hpo_terms.html +8 -1
  58. scout/server/blueprints/public/templates/public/index.html +5 -1
  59. scout/server/blueprints/variant/controllers.py +19 -10
  60. scout/server/blueprints/variant/templates/variant/acmg.html +15 -2
  61. scout/server/blueprints/variant/templates/variant/cancer-variant.html +1 -1
  62. scout/server/blueprints/variant/templates/variant/components.html +38 -16
  63. scout/server/blueprints/variant/templates/variant/sv-variant.html +2 -2
  64. scout/server/blueprints/variant/templates/variant/utils.html +23 -11
  65. scout/server/blueprints/variant/templates/variant/variant.html +42 -1
  66. scout/server/blueprints/variant/views.py +12 -0
  67. scout/server/blueprints/variants/controllers.py +20 -3
  68. scout/server/blueprints/variants/forms.py +8 -3
  69. scout/server/blueprints/variants/templates/variants/components.html +34 -0
  70. scout/server/blueprints/variants/templates/variants/indicators.html +11 -13
  71. scout/server/blueprints/variants/templates/variants/mei-variants.html +8 -6
  72. scout/server/blueprints/variants/templates/variants/sv-variants.html +9 -7
  73. scout/server/blueprints/variants/templates/variants/utils.html +35 -34
  74. scout/server/blueprints/variants/templates/variants/variants.html +4 -25
  75. scout/server/config.py +8 -0
  76. scout/server/extensions/bionano_extension.py +0 -1
  77. scout/server/extensions/chanjo2_extension.py +54 -13
  78. scout/server/links.py +15 -0
  79. scout/server/static/bs_styles.css +34 -6
  80. scout/server/templates/utils.html +9 -10
  81. scout/server/utils.py +40 -5
  82. scout/utils/acmg.py +25 -26
  83. scout/utils/ensembl_biomart_clients.py +2 -1
  84. scout/utils/ensembl_rest_clients.py +25 -32
  85. scout/utils/hgvs.py +1 -1
  86. scout/utils/scout_requests.py +1 -3
  87. {scout_browser-4.98.0.dist-info → scout_browser-4.100.0.dist-info}/METADATA +10 -14
  88. {scout_browser-4.98.0.dist-info → scout_browser-4.100.0.dist-info}/RECORD +91 -87
  89. {scout_browser-4.98.0.dist-info → scout_browser-4.100.0.dist-info}/WHEEL +0 -0
  90. {scout_browser-4.98.0.dist-info → scout_browser-4.100.0.dist-info}/entry_points.txt +0 -0
  91. {scout_browser-4.98.0.dist-info → scout_browser-4.100.0.dist-info}/licenses/LICENSE +0 -0
@@ -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 %}
@@ -32,6 +32,25 @@
32
32
  </tbody>
33
33
  </table>
34
34
  {% endif %}
35
+
36
+ {% if variant.clnsig_onc %}
37
+ <table id='clinsig_table' class="table table-bordered table-sm">
38
+ <thead>
39
+ <th>Oncogenicity</th>
40
+ <th>Disease name</th>
41
+ <th>Revstat</th>
42
+ </thead>
43
+ <tbody>
44
+ {% for classif in variant.clnsig_onc %}
45
+ <tr>
46
+ <td>{{ classif.value|capitalize }}</td>
47
+ <td>{{ classif.dn|replace("_", " ")|replace(",", ", ") }}</td>
48
+ <td>{{ classif.revstat }}</td>
49
+ </tr>
50
+ {% endfor %}
51
+ </tbody>
52
+ </table>
53
+ {% endif %}
35
54
  {% endmacro %}
36
55
 
37
56
  {% macro acmg_classification_item(variant, data) %}
@@ -113,27 +132,31 @@
113
132
  </div>
114
133
  {% endif %}
115
134
  {% for gene in variant.genes %}
116
- <div class="d-flex flex-wrap ms-1">
135
+ <div class="ms-1">
117
136
  {% if gene.alamut_link %}
118
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>
119
138
  {% endif %}
120
139
  </div>
121
140
  {% endfor %}
122
- {{ gene_coverage(institute, variant, case, config) }}
123
141
  </li>
124
142
  <li class="list-group-item">
125
143
  <div>
126
144
  {{ igv_track_selection(igv_tracks, current_user) }}
127
145
  </div>
128
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 %}
129
152
  </ul>
130
153
  {% endmacro %}
131
154
 
132
155
  {% macro gene_coverage(institute, variant, case, config) %}
133
156
  {% if case.chanjo_coverage and config.chanjo_report %}
134
- <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">
135
158
  {% for gene in variant.genes %}
136
- <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) }}">
137
160
  Gene coverage: {{ gene.common.hgnc_symbol if gene.common else gene.hgnc_id }}
138
161
  </a>
139
162
  {% endfor %}
@@ -141,14 +164,12 @@
141
164
  {% endif %}
142
165
  {% if case.chanjo2_coverage %}
143
166
  <div class="d-flex flex-wrap ms-1" data-bs-toggle="tooltip" title="Chanjo2 coverage reports">
144
- {% for gene in variant.genes %}
145
- {{ 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 -->
146
- {% if gene.common.hgnc_id in gene_has_full_coverage and gene.common.hgnc_id[gene.common.hgnc_id] %}
147
- <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>
148
- {% else %}
149
- <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>
150
- {% endif %}
151
- {% 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 %}
152
173
  </div>
153
174
  {% endif %}
154
175
  {% endmacro %}
@@ -319,8 +340,8 @@
319
340
  <div class="card-body mt-1 ms-3 mb-1" style="padding: 0;">
320
341
  Matching manually ranked variants:&nbsp;
321
342
  {% for manual_rank, manual_rank_info in matching_manual_ranked.items() %}
322
- <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">
323
- {{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)
324
345
  </a>
325
346
  <div class="collapse" id="collapse_mr{{manual_rank}}">
326
347
  <div>
@@ -341,8 +362,8 @@
341
362
  <div class="card-body mt-1 ms-3 mb-1" style="padding: 0;">
342
363
  Matching tiered:&nbsp;
343
364
  {% for tier, tiered_info in matching_tiered.items() %}
344
- <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">
345
- {{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)
346
367
  </a>
347
368
  <div class="collapse" id="collapse_{{tier}}">
348
369
  <div>
@@ -412,6 +433,7 @@
412
433
  <a href="{{ gene.oncokb_link }}" class="btn btn-secondary text-white" rel="noopener" referrerpolicy="no-referrer" target="_blank">OncoKB</a>
413
434
  <a href="{{ gene.civic_link }}" class="btn btn-secondary text-white" rel="noopener" referrerpolicy="no-referrer" target="_blank">CIViC</a>
414
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>
415
437
  {% endif %}
416
438
  {% if str %}
417
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,12 +116,12 @@
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
- {% if variant.category == 'sv' %}
122
- <div class="panel-heading">Overlapping SNVs</div>
121
+ {% if variant.category != "snv" %}
122
+ <div class="panel-heading">Gene overlapping variants</div>
123
123
  {% else %}
124
- <div class="panel-heading">Overlapping SVs</div>
124
+ <div class="panel-heading">Gene overlapping non-SNVs</div>
125
125
  {% endif %}
126
126
  <div class="card-body">
127
127
  <div class="table-responsive">
@@ -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.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,6 +244,8 @@ 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):
247
+ set_overlapping_variants(variant_obj)
248
+
236
249
  # show previous classifications for research variants
237
250
  clinical_var_obj = variant_obj
238
251
  if variant_obj["variant_type"] == "research":
@@ -279,6 +292,8 @@ def mei_variants(
279
292
  case_dismissed_vars = store.case_dismissed_variants(institute_obj, case_obj)
280
293
 
281
294
  for variant_obj in variants_query.skip(skip_count).limit(per_page):
295
+ set_overlapping_variants(variant_obj)
296
+
282
297
  # show previous classifications for research variants
283
298
  clinical_var_obj = variant_obj
284
299
  if variant_obj["variant_type"] == "research":
@@ -1448,6 +1463,8 @@ def cancer_variants(store, institute_id, case_name, variants_query, variant_coun
1448
1463
  variant_obj["second_rep_gene"] = secondary_gene
1449
1464
  variant_obj["clinical_assessments"] = get_manual_assessments(variant_obj)
1450
1465
 
1466
+ set_overlapping_variants(variant_obj)
1467
+
1451
1468
  evaluations = []
1452
1469
  # Get previous ClinGen-CGC-VIGG evaluations of the variant from other cases
1453
1470
  for evaluation_obj in store.get_ccv_evaluations(variant_obj):
@@ -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()]
@@ -1,4 +1,5 @@
1
1
  {% from "variant/gene_disease_relations.html" import inheritance_badge %}
2
+ {% from "variants/utils.html" import compounds_table, overlapping_tooltip_table %}
2
3
 
3
4
  {% macro variant_gene_symbols_cell(variant, inherit_palette) %}
4
5
  <div class="d-flex justify-content-between align-items-center">
@@ -419,3 +420,36 @@
419
420
  <span class="text-body">N/A</span>
420
421
  {% endif %}
421
422
  {% endmacro %}
423
+
424
+
425
+ {% macro overlapping_cell(variant, institute, case) %}
426
+ {% if variant.compounds %}
427
+ {% set ns=namespace(show_compounds=false) %}
428
+ {% for compound in variant.compounds if not compound.is_dismissed %}
429
+ {% set ns.show_compounds = true %}
430
+ {% endfor %}
431
+ {% if ns.show_compounds %}
432
+ <a href="#" class="badge bg-primary text-white" data-bs-toggle="popover" data-bs-placement="left"
433
+ data-bs-html="true" data-bs-trigger="hover click"
434
+ data-bs-content="{{ compounds_table(institute, case, variant.compounds[:20], is_popover=true) }}">Compounds</a>
435
+ {% endif %}
436
+ {% endif %}
437
+
438
+ {% if variant.overlapping %}
439
+ <a href="#" class="badge bg-warning" data-bs-toggle="popover" data-bs-placement="left"
440
+ data-bs-html="true" data-bs-trigger="hover click"
441
+ {% if variant.category == "SNV" %}
442
+ data-bs-content="<div>Gene overlapping non-SNVs</div>
443
+ {{ overlapping_tooltip_table(institute, case, variant.overlapping[:20]) }}">Gene overlapping (DNA)</a>
444
+ {% else %}
445
+ data-bs-content="<div>Gene overlapping variants</div>
446
+ {{ overlapping_tooltip_table(institute, case, variant.overlapping[:40]) }}">Gene overlapping (DNA)</a>
447
+ {% endif %}
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 %}
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 %}
@@ -1,6 +1,6 @@
1
1
  {% extends "layout.html" %}
2
2
  {% from "variants/utils.html" import mei_filters, cell_rank, pagination_footer, pagination_hidden_div, dismiss_variants_block, filter_form_footer, filter_script_main, update_stash_filter_button_status %}
3
- {% from "variants/components.html" import external_scripts, external_stylesheets, frequency_cell_general, variant_gene_symbols_cell, variant_funct_anno_cell %}
3
+ {% from "variants/components.html" import external_scripts, external_stylesheets, frequency_cell_general, overlapping_cell, variant_gene_symbols_cell, variant_funct_anno_cell %}
4
4
 
5
5
  {% block title %}
6
6
  {{ super() }} - {{ institute.display_name }} - {{ case.display_name }} - Mobile Element Insertion variants
@@ -57,16 +57,17 @@ onsubmit="return validateForm()">
57
57
  <thead class="table-light thead">
58
58
  <tr>
59
59
  <th style="width:3%"></th>
60
- <th>Rank</th>
61
- <th>Score</th>
60
+ <th title="Rank position">Rank</th>
61
+ <th title="Rank score">Score</th>
62
62
  <th>Type</th>
63
63
  <th style="width:18%">Element</th>
64
- <th>Chr</th>
64
+ <th title="Chromosome">Chr</th>
65
65
  <th style="width:9%">Start loc</th>
66
66
  <th>Frequency</th>
67
67
  <th>Gene(s)</th>
68
- <th>Function</th>
69
- </tr>
68
+ <th title="Functional annotation">Function</th>
69
+ <th title="Gene overlapping variants">Overlap</th>
70
+ </tr>
70
71
  </thead>
71
72
  <tbody>
72
73
  {% for variant in variants %}
@@ -113,6 +114,7 @@ onsubmit="return validateForm()">
113
114
  <td style="word-wrap:break-word;">
114
115
  {{ variant_funct_anno_cell(variant) }}
115
116
  </td>
117
+ <td>{{ overlapping_cell(variant, institute, case) }}</td>
116
118
  </tr>
117
119
  {% endmacro %}
118
120
 
@@ -1,6 +1,6 @@
1
1
  {% extends "layout.html" %}
2
2
  {% from "variants/utils.html" import sv_filters, cell_rank, pagination_footer, pagination_hidden_div, dismiss_variants_block, filter_form_footer, filter_script_main, update_stash_filter_button_status, callers_cell %}
3
- {% from "variants/components.html" import external_scripts, external_stylesheets, frequency_cell_general, observed_cell_general, variant_gene_symbols_cell, variant_funct_anno_cell %}
3
+ {% from "variants/components.html" import external_scripts, external_stylesheets, frequency_cell_general, observed_cell_general, overlapping_cell, variant_gene_symbols_cell, variant_funct_anno_cell %}
4
4
 
5
5
  {% block title %}
6
6
  {{ super() }} - {{ institute.display_name }} - {{ case.display_name }} - SV variants
@@ -57,18 +57,19 @@ onsubmit="return validateForm()">
57
57
  <thead class="table-light thead">
58
58
  <tr>
59
59
  <th style="width:3%"></th>
60
- <th>Rank</th>
61
- <th>Score</th>
60
+ <th title="Rank position">Rank</th>
61
+ <th title="Rank score">Score</th>
62
62
  <th>Callers</th>
63
63
  <th>Type</th>
64
- <th>Chr</th>
64
+ <th title="Chromosome">Chr</th>
65
65
  <th>Start</th>
66
66
  <th>End</th>
67
67
  <th>Length</th>
68
- <th>Pop Freq</th>
69
- <th>Observed</th>
68
+ <th title="Population Frequency">Pop Freq</th>
69
+ <th title="Observed database matches">Observed</th>
70
70
  <th>Gene(s)</th>
71
- <th>Function</th>
71
+ <th title="Functional annotation">Function</th>
72
+ <th title="Gene overlapping variants">Overlap</th>
72
73
  </tr>
73
74
  </thead>
74
75
  <tbody>
@@ -121,6 +122,7 @@ onsubmit="return validateForm()">
121
122
  <td style="word-wrap:break-word;">
122
123
  {{ variant_funct_anno_cell(variant) }}
123
124
  </td>
125
+ <td>{{ overlapping_cell(variant, institute, case) }}</td>
124
126
  </tr>
125
127
  {% endmacro %}
126
128