scout-browser 4.97.0__py3-none-any.whl → 4.99.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/institute.py +42 -55
- scout/adapter/mongo/variant.py +19 -15
- scout/adapter/mongo/variant_loader.py +11 -11
- scout/build/individual.py +2 -0
- scout/build/variant/variant.py +8 -0
- scout/commands/download/ensembl.py +18 -2
- scout/commands/update/individual.py +2 -0
- scout/commands/update/panelapp.py +15 -2
- scout/constants/__init__.py +6 -7
- scout/constants/clnsig.py +2 -0
- scout/constants/file_types.py +12 -0
- scout/constants/igv_tracks.py +8 -6
- scout/constants/panels.py +3 -0
- scout/constants/variant_tags.py +6 -6
- scout/demo/643594.config.yaml +1 -0
- scout/load/panelapp.py +11 -5
- scout/models/case/case_loading_models.py +4 -0
- scout/parse/variant/clnsig.py +38 -0
- scout/parse/variant/genotype.py +4 -10
- scout/parse/variant/models.py +5 -11
- scout/parse/variant/rank_score.py +5 -13
- scout/parse/variant/variant.py +90 -111
- scout/server/app.py +33 -22
- scout/server/blueprints/alignviewers/controllers.py +29 -10
- scout/server/blueprints/alignviewers/templates/alignviewers/igv_viewer.html +41 -11
- scout/server/blueprints/cases/templates/cases/case.html +1 -1
- scout/server/blueprints/cases/templates/cases/utils.html +6 -6
- scout/server/blueprints/clinvar/controllers.py +29 -14
- scout/server/blueprints/clinvar/templates/clinvar/multistep_add_variant.html +13 -4
- scout/server/blueprints/clinvar/views.py +14 -2
- scout/server/blueprints/institutes/controllers.py +10 -2
- scout/server/blueprints/institutes/templates/overview/filters.html +14 -1
- scout/server/blueprints/login/controllers.py +112 -12
- scout/server/blueprints/login/views.py +38 -60
- scout/server/blueprints/public/templates/public/index.html +5 -1
- scout/server/blueprints/variant/controllers.py +1 -1
- scout/server/blueprints/variant/templates/variant/acmg.html +6 -2
- scout/server/blueprints/variant/templates/variant/components.html +19 -0
- scout/server/blueprints/variant/templates/variant/utils.html +3 -3
- scout/server/blueprints/variants/controllers.py +10 -1
- scout/server/blueprints/variants/templates/variants/components.html +28 -0
- scout/server/blueprints/variants/templates/variants/mei-variants.html +8 -6
- scout/server/blueprints/variants/templates/variants/sv-variants.html +9 -7
- scout/server/blueprints/variants/templates/variants/utils.html +8 -12
- scout/server/blueprints/variants/templates/variants/variants.html +4 -25
- scout/server/config.py +8 -0
- scout/server/utils.py +22 -5
- scout/utils/acmg.py +25 -26
- scout/utils/ensembl_biomart_clients.py +1 -1
- scout/utils/ensembl_rest_clients.py +25 -32
- scout/utils/hgvs.py +1 -1
- {scout_browser-4.97.0.dist-info → scout_browser-4.99.0.dist-info}/METADATA +10 -14
- {scout_browser-4.97.0.dist-info → scout_browser-4.99.0.dist-info}/RECORD +56 -56
- {scout_browser-4.97.0.dist-info → scout_browser-4.99.0.dist-info}/WHEEL +0 -0
- {scout_browser-4.97.0.dist-info → scout_browser-4.99.0.dist-info}/entry_points.txt +0 -0
- {scout_browser-4.97.0.dist-info → scout_browser-4.99.0.dist-info}/licenses/LICENSE +0 -0
scout/adapter/mongo/institute.py
CHANGED
@@ -60,36 +60,51 @@ class InstituteHandler(object):
|
|
60
60
|
) -> Union[dict, str]:
|
61
61
|
"""Update the information for an institute."""
|
62
62
|
|
63
|
-
|
63
|
+
def get_phenotype_groups() -> dict:
|
64
|
+
"""Returns a dictionary with phenotype descriptions and abbreviations."""
|
65
|
+
existing_groups = (
|
66
|
+
institute_obj.get("phenotype_groups", PHENOTYPE_GROUPS) if add_groups else {}
|
67
|
+
)
|
68
|
+
|
69
|
+
if not phenotype_groups:
|
70
|
+
return existing_groups
|
71
|
+
|
72
|
+
group_abbreviations_list = list(group_abbreviations) if group_abbreviations else []
|
73
|
+
|
74
|
+
for i, hpo_term in enumerate(phenotype_groups):
|
75
|
+
hpo_obj = self.hpo_term(hpo_term)
|
76
|
+
if not hpo_obj:
|
77
|
+
continue
|
78
|
+
|
79
|
+
existing_groups[hpo_term] = {
|
80
|
+
"name": hpo_obj["description"],
|
81
|
+
"abbr": group_abbreviations_list[i] if group_abbreviations_list else None,
|
82
|
+
}
|
83
|
+
|
84
|
+
return existing_groups
|
85
|
+
|
64
86
|
institute_obj = self.institute(internal_id)
|
65
87
|
if not institute_obj:
|
66
88
|
raise IntegrityError("Institute {} does not exist in database".format(internal_id))
|
67
89
|
|
68
|
-
updates = {"$set": {}}
|
90
|
+
updates = {"$set": {}, "$unset": {}}
|
69
91
|
updated_institute = institute_obj
|
70
92
|
|
71
93
|
if sanger_recipient:
|
72
|
-
|
73
|
-
|
74
|
-
raise IntegrityError("user {} does not exist in database".format(sanger_recipient))
|
75
|
-
|
76
|
-
LOG.info(
|
77
|
-
"Updating sanger recipients for institute: {0} with {1}".format(
|
78
|
-
internal_id, sanger_recipient
|
79
|
-
)
|
80
|
-
)
|
81
|
-
updates["$push"] = {"sanger_recipients": sanger_recipient}
|
94
|
+
old_recipients = institute_obj.get("sanger_recipients", [])
|
95
|
+
sanger_recipients = old_recipients + [sanger_recipient]
|
82
96
|
|
83
97
|
if remove_sanger:
|
84
|
-
|
85
|
-
"
|
86
|
-
remove_sanger, internal_id
|
87
|
-
)
|
98
|
+
sanger_recipients = list(
|
99
|
+
set(institute_obj.get("sanger_recipients", [])) - set([remove_sanger])
|
88
100
|
)
|
89
|
-
updates["$pull"] = {"sanger_recipients": remove_sanger}
|
90
101
|
|
91
|
-
|
92
|
-
|
102
|
+
UPDATE_SETTINGS = {
|
103
|
+
"alamut_institution": alamut_institution, # Admin setting
|
104
|
+
"alamut_key": alamut_key, # Admin setting
|
105
|
+
"check_show_all_vars": check_show_all_vars is not None,
|
106
|
+
"clinvar_key": clinvar_key, # Admin setting
|
107
|
+
"clinvar_submitters": clinvar_submitters,
|
93
108
|
"cohorts": cohorts,
|
94
109
|
"collaborators": sharing_institutes,
|
95
110
|
"coverage_cutoff": coverage_cutoff,
|
@@ -98,52 +113,24 @@ class InstituteHandler(object):
|
|
98
113
|
"gene_panels": gene_panels,
|
99
114
|
"gene_panels_matching": gene_panels_matching,
|
100
115
|
"loqusdb_id": loqusdb_ids,
|
116
|
+
"phenotype_groups": get_phenotype_groups(),
|
101
117
|
"sanger_recipients": sanger_recipients,
|
102
|
-
"
|
103
|
-
|
104
|
-
for key, value in GENERAL_SETTINGS.items():
|
105
|
-
if value not in [None, ""]:
|
106
|
-
updates["$set"][key] = value
|
107
|
-
|
108
|
-
if phenotype_groups is not None:
|
109
|
-
if group_abbreviations:
|
110
|
-
group_abbreviations = list(group_abbreviations)
|
111
|
-
existing_groups = {}
|
112
|
-
if add_groups:
|
113
|
-
existing_groups = institute_obj.get("phenotype_groups", PHENOTYPE_GROUPS)
|
114
|
-
for i, hpo_term in enumerate(phenotype_groups):
|
115
|
-
hpo_obj = self.hpo_term(hpo_term)
|
116
|
-
if not hpo_obj:
|
117
|
-
return "Term {} does not exist in database".format(hpo_term)
|
118
|
-
hpo_id = hpo_obj["hpo_id"]
|
119
|
-
description = hpo_obj["description"]
|
120
|
-
abbreviation = None
|
121
|
-
if group_abbreviations:
|
122
|
-
abbreviation = group_abbreviations[i]
|
123
|
-
existing_groups[hpo_term] = {"name": description, "abbr": abbreviation}
|
124
|
-
updates["$set"]["phenotype_groups"] = existing_groups
|
125
|
-
|
126
|
-
ADMIN_SETTINGS = {
|
127
|
-
"alamut_key": alamut_key,
|
128
|
-
"alamut_institution": alamut_institution,
|
129
|
-
"clinvar_key": clinvar_key,
|
130
|
-
"show_all_cases_status": show_all_cases_status,
|
131
|
-
"soft_filters": soft_filters,
|
118
|
+
"show_all_cases_status": show_all_cases_status, # Admin setting
|
119
|
+
"soft_filters": soft_filters, # Admin setting
|
132
120
|
}
|
133
|
-
for key, value in
|
134
|
-
if value
|
121
|
+
for key, value in UPDATE_SETTINGS.items():
|
122
|
+
if bool(value) is True:
|
135
123
|
updates["$set"][key] = value
|
124
|
+
else:
|
125
|
+
updates["$unset"][key] = "" # Remove the key from the institute document
|
136
126
|
|
137
|
-
updates["$set"
|
138
|
-
|
139
|
-
if updates["$set"].keys() or updates.get("$push") or updates.get("$pull"):
|
127
|
+
if any(updates.get(op) for op in ["$set", "$unset"]):
|
140
128
|
updates["$set"]["updated_at"] = datetime.now()
|
141
129
|
updated_institute = self.institute_collection.find_one_and_update(
|
142
130
|
{"_id": internal_id},
|
143
131
|
updates,
|
144
132
|
return_document=pymongo.ReturnDocument.AFTER,
|
145
133
|
)
|
146
|
-
|
147
134
|
LOG.info("Institute updated")
|
148
135
|
|
149
136
|
return updated_institute
|
scout/adapter/mongo/variant.py
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# stdlib modules
|
3
3
|
import logging
|
4
4
|
import re
|
5
|
-
from typing import Any
|
5
|
+
from typing import Any, Dict, Iterable
|
6
6
|
|
7
7
|
# Third party modules
|
8
8
|
import pymongo
|
@@ -689,25 +689,30 @@ class VariantHandler(VariantLoader):
|
|
689
689
|
result = self.variant_collection.delete_many(query)
|
690
690
|
LOG.info("{0} variants deleted".format(result.deleted_count))
|
691
691
|
|
692
|
-
def
|
692
|
+
def hgnc_overlapping(self, variant_obj: dict, limit: int = None) -> Iterable[Dict]:
|
693
693
|
"""Return overlapping variants.
|
694
694
|
|
695
|
-
Look at the genes that a variant overlaps
|
696
|
-
Then return all variants that overlap these genes.
|
695
|
+
Look at the genes that a variant overlaps, then return all variants that overlap these genes.
|
697
696
|
|
698
|
-
|
699
|
-
|
697
|
+
The operation is slightly different depending on the category of the variants that we want to collect.
|
698
|
+
If variant_obj is an SV it will return the hgnc_id matching SVs, SNVs, and MEIs but
|
699
|
+
for SNVs we will only return the SVs and MEIs since the genmod compounds are way better.
|
700
700
|
|
701
|
-
|
702
|
-
variant_obj(dict)
|
701
|
+
Do not return the present variant as matching.
|
703
702
|
|
704
|
-
|
705
|
-
|
703
|
+
limit: A maximum count of returned variants is introduced: mainly this is a problem when SVs are huge since there can be many genes and overlapping variants.
|
704
|
+
We sort to offer the LIMIT most severe overlapping variants.
|
706
705
|
"""
|
707
|
-
|
708
|
-
|
706
|
+
category = (
|
707
|
+
{"$in": ["sv", "mei"]}
|
708
|
+
if variant_obj["category"] == "snv"
|
709
|
+
else {"$in": ["sv", "snv", "mei", "cancer", "cancer_sv"]}
|
710
|
+
)
|
711
|
+
|
709
712
|
variant_type = variant_obj.get("variant_type", "clinical")
|
710
713
|
hgnc_ids = variant_obj["hgnc_ids"]
|
714
|
+
if not limit:
|
715
|
+
limit = 30 if variant_obj["category"] == "snv" else 45
|
711
716
|
|
712
717
|
query = {
|
713
718
|
"$and": [
|
@@ -715,13 +720,12 @@ class VariantHandler(VariantLoader):
|
|
715
720
|
{"category": category},
|
716
721
|
{"variant_type": variant_type},
|
717
722
|
{"hgnc_ids": {"$in": hgnc_ids}},
|
723
|
+
{"variant_id": {"$ne": variant_obj["variant_id"]}},
|
718
724
|
]
|
719
725
|
}
|
720
726
|
sort_key = [("rank_score", pymongo.DESCENDING)]
|
721
|
-
# We collect the 30 most severe overlapping variants
|
722
|
-
variants = self.variant_collection.find(query).sort(sort_key).limit(limit)
|
723
727
|
|
724
|
-
return
|
728
|
+
return self.variant_collection.find(query).sort(sort_key).limit(limit)
|
725
729
|
|
726
730
|
def evaluated_variant_ids_from_events(self, case_id, institute_id):
|
727
731
|
"""Returns variant ids for variants that have been evaluated
|
@@ -621,16 +621,16 @@ class VariantLoader(object):
|
|
621
621
|
|
622
622
|
def load_variants(
|
623
623
|
self,
|
624
|
-
case_obj,
|
625
|
-
variant_type="clinical",
|
626
|
-
category="snv",
|
627
|
-
rank_threshold=None,
|
628
|
-
chrom=None,
|
629
|
-
start=None,
|
630
|
-
end=None,
|
631
|
-
gene_obj=None,
|
632
|
-
custom_images=None,
|
633
|
-
build="37",
|
624
|
+
case_obj: dict,
|
625
|
+
variant_type: str = "clinical",
|
626
|
+
category: str = "snv",
|
627
|
+
rank_threshold: float = None,
|
628
|
+
chrom: str = None,
|
629
|
+
start: int = None,
|
630
|
+
end: int = None,
|
631
|
+
gene_obj: dict = None,
|
632
|
+
custom_images: list = None,
|
633
|
+
build: str = "37",
|
634
634
|
):
|
635
635
|
"""Load variants for a case into scout.
|
636
636
|
|
@@ -675,7 +675,7 @@ class VariantLoader(object):
|
|
675
675
|
)
|
676
676
|
|
677
677
|
gene_to_panels = self.gene_to_panels(case_obj)
|
678
|
-
genes =
|
678
|
+
genes = list(self.all_genes(build=build))
|
679
679
|
hgncid_to_gene = self.hgncid_to_gene(genes=genes, build=build)
|
680
680
|
genomic_intervals = self.get_coding_intervals(genes=genes, build=build)
|
681
681
|
|
scout/build/individual.py
CHANGED
@@ -6,9 +6,11 @@ from scout.exceptions import PedigreeError
|
|
6
6
|
|
7
7
|
log = logging.getLogger(__name__)
|
8
8
|
BUILD_INDIVIDUAL_FILES = [
|
9
|
+
"assembly_alignment_path",
|
9
10
|
"bam_file",
|
10
11
|
"d4_file",
|
11
12
|
"mt_bam",
|
13
|
+
"paraphase_alignment_path",
|
12
14
|
"rhocall_bed",
|
13
15
|
"rhocall_wig",
|
14
16
|
"rna_alignment_path",
|
scout/build/variant/variant.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
import logging
|
3
|
+
from typing import List
|
3
4
|
|
4
5
|
from scout.utils.convert import call_safe
|
5
6
|
from scout.utils.dict_utils import remove_nonetype
|
@@ -115,6 +116,7 @@ def build_variant(
|
|
115
116
|
revel_score = float, REVEL rankscore
|
116
117
|
revel = float, REVEL score
|
117
118
|
clnsig = list, # list of <clinsig>
|
119
|
+
|
118
120
|
spidex = float,
|
119
121
|
|
120
122
|
missing_data = bool, # default False
|
@@ -247,6 +249,7 @@ def build_variant(
|
|
247
249
|
add_hgnc_symbols(variant_obj, variant_obj["hgnc_ids"], hgncid_to_gene)
|
248
250
|
link_gene_panels(variant_obj, gene_to_panels)
|
249
251
|
add_clnsig_objects(variant_obj, variant.get("clnsig", []))
|
252
|
+
add_clnsig_onc_objects(variant_obj, variant.get("clnsig_onc"))
|
250
253
|
|
251
254
|
add_callers(variant_obj, variant.get("callers", {}))
|
252
255
|
|
@@ -337,6 +340,11 @@ def add_clnsig_objects(variant_obj, clnsig_list):
|
|
337
340
|
variant_obj["clnsig"] = clnsig_objects
|
338
341
|
|
339
342
|
|
343
|
+
def add_clnsig_onc_objects(variant_obj: dict, onc_clnsig: List[dict]):
|
344
|
+
if onc_clnsig:
|
345
|
+
variant_obj["clnsig_onc"] = onc_clnsig
|
346
|
+
|
347
|
+
|
340
348
|
def add_callers(variant_obj, call_info):
|
341
349
|
"""Add call_info to variant_obj
|
342
350
|
Args: variant_obj (Dict)
|
@@ -8,9 +8,20 @@ import click
|
|
8
8
|
|
9
9
|
from scout.utils.ensembl_biomart_clients import EnsemblBiomartHandler
|
10
10
|
|
11
|
+
CHROM_SEPARATOR = "[success]"
|
12
|
+
NR_EXPECTED_CHROMS = 24
|
13
|
+
|
11
14
|
LOG = logging.getLogger(__name__)
|
12
15
|
|
13
16
|
|
17
|
+
def integrity_check(nr_chromosomes_in_file: int):
|
18
|
+
if nr_chromosomes_in_file < NR_EXPECTED_CHROMS:
|
19
|
+
raise BufferError(
|
20
|
+
"Ensembl resource does not seem to be complete. Please retry downloading genes/transcripts."
|
21
|
+
)
|
22
|
+
LOG.info("Integrity check OK.")
|
23
|
+
|
24
|
+
|
14
25
|
def print_ensembl(
|
15
26
|
out_dir: pathlib.Path, resource_type: List[str], genome_build: Optional[str] = None
|
16
27
|
):
|
@@ -31,14 +42,19 @@ def print_ensembl(
|
|
31
42
|
|
32
43
|
file_name: str = f"ensembl_{resource_type}_{build}.txt"
|
33
44
|
file_path = out_dir / file_name
|
45
|
+
nr_chroms_in_file = 0
|
34
46
|
|
35
47
|
LOG.info("Print ensembl info %s to %s", build, file_path)
|
36
48
|
|
37
49
|
with file_path.open("w", encoding="utf-8") as outfile:
|
38
50
|
for line in ensembl_client.stream_resource(interval_type=resource_type):
|
39
|
-
|
51
|
+
if line.strip() == CHROM_SEPARATOR:
|
52
|
+
nr_chroms_in_file += 1
|
53
|
+
else:
|
54
|
+
outfile.write(line + "\n")
|
40
55
|
|
41
|
-
LOG.info(f"{file_name} file saved to disk")
|
56
|
+
LOG.info(f"{file_name} file saved to disk.")
|
57
|
+
integrity_check(nr_chroms_in_file)
|
42
58
|
|
43
59
|
|
44
60
|
@click.command("ensembl", help="Download files with ensembl info")
|
@@ -7,6 +7,7 @@ import click
|
|
7
7
|
from scout.server.extensions import store
|
8
8
|
|
9
9
|
UPDATE_DICT = {
|
10
|
+
"assembly_alignment_path": "path",
|
10
11
|
"bam_file": "path",
|
11
12
|
"bionano_access.sample": "str",
|
12
13
|
"bionano_access.project": "str",
|
@@ -16,6 +17,7 @@ UPDATE_DICT = {
|
|
16
17
|
"chromograph_images.upd_regions": "str",
|
17
18
|
"chromograph_images.upd_sites": "str",
|
18
19
|
"mt_bam": "path",
|
20
|
+
"paraphase_alignment_path": "path",
|
19
21
|
"reviewer.alignment": "path",
|
20
22
|
"reviewer.alignment_index": "path",
|
21
23
|
"reviewer.vcf": "path",
|
@@ -5,6 +5,7 @@ import logging
|
|
5
5
|
import click
|
6
6
|
from flask.cli import current_app, with_appcontext
|
7
7
|
|
8
|
+
from scout.constants.panels import PANELAPPGREEN_DISPLAY_NAME, PANELAPPGREEN_NAME
|
8
9
|
from scout.load.panelapp import load_panelapp_green_panel
|
9
10
|
from scout.server.extensions import store
|
10
11
|
|
@@ -31,8 +32,15 @@ LOG = logging.getLogger(__name__)
|
|
31
32
|
is_flag=True,
|
32
33
|
help="Force update even if updated panel contains less genes",
|
33
34
|
)
|
35
|
+
@click.option("--panel-id", help="Panel ID", default=PANELAPPGREEN_NAME, show_default=True)
|
36
|
+
@click.option(
|
37
|
+
"--panel-display-name",
|
38
|
+
help="Panel display name",
|
39
|
+
default=PANELAPPGREEN_DISPLAY_NAME,
|
40
|
+
show_default=True,
|
41
|
+
)
|
34
42
|
@with_appcontext
|
35
|
-
def panelapp_green(institute, force, signed_off):
|
43
|
+
def panelapp_green(institute, force, signed_off, panel_id, panel_display_name):
|
36
44
|
"""
|
37
45
|
Update the automatically generated PanelApp Green Genes panel in the database.
|
38
46
|
"""
|
@@ -47,7 +55,12 @@ def panelapp_green(institute, force, signed_off):
|
|
47
55
|
|
48
56
|
try:
|
49
57
|
load_panelapp_green_panel(
|
50
|
-
adapter=store,
|
58
|
+
adapter=store,
|
59
|
+
institute=institute,
|
60
|
+
force=force,
|
61
|
+
signed_off=signed_off,
|
62
|
+
panel_id=panel_id,
|
63
|
+
panel_display_name=panel_display_name,
|
51
64
|
)
|
52
65
|
except Exception as err:
|
53
66
|
LOG.error(err)
|
scout/constants/__init__.py
CHANGED
@@ -45,7 +45,11 @@ from .disease_parsing import (
|
|
45
45
|
MIMNR_PATTERN,
|
46
46
|
OMIM_STATUS_MAP,
|
47
47
|
)
|
48
|
-
from .file_types import
|
48
|
+
from .file_types import (
|
49
|
+
DNA_SAMPLE_VARIANT_CATEGORIES,
|
50
|
+
ORDERED_FILE_TYPE_MAP,
|
51
|
+
ORDERED_OMICS_FILE_TYPE_MAP,
|
52
|
+
)
|
49
53
|
from .filters import (
|
50
54
|
CLINICAL_FILTER_BASE,
|
51
55
|
CLINICAL_FILTER_BASE_CANCER,
|
@@ -64,12 +68,7 @@ from .gene_tags import (
|
|
64
68
|
PANEL_GENE_INFO_TRANSCRIPTS,
|
65
69
|
UPDATE_GENES_RESOURCES,
|
66
70
|
)
|
67
|
-
from .igv_tracks import
|
68
|
-
CASE_SPECIFIC_TRACKS,
|
69
|
-
HUMAN_REFERENCE,
|
70
|
-
IGV_TRACKS,
|
71
|
-
USER_DEFAULT_TRACKS,
|
72
|
-
)
|
71
|
+
from .igv_tracks import CASE_SPECIFIC_TRACKS, HUMAN_REFERENCE, IGV_TRACKS, USER_DEFAULT_TRACKS
|
73
72
|
from .indexes import ID_PROJECTION, INDEXES
|
74
73
|
from .panels import PANELAPP_CONFIDENCE_EXCLUDE
|
75
74
|
from .phenotype import (
|
scout/constants/clnsig.py
CHANGED
scout/constants/file_types.py
CHANGED
@@ -23,6 +23,18 @@ ORDERED_FILE_TYPE_MAP = OrderedDict(
|
|
23
23
|
]
|
24
24
|
)
|
25
25
|
|
26
|
+
DNA_SAMPLE_VARIANT_CATEGORIES = [
|
27
|
+
"snv",
|
28
|
+
"sv",
|
29
|
+
"mei",
|
30
|
+
"str",
|
31
|
+
"vcf_snv_mt",
|
32
|
+
"vcf_snv_research_mt",
|
33
|
+
"vcf_snv_research",
|
34
|
+
"vcf_sv_research_mt",
|
35
|
+
"vcf_sv_research",
|
36
|
+
"vcf_mei_research",
|
37
|
+
]
|
26
38
|
|
27
39
|
ORDERED_OMICS_FILE_TYPE_MAP = OrderedDict(
|
28
40
|
[
|
scout/constants/igv_tracks.py
CHANGED
@@ -11,7 +11,7 @@ HG38REF_INDEX_URL = "https://s3.amazonaws.com/igv.broadinstitute.org/genomes/seq
|
|
11
11
|
HG38ALIAS_URL = "https://igv.org/genomes/data/hg38/hg38_alias.tab"
|
12
12
|
HG38CYTOBAND_URL = "https://igv-genepattern-org.s3.amazonaws.com/genomes/hg38/cytoBandIdeo.txt.gz"
|
13
13
|
|
14
|
-
HG38GENES_URL = "https://
|
14
|
+
HG38GENES_URL = "https://hgdownload.soe.ucsc.edu/goldenPath/hg38/database/ncbiRefSeq.txt.gz"
|
15
15
|
HG38GENES_FORMAT = "refgene"
|
16
16
|
|
17
17
|
HG19GENES_URL = "https://s3.amazonaws.com/igv.org.genomes/hg19/ncbiRefSeq.sorted.txt.gz"
|
@@ -124,11 +124,13 @@ HUMAN_GENES_38 = {
|
|
124
124
|
}
|
125
125
|
|
126
126
|
CASE_SPECIFIC_TRACKS = {
|
127
|
-
"
|
128
|
-
"
|
129
|
-
"
|
130
|
-
"
|
131
|
-
"
|
127
|
+
"paraphase_alignments": "Paraphase Alignment",
|
128
|
+
"assembly_alignments": "de novo Assembly Alignment",
|
129
|
+
"rhocall_beds": "Rhocall Zygosity",
|
130
|
+
"rhocall_wigs": "Rhocall Regions",
|
131
|
+
"tiddit_coverage_wigs": "TIDDIT Coverage",
|
132
|
+
"upd_regions_beds": "UPD regions",
|
133
|
+
"upd_sites_beds": "UPD sites",
|
132
134
|
}
|
133
135
|
|
134
136
|
HUMAN_REFERENCE = {"37": HUMAN_REFERENCE_37, "38": HUMAN_REFERENCE_38}
|
scout/constants/panels.py
CHANGED
scout/constants/variant_tags.py
CHANGED
@@ -244,7 +244,7 @@ CANCER_TIER_OPTIONS = {
|
|
244
244
|
"4": {
|
245
245
|
"label": "Tier IV",
|
246
246
|
"description": "Observed at high frequency in the population. No published evidence.",
|
247
|
-
"label_class": "
|
247
|
+
"label_class": "success",
|
248
248
|
},
|
249
249
|
}
|
250
250
|
|
@@ -334,7 +334,7 @@ MANUAL_RANK_OPTIONS = OrderedDict(
|
|
334
334
|
"label": "VUS",
|
335
335
|
"name": "Unknown Significance",
|
336
336
|
"description": "Variant of unknown significance",
|
337
|
-
"label_class": "
|
337
|
+
"label_class": "primary",
|
338
338
|
},
|
339
339
|
),
|
340
340
|
(
|
@@ -361,7 +361,7 @@ MANUAL_RANK_OPTIONS = OrderedDict(
|
|
361
361
|
"label": "RF",
|
362
362
|
"name": "Risk Factor",
|
363
363
|
"description": "Established risk allele - strong evidence for a small risk increase",
|
364
|
-
"label_class": "
|
364
|
+
"label_class": "dark",
|
365
365
|
},
|
366
366
|
),
|
367
367
|
(
|
@@ -370,7 +370,7 @@ MANUAL_RANK_OPTIONS = OrderedDict(
|
|
370
370
|
"label": "LRF",
|
371
371
|
"name": "Likely Risk Factor",
|
372
372
|
"description": "Likely risk allele - some evidence for a small risk increase",
|
373
|
-
"label_class": "
|
373
|
+
"label_class": "dark",
|
374
374
|
},
|
375
375
|
),
|
376
376
|
(
|
@@ -379,7 +379,7 @@ MANUAL_RANK_OPTIONS = OrderedDict(
|
|
379
379
|
"label": "URF",
|
380
380
|
"name": "Uncertain Risk Factor",
|
381
381
|
"description": "Uncertain risk allele - uncertain evidence for a small risk increase",
|
382
|
-
"label_class": "
|
382
|
+
"label_class": "dark",
|
383
383
|
},
|
384
384
|
),
|
385
385
|
(
|
@@ -388,7 +388,7 @@ MANUAL_RANK_OPTIONS = OrderedDict(
|
|
388
388
|
"label": "O",
|
389
389
|
"name": "Other",
|
390
390
|
"description": "Other, phenotype not related to disease",
|
391
|
-
"label_class": "
|
391
|
+
"label_class": "dark",
|
392
392
|
},
|
393
393
|
),
|
394
394
|
]
|
scout/demo/643594.config.yaml
CHANGED
scout/load/panelapp.py
CHANGED
@@ -11,7 +11,6 @@ from scout.parse.panelapp import parse_panelapp_panel
|
|
11
11
|
from scout.server.extensions import panelapp
|
12
12
|
|
13
13
|
LOG = logging.getLogger(__name__)
|
14
|
-
PANEL_NAME = "PANELAPP-GREEN"
|
15
14
|
|
16
15
|
|
17
16
|
def load_panelapp_panel(
|
@@ -72,7 +71,14 @@ def get_panelapp_genes(
|
|
72
71
|
return genes
|
73
72
|
|
74
73
|
|
75
|
-
def load_panelapp_green_panel(
|
74
|
+
def load_panelapp_green_panel(
|
75
|
+
adapter: MongoAdapter,
|
76
|
+
institute: str,
|
77
|
+
force: bool,
|
78
|
+
signed_off: bool,
|
79
|
+
panel_id: str,
|
80
|
+
panel_display_name: str,
|
81
|
+
):
|
76
82
|
"""Load/Update the panel containing all Panelapp Green genes."""
|
77
83
|
|
78
84
|
def parse_types_filter(types_filter: str, available_types: List[str]) -> List[str]:
|
@@ -85,10 +91,10 @@ def load_panelapp_green_panel(adapter: MongoAdapter, institute: str, force: bool
|
|
85
91
|
return [available_types[i] for i in index_list]
|
86
92
|
|
87
93
|
# check and set panel version
|
88
|
-
old_panel = adapter.gene_panel(panel_id=
|
94
|
+
old_panel = adapter.gene_panel(panel_id=panel_id)
|
89
95
|
green_panel = {
|
90
|
-
"panel_name":
|
91
|
-
"display_name":
|
96
|
+
"panel_name": panel_id,
|
97
|
+
"display_name": panel_display_name,
|
92
98
|
"institute": institute,
|
93
99
|
"version": float(math.floor(old_panel["version"]) + 1) if old_panel else 1.0,
|
94
100
|
"date": datetime.now(),
|
@@ -25,9 +25,11 @@ LOG = logging.getLogger(__name__)
|
|
25
25
|
REPID = "{REPID}"
|
26
26
|
|
27
27
|
SAMPLES_FILE_PATH_CHECKS = [
|
28
|
+
"assembly_alignment_path",
|
28
29
|
"bam_file",
|
29
30
|
"d4_file",
|
30
31
|
"mitodel_file",
|
32
|
+
"paraphase_alignment_path",
|
31
33
|
"rhocall_bed",
|
32
34
|
"rhocall_wig",
|
33
35
|
"rna_alignment_path",
|
@@ -201,6 +203,7 @@ class REViewer(BaseModel):
|
|
201
203
|
|
202
204
|
class SampleLoader(BaseModel):
|
203
205
|
alignment_path: Optional[str] = None
|
206
|
+
assembly_alignment_path: Optional[str] = None
|
204
207
|
analysis_type: Literal[ANALYSIS_TYPES] = None
|
205
208
|
bam_file: Optional[str] = ""
|
206
209
|
bam_path: Optional[str] = None
|
@@ -221,6 +224,7 @@ class SampleLoader(BaseModel):
|
|
221
224
|
mother: Optional[str] = None
|
222
225
|
msi: Optional[str] = None
|
223
226
|
mt_bam: Optional[str] = None
|
227
|
+
paraphase_alignment_path: Optional[str] = None
|
224
228
|
phenotype: Literal["affected", "unaffected", "unknown"]
|
225
229
|
predicted_ancestry: Optional[str] = None
|
226
230
|
reviewer: Optional[REViewer] = REViewer()
|
scout/parse/variant/clnsig.py
CHANGED
@@ -3,9 +3,47 @@ from typing import Dict, List, Optional, Union
|
|
3
3
|
|
4
4
|
import cyvcf2
|
5
5
|
|
6
|
+
from scout.constants.clnsig import ONC_CLNSIG
|
7
|
+
|
6
8
|
LOG = logging.getLogger(__name__)
|
7
9
|
|
8
10
|
|
11
|
+
def split_groups(value: str) -> List[str]:
|
12
|
+
"""Removes leading underscore from a string and splits it into a list of items."""
|
13
|
+
return [
|
14
|
+
item.lstrip("_").replace(" ", "_")
|
15
|
+
for group in value.replace("&", ",").split(",")
|
16
|
+
for item in group.split("/")
|
17
|
+
]
|
18
|
+
|
19
|
+
|
20
|
+
def parse_clnsig_onc(variant: cyvcf2.Variant) -> List[dict]:
|
21
|
+
"""Collect somatic oncogenicity ClinVar classifications for a variant, if available."""
|
22
|
+
if not variant.INFO.get("ONC"):
|
23
|
+
return []
|
24
|
+
acc = int(variant.INFO.get("CLNVID", 0))
|
25
|
+
onc_sig_groups = split_groups(value=variant.INFO.get("ONC", "").lower())
|
26
|
+
onc_revstat = ",".join(split_groups(value=variant.INFO.get("ONCREVSTAT", "").lower()))
|
27
|
+
onc_dn_groups = split_groups(variant.INFO.get("ONCDN", ""))
|
28
|
+
|
29
|
+
onc_clnsig_accessions = []
|
30
|
+
|
31
|
+
for i, onc_sig in enumerate(onc_sig_groups):
|
32
|
+
if (
|
33
|
+
onc_sig.capitalize() not in ONC_CLNSIG
|
34
|
+
): # This is excluding entries with ONC=no_classification_for_the_single_variant
|
35
|
+
continue
|
36
|
+
onc_clnsig_accessions.append(
|
37
|
+
{
|
38
|
+
"accession": acc,
|
39
|
+
"value": onc_sig,
|
40
|
+
"revstat": onc_revstat,
|
41
|
+
"dn": onc_dn_groups[i].replace("|", ","),
|
42
|
+
}
|
43
|
+
)
|
44
|
+
return onc_clnsig_accessions
|
45
|
+
|
46
|
+
|
9
47
|
def parse_clnsig_low_penetrance(sig_groups: List[str]) -> List[str]:
|
10
48
|
"""If 'low_penetrance' is among the clnsig terms of an array, the term gets appended to the term immediately before in the array."""
|
11
49
|
result = []
|