scout-browser 4.100.2__py3-none-any.whl → 4.102.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.
- scout/adapter/mongo/case.py +20 -6
- scout/adapter/mongo/clinvar.py +7 -7
- scout/adapter/mongo/hgnc.py +7 -2
- scout/adapter/mongo/omics_variant.py +8 -0
- scout/adapter/mongo/variant_loader.py +6 -2
- scout/constants/__init__.py +1 -0
- scout/constants/file_types.py +1 -1
- scout/constants/igv_tracks.py +6 -2
- scout/constants/phenotype.py +1 -0
- scout/load/hpo.py +8 -2
- scout/server/blueprints/alignviewers/controllers.py +8 -6
- scout/server/blueprints/alignviewers/templates/alignviewers/igv_viewer.html +2 -0
- scout/server/blueprints/alignviewers/templates/alignviewers/utils.html +1 -1
- scout/server/blueprints/cases/controllers.py +56 -28
- scout/server/blueprints/cases/templates/cases/case_report.html +9 -88
- scout/server/blueprints/cases/templates/cases/matchmaker.html +1 -1
- scout/server/blueprints/cases/templates/cases/phenotype.html +1 -1
- scout/server/blueprints/cases/templates/cases/utils.html +27 -25
- scout/server/blueprints/cases/views.py +32 -33
- scout/server/blueprints/clinvar/controllers.py +18 -23
- scout/server/blueprints/clinvar/templates/clinvar/multistep_add_variant.html +0 -2
- scout/server/blueprints/diagnoses/controllers.py +4 -8
- scout/server/blueprints/diagnoses/templates/diagnoses/diagnoses.html +1 -1
- scout/server/blueprints/diagnoses/templates/diagnoses/disease_term.html +1 -1
- scout/server/blueprints/diagnoses/views.py +2 -2
- scout/server/blueprints/institutes/controllers.py +107 -73
- scout/server/blueprints/institutes/templates/overview/cases.html +8 -7
- scout/server/blueprints/login/controllers.py +2 -1
- scout/server/blueprints/login/views.py +5 -2
- scout/server/blueprints/omics_variants/views.py +2 -2
- scout/server/blueprints/panels/views.py +11 -2
- scout/server/blueprints/phenotypes/controllers.py +15 -2
- scout/server/blueprints/phenotypes/templates/phenotypes/hpo_terms.html +1 -1
- scout/server/blueprints/variant/controllers.py +10 -11
- scout/server/blueprints/variant/templates/variant/utils.html +1 -1
- scout/server/blueprints/variant/templates/variant/variant_details.html +68 -60
- scout/server/blueprints/variant/utils.py +25 -0
- scout/server/blueprints/variants/controllers.py +11 -42
- scout/server/blueprints/variants/templates/variants/cancer-variants.html +3 -3
- scout/server/blueprints/variants/templates/variants/indicators.html +18 -15
- scout/server/blueprints/variants/templates/variants/utils.html +1 -1
- scout/server/blueprints/variants/views.py +9 -8
- scout/server/config.py +3 -0
- scout/server/extensions/beacon_extension.py +7 -2
- scout/server/templates/bootstrap_global.html +11 -1
- scout/server/templates/layout.html +6 -1
- scout/server/utils.py +24 -3
- {scout_browser-4.100.2.dist-info → scout_browser-4.102.0.dist-info}/METADATA +1 -1
- {scout_browser-4.100.2.dist-info → scout_browser-4.102.0.dist-info}/RECORD +52 -52
- {scout_browser-4.100.2.dist-info → scout_browser-4.102.0.dist-info}/WHEEL +0 -0
- {scout_browser-4.100.2.dist-info → scout_browser-4.102.0.dist-info}/entry_points.txt +0 -0
- {scout_browser-4.100.2.dist-info → scout_browser-4.102.0.dist-info}/licenses/LICENSE +0 -0
@@ -25,7 +25,11 @@ from scout.server.blueprints.variant.utils import (
|
|
25
25
|
update_representative_gene,
|
26
26
|
)
|
27
27
|
from scout.server.extensions import beacon, store
|
28
|
-
from scout.server.utils import
|
28
|
+
from scout.server.utils import (
|
29
|
+
get_case_genome_build,
|
30
|
+
institute_and_case,
|
31
|
+
user_institutes,
|
32
|
+
)
|
29
33
|
|
30
34
|
from .forms import BeaconDatasetForm, CaseFilterForm
|
31
35
|
|
@@ -47,6 +51,28 @@ VAR_SPECIFIC_EVENTS = [
|
|
47
51
|
"cancel_sanger",
|
48
52
|
]
|
49
53
|
|
54
|
+
# Projection for fetching cases
|
55
|
+
ALL_CASES_PROJECTION = {
|
56
|
+
"analysis_date": 1,
|
57
|
+
"assignees": 1,
|
58
|
+
"beacon": 1,
|
59
|
+
"case_id": 1,
|
60
|
+
"display_name": 1,
|
61
|
+
"genome_build": 1,
|
62
|
+
"individuals": 1,
|
63
|
+
"is_rerun": 1,
|
64
|
+
"is_research": 1,
|
65
|
+
"mme_submission": 1,
|
66
|
+
"owner": 1,
|
67
|
+
"panels": 1,
|
68
|
+
"phenotype_terms": 1,
|
69
|
+
"rank_model_version": 1,
|
70
|
+
"status": 1,
|
71
|
+
"sv_rank_model_version": 1,
|
72
|
+
"track": 1,
|
73
|
+
"vcf_files": 1,
|
74
|
+
}
|
75
|
+
|
50
76
|
|
51
77
|
def get_timeline_data(limit):
|
52
78
|
"""Retrieve chronologially ordered events from the database to display them in the timeline page
|
@@ -519,92 +545,106 @@ def export_case_samples(institute_id, filtered_cases) -> Response:
|
|
519
545
|
)
|
520
546
|
|
521
547
|
|
522
|
-
def
|
523
|
-
|
524
|
-
|
548
|
+
def get_cases_by_query(
|
549
|
+
store: MongoAdapter,
|
550
|
+
request: request,
|
551
|
+
institute_id: str,
|
552
|
+
) -> list:
|
553
|
+
"""Fetch additional cases based on filters given in request query form.
|
525
554
|
|
526
|
-
|
527
|
-
|
528
|
-
data["institute"] = institute_obj
|
529
|
-
data["form"] = CaseFilterForm(request.form)
|
530
|
-
data["status_ncases"] = store.nr_cases_by_status(institute_id=institute_id)
|
531
|
-
data["nr_cases"] = sum(data["status_ncases"].values())
|
555
|
+
Sets metadata in data, e.g. sort order.
|
556
|
+
"""
|
532
557
|
|
533
|
-
|
534
|
-
|
535
|
-
|
558
|
+
name_query = request.form
|
559
|
+
all_cases = store.cases(
|
560
|
+
collaborator=institute_id,
|
561
|
+
name_query=name_query,
|
562
|
+
skip_assigned=request.form.get("skip_assigned"),
|
563
|
+
is_research=request.form.get("is_research"),
|
564
|
+
has_rna_data=request.form.get("has_rna"),
|
565
|
+
verification_pending=request.form.get("validation_ordered"),
|
566
|
+
has_clinvar_submission=request.form.get("clinvar_submitted"),
|
567
|
+
projection=ALL_CASES_PROJECTION,
|
568
|
+
)
|
569
|
+
return all_cases
|
536
570
|
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
"rank_model_version": 1,
|
553
|
-
"status": 1,
|
554
|
-
"sv_rank_model_version": 1,
|
555
|
-
"track": 1,
|
556
|
-
"vcf_files": 1,
|
557
|
-
}
|
571
|
+
|
572
|
+
def get_and_set_cases_by_status(
|
573
|
+
store: MongoAdapter,
|
574
|
+
request: request,
|
575
|
+
institute_obj: dict,
|
576
|
+
previous_query_result_cases: list,
|
577
|
+
data: dict,
|
578
|
+
) -> dict:
|
579
|
+
"""Process cases for statuses that require all cases to be shown.
|
580
|
+
Group cases by status, process additional cases for the remaining statuses
|
581
|
+
and ensure that we don't dim cases that already appeared in query search results.
|
582
|
+
"""
|
583
|
+
|
584
|
+
status_show_all_cases = institute_obj.get("show_all_cases_status", ["prioritized"])
|
585
|
+
nr_cases_showall_statuses = 0
|
558
586
|
|
559
587
|
# Group cases by status
|
560
588
|
case_groups = {status: [] for status in CASE_STATUSES}
|
561
|
-
nr_cases_showall_statuses = 0
|
562
|
-
status_show_all_cases = institute_obj.get("show_all_cases_status") or ["prioritized"]
|
563
589
|
|
564
|
-
# Process cases for statuses that require all cases to be shown
|
565
590
|
for status in status_show_all_cases:
|
566
591
|
cases_in_status = store.cases_by_status(
|
567
|
-
institute_id=
|
592
|
+
institute_id=institute_obj["_id"], status=status, projection=ALL_CASES_PROJECTION
|
568
593
|
)
|
569
594
|
cases_in_status = _sort_cases(data, request, cases_in_status)
|
570
595
|
for case_obj in cases_in_status:
|
571
596
|
populate_case_obj(case_obj, store)
|
597
|
+
case_obj["dimmed_in_search"] = True
|
572
598
|
case_groups[status].append(case_obj)
|
573
599
|
nr_cases_showall_statuses += 1
|
574
600
|
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
601
|
+
nr_name_query_matching_displayed_cases = 0
|
602
|
+
limit = int(request.form.get("search_limit", 100))
|
603
|
+
for case_obj in previous_query_result_cases:
|
604
|
+
if case_obj["status"] in status_show_all_cases:
|
605
|
+
for group_case in case_groups[status]:
|
606
|
+
if group_case["_id"] == case_obj["_id"]:
|
607
|
+
group_case["dimmed_in_search"] = False
|
608
|
+
elif nr_name_query_matching_displayed_cases == limit:
|
609
|
+
break
|
610
|
+
else:
|
611
|
+
populate_case_obj(case_obj, store)
|
612
|
+
case_groups[case_obj["status"]].append(case_obj)
|
613
|
+
nr_name_query_matching_displayed_cases += 1
|
614
|
+
|
615
|
+
data["found_cases"] = nr_name_query_matching_displayed_cases + nr_cases_showall_statuses
|
616
|
+
data["limit"] = limit
|
617
|
+
return case_groups
|
618
|
+
|
619
|
+
|
620
|
+
def cases(store: MongoAdapter, request: request, institute_id: str):
|
621
|
+
"""Preprocess case objects for the 'cases' view.
|
622
|
+
|
623
|
+
Returns data dict for view display, or response in case of file export.
|
624
|
+
"""
|
625
|
+
data = {}
|
626
|
+
|
627
|
+
# Initialize data (institute info, filters, and case counts)
|
628
|
+
institute_obj = institute_and_case(store, institute_id)
|
629
|
+
data["institute"] = institute_obj
|
630
|
+
data["form"] = CaseFilterForm(request.form)
|
631
|
+
data["status_ncases"] = store.nr_cases_by_status(institute_id=institute_id)
|
632
|
+
data["nr_cases"] = sum(data["status_ncases"].values())
|
633
|
+
|
634
|
+
# Fetch Sanger unevaluated and validated cases
|
635
|
+
sanger_ordered_not_validated = get_sanger_unevaluated(store, institute_id, current_user.email)
|
636
|
+
data["sanger_unevaluated"], data["sanger_validated_by_others"] = sanger_ordered_not_validated
|
637
|
+
|
638
|
+
all_cases = get_cases_by_query(store, request, institute_id)
|
588
639
|
all_cases = _sort_cases(data, request, all_cases)
|
589
640
|
|
590
641
|
if request.form.get("export"):
|
591
642
|
return export_case_samples(institute_id, all_cases)
|
592
643
|
|
593
|
-
|
594
|
-
nr_cases = 0
|
595
|
-
for case_obj in all_cases:
|
596
|
-
if case_obj["status"] not in status_show_all_cases:
|
597
|
-
if nr_cases == limit:
|
598
|
-
break
|
599
|
-
populate_case_obj(case_obj, store)
|
600
|
-
case_groups[case_obj["status"]].append(case_obj)
|
601
|
-
nr_cases += 1
|
644
|
+
case_groups = get_and_set_cases_by_status(store, request, institute_obj, all_cases, data)
|
602
645
|
|
603
646
|
# Compile the final data
|
604
647
|
data["cases"] = [(status, case_groups[status]) for status in CASE_STATUSES]
|
605
|
-
data["found_cases"] = nr_cases + nr_cases_showall_statuses
|
606
|
-
data["limit"] = limit
|
607
|
-
|
608
648
|
return data
|
609
649
|
|
610
650
|
|
@@ -615,7 +655,9 @@ def populate_case_obj(case_obj: dict, store: MongoAdapter):
|
|
615
655
|
analysis_types = set(["mixed"])
|
616
656
|
case_obj["analysis_types"] = list(analysis_types)
|
617
657
|
|
618
|
-
case_obj["assignees"] = [
|
658
|
+
case_obj["assignees"] = [
|
659
|
+
store.user(user_id=user_id) for user_id in case_obj.get("assignees", [])
|
660
|
+
]
|
619
661
|
|
620
662
|
last_analysis_date = case_obj.get("analysis_date", datetime.datetime.now())
|
621
663
|
all_analyses_dates = {
|
@@ -821,7 +863,7 @@ def gene_variants(store, pymongo_cursor, variant_count, page=1, per_page=50):
|
|
821
863
|
case_display_name = variant_case_obj.get("display_name")
|
822
864
|
variant_obj["case_display_name"] = case_display_name
|
823
865
|
|
824
|
-
genome_build =
|
866
|
+
genome_build = get_case_genome_build(variant_case_obj)
|
825
867
|
update_variant_genes(store, variant_obj, genome_build)
|
826
868
|
variants.append(variant_obj)
|
827
869
|
|
@@ -885,14 +927,6 @@ def update_variant_genes(store, variant_obj, genome_build):
|
|
885
927
|
variant_obj["functional_annotations"] = get_annotations(gene_symbols, functional_annotations)
|
886
928
|
|
887
929
|
|
888
|
-
def get_genome_build(variant_case_obj):
|
889
|
-
"""Find genom build in `variant_case_obj`. If not found use build #37"""
|
890
|
-
build = str(variant_case_obj.get("genome_build"))
|
891
|
-
if build in ["37", "38"]:
|
892
|
-
return build
|
893
|
-
return "37"
|
894
|
-
|
895
|
-
|
896
930
|
def get_hgvs(gene_obj: Dict) -> Tuple[str, str, str]:
|
897
931
|
"""Analyse gene object for hgvs info
|
898
932
|
Return:
|
@@ -63,7 +63,7 @@
|
|
63
63
|
|
64
64
|
|
65
65
|
{% macro case_row(case) %}
|
66
|
-
<tr class="{% if case.status == 'solved' %}causative{% endif %}">
|
66
|
+
<tr class="{% if case.status == 'solved' %}causative{% elif case.dimmed_in_search %}dismiss{% endif %}">
|
67
67
|
<td>
|
68
68
|
<a class="me-2"
|
69
69
|
{% if case.individuals|length == 1 %} data-bs-toggle="tooltip" title="{{case.individuals[0].display_name}}" {% endif %}
|
@@ -94,13 +94,14 @@
|
|
94
94
|
<span class="badge bg-primary">migrated</span>
|
95
95
|
{% endif %}
|
96
96
|
</td>
|
97
|
-
<td
|
98
|
-
{{ case.analysis_date.date() }}
|
99
|
-
|
97
|
+
<td>
|
98
|
+
<div class="d-flex align-items-center justify-content-between">{{ case.analysis_date.date() }}
|
99
|
+
{% if case.rerun_requested %}
|
100
100
|
<span class="badge bg-secondary">rerun pending</span>
|
101
|
-
|
102
|
-
|
103
|
-
|
101
|
+
{% elif case.is_rerun %}
|
102
|
+
<span class="badge bg-secondary">rerun</span>
|
103
|
+
{% endif %}
|
104
|
+
</div>
|
104
105
|
</td>
|
105
106
|
<td>
|
106
107
|
{% if case.is_research %}
|
@@ -98,7 +98,7 @@ def google_login() -> Optional[Response]:
|
|
98
98
|
|
99
99
|
redirect_uri: str = url_for("login.authorized", _external=True)
|
100
100
|
try:
|
101
|
-
return oauth_client.google.authorize_redirect(redirect_uri)
|
101
|
+
return oauth_client.google.authorize_redirect(redirect_uri, prompt="select_account")
|
102
102
|
except Exception:
|
103
103
|
flash("An error has occurred while logging in user using Google OAuth", "warning")
|
104
104
|
return None
|
@@ -151,6 +151,7 @@ def perform_flask_login(user_dict: "LoginUser") -> Response:
|
|
151
151
|
|
152
152
|
def logout_oidc_user(session, provider: str):
|
153
153
|
"""Log out a user from an OIDC login provider-"""
|
154
|
+
|
154
155
|
logout_url = current_app.config[provider].get("logout_url")
|
155
156
|
if not logout_url or not session.get("token_response"):
|
156
157
|
return
|
@@ -13,7 +13,7 @@ from flask import (
|
|
13
13
|
session,
|
14
14
|
url_for,
|
15
15
|
)
|
16
|
-
from flask_login import
|
16
|
+
from flask_login import logout_user
|
17
17
|
|
18
18
|
from scout.server.extensions import login_manager, oauth_client, store
|
19
19
|
from scout.server.utils import public_endpoint
|
@@ -102,11 +102,14 @@ def authorized():
|
|
102
102
|
|
103
103
|
@login_bp.route("/logout")
|
104
104
|
def logout():
|
105
|
+
session.pop("email", None)
|
106
|
+
session.pop("name", None)
|
107
|
+
session.pop("locale", None)
|
108
|
+
session.pop("consent_given", None)
|
105
109
|
logout_user() # logs out user from scout
|
106
110
|
for provider in ["GOOGLE", "KEYCLOAK"]:
|
107
111
|
if current_app.config.get(provider):
|
108
112
|
controllers.logout_oidc_user(session, provider)
|
109
|
-
session.clear()
|
110
113
|
flash("you logged out", "success")
|
111
114
|
return redirect(url_for("public.index"))
|
112
115
|
|
@@ -17,7 +17,7 @@ from scout.server.blueprints.variants.controllers import (
|
|
17
17
|
)
|
18
18
|
from scout.server.blueprints.variants.forms import OutlierFiltersForm
|
19
19
|
from scout.server.extensions import store
|
20
|
-
from scout.server.utils import institute_and_case, templated
|
20
|
+
from scout.server.utils import get_case_genome_build, institute_and_case, templated
|
21
21
|
|
22
22
|
from . import controllers
|
23
23
|
|
@@ -71,7 +71,7 @@ def outliers(institute_id, case_name):
|
|
71
71
|
# Populate chromosome select choices
|
72
72
|
populate_chrom_choices(form, case_obj)
|
73
73
|
|
74
|
-
genome_build =
|
74
|
+
genome_build = get_case_genome_build(case_obj)
|
75
75
|
cytobands = store.cytoband_by_chrom(genome_build)
|
76
76
|
|
77
77
|
update_form_hgnc_symbols(store, case_obj, form)
|
@@ -3,7 +3,16 @@ import datetime
|
|
3
3
|
import json
|
4
4
|
import logging
|
5
5
|
|
6
|
-
from flask import
|
6
|
+
from flask import (
|
7
|
+
Blueprint,
|
8
|
+
Response,
|
9
|
+
flash,
|
10
|
+
redirect,
|
11
|
+
render_template,
|
12
|
+
request,
|
13
|
+
send_file,
|
14
|
+
url_for,
|
15
|
+
)
|
7
16
|
from flask_login import current_user
|
8
17
|
from markupsafe import escape
|
9
18
|
|
@@ -96,7 +105,7 @@ def panels():
|
|
96
105
|
|
97
106
|
panel_groups.append((institute_obj, institute_panels))
|
98
107
|
return dict(
|
99
|
-
panel_groups=panel_groups,
|
108
|
+
panel_groups=sorted(panel_groups, key=lambda x: x[0]["_id"]),
|
100
109
|
panel_names=panel_names,
|
101
110
|
panel_versions=panel_versions,
|
102
111
|
institutes=institutes,
|
@@ -1,7 +1,17 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
|
3
|
+
from typing import Optional
|
3
4
|
|
4
|
-
|
5
|
+
from scout.adapter import MongoAdapter
|
6
|
+
from scout.constants import HPO_LINK_URL
|
7
|
+
|
8
|
+
|
9
|
+
def hpo_terms(
|
10
|
+
store: MongoAdapter,
|
11
|
+
query: Optional[str] = None,
|
12
|
+
limit: Optional[str] = None,
|
13
|
+
page: Optional[str] = None,
|
14
|
+
) -> dict:
|
5
15
|
"""Retrieves a list of HPO terms from scout database
|
6
16
|
|
7
17
|
Args:
|
@@ -29,4 +39,7 @@ def hpo_terms(store, query=None, limit=None, page=None):
|
|
29
39
|
hpo_phenotypes["phenotypes"] = list(store.hpo_terms(query=query, limit=limit, skip=skip))
|
30
40
|
else:
|
31
41
|
hpo_phenotypes["phenotypes"] = list(store.hpo_terms(limit=limit, skip=skip))
|
32
|
-
|
42
|
+
|
43
|
+
data = hpo_phenotypes
|
44
|
+
data["hpo_link_url"] = HPO_LINK_URL
|
45
|
+
return data
|
@@ -34,7 +34,7 @@
|
|
34
34
|
</thead>
|
35
35
|
{% for pheno in phenotypes %}
|
36
36
|
<tr>
|
37
|
-
<td><a href="
|
37
|
+
<td><a href="{{hpo_link_url}}{{pheno.hpo_id}}" referrerpolicy="no-referrer" target="_blank">{{ pheno.hpo_id }}</a></td>
|
38
38
|
<td><span class="text-body">{{ pheno.description }}</span></td>
|
39
39
|
<td><span class="text-body">{{pheno.genes|length}}</span></td>
|
40
40
|
</tr>
|
@@ -28,6 +28,7 @@ from scout.constants import (
|
|
28
28
|
VERBS_MAP,
|
29
29
|
)
|
30
30
|
from scout.server.blueprints.variant.utils import (
|
31
|
+
get_str_mc,
|
31
32
|
update_representative_gene,
|
32
33
|
update_variant_case_panels,
|
33
34
|
)
|
@@ -40,6 +41,7 @@ from scout.server.utils import (
|
|
40
41
|
case_has_chanjo_coverage,
|
41
42
|
case_has_mt_alignments,
|
42
43
|
case_has_rna_tracks,
|
44
|
+
get_case_genome_build,
|
43
45
|
user_institutes,
|
44
46
|
variant_institute_and_case,
|
45
47
|
)
|
@@ -232,9 +234,7 @@ def variant(
|
|
232
234
|
|
233
235
|
variant_id = variant_obj["variant_id"]
|
234
236
|
|
235
|
-
genome_build =
|
236
|
-
if genome_build not in ["37", "38"]:
|
237
|
-
genome_build = "37"
|
237
|
+
genome_build = get_case_genome_build(case_obj)
|
238
238
|
|
239
239
|
# is variant located on the mitochondria
|
240
240
|
variant_obj["is_mitochondrial"] = any(
|
@@ -314,6 +314,9 @@ def variant(
|
|
314
314
|
|
315
315
|
variant_obj["end_position"] = end_position(variant_obj)
|
316
316
|
|
317
|
+
# common motif count for STR variants
|
318
|
+
variant_obj["str_mc"] = get_str_mc(variant_obj)
|
319
|
+
|
317
320
|
# Add general variant links
|
318
321
|
variant_obj.update(get_variant_links(institute_obj, variant_obj, int(genome_build)))
|
319
322
|
variant_obj["frequencies"] = frequencies(variant_obj)
|
@@ -425,9 +428,7 @@ def get_gene_has_full_coverage(institute_obj, case_obj, variant_obj) -> Dict[int
|
|
425
428
|
if not case_obj.get("chanjo2_coverage"):
|
426
429
|
return {}
|
427
430
|
|
428
|
-
genome_build =
|
429
|
-
if genome_build not in ["37", "38"]:
|
430
|
-
genome_build = "37"
|
431
|
+
genome_build = get_case_genome_build(case_obj)
|
431
432
|
|
432
433
|
gene_has_full_coverage: dict = {
|
433
434
|
hgnc_id: chanjo2.get_gene_complete_coverage(
|
@@ -436,7 +437,7 @@ def get_gene_has_full_coverage(institute_obj, case_obj, variant_obj) -> Dict[int
|
|
436
437
|
individuals=case_obj.get("individuals"),
|
437
438
|
build=genome_build,
|
438
439
|
)
|
439
|
-
for hgnc_id in [gene.get("hgnc_id") for gene in variant_obj.get("genes")]
|
440
|
+
for hgnc_id in [gene.get("hgnc_id") for gene in variant_obj.get("genes", [])]
|
440
441
|
}
|
441
442
|
return gene_has_full_coverage
|
442
443
|
|
@@ -555,7 +556,7 @@ def observations(store: MongoAdapter, loqusdb: LoqusDB, variant_obj: dict) -> Di
|
|
555
556
|
f"Could not find a Loqus instance with id:{loqus_id}",
|
556
557
|
"warning",
|
557
558
|
)
|
558
|
-
obs_data[loqus_id]
|
559
|
+
obs_data[loqus_id] = {"observations": "N/A"}
|
559
560
|
continue
|
560
561
|
|
561
562
|
if obs_data[loqus_id] == {}: # Variant was not found
|
@@ -656,9 +657,7 @@ def variant_acmg(store: MongoAdapter, institute_id: str, case_name: str, variant
|
|
656
657
|
store, variant_obj, institute_id, case_name
|
657
658
|
)
|
658
659
|
|
659
|
-
genome_build =
|
660
|
-
if genome_build not in ["37", "38"]:
|
661
|
-
genome_build = "37"
|
660
|
+
genome_build = get_case_genome_build(case_obj)
|
662
661
|
|
663
662
|
add_gene_info(store, variant_obj, genome_build=genome_build)
|
664
663
|
|
@@ -396,7 +396,7 @@
|
|
396
396
|
<div class="col-1">
|
397
397
|
<!--Define build variable to be used in the UCSC link-->
|
398
398
|
{% set build = "hg19" %}
|
399
|
-
{% if case.genome_build == 38 or variant.chromosome == "MT" %}
|
399
|
+
{% if case.genome_build == "38" or variant.chromosome == "MT" %}
|
400
400
|
{% set build = "hg38" %}
|
401
401
|
{% endif %}
|
402
402
|
|
@@ -164,38 +164,42 @@
|
|
164
164
|
</div>
|
165
165
|
{% endmacro %}
|
166
166
|
|
167
|
+
{% macro frequencies_table(variant) %}
|
168
|
+
<table class="table table-sm align-middle mb-1" style="font-size: 0.875rem;">
|
169
|
+
<thead class="table-light">
|
170
|
+
<tr>
|
171
|
+
<th scope="col" class="py-1 px-2">Source</th>
|
172
|
+
<th scope="col" class="py-1 px-2">Frequency</th>
|
173
|
+
</tr>
|
174
|
+
</thead>
|
175
|
+
<tbody>
|
176
|
+
{% for freq_name, value, link in variant.frequencies %}
|
177
|
+
<tr>
|
178
|
+
<td class="py-1 px-2">
|
179
|
+
{% if link %}
|
180
|
+
<a href="{{ link }}" target="_blank" rel="noopener" referrerpolicy="no-referrer">{{ freq_name }}</a>
|
181
|
+
{% else %}
|
182
|
+
{{ freq_name }}
|
183
|
+
{% endif %}
|
184
|
+
</td>
|
185
|
+
<td class="py-1 px-2">
|
186
|
+
{% if value %}
|
187
|
+
<span class="badge bg-secondary" style="font-size: 0.75rem;">{{ value|human_decimal }}</span>
|
188
|
+
{% else %}
|
189
|
+
-
|
190
|
+
{% endif %}
|
191
|
+
</td>
|
192
|
+
</tr>
|
193
|
+
{% endfor %}
|
194
|
+
</tbody>
|
195
|
+
</table>
|
196
|
+
{% endmacro %}
|
197
|
+
|
167
198
|
{% macro frequencies(variant) %}
|
168
199
|
<div class="card panel-default">
|
169
200
|
<div class="panel-heading">Frequencies</div>
|
170
201
|
<div class="card-body">
|
171
|
-
|
172
|
-
<thead class="thead table-light">
|
173
|
-
<tr>
|
174
|
-
<th scope="col">Source</th>
|
175
|
-
<th scope="col">Frequency</th>
|
176
|
-
</tr>
|
177
|
-
</thead>
|
178
|
-
<tbody>
|
179
|
-
{% for freq_name, value, link in variant.frequencies %}
|
180
|
-
<tr>
|
181
|
-
<td>
|
182
|
-
{% if link %}
|
183
|
-
<a href="{{ link }}" target="_blank" rel="noopener" referrerpolicy="no-referrer">{{ freq_name }}</a>
|
184
|
-
{% else %}
|
185
|
-
{{ freq_name }}
|
186
|
-
{% endif %}
|
187
|
-
</td>
|
188
|
-
<td>
|
189
|
-
{% if value %}
|
190
|
-
<span class="badge bg-secondary">{{ value|human_decimal }}</span>
|
191
|
-
{% else %}
|
192
|
-
-
|
193
|
-
{% endif %}
|
194
|
-
</td>
|
195
|
-
</tr>
|
196
|
-
{% endfor %}
|
197
|
-
</tbody>
|
198
|
-
</table>
|
202
|
+
{{ frequencies_table(variant) }}
|
199
203
|
</div>
|
200
204
|
</div>
|
201
205
|
{% endmacro %}
|
@@ -282,6 +286,41 @@
|
|
282
286
|
</div>
|
283
287
|
{% endmacro %}
|
284
288
|
|
289
|
+
{% macro old_observations_table(variant) %}
|
290
|
+
<table class="table">
|
291
|
+
<thead class="thead table-light">
|
292
|
+
<tr>
|
293
|
+
<th scope="col">Local archive</th>
|
294
|
+
<th scope="col">Nr obs.</th>
|
295
|
+
<th scope="col">Nr homo.</th>
|
296
|
+
<th scope="col">Frequency</th>
|
297
|
+
</tr>
|
298
|
+
</thead>
|
299
|
+
<tbody>
|
300
|
+
<tr>
|
301
|
+
<td>RD</td>
|
302
|
+
<td>{{ variant.local_obs_old|default('N/A') }}</td>
|
303
|
+
<td>{{ variant.local_obs_hom_old|default('N/A') }}</td>
|
304
|
+
<td>{% if variant.local_obs_old_freq %} {{variant.local_obs_old_freq|round(6)}} {% elif variant.local_obs_old_nr_cases and variant.local_obs_old %} {{ (variant.local_obs_old/variant.local_obs_old_nr_cases)|round(5) }} {% elif variant.local_obs_old_nr_cases %} 0 / {{variant.local_obs_old_nr_cases}} {% else %} N/A {% endif %}</td>
|
305
|
+
</tr>
|
306
|
+
{% if variant.category in ['cancer', 'cancer_sv'] %}
|
307
|
+
<tr>
|
308
|
+
<td>Cancer Germline</td>
|
309
|
+
<td>{{ variant.local_obs_cancer_germline_old|default('N/A') }}</td>
|
310
|
+
<td>{{ variant.local_obs_cancer_germline_hom_old|default('N/A') }}</td>
|
311
|
+
<td>{% if variant.local_obs_cancer_germline_old_freq %} {{variant.local_obs_cancer_germline_old_freq|round(6)}} {% elif variant.local_obs_cancer_germline_old_nr_cases and variant.local_obs_cancer_germline_old %} {{ (variant.local_obs_cancer_germline_old/variant.local_obs_cancer_germline_old_nr_cases)|round(5) }} {% elif variant.local_obs_cancer_germline_old_nr_cases %} 0 / {{variant.local_obs_cancer_germline_old_nr_cases}} {% else %} N/A {% endif %}</td>
|
312
|
+
</tr>
|
313
|
+
<tr>
|
314
|
+
<td>Cancer Somatic</td>
|
315
|
+
<td>{{ variant.local_obs_cancer_somatic_old|default('N/A') }}</td>
|
316
|
+
<td>{{ variant.local_obs_cancer_somatic_hom_old|default('N/A') }}</td>
|
317
|
+
<td>{% if variant.local_obs_cancer_somatic_old_freq %} {{variant.local_obs_cancer_somatic_old_freq|round(6)}} {% elif variant.local_obs_cancer_somatic_old_nr_cases and variant.local_obs_cancer_somatic_old %} {{ (variant.local_obs_cancer_somatic_old/variant.local_obs_cancer_somatic_old_nr_cases)|round(5) }} {% elif variant.local_obs_cancer_somatic_old_nr_cases %} 0 / {{variant.local_obs_cancer_somatic_old_nr_cases}} {% else %} N/A {% endif %}</td>
|
318
|
+
</tr>
|
319
|
+
{% endif %}
|
320
|
+
</tbody>
|
321
|
+
</table>
|
322
|
+
{% endmacro %}
|
323
|
+
|
285
324
|
{% macro old_observations(variant, obs_date) %}
|
286
325
|
{% if "SHOW_OBSERVED_VARIANT_ARCHIVE" in config and config["SHOW_OBSERVED_VARIANT_ARCHIVE"] == true %}
|
287
326
|
<div class="card panel-default">
|
@@ -289,38 +328,7 @@
|
|
289
328
|
<a href="https://github.com/moonso/loqusdb" target="_blank" data-bs-toggle="tooltip" title="Local observations annotated from an archive copy of the loqusdb local frequency database. Only variants above a quality threshold are included, and each case is included only once. {% if variant.local_obs_old_desc %} {{variant.local_obs_old_desc}} {% endif %}">Local observations (archive {{ obs_date or variant.local_obs_old_date or "version"}})</a>
|
290
329
|
</div>
|
291
330
|
<div class="card-body">
|
292
|
-
|
293
|
-
<thead class="thead table-light">
|
294
|
-
<tr>
|
295
|
-
<th scope="col">Archive</th>
|
296
|
-
<th scope="col">Nr obs.</th>
|
297
|
-
<th scope="col">Nr homo.</th>
|
298
|
-
<th scope="col">Frequency</th>
|
299
|
-
</tr>
|
300
|
-
</thead>
|
301
|
-
<tbody>
|
302
|
-
<tr>
|
303
|
-
<td>RD</td>
|
304
|
-
<td>{{ variant.local_obs_old|default('N/A') }}</td>
|
305
|
-
<td>{{ variant.local_obs_hom_old|default('N/A') }}</td>
|
306
|
-
<td>{% if variant.local_obs_old_freq %} {{variant.local_obs_old_freq|round(6)}} {% elif variant.local_obs_old_nr_cases and variant.local_obs_old %} {{ (variant.local_obs_old/variant.local_obs_old_nr_cases)|round(5) }} {% elif variant.local_obs_old_nr_cases %} 0 / {{variant.local_obs_old_nr_cases}} {% else %} N/A {% endif %}</td>
|
307
|
-
</tr>
|
308
|
-
{% if variant.category in ['cancer', 'cancer_sv'] %}
|
309
|
-
<tr>
|
310
|
-
<td>Cancer Germline</td>
|
311
|
-
<td>{{ variant.local_obs_cancer_germline_old|default('N/A') }}</td>
|
312
|
-
<td>{{ variant.local_obs_cancer_germline_hom_old|default('N/A') }}</td>
|
313
|
-
<td>{% if variant.local_obs_cancer_germline_old_freq %} {{variant.local_obs_cancer_germline_old_freq|round(6)}} {% elif variant.local_obs_cancer_germline_old_nr_cases and variant.local_obs_cancer_germline_old %} {{ (variant.local_obs_cancer_germline_old/variant.local_obs_cancer_germline_old_nr_cases)|round(5) }} {% elif variant.local_obs_cancer_germline_old_nr_cases %} 0 / {{variant.local_obs_cancer_germline_old_nr_cases}} {% else %} N/A {% endif %}</td>
|
314
|
-
</tr>
|
315
|
-
<tr>
|
316
|
-
<td>Cancer Somatic</td>
|
317
|
-
<td>{{ variant.local_obs_cancer_somatic_old|default('N/A') }}</td>
|
318
|
-
<td>{{ variant.local_obs_cancer_somatic_hom_old|default('N/A') }}</td>
|
319
|
-
<td>{% if variant.local_obs_cancer_somatic_old_freq %} {{variant.local_obs_cancer_somatic_old_freq|round(6)}} {% elif variant.local_obs_cancer_somatic_old_nr_cases and variant.local_obs_cancer_somatic_old %} {{ (variant.local_obs_cancer_somatic_old/variant.local_obs_cancer_somatic_old_nr_cases)|round(5) }} {% elif variant.local_obs_cancer_somatic_old_nr_cases %} 0 / {{variant.local_obs_cancer_somatic_old_nr_cases}} {% else %} N/A {% endif %}</td>
|
320
|
-
</tr>
|
321
|
-
{% endif %}
|
322
|
-
</tbody>
|
323
|
-
</table>
|
331
|
+
{{ old_observations_table(variant) }}
|
324
332
|
</div>
|
325
333
|
</div>
|
326
334
|
{% endif %}
|