scout-browser 4.82.1__py3-none-any.whl → 4.83__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- scout/__version__.py +1 -1
- scout/adapter/client.py +1 -0
- scout/adapter/mongo/base.py +0 -1
- scout/adapter/mongo/case.py +15 -37
- scout/adapter/mongo/case_events.py +98 -2
- scout/adapter/mongo/hgnc.py +39 -22
- scout/adapter/mongo/institute.py +3 -9
- scout/adapter/mongo/panel.py +2 -1
- scout/adapter/mongo/variant.py +3 -2
- scout/adapter/mongo/variant_loader.py +92 -79
- scout/commands/base.py +1 -0
- scout/commands/update/case.py +10 -10
- scout/commands/update/individual.py +6 -1
- scout/constants/file_types.py +4 -0
- scout/load/__init__.py +0 -1
- scout/load/all.py +3 -4
- scout/load/panel.py +8 -4
- scout/load/setup.py +1 -0
- scout/models/case/case_loading_models.py +6 -16
- scout/parse/case.py +0 -1
- scout/parse/disease_terms.py +1 -0
- scout/parse/omim.py +1 -0
- scout/parse/panel.py +40 -15
- scout/resources/__init__.py +3 -0
- scout/server/app.py +4 -50
- scout/server/blueprints/alignviewers/controllers.py +15 -17
- scout/server/blueprints/alignviewers/templates/alignviewers/igv_viewer.html +13 -3
- scout/server/blueprints/alignviewers/views.py +10 -15
- scout/server/blueprints/cases/controllers.py +70 -73
- scout/server/blueprints/cases/templates/cases/case.html +37 -21
- scout/server/blueprints/cases/templates/cases/case_bionano.html +3 -24
- scout/server/blueprints/cases/templates/cases/case_report.html +5 -3
- scout/server/blueprints/cases/templates/cases/case_sma.html +2 -13
- scout/server/blueprints/cases/templates/cases/collapsible_actionbar.html +1 -1
- scout/server/blueprints/cases/templates/cases/individuals_table.html +2 -12
- scout/server/blueprints/cases/templates/cases/phenotype.html +8 -6
- scout/server/blueprints/cases/templates/cases/utils.html +20 -3
- scout/server/blueprints/cases/views.py +8 -6
- scout/server/blueprints/variant/controllers.py +5 -5
- scout/server/blueprints/variant/templates/variant/acmg.html +25 -16
- scout/server/blueprints/variant/templates/variant/components.html +11 -6
- scout/server/blueprints/variant/views.py +5 -2
- scout/server/blueprints/variants/controllers.py +3 -5
- scout/server/blueprints/variants/templates/variants/str-variants.html +1 -1
- scout/server/blueprints/variants/views.py +1 -1
- scout/server/config.py +16 -4
- scout/server/extensions/__init__.py +4 -2
- scout/server/extensions/beacon_extension.py +1 -0
- scout/server/extensions/chanjo_extension.py +58 -0
- scout/server/extensions/phenopacket_extension.py +1 -0
- scout/server/static/bs_styles.css +18 -0
- scout/server/utils.py +16 -2
- scout/utils/acmg.py +33 -20
- scout/utils/track_resources.py +70 -0
- {scout_browser-4.82.1.dist-info → scout_browser-4.83.dist-info}/METADATA +1 -1
- {scout_browser-4.82.1.dist-info → scout_browser-4.83.dist-info}/RECORD +60 -60
- scout/load/case.py +0 -36
- scout/utils/cloud_resources.py +0 -61
- {scout_browser-4.82.1.dist-info → scout_browser-4.83.dist-info}/LICENSE +0 -0
- {scout_browser-4.82.1.dist-info → scout_browser-4.83.dist-info}/WHEEL +0 -0
- {scout_browser-4.82.1.dist-info → scout_browser-4.83.dist-info}/entry_points.txt +0 -0
- {scout_browser-4.82.1.dist-info → scout_browser-4.83.dist-info}/top_level.txt +0 -0
@@ -48,6 +48,7 @@ from scout.server.utils import (
|
|
48
48
|
case_has_chanjo2_coverage,
|
49
49
|
case_has_chanjo_coverage,
|
50
50
|
case_has_mt_alignments,
|
51
|
+
case_has_mtdna_report,
|
51
52
|
case_has_rna_tracks,
|
52
53
|
institute_and_case,
|
53
54
|
)
|
@@ -62,6 +63,8 @@ JSON_HEADERS = {
|
|
62
63
|
|
63
64
|
COVERAGE_REPORT_TIMEOUT = 20
|
64
65
|
|
66
|
+
PANEL_PROJECTION = {"version": 1, "display_name": 1, "genes": 1}
|
67
|
+
|
65
68
|
|
66
69
|
def phenomizer_diseases(hpo_ids, case_obj, p_value_treshold=1):
|
67
70
|
"""Return the list of HGNC symbols that match annotated HPO terms on Phenomizer
|
@@ -278,22 +281,16 @@ def sma_case(store, institute_obj, case_obj):
|
|
278
281
|
return data
|
279
282
|
|
280
283
|
|
281
|
-
def case(
|
284
|
+
def case(
|
285
|
+
store: MongoAdapter, institute_obj: dict, case_obj: dict, hide_matching: bool = True
|
286
|
+
) -> dict:
|
282
287
|
"""Preprocess a single case.
|
283
288
|
|
284
289
|
Prepare the case to be displayed in the case view.
|
285
290
|
|
286
|
-
|
287
|
-
store(adapter.MongoAdapter)
|
288
|
-
institute_obj(models.Institute)
|
289
|
-
case_obj(models.Case)
|
290
|
-
|
291
|
-
Returns:
|
292
|
-
data(dict): includes the cases, how many there are and the limit.
|
293
|
-
|
291
|
+
The return data dict includes the cases, how many there are and the limit.
|
294
292
|
"""
|
295
293
|
# Convert individual information to more readable format
|
296
|
-
|
297
294
|
_populate_case_individuals(case_obj)
|
298
295
|
|
299
296
|
case_obj["assignees"] = [
|
@@ -305,6 +302,7 @@ def case(store, institute_obj, case_obj):
|
|
305
302
|
case_has_mt_alignments(case_obj)
|
306
303
|
case_has_chanjo_coverage(case_obj)
|
307
304
|
case_has_chanjo2_coverage(case_obj)
|
305
|
+
case_has_mtdna_report(case_obj)
|
308
306
|
|
309
307
|
case_groups = {}
|
310
308
|
case_group_label = {}
|
@@ -395,31 +393,40 @@ def case(store, institute_obj, case_obj):
|
|
395
393
|
"case_images", case_obj["custom_images"].get("case", {})
|
396
394
|
)
|
397
395
|
|
398
|
-
|
399
|
-
|
396
|
+
other_causatives = []
|
397
|
+
other_causatives_in_default_panels = []
|
398
|
+
default_managed_variants = []
|
399
|
+
managed_variants = []
|
400
400
|
|
401
|
-
|
402
|
-
|
403
|
-
|
401
|
+
if hide_matching is False:
|
402
|
+
# Limit secondary findings according to institute settings
|
403
|
+
limit_genes = store.safe_genes_filter(institute_obj["_id"])
|
404
404
|
|
405
|
-
|
406
|
-
|
407
|
-
|
405
|
+
limit_genes_default_panels = _limit_genes_on_default_panels(
|
406
|
+
case_obj["default_genes"], limit_genes
|
407
|
+
)
|
408
408
|
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
"managed_variants": [
|
409
|
+
other_causatives, other_causatives_in_default_panels = _matching_causatives(
|
410
|
+
store, case_obj, limit_genes, limit_genes_default_panels
|
411
|
+
)
|
412
|
+
|
413
|
+
managed_variants = [
|
415
414
|
var for var in store.check_managed(case_obj=case_obj, limit_genes=limit_genes)
|
416
|
-
]
|
417
|
-
|
415
|
+
]
|
416
|
+
default_managed_variants = [
|
418
417
|
var
|
419
418
|
for var in store.check_managed(
|
420
419
|
case_obj=case_obj, limit_genes=limit_genes_default_panels
|
421
420
|
)
|
422
|
-
]
|
421
|
+
]
|
422
|
+
|
423
|
+
data = {
|
424
|
+
"institute": institute_obj,
|
425
|
+
"case": case_obj,
|
426
|
+
"other_causatives": other_causatives,
|
427
|
+
"default_other_causatives": other_causatives_in_default_panels,
|
428
|
+
"managed_variants": managed_variants,
|
429
|
+
"default_managed_variants": default_managed_variants,
|
423
430
|
"comments": store.events(institute_obj, case=case_obj, comments=True),
|
424
431
|
"hpo_groups": pheno_groups,
|
425
432
|
"case_groups": case_groups,
|
@@ -441,6 +448,7 @@ def case(store, institute_obj, case_obj):
|
|
441
448
|
"mme_nodes": matchmaker.connected_nodes,
|
442
449
|
"gens_info": gens.connection_settings(case_obj.get("genome_build")),
|
443
450
|
"display_rerunner": rerunner.connection_settings.get("display", False),
|
451
|
+
"hide_matching": hide_matching,
|
444
452
|
}
|
445
453
|
|
446
454
|
return data
|
@@ -496,8 +504,12 @@ def _get_default_panel_genes(store: MongoAdapter, case_obj: dict) -> list:
|
|
496
504
|
continue
|
497
505
|
panel_name = panel_info["panel_name"]
|
498
506
|
panel_version = panel_info.get("version")
|
499
|
-
panel_obj = store.gene_panel(
|
500
|
-
|
507
|
+
panel_obj = store.gene_panel(
|
508
|
+
panel_name,
|
509
|
+
version=panel_version,
|
510
|
+
projection=PANEL_PROJECTION,
|
511
|
+
)
|
512
|
+
latest_panel = store.gene_panel(panel_name, projection=PANEL_PROJECTION)
|
501
513
|
panel_info["removed"] = False if latest_panel is None else latest_panel.get("hidden", False)
|
502
514
|
if not panel_obj:
|
503
515
|
panel_obj = latest_panel
|
@@ -555,19 +567,17 @@ def check_outdated_gene_panel(panel_obj, latest_panel):
|
|
555
567
|
missing_genes, extra_genes
|
556
568
|
"""
|
557
569
|
# Create a list of minified gene object for the case panel {hgnc_id, gene_symbol}
|
558
|
-
case_panel_genes = [
|
559
|
-
{"hgnc_id": gene["hgnc_id"], "symbol": gene.get("symbol", gene["hgnc_id"])}
|
560
|
-
for gene in panel_obj["genes"]
|
561
|
-
]
|
570
|
+
case_panel_genes = set([gene.get("symbol", gene["hgnc_id"]) for gene in panel_obj["genes"]])
|
562
571
|
# And for the latest panel
|
563
|
-
latest_panel_genes =
|
564
|
-
|
565
|
-
|
566
|
-
]
|
572
|
+
latest_panel_genes = set(
|
573
|
+
[gene.get("symbol", gene["hgnc_id"]) for gene in latest_panel["genes"]]
|
574
|
+
)
|
567
575
|
# Extract the genes unique to case panel
|
568
|
-
extra_genes =
|
576
|
+
extra_genes = case_panel_genes.difference(latest_panel_genes)
|
577
|
+
|
569
578
|
# Extract the genes unique to latest panel
|
570
|
-
missing_genes =
|
579
|
+
missing_genes = latest_panel_genes.difference(case_panel_genes)
|
580
|
+
|
571
581
|
return extra_genes, missing_genes
|
572
582
|
|
573
583
|
|
@@ -674,7 +684,7 @@ def case_report_content(store: MongoAdapter, institute_obj: dict, case_obj: dict
|
|
674
684
|
return data
|
675
685
|
|
676
686
|
|
677
|
-
def mt_coverage_stats(individuals, ref_chrom="14"):
|
687
|
+
def mt_coverage_stats(individuals, ref_chrom="14") -> dict:
|
678
688
|
"""Send a request to chanjo report endpoint to retrieve MT vs autosome coverage stats
|
679
689
|
|
680
690
|
Args:
|
@@ -732,10 +742,9 @@ def mt_excel_files(store, case_obj, temp_excel_dir):
|
|
732
742
|
"""
|
733
743
|
today = datetime.datetime.now().strftime(DATE_DAY_FORMATTER)
|
734
744
|
samples = case_obj.get("individuals")
|
735
|
-
file_header = MT_EXPORT_HEADER
|
736
745
|
coverage_stats = None
|
737
746
|
# if chanjo connection is established, include MT vs AUTOSOME coverage stats
|
738
|
-
if current_app.config.get("
|
747
|
+
if current_app.config.get("chanjo_report"):
|
739
748
|
coverage_stats = mt_coverage_stats(samples)
|
740
749
|
|
741
750
|
query = {"chrom": "MT"}
|
@@ -765,9 +774,8 @@ def mt_excel_files(store, case_obj, temp_excel_dir):
|
|
765
774
|
for col, field in enumerate(line): # each field in line becomes a cell
|
766
775
|
Report_Sheet.write(row, col, field)
|
767
776
|
|
768
|
-
if
|
769
|
-
|
770
|
-
): # it's None if app is not connected to Chanjo or {} if samples are not in Chanjo db
|
777
|
+
# coverage_stats is None if app is not connected to Chanjo or {} if samples are not in Chanjo db
|
778
|
+
if coverage_stats and sample_id in coverage_stats:
|
771
779
|
# Write coverage stats header after introducing 2 empty lines
|
772
780
|
for col, field in enumerate(MT_COV_STATS_HEADER):
|
773
781
|
Report_Sheet.write(row + 3, col, field)
|
@@ -805,27 +813,6 @@ def update_synopsis(store, institute_obj, case_obj, user_obj, new_synopsis):
|
|
805
813
|
store.update_synopsis(institute_obj, case_obj, user_obj, link, content=new_synopsis)
|
806
814
|
|
807
815
|
|
808
|
-
def _update_case(store, case_obj, user_obj, institute_obj, verb):
|
809
|
-
"""Update case with new sample data, and create an associated event"""
|
810
|
-
store.update_case(case_obj, keep_date=True)
|
811
|
-
|
812
|
-
link = url_for(
|
813
|
-
"cases.case",
|
814
|
-
institute_id=institute_obj["_id"],
|
815
|
-
case_name=case_obj["display_name"],
|
816
|
-
)
|
817
|
-
|
818
|
-
store.create_event(
|
819
|
-
institute=institute_obj,
|
820
|
-
case=case_obj,
|
821
|
-
user=user_obj,
|
822
|
-
link=link,
|
823
|
-
category="case",
|
824
|
-
verb=verb,
|
825
|
-
subject=case_obj["display_name"],
|
826
|
-
)
|
827
|
-
|
828
|
-
|
829
816
|
def update_individuals(store, institute_obj, case_obj, user_obj, ind, age, tissue):
|
830
817
|
"""Handle update of individual data (age and/or Tissue type) for a case"""
|
831
818
|
|
@@ -841,8 +828,13 @@ def update_individuals(store, institute_obj, case_obj, user_obj, ind, age, tissu
|
|
841
828
|
|
842
829
|
case_obj["individuals"] = case_individuals
|
843
830
|
|
844
|
-
|
845
|
-
|
831
|
+
link = url_for(
|
832
|
+
"cases.case",
|
833
|
+
institute_id=institute_obj["_id"],
|
834
|
+
case_name=case_obj["display_name"],
|
835
|
+
)
|
836
|
+
|
837
|
+
store.update_case_individual(case_obj, user_obj, institute_obj, link)
|
846
838
|
|
847
839
|
|
848
840
|
def update_cancer_samples(
|
@@ -866,8 +858,13 @@ def update_cancer_samples(
|
|
866
858
|
|
867
859
|
case_obj["individuals"] = case_samples
|
868
860
|
|
869
|
-
|
870
|
-
|
861
|
+
link = url_for(
|
862
|
+
"cases.case",
|
863
|
+
institute_id=institute_obj["_id"],
|
864
|
+
case_name=case_obj["display_name"],
|
865
|
+
)
|
866
|
+
|
867
|
+
store.update_case_sample(case_obj, user_obj, institute_obj, link)
|
871
868
|
|
872
869
|
|
873
870
|
def _all_hpo_gene_list_genes(
|
@@ -1431,13 +1428,13 @@ def _matching_causatives(
|
|
1431
1428
|
other_causatives_in_default_panels = []
|
1432
1429
|
|
1433
1430
|
for causative in matching_causatives:
|
1434
|
-
hgnc_ids =
|
1431
|
+
hgnc_ids = {gene.get("hgnc_id") for gene in causative.get("genes", [])}
|
1435
1432
|
# Fetch all matching causatives if no causatives_filter defined
|
1436
1433
|
# or only causatives matching the filter:
|
1437
|
-
if not other_causatives_filter or (
|
1434
|
+
if not other_causatives_filter or (hgnc_ids & set(other_causatives_filter)):
|
1438
1435
|
other_causatives.append(causative)
|
1439
1436
|
# Only matching causatives in default gene panels:
|
1440
|
-
if
|
1437
|
+
if hgnc_ids & set(other_causatives_in_default_panels_filter):
|
1441
1438
|
other_causatives_in_default_panels.append(causative)
|
1442
1439
|
|
1443
1440
|
return other_causatives, other_causatives_in_default_panels
|
@@ -120,30 +120,46 @@
|
|
120
120
|
</div>
|
121
121
|
|
122
122
|
<div class="card panel-default" >
|
123
|
-
{% if other_causatives|length > 0%}
|
124
123
|
<div class="row mt-0">
|
125
|
-
<div class="col-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
<div class="col-sm-12 col-md-12">{{ matching_managed_variants(managed_variants, institute, case) }}</div>
|
137
|
-
</div>
|
138
|
-
{% endif %}
|
139
|
-
|
140
|
-
{% if default_managed_variants|length > 0%}
|
141
|
-
<div class="row mt-0">
|
142
|
-
<div class="col-sm-12 col-md-12">{{ matching_managed_variants(default_managed_variants, institute, case, default=True) }}</div>
|
124
|
+
<div class="col-sm-12 col-md-12 ms-3">
|
125
|
+
<div data-bs-toggle='tooltip' class="panel-heading" title="Check if there are any variants in this case
|
126
|
+
marked as causative in another case for this institute, or are on the managed variants list.">
|
127
|
+
<strong>{% if hide_matching == false %}
|
128
|
+
<a href="{{ url_for('cases.case', institute_id=institute._id, case_name=case.display_name, hide_matching='True') }}" class="text-body"><span class="me-1 fa fa-caret-right"></span>Search for matching causatives and managed variants</a>
|
129
|
+
{% else %}
|
130
|
+
<a href="{{ url_for('cases.case', institute_id=institute._id, case_name=case.display_name, hide_matching='False') }}" class="text-body"><span class="me-1 fa fa-caret-down"></span>Search for matching causatives and managed variants</a>
|
131
|
+
{% endif %}
|
132
|
+
</strong>
|
133
|
+
</div>
|
134
|
+
</div>
|
143
135
|
</div>
|
136
|
+
{% if hide_matching == false %}
|
137
|
+
{% if other_causatives|length > 0 %}
|
138
|
+
<div class="row mt-0 ms-3">
|
139
|
+
<div class="col-xs-12 col-md-12 ms-3">{{ matching_causatives(other_causatives, institute, case) }}</div>
|
140
|
+
</div>
|
141
|
+
{% endif %}
|
142
|
+
{% if default_other_causatives|length > 0%}
|
143
|
+
<div class="row mt-0 ms-3">
|
144
|
+
<div class="col-xs-12 col-md-12 ms-3">{{ matching_causatives(default_other_causatives, institute, case, default=True) }}</div>
|
145
|
+
</div>
|
146
|
+
{% endif %}
|
147
|
+
{% if managed_variants|length > 0%}
|
148
|
+
<div class="row mt-0 ms-3">
|
149
|
+
<div class="col-sm-12 col-md-12 ms-3">{{ matching_managed_variants(managed_variants, institute, case) }}</div>
|
150
|
+
</div>
|
151
|
+
{% endif %}
|
152
|
+
{% if default_managed_variants|length > 0%}
|
153
|
+
<div class="row mt-0 ms-3">
|
154
|
+
<div class="col-sm-12 col-md-12 ms-3">{{ matching_managed_variants(default_managed_variants, institute, case, default=True) }}</div>
|
155
|
+
</div>
|
156
|
+
{% endif %}
|
157
|
+
{% if other_causatives|length == 0 and default_other_causatives|length == 0 and managed_variants|length == 0 and default_managed_variants|length == 0%}
|
158
|
+
<div class="row mt-0 ms-3">
|
159
|
+
<div class="col-sm-12 col-md-12 ms-3">No matching causatives or managed variants found</div>
|
160
|
+
</div>
|
161
|
+
{% endif %}
|
144
162
|
{% endif %}
|
145
|
-
</div>
|
146
|
-
|
147
163
|
<div class="row">
|
148
164
|
<div class="col">{{ causatives_list(causatives, partial_causatives, evaluated_variants, institute, case, manual_rank_options, cancer_tier_options) }}</div>
|
149
165
|
<div class="col">{{ suspects_list(suspects, institute, case, manual_rank_options, cancer_tier_options) }}</div>
|
@@ -1,5 +1,6 @@
|
|
1
1
|
{% extends "cases/case_tabular_view.html" %}
|
2
2
|
{% from "utils.html" import comments_panel, activity_panel %}
|
3
|
+
{% from "cases/utils.html" import sex_table_cell_content %}
|
3
4
|
|
4
5
|
{% block title %}
|
5
6
|
{{ super() }}
|
@@ -96,18 +97,7 @@
|
|
96
97
|
{% if loop.index == 1 %}
|
97
98
|
<td> {{ ind.display_name }}</td>
|
98
99
|
<td style="font-weight: bold;">
|
99
|
-
|
100
|
-
{% if ind.sex_human == 'female' %}
|
101
|
-
F
|
102
|
-
{% elif ind.sex_human == 'male' %}
|
103
|
-
M
|
104
|
-
{% else %}
|
105
|
-
{{ind.sex_human}}
|
106
|
-
{% endif %}
|
107
|
-
{% endif %}
|
108
|
-
{% if ind.confirmed_sex %}
|
109
|
-
<i class="fa fa-check"></i>
|
110
|
-
{% endif %}
|
100
|
+
{{ sex_table_cell_content(ind) }}
|
111
101
|
</td>
|
112
102
|
<td>{{ ind.phenotype_human }}</td>
|
113
103
|
{% else %}
|
@@ -130,18 +120,7 @@
|
|
130
120
|
<tr class="bg-secondary text-white">
|
131
121
|
<td> {{ ind.display_name }}</td>
|
132
122
|
<td style="font-weight: bold;">
|
133
|
-
|
134
|
-
{% if ind.sex_human == 'female' %}
|
135
|
-
F
|
136
|
-
{% elif ind.sex_human == 'male' %}
|
137
|
-
M
|
138
|
-
{% else %}
|
139
|
-
{{ind.sex_human}}
|
140
|
-
{% endif %}
|
141
|
-
{% endif %}
|
142
|
-
{% if ind.confirmed_sex %}
|
143
|
-
<i class="fa fa-check"></i>
|
144
|
-
{% endif %}
|
123
|
+
{{ sex_table_cell_content(ind) }}
|
145
124
|
</td>
|
146
125
|
<td>{{ ind.phenotype_human }}</td>
|
147
126
|
<td colspan="4">N/A</td>
|
@@ -124,9 +124,11 @@
|
|
124
124
|
{% else %}
|
125
125
|
n.a.
|
126
126
|
{% endif %}
|
127
|
-
|
128
|
-
|
129
|
-
|
127
|
+
{% if ind.confirmed_sex %}
|
128
|
+
<span class="badge rounded-pill py-1 bg-secondary">V</span>
|
129
|
+
{% else %}
|
130
|
+
<span class="fa fa-exclamation-circle text-danger" data-bs-toggle='tooltip' title="Sex is not confirmed."></span>
|
131
|
+
{% endif %}
|
130
132
|
</td>
|
131
133
|
<td>
|
132
134
|
{% if ind.phenotype==2 %} <!--for later use-->
|
@@ -1,6 +1,6 @@
|
|
1
1
|
{% extends "cases/case_tabular_view.html" %}
|
2
2
|
{% from "utils.html" import comments_panel, activity_panel %}
|
3
|
-
{% from "cases/utils.html" import individuals_table %}
|
3
|
+
{% from "cases/utils.html" import individuals_table, sex_table_cell_content %}
|
4
4
|
|
5
5
|
{% block title %}
|
6
6
|
{{ super() }}
|
@@ -100,18 +100,7 @@
|
|
100
100
|
{% endif %}>
|
101
101
|
<td>{{ ind.display_name }}</td>
|
102
102
|
<td style="font-weight: bold;">
|
103
|
-
{
|
104
|
-
{% if ind.sex_human == 'female' %}
|
105
|
-
F
|
106
|
-
{% elif ind.sex_human == 'male' %}
|
107
|
-
M
|
108
|
-
{% else %}
|
109
|
-
{{ind.sex_human}}
|
110
|
-
{% endif %}
|
111
|
-
{% endif %}
|
112
|
-
{% if ind.confirmed_sex %}
|
113
|
-
<i class="fa fa-check"></i>
|
114
|
-
{% endif %}
|
103
|
+
{{ sex_table_cell_content(ind) }}
|
115
104
|
</td>
|
116
105
|
<td>{{ ind.phenotype_human }}</td>
|
117
106
|
<td>{{ ind.is_sma }}</td>
|
@@ -108,7 +108,7 @@
|
|
108
108
|
{% endif %}
|
109
109
|
|
110
110
|
<!-- Display mtDNA report for non-cancer cases -->
|
111
|
-
{% if case.
|
111
|
+
{% if case.mtdna_report %}
|
112
112
|
<div href="#" class="bg-dark list-group-item text-white">
|
113
113
|
<div class="d-flex flex-row flex-fill bd-highlight">
|
114
114
|
<div>
|
@@ -1,3 +1,4 @@
|
|
1
|
+
{% from "cases/utils.html" import sex_table_cell_content %}
|
1
2
|
|
2
3
|
{% macro cancer_individuals_table(case, institute, tissues, gens_info=None) %}
|
3
4
|
<form method="POST" action="{{ url_for('cases.update_cancer_sample', institute_id=institute._id, case_name=case.display_name) }}">
|
@@ -138,18 +139,7 @@
|
|
138
139
|
<option {% if not ind.sex_human in ["female", "male"] %} selected= {% endif %} value="unknown">Unknown</option>
|
139
140
|
</select>
|
140
141
|
<div class="sex-display fw-bold">
|
141
|
-
{
|
142
|
-
{% if ind.sex_human == 'female' %}
|
143
|
-
F
|
144
|
-
{% elif ind.sex_human == 'male' %}
|
145
|
-
M
|
146
|
-
{% else %}
|
147
|
-
{{ind.sex_human}}
|
148
|
-
{% endif %}
|
149
|
-
{% endif %}
|
150
|
-
{% if ind.confirmed_sex %}
|
151
|
-
<i class="fa fa-check"></i>
|
152
|
-
{% endif %}
|
142
|
+
{{ sex_table_cell_content(ind) }}
|
153
143
|
</div>
|
154
144
|
</td>
|
155
145
|
<td><input name="age_{{ind.individual_id}}" type="number" step="0.1" min="0"
|
@@ -236,11 +236,13 @@
|
|
236
236
|
<!-- Display and remove added HPO terms -->
|
237
237
|
<div class="row mt-3">
|
238
238
|
<div class="col-12 ms-3">
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
239
|
+
{% if "phenotype_terms" in case and case.phenotype_terms|length > 0 %}
|
240
|
+
{% for hpo_term in case.phenotype_terms %}
|
241
|
+
{{ hpo_item(hpo_term, case) }}
|
242
|
+
{% endfor %}
|
243
|
+
{% else %}
|
244
|
+
<span class="text-mute">No phenotypes added yet</span>
|
245
|
+
{% endif %}
|
244
246
|
</div>
|
245
247
|
</div>
|
246
248
|
|
@@ -251,7 +253,7 @@
|
|
251
253
|
<input class="ms-3" name="min_match" type="number" min="0" step="1" placeholder="Min matches" style="width:130px"/>
|
252
254
|
{% if config.PHENOMIZER_USERNAME %}
|
253
255
|
<button class="btn btn-secondary btn-sm" type="submit" name="action" value="PHENOMIZER"
|
254
|
-
{%if case.phenotype_terms|length == 0 %} disabled {%endif%}>Phenomizer</button>
|
256
|
+
{% if "phenotype_terms" not in case or case.phenotype_terms|length == 0 %} disabled {% endif %}>Phenomizer</button>
|
255
257
|
{% endif %}
|
256
258
|
</div>
|
257
259
|
<div class="col-1">
|
@@ -633,8 +633,8 @@
|
|
633
633
|
|
634
634
|
{% macro matching_causatives(other_causatives, institute, case, default=False) %}
|
635
635
|
<div data-bs-toggle='tooltip' class="panel-heading" title="If there are any variants in this case
|
636
|
-
|
637
|
-
<strong><a data-bs-toggle="collapse" href="#matchingCausatives{% if default %}Default{% endif %}" class="text-body">Matching causatives {% if default %}in case default panels{% endif %}({{other_causatives|length}})</a></strong>
|
636
|
+
matching a causative in another case for this institute. {% if default %}Variants in default panels for the case only.{% endif %}">
|
637
|
+
<strong><a data-bs-toggle="collapse" href="#matchingCausatives{% if default %}Default{% endif %}" class="text-body" aria-expanded="false"><span class="collapse-icon me-1"></span>Matching causatives {% if default %}in case default panels{% endif %}({{other_causatives|length}})</a></strong>
|
638
638
|
</div>
|
639
639
|
<ul class="list-group collapse" id="matchingCausatives{% if default %}Default{% endif %}">
|
640
640
|
{% for variant in other_causatives %}
|
@@ -650,7 +650,7 @@
|
|
650
650
|
{% macro matching_managed_variants(managed_variants, institute, case, default=False) %}
|
651
651
|
<div data-bs-toggle='tooltip' class="panel-heading" title="Any variants in this case
|
652
652
|
that have been marked as managed. {% if default %}Variants in default panels for the case only.{% endif %}">
|
653
|
-
<strong><a data-bs-toggle="collapse" class="text-body" href="#matchingManaged{% if default %}Default{% endif %}">Managed variants {% if default %}in case default panels{% endif %}({{managed_variants|length}})</a></strong>
|
653
|
+
<strong><a data-bs-toggle="collapse" class="text-body" href="#matchingManaged{% if default %}Default{% endif %}" aria-expanded="false"><span class="collapse-icon me-1"></span>Managed variants {% if default %}in case default panels{% endif %}({{managed_variants|length}})</a></strong>
|
654
654
|
</div>
|
655
655
|
<ul class="list-group">
|
656
656
|
{% for variant in managed_variants %}
|
@@ -681,3 +681,20 @@
|
|
681
681
|
</div>
|
682
682
|
</form>
|
683
683
|
{% endmacro %}
|
684
|
+
|
685
|
+
{% macro sex_table_cell_content(ind) %}
|
686
|
+
{% if ind.sex_human in ['female','male'] %}
|
687
|
+
{% if ind.sex_human == 'female' %}
|
688
|
+
F
|
689
|
+
{% elif ind.sex_human == 'male' %}
|
690
|
+
M
|
691
|
+
{% else %}
|
692
|
+
{{ind.sex_human}}
|
693
|
+
{% endif %}
|
694
|
+
{% endif %}
|
695
|
+
{% if ind.confirmed_sex %}
|
696
|
+
<i class="fa fa-check"></i>
|
697
|
+
{% else %}
|
698
|
+
<span class="fa fa-exclamation-circle text-danger" data-bs-toggle='tooltip' title="Sex is not confirmed."></span>
|
699
|
+
{% endif %}
|
700
|
+
{% endmacro %}
|
@@ -4,6 +4,7 @@ import json
|
|
4
4
|
import logging
|
5
5
|
import os.path
|
6
6
|
import shutil
|
7
|
+
from ast import literal_eval
|
7
8
|
from io import BytesIO
|
8
9
|
from operator import itemgetter
|
9
10
|
from typing import Generator, Optional, Union
|
@@ -86,7 +87,6 @@ def case(
|
|
86
87
|
So do case_id, but we still call institute_and_case again to fetch institute
|
87
88
|
and reuse its user access verification.
|
88
89
|
"""
|
89
|
-
|
90
90
|
if case_id:
|
91
91
|
case_obj = store.case(case_id=case_id, projection={"display_name": 1, "owner": 1})
|
92
92
|
|
@@ -102,7 +102,12 @@ def case(
|
|
102
102
|
flash("Case {} does not exist in database!".format(case_name))
|
103
103
|
return redirect(request.referrer)
|
104
104
|
|
105
|
-
|
105
|
+
hide_matching = (
|
106
|
+
literal_eval(request.args.get("hide_matching"))
|
107
|
+
if request.args.get("hide_matching")
|
108
|
+
else True
|
109
|
+
)
|
110
|
+
data = controllers.case(store, institute_obj, case_obj, hide_matching)
|
106
111
|
|
107
112
|
return dict(
|
108
113
|
**data,
|
@@ -271,10 +276,7 @@ def pdf_case_report(institute_id, case_name):
|
|
271
276
|
store=store, institute_obj=institute_obj, case_obj=case_obj
|
272
277
|
)
|
273
278
|
# add coverage report on the bottom of this report
|
274
|
-
if (
|
275
|
-
current_app.config.get("SQLALCHEMY_DATABASE_URI")
|
276
|
-
and case_obj.get("track", "rare") != "cancer"
|
277
|
-
):
|
279
|
+
if current_app.config.get("chanjo_report") and case_obj.get("track", "rare") != "cancer":
|
278
280
|
data["coverage_report"] = controllers.coverage_report_contents(
|
279
281
|
request.url_root, institute_obj, case_obj
|
280
282
|
)
|
@@ -28,7 +28,7 @@ from scout.server.blueprints.variant.utils import (
|
|
28
28
|
update_variant_case_panels,
|
29
29
|
)
|
30
30
|
from scout.server.blueprints.variants.utils import update_case_panels
|
31
|
-
from scout.server.extensions import LoqusDB,
|
31
|
+
from scout.server.extensions import LoqusDB, config_igv_tracks, gens
|
32
32
|
from scout.server.links import disease_link, get_variant_links
|
33
33
|
from scout.server.utils import (
|
34
34
|
case_has_alignments,
|
@@ -142,9 +142,9 @@ def get_igv_tracks(build: str = "37") -> set:
|
|
142
142
|
# Collect hardcoded tracks, common for all Scout instances
|
143
143
|
for track in IGV_TRACKS.get(build, []):
|
144
144
|
igv_tracks.add(track.get("name"))
|
145
|
-
# Collect instance-
|
146
|
-
if hasattr(
|
147
|
-
for track in
|
145
|
+
# Collect instance-specific public tracks, if available
|
146
|
+
if hasattr(config_igv_tracks, "tracks"):
|
147
|
+
for track in config_igv_tracks.tracks.get(build, []):
|
148
148
|
igv_tracks.add(track.get("name"))
|
149
149
|
return igv_tracks
|
150
150
|
|
@@ -372,7 +372,7 @@ def variant(
|
|
372
372
|
"ACMG_OPTIONS": ACMG_OPTIONS,
|
373
373
|
"case_tag_options": CASE_TAGS,
|
374
374
|
"inherit_palette": INHERITANCE_PALETTE,
|
375
|
-
"igv_tracks": get_igv_tracks(genome_build),
|
375
|
+
"igv_tracks": get_igv_tracks("38" if variant_obj["is_mitochondrial"] else genome_build),
|
376
376
|
"has_rna_tracks": case_has_rna_tracks(case_obj),
|
377
377
|
"gens_info": gens.connection_settings(genome_build),
|
378
378
|
"evaluations": evaluations,
|