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
scout/adapter/mongo/case.py
CHANGED
@@ -6,7 +6,7 @@ import operator
|
|
6
6
|
import re
|
7
7
|
from collections import OrderedDict
|
8
8
|
from copy import deepcopy
|
9
|
-
from typing import Any, Dict, List, Optional
|
9
|
+
from typing import Any, Dict, List, Optional, Tuple
|
10
10
|
|
11
11
|
import pymongo
|
12
12
|
from bson import ObjectId
|
@@ -928,21 +928,35 @@ class CaseHandler(object):
|
|
928
928
|
|
929
929
|
self.load_omics_variants(case_obj=case_obj, build=build, file_type=omics_file)
|
930
930
|
|
931
|
-
def
|
932
|
-
"""
|
931
|
+
def get_load_type_categories(self, case_obj: dict) -> List[Tuple[str, str]]:
|
932
|
+
"""Return an (ordered) list of tuples pairing variant type and category for loading.
|
933
|
+
|
934
|
+
It is important for predictable variant collisions to retain the order specified in
|
935
|
+
the file type map CLINICAL_ORDERED_FILE_TYPE_MAP. Hence the set operation is made in parallel
|
936
|
+
with the list construction."""
|
937
|
+
|
933
938
|
CLINICAL_ORDERED_FILE_TYPE_MAP = OrderedDict(
|
934
939
|
(key, value)
|
935
940
|
for key, value in ORDERED_FILE_TYPE_MAP.items()
|
936
941
|
if value["variant_type"] != "research"
|
937
942
|
)
|
938
|
-
|
943
|
+
|
944
|
+
load_type_cat = []
|
945
|
+
cat_seen = set()
|
939
946
|
for file_name, vcf_dict in CLINICAL_ORDERED_FILE_TYPE_MAP.items():
|
940
947
|
if not case_obj["vcf_files"].get(file_name):
|
941
948
|
LOG.debug("didn't find {}, skipping".format(file_name))
|
942
949
|
continue
|
943
|
-
|
950
|
+
pair = (vcf_dict["variant_type"], vcf_dict["category"])
|
951
|
+
if pair not in cat_seen:
|
952
|
+
cat_seen.add(pair)
|
953
|
+
load_type_cat.append(pair)
|
954
|
+
return load_type_cat
|
955
|
+
|
956
|
+
def _load_clinical_variants(self, case_obj: dict, build: str, update: bool = False):
|
957
|
+
"""Load variants in the order specified by CLINICAL_ORDERED_FILE_TYPE_MAP."""
|
944
958
|
|
945
|
-
for variant_type, category in
|
959
|
+
for variant_type, category in self.get_load_type_categories(case_obj):
|
946
960
|
if update:
|
947
961
|
self.delete_variants(
|
948
962
|
case_id=case_obj["_id"],
|
scout/adapter/mongo/clinvar.py
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
import logging
|
3
|
+
import re
|
3
4
|
from datetime import datetime
|
4
5
|
from typing import List, Optional
|
5
6
|
|
6
7
|
import pymongo
|
7
|
-
from bson import ObjectId
|
8
8
|
from bson.objectid import ObjectId
|
9
9
|
from pymongo import ReturnDocument
|
10
10
|
|
@@ -393,14 +393,14 @@ class ClinVarHandler(object):
|
|
393
393
|
self.clinvar_collection.delete_one({"_id": object_id})
|
394
394
|
|
395
395
|
# in any case remove reference to it in the submission object 'case_data' list field
|
396
|
-
self.clinvar_submission_collection.find_one_and_update(
|
397
|
-
{"_id": ObjectId(submission_id)}, {"$pull": {"case_data": object_id}}
|
398
|
-
)
|
399
396
|
|
400
397
|
return self.clinvar_submission_collection.find_one_and_update(
|
401
|
-
{"_id": submission_id},
|
402
|
-
{
|
403
|
-
|
398
|
+
{"_id": ObjectId(submission_id)},
|
399
|
+
{
|
400
|
+
"$set": {"updated_at": datetime.now()},
|
401
|
+
"$pull": {"case_data": {"$regex": f"^{re.escape(object_id)}"}},
|
402
|
+
},
|
403
|
+
return_document=ReturnDocument.AFTER,
|
404
404
|
)
|
405
405
|
|
406
406
|
def case_to_clinVars(self, case_id):
|
scout/adapter/mongo/hgnc.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import logging
|
2
|
-
from typing import Dict, Set
|
2
|
+
from typing import Dict, Optional, Set
|
3
3
|
|
4
4
|
import intervaltree
|
5
5
|
from pymongo.errors import BulkWriteError, DuplicateKeyError
|
@@ -44,7 +44,9 @@ class GeneHandler(object):
|
|
44
44
|
|
45
45
|
return result
|
46
46
|
|
47
|
-
def hgnc_gene_caption(
|
47
|
+
def hgnc_gene_caption(
|
48
|
+
self, hgnc_identifier: Optional[int] = None, build: Optional[str] = None
|
49
|
+
) -> Optional[dict]:
|
48
50
|
"""Fetch the current hgnc gene symbol and similar caption info for a gene in a lightweight dict
|
49
51
|
Avoid populating transcripts, exons etc that would be added on a full gene object. Use hgnc_gene() if
|
50
52
|
you need to use those.
|
@@ -57,6 +59,9 @@ class GeneHandler(object):
|
|
57
59
|
gene_caption(dict): light pymongo document with keys "hgnc_symbol", "description", "chromosome", "start", "end".
|
58
60
|
"""
|
59
61
|
|
62
|
+
if not hgnc_identifier:
|
63
|
+
return
|
64
|
+
|
60
65
|
query = {"hgnc_id": int(hgnc_identifier)}
|
61
66
|
|
62
67
|
if build in ["37", "38"]:
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import logging
|
2
|
+
import os
|
2
3
|
from typing import Dict, Iterable, List, Optional
|
3
4
|
|
4
5
|
from pymongo import ASCENDING, DESCENDING
|
@@ -130,6 +131,13 @@ class OmicsVariantHandler:
|
|
130
131
|
|
131
132
|
nr_inserted = 0
|
132
133
|
|
134
|
+
file_path = case_obj["omics_files"].get(file_type) if case_obj.get("omics_files") else None
|
135
|
+
if file_path is None or os.path.exists(file_path) is False:
|
136
|
+
LOG.warning(
|
137
|
+
f"File '{file_path}' not found on disk. Please update case {case_obj['_id']} with a valid file path for {file_type}."
|
138
|
+
)
|
139
|
+
return
|
140
|
+
|
133
141
|
file_handle = open(case_obj["omics_files"].get(file_type), "r")
|
134
142
|
|
135
143
|
for omics_info in parse_omics_file(file_handle, omics_file_type=omics_file_type):
|
@@ -642,7 +642,6 @@ class VariantLoader(object):
|
|
642
642
|
Returns:
|
643
643
|
nr_inserted(int)
|
644
644
|
"""
|
645
|
-
|
646
645
|
institute_id = case_obj["owner"]
|
647
646
|
|
648
647
|
nr_inserted = 0
|
@@ -659,9 +658,14 @@ class VariantLoader(object):
|
|
659
658
|
continue
|
660
659
|
|
661
660
|
LOG.info(f"Loading'{vcf_file_key}' variants")
|
662
|
-
variant_file =
|
661
|
+
variant_file = (
|
662
|
+
case_obj["vcf_files"].get(vcf_file_key) if case_obj.get("vcf_files") else None
|
663
|
+
)
|
663
664
|
|
664
665
|
if not variant_file or not self._has_variants_in_file(variant_file):
|
666
|
+
LOG.warning(
|
667
|
+
f"File '{variant_file}' not found on disk. Please update case {case_obj['_id']} with a valid file path for variant category: '{category}'."
|
668
|
+
)
|
665
669
|
continue
|
666
670
|
|
667
671
|
vcf_obj = VCF(variant_file)
|
scout/constants/__init__.py
CHANGED
scout/constants/file_types.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
from collections import OrderedDict
|
2
2
|
|
3
|
-
# Variants in Scout will be
|
3
|
+
# Variants in Scout will be loaded for a case in the same order as these ordered dictionaries
|
4
4
|
ORDERED_FILE_TYPE_MAP = OrderedDict(
|
5
5
|
[
|
6
6
|
("vcf_cancer", {"category": "cancer", "variant_type": "clinical"}),
|
scout/constants/igv_tracks.py
CHANGED
@@ -4,11 +4,15 @@ HG19REF_URL = (
|
|
4
4
|
)
|
5
5
|
HG19REF_INDEX_URL = "https://s3.amazonaws.com/igv.broadinstitute.org/genomes/seq/1kg_v37/human_g1k_v37_decoy.fasta.fai"
|
6
6
|
HG19CYTOBAND_URL = "https://raw.githubusercontent.com/Clinical-Genomics/reference-files/refs/heads/master/rare-disease/region/grch37_cytoband.bed"
|
7
|
-
HG19ALIAS_URL =
|
7
|
+
HG19ALIAS_URL = (
|
8
|
+
"https://raw.githubusercontent.com/igvteam/igv-data/refs/heads/main/data/hg19/hg19_alias.tab"
|
9
|
+
)
|
8
10
|
|
9
11
|
HG38REF_URL = "https://s3.amazonaws.com/igv.broadinstitute.org/genomes/seq/hg38/hg38.fa"
|
10
12
|
HG38REF_INDEX_URL = "https://s3.amazonaws.com/igv.broadinstitute.org/genomes/seq/hg38/hg38.fa.fai"
|
11
|
-
HG38ALIAS_URL =
|
13
|
+
HG38ALIAS_URL = (
|
14
|
+
"https://raw.githubusercontent.com/igvteam/igv-data/refs/heads/main/data/hg38/hg38_alias.tab"
|
15
|
+
)
|
12
16
|
HG38CYTOBAND_URL = "https://igv-genepattern-org.s3.amazonaws.com/genomes/hg38/cytoBandIdeo.txt.gz"
|
13
17
|
|
14
18
|
HG38GENES_URL = "https://hgdownload.soe.ucsc.edu/goldenPath/hg38/database/ncbiRefSeq.txt.gz"
|
scout/constants/phenotype.py
CHANGED
@@ -2,6 +2,7 @@ HPO_URL = "http://purl.obolibrary.org/obo/hp/hpoa/{}"
|
|
2
2
|
HPOTERMS_URL = (
|
3
3
|
"https://raw.githubusercontent.com/obophenotype/human-phenotype-ontology/master/hp.obo"
|
4
4
|
)
|
5
|
+
HPO_LINK_URL = "https://hpo.jax.org/browse/term/"
|
5
6
|
|
6
7
|
ORPHA_URLS = {
|
7
8
|
"orpha_to_hpo": "https://www.orphadata.com/data/xml/en_product4.xml",
|
scout/load/hpo.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import logging
|
2
2
|
from datetime import datetime
|
3
|
-
from typing import
|
3
|
+
from typing import Iterable, Optional
|
4
4
|
|
5
5
|
from click import progressbar
|
6
6
|
|
@@ -45,7 +45,13 @@ def load_hpo_terms(
|
|
45
45
|
if not gene_info:
|
46
46
|
continue
|
47
47
|
|
48
|
-
|
48
|
+
if gene_info["true"] is not None:
|
49
|
+
hgnc_id = gene_info["true"]
|
50
|
+
elif len(gene_info["ids"]) == 1:
|
51
|
+
# unique aliases can be used
|
52
|
+
hgnc_id = list(gene_info["ids"])[0]
|
53
|
+
else:
|
54
|
+
continue
|
49
55
|
|
50
56
|
if hpo_id not in hpo_terms:
|
51
57
|
continue
|
@@ -8,7 +8,11 @@ from flask_login import current_user
|
|
8
8
|
|
9
9
|
from scout.constants import CASE_SPECIFIC_TRACKS, HUMAN_REFERENCE, IGV_TRACKS
|
10
10
|
from scout.server.extensions import config_igv_tracks, store
|
11
|
-
from scout.server.utils import
|
11
|
+
from scout.server.utils import (
|
12
|
+
case_append_alignments,
|
13
|
+
find_index,
|
14
|
+
get_case_genome_build,
|
15
|
+
)
|
12
16
|
from scout.utils.ensembl_rest_clients import EnsemblRestApiClient
|
13
17
|
|
14
18
|
LOG = logging.getLogger(__name__)
|
@@ -88,7 +92,8 @@ def make_igv_tracks(
|
|
88
92
|
display_obj["locus"] = "chr{0}:{1}-{2}".format(chromosome, start, stop)
|
89
93
|
|
90
94
|
# Set genome build for displaying alignments:
|
91
|
-
|
95
|
+
|
96
|
+
if get_case_genome_build(case_obj) == "38" or chromosome == "M":
|
92
97
|
build = "38"
|
93
98
|
else:
|
94
99
|
build = "37"
|
@@ -137,10 +142,7 @@ def make_sashimi_tracks(
|
|
137
142
|
"""
|
138
143
|
|
139
144
|
locus = "All"
|
140
|
-
|
141
|
-
build = "38"
|
142
|
-
if "37" in str(case_obj.get("rna_genome_build", "38")):
|
143
|
-
build = "37"
|
145
|
+
build = "37" if "37" in str(case_obj.get("rna_genome_build", "38")) else "38"
|
144
146
|
|
145
147
|
if variant_id:
|
146
148
|
variant_obj = store.variant(document_id=variant_id)
|
@@ -35,6 +35,8 @@
|
|
35
35
|
$(document).ready(function () {
|
36
36
|
var div = $("#igvDiv")[0],
|
37
37
|
options = {
|
38
|
+
loadDefaultGenomes: false,
|
39
|
+
genomeList: "https://raw.githubusercontent.com/igvteam/igv-data/main/genomes/web/genomes.json",
|
38
40
|
showNavigation: true,
|
39
41
|
showRuler: true,
|
40
42
|
{% if display_center_guide %}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
{% macro igv_script() %}
|
2
2
|
<link rel="shortcut icon" href="//igv.org/web/img/favicon.ico">
|
3
3
|
<!-- IGV JS-->
|
4
|
-
<script src="https://cdn.jsdelivr.net/npm/igv@3.
|
4
|
+
<script src="https://cdn.jsdelivr.net/npm/igv@3.3.0/dist/igv.min.js" integrity="sha512-U3drIflKJksG0+kiVuqYrQaI9SsloPhKfISeZr8bzVpO/oRFz7hE1vdJirvDyYIfv51CSucKJgcLAdupqitBcQ==" crossorigin="anonymous"></script>
|
5
5
|
{% endmacro %}
|
@@ -22,6 +22,7 @@ from scout.constants import (
|
|
22
22
|
CUSTOM_CASE_REPORTS,
|
23
23
|
DATE_DAY_FORMATTER,
|
24
24
|
GENOME_REGION,
|
25
|
+
HPO_LINK_URL,
|
25
26
|
INHERITANCE_PALETTE,
|
26
27
|
MITODEL_HEADER,
|
27
28
|
MT_COV_STATS_HEADER,
|
@@ -66,6 +67,7 @@ from scout.server.utils import (
|
|
66
67
|
case_has_mt_alignments,
|
67
68
|
case_has_mtdna_report,
|
68
69
|
case_has_rna_tracks,
|
70
|
+
get_case_genome_build,
|
69
71
|
get_case_mito_chromosome,
|
70
72
|
institute_and_case,
|
71
73
|
)
|
@@ -157,7 +159,12 @@ def coverage_report_contents(base_url, institute_obj, case_obj):
|
|
157
159
|
return html_body_content
|
158
160
|
|
159
161
|
|
160
|
-
def _populate_case_groups(
|
162
|
+
def _populate_case_groups(
|
163
|
+
store: MongoAdapter,
|
164
|
+
case_obj: dict,
|
165
|
+
case_groups: Dict[str, List[str]],
|
166
|
+
case_group_label: Dict[str, str],
|
167
|
+
):
|
161
168
|
"""Case groups allow display of information about user linked cases together on one case.
|
162
169
|
Notably variantS lists show shared annotations and alignment views show all alignments
|
163
170
|
available for the group.
|
@@ -178,20 +185,21 @@ def _populate_case_groups(store, case_obj, case_groups, case_group_label):
|
|
178
185
|
case_group_label[group] = store.case_group_label(group)
|
179
186
|
|
180
187
|
|
181
|
-
def _get_partial_causatives(store: MongoAdapter, case_obj:
|
182
|
-
"""
|
183
|
-
|
184
|
-
store(adapter.MongoAdapter)
|
185
|
-
case_obj(models.Case)
|
186
|
-
Returns:
|
187
|
-
partial(list(dict))
|
188
|
+
def _get_partial_causatives(store: MongoAdapter, institute_obj: dict, case_obj: dict) -> List[Dict]:
|
189
|
+
"""Check for partial causatives and associated phenotypes.
|
190
|
+
Return any partial causatives a case has, populated as causative objs.
|
188
191
|
"""
|
189
192
|
|
190
193
|
partial_causatives = []
|
191
194
|
if case_obj.get("partial_causatives"):
|
192
195
|
for var_id, values in case_obj["partial_causatives"].items():
|
196
|
+
variant_obj = store.variant(var_id)
|
197
|
+
if variant_obj:
|
198
|
+
decorated_variant_obj = _get_decorated_var(
|
199
|
+
store, var_obj=variant_obj, institute_obj=institute_obj, case_obj=case_obj
|
200
|
+
)
|
193
201
|
causative_obj = {
|
194
|
-
"variant":
|
202
|
+
"variant": decorated_variant_obj or var_id,
|
195
203
|
"disease_terms": values.get("diagnosis_phenotypes"),
|
196
204
|
"hpo_terms": values.get("phenotype_terms"),
|
197
205
|
}
|
@@ -287,7 +295,7 @@ def bionano_case(store, institute_obj, case_obj) -> Dict:
|
|
287
295
|
return data
|
288
296
|
|
289
297
|
|
290
|
-
def sma_case(store, institute_obj, case_obj):
|
298
|
+
def sma_case(store: MongoAdapter, institute_obj: dict, case_obj: dict) -> dict:
|
291
299
|
"""Preprocess a case for tabular view, SMA."""
|
292
300
|
|
293
301
|
_populate_case_individuals(case_obj)
|
@@ -299,11 +307,31 @@ def sma_case(store, institute_obj, case_obj):
|
|
299
307
|
"case": case_obj,
|
300
308
|
"comments": store.events(institute_obj, case=case_obj, comments=True),
|
301
309
|
"events": _get_events(store, institute_obj, case_obj),
|
302
|
-
"region": GENOME_REGION[case_obj
|
310
|
+
"region": GENOME_REGION[get_case_genome_build(case_obj)],
|
303
311
|
}
|
304
312
|
return data
|
305
313
|
|
306
314
|
|
315
|
+
def _get_suspects_or_causatives(
|
316
|
+
store: MongoAdapter, institute_obj: dict, case_obj: dict, kind: str = "suspects"
|
317
|
+
) -> list:
|
318
|
+
"""Fetch the variant objects for suspects and causatives and decorate them.
|
319
|
+
If no longer available, append variant_id instead."""
|
320
|
+
|
321
|
+
marked_vars = []
|
322
|
+
for variant_id in case_obj.get(kind, []):
|
323
|
+
variant_obj = store.variant(variant_id)
|
324
|
+
if variant_obj:
|
325
|
+
marked_vars.append(
|
326
|
+
_get_decorated_var(
|
327
|
+
store, var_obj=variant_obj, institute_obj=institute_obj, case_obj=case_obj
|
328
|
+
)
|
329
|
+
)
|
330
|
+
else:
|
331
|
+
marked_vars.append(variant_id)
|
332
|
+
return marked_vars
|
333
|
+
|
334
|
+
|
307
335
|
def case(
|
308
336
|
store: MongoAdapter, institute_obj: dict, case_obj: dict, hide_matching: bool = True
|
309
337
|
) -> dict:
|
@@ -331,22 +359,16 @@ def case(
|
|
331
359
|
case_group_label = {}
|
332
360
|
_populate_case_groups(store, case_obj, case_groups, case_group_label)
|
333
361
|
|
334
|
-
|
335
|
-
suspects = [
|
336
|
-
store.variant(variant_id) or variant_id for variant_id in case_obj.get("suspects", [])
|
337
|
-
]
|
362
|
+
suspects = _get_suspects_or_causatives(store, institute_obj, case_obj, "suspects")
|
338
363
|
_populate_assessments(suspects)
|
339
|
-
|
340
|
-
|
341
|
-
]
|
364
|
+
|
365
|
+
causatives = _get_suspects_or_causatives(store, institute_obj, case_obj, "causatives")
|
342
366
|
_populate_assessments(causatives)
|
343
367
|
|
344
|
-
# get evaluated variants
|
345
368
|
evaluated_variants = store.evaluated_variants(case_obj["_id"], case_obj["owner"])
|
346
369
|
_populate_assessments(evaluated_variants)
|
347
370
|
|
348
|
-
|
349
|
-
partial_causatives = _get_partial_causatives(store, case_obj)
|
371
|
+
partial_causatives = _get_partial_causatives(store, institute_obj, case_obj)
|
350
372
|
_populate_assessments(partial_causatives)
|
351
373
|
|
352
374
|
case_obj["clinvar_variants"] = store.case_to_clinVars(case_obj["_id"])
|
@@ -367,9 +389,7 @@ def case(
|
|
367
389
|
for hpo_term in itertools.chain(
|
368
390
|
case_obj.get("phenotype_groups") or [], case_obj.get("phenotype_terms") or []
|
369
391
|
):
|
370
|
-
hpo_term["hpo_link"] = "
|
371
|
-
hpo_term["phenotype_id"]
|
372
|
-
)
|
392
|
+
hpo_term["hpo_link"] = f"{HPO_LINK_URL}{hpo_term['phenotype_id']}"
|
373
393
|
|
374
394
|
_set_rank_model_links(case_obj)
|
375
395
|
|
@@ -471,7 +491,7 @@ def case(
|
|
471
491
|
"tissue_types": SAMPLE_SOURCE,
|
472
492
|
"report_types": CUSTOM_CASE_REPORTS,
|
473
493
|
"mme_nodes": matchmaker.connected_nodes,
|
474
|
-
"gens_info": gens.connection_settings(case_obj
|
494
|
+
"gens_info": gens.connection_settings(get_case_genome_build(case_obj)),
|
475
495
|
"display_rerunner": rerunner.connection_settings.get("display", False),
|
476
496
|
"hide_matching": hide_matching,
|
477
497
|
"audits": store.case_events_by_verb(
|
@@ -676,7 +696,9 @@ def case_report_variants(store: MongoAdapter, case_obj: dict, institute_obj: dic
|
|
676
696
|
add_bayesian_acmg_classification(var_obj)
|
677
697
|
add_bayesian_ccv_classification(var_obj)
|
678
698
|
evaluated_variants_by_type[eval_category].append(
|
679
|
-
_get_decorated_var(
|
699
|
+
_get_decorated_var(
|
700
|
+
store, var_obj=var_obj, institute_obj=institute_obj, case_obj=case_obj
|
701
|
+
)
|
680
702
|
)
|
681
703
|
|
682
704
|
for var_obj in store.evaluated_variants(
|
@@ -689,7 +711,9 @@ def case_report_variants(store: MongoAdapter, case_obj: dict, institute_obj: dic
|
|
689
711
|
data["variants"] = evaluated_variants_by_type
|
690
712
|
|
691
713
|
|
692
|
-
def _get_decorated_var(
|
714
|
+
def _get_decorated_var(
|
715
|
+
store: MongoAdapter, var_obj: dict, institute_obj: dict, case_obj: dict
|
716
|
+
) -> dict:
|
693
717
|
"""Decorate a variant object for display using the variant controller"""
|
694
718
|
return variant_decorator(
|
695
719
|
store=store,
|
@@ -719,7 +743,9 @@ def _append_evaluated_variant_by_type(
|
|
719
743
|
add_bayesian_ccv_classification(var_obj)
|
720
744
|
|
721
745
|
evaluated_variants_by_type[eval_category].append(
|
722
|
-
_get_decorated_var(
|
746
|
+
_get_decorated_var(
|
747
|
+
store, var_obj=var_obj, institute_obj=institute_obj, case_obj=case_obj
|
748
|
+
)
|
723
749
|
)
|
724
750
|
|
725
751
|
|
@@ -765,6 +791,7 @@ def case_report_content(store: MongoAdapter, institute_obj: dict, case_obj: dict
|
|
765
791
|
data["genetic_models"] = dict(GENETIC_MODELS)
|
766
792
|
data["report_created_at"] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
|
767
793
|
data["current_scout_version"] = __version__
|
794
|
+
data["hpo_link_url"] = HPO_LINK_URL
|
768
795
|
|
769
796
|
case_report_variants(store, case_obj, institute_obj, data)
|
770
797
|
|
@@ -1395,6 +1422,7 @@ def matchmaker_matches(request, institute_id, case_name):
|
|
1395
1422
|
pat_matches = parse_matches(patient_id, server_resp["content"]["matches"])
|
1396
1423
|
matches[patient_id] = pat_matches
|
1397
1424
|
|
1425
|
+
data["hpo_link_url"] = HPO_LINK_URL
|
1398
1426
|
data["matches"] = matches
|
1399
1427
|
return data
|
1400
1428
|
|
@@ -2,6 +2,8 @@
|
|
2
2
|
{% from "utils.html" import comments_table, variant_related_comments_table %}
|
3
3
|
{% from "variant/gene_disease_relations.html" import inheritance_badge %}
|
4
4
|
{% from "variants/components.html" import fusion_variants_header, default_fusion_variant_cells %}
|
5
|
+
{% from "variant/variant_details.html" import frequencies_table, old_observations_table %}
|
6
|
+
{% from "variant/components.html" import clinsig_table %}
|
5
7
|
|
6
8
|
{% extends "report_base.html" %}
|
7
9
|
|
@@ -192,7 +194,7 @@
|
|
192
194
|
<ul>
|
193
195
|
{% for pheno in case.phenotype_terms %}
|
194
196
|
<li>
|
195
|
-
{{pheno.feature}} - (<a style="text-decoration:none;" href="
|
197
|
+
{{pheno.feature}} - (<a style="text-decoration:none;" href="{{ hpo_link_url }}{{pheno.phenotype_id}}" target="_blank">{{pheno.phenotype_id}})</a>
|
196
198
|
{% for feature_ind in pheno.individuals %} <!-- display eventual individual-level HPO terms -->
|
197
199
|
{% for case_ind in case.individuals %}
|
198
200
|
{% if feature_ind.individual_name == case_ind.display_name %}
|
@@ -588,78 +590,14 @@
|
|
588
590
|
<table class="table table-sm">
|
589
591
|
<tr>
|
590
592
|
<td style="width:60%;">
|
591
|
-
{{ genotype_table(variant) }}
|
593
|
+
{{ genotype_table(variant) }}<br>
|
594
|
+
{{ clinsig_table(variant) }}
|
592
595
|
</td>
|
593
596
|
<td style="width:3%"></td>
|
594
597
|
<td>
|
595
|
-
|
596
|
-
|
597
|
-
<tr>
|
598
|
-
<th>Pop. frequency
|
599
|
-
{% if variant.frequency == 'common' %}
|
600
|
-
<span class="badge bg-danger">{{variant.frequency}}</span>
|
601
|
-
{% elif variant.frequency == 'uncommon' %}
|
602
|
-
<span class="badge bg-warning text-dark">{{variant.frequency}}</span>
|
603
|
-
{% else %}
|
604
|
-
<span class="badge bg-success">{{variant.frequency}}</span>
|
605
|
-
{% endif %}
|
606
|
-
</th>
|
607
|
-
<th>
|
608
|
-
</th>
|
609
|
-
</tr>
|
610
|
-
</thead>
|
611
|
-
<tbody>
|
612
|
-
<tr>
|
613
|
-
<td>
|
614
|
-
{% if variant.dbsnp_id %}
|
615
|
-
<a style="text-decoration:none;" href="{{ variant.thousandg_link }}" rel="noopener" target="_blank">1000G</a>
|
616
|
-
{% else %}
|
617
|
-
1000G
|
618
|
-
{% endif %}
|
619
|
-
</td>
|
620
|
-
<td>
|
621
|
-
{% if variant.max_thousand_genomes_frequency %}
|
622
|
-
{{ variant.max_thousand_genomes_frequency|human_decimal }} <small>(max)</small> |
|
623
|
-
{% endif %}
|
624
|
-
{{ variant.thousand_genomes_frequency|human_decimal if variant.thousand_genomes_frequency }}
|
625
|
-
{% if not variant.max_thousand_genomes_frequency and not variant.thousand_genomes_frequency %}
|
626
|
-
<span class="text-muted">Not annotated</span>
|
627
|
-
{% endif %}
|
628
|
-
</td>
|
629
|
-
</tr>
|
630
|
-
<tr>
|
631
|
-
<td><a style="text-decoration:none;" title="Exome Aggregation Consortium" rel="noopener" target="_blank" href="{{ variant.exac_link }}">ExAC</a></td>
|
632
|
-
<td>
|
633
|
-
{% if variant.max_exac_frequency %}
|
634
|
-
{{ variant.max_exac_frequency|human_decimal }} <small>(max)</small> |
|
635
|
-
{% endif %}
|
636
|
-
{{ variant.exac_frequency|human_decimal if variant.exac_frequency }}
|
637
|
-
{% if not variant.max_exac_frequency and not variant.exac_frequency %}
|
638
|
-
<span class="text-muted">Not annotated</span>
|
639
|
-
{% endif %}
|
640
|
-
</td>
|
641
|
-
</tr>
|
642
|
-
<tr>
|
643
|
-
<td><a style="text-decoration:none;" title="genome Aggregation Database" rel="noopener" target="_blank" href="{{ variant.gnomad_link }}">gnomAD</a></td>
|
644
|
-
<td>
|
645
|
-
{% if 'gnomad_frequency' in variant%}
|
646
|
-
{% if variant.max_gnomad_frequency %}
|
647
|
-
{{ variant.max_gnomad_frequency|human_decimal }}
|
648
|
-
<small>(max)</small> |
|
649
|
-
{% endif %}
|
650
|
-
{{ variant.gnomad_frequency|human_decimal if variant.gnomad_frequency }}
|
651
|
-
{% else %}
|
652
|
-
<span class="text-muted">Not annotated</span>
|
653
|
-
{% endif %}
|
654
|
-
</td>
|
655
|
-
<td>
|
656
|
-
</td>
|
657
|
-
</tr>
|
658
|
-
</tbody>
|
659
|
-
</table>
|
598
|
+
{{ frequencies_table(variant) }}
|
599
|
+
{{ old_observations_table(variant) }}
|
660
600
|
</td>
|
661
|
-
</tr>
|
662
|
-
</table>
|
663
601
|
<table id="panel-table" class="table table-sm" style="background-color: transparent">
|
664
602
|
<thead>
|
665
603
|
<tr>
|
@@ -1074,25 +1012,8 @@
|
|
1074
1012
|
</td>
|
1075
1013
|
<td style="width:3%"></td>
|
1076
1014
|
<td>
|
1077
|
-
|
1078
|
-
|
1079
|
-
<th colspan=2>Pop. frequency</th>
|
1080
|
-
</thead>
|
1081
|
-
<tbody>
|
1082
|
-
{% for freq_name, value, link in variant.frequencies %}
|
1083
|
-
<tr>
|
1084
|
-
<td>{{ freq_name }}</td>
|
1085
|
-
<td>
|
1086
|
-
{% if value %}
|
1087
|
-
<span class="badge bg-secondary">{{ value|human_decimal }}</span>
|
1088
|
-
{% else %}
|
1089
|
-
<span class="text-muted">Not annotated</span>
|
1090
|
-
{% endif %}
|
1091
|
-
</td>
|
1092
|
-
</tr>
|
1093
|
-
{% endfor %}
|
1094
|
-
</tbody>
|
1095
|
-
</table>
|
1015
|
+
{{ frequencies_table(variant) }}
|
1016
|
+
{{ old_observations_table(variant) }}
|
1096
1017
|
</td>
|
1097
1018
|
</tr>
|
1098
1019
|
</table>
|
@@ -85,7 +85,7 @@
|
|
85
85
|
<ul class="list-group list-group-flush">
|
86
86
|
{% for hpo in case.mme_submission.features %}
|
87
87
|
<li class="list-group-item">
|
88
|
-
<a class="text-white" target="_blank" href="
|
88
|
+
<a class="text-white" target="_blank" href="{{hpo_link_url}}{{hpo.id}}">
|
89
89
|
<span class="badge bg-sm bg-info">{{hpo.id}}</span>
|
90
90
|
</a>{{hpo.label}}
|
91
91
|
</li>
|
@@ -191,7 +191,7 @@
|
|
191
191
|
{% endmacro %}
|
192
192
|
|
193
193
|
{% macro hpo_panel(case, institute, config) %}
|
194
|
-
{% set url = 'https://hpo.jax.org/
|
194
|
+
{% set url = 'https://hpo.jax.org/' %}
|
195
195
|
<div id="phenotypes_panel" class="panel-heading">
|
196
196
|
<h6 class="mt-3"><span class="fa fa-stethoscope"></span> Phenotype terms (<a target="_blank" class="" href="{{ url }}" rel="noopener">HPO</a>)</h6>
|
197
197
|
</div>
|