scout-browser 4.89.2__py3-none-any.whl → 4.90__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/mongo/panel.py +21 -58
- scout/adapter/mongo/query.py +9 -0
- scout/build/panel.py +36 -72
- scout/constants/__init__.py +28 -45
- scout/constants/acmg.py +76 -16
- scout/constants/gene_tags.py +4 -2
- scout/constants/panels.py +11 -0
- scout/constants/query_terms.py +1 -0
- scout/constants/variant_tags.py +58 -3
- scout/export/panel.py +30 -33
- scout/parse/panel.py +40 -49
- scout/server/blueprints/alignviewers/views.py +3 -0
- scout/server/blueprints/cases/controllers.py +4 -0
- scout/server/blueprints/cases/templates/cases/case_sma.html +14 -6
- scout/server/blueprints/cases/templates/cases/collapsible_actionbar.html +10 -2
- scout/server/blueprints/cases/templates/cases/matchmaker.html +12 -7
- scout/server/blueprints/institutes/controllers.py +11 -4
- scout/server/blueprints/institutes/templates/overview/causatives.html +1 -1
- scout/server/blueprints/institutes/templates/overview/gene_variants.html +3 -5
- scout/server/blueprints/institutes/templates/overview/utils.html +2 -2
- scout/server/blueprints/institutes/templates/overview/verified.html +1 -1
- scout/server/blueprints/institutes/views.py +22 -6
- scout/server/blueprints/omics_variants/templates/omics_variants/outliers.html +1 -1
- scout/server/blueprints/omics_variants/views.py +2 -0
- scout/server/blueprints/panels/controllers.py +8 -16
- scout/server/blueprints/panels/templates/panels/gene-edit.html +2 -2
- scout/server/blueprints/panels/templates/panels/panel.html +21 -13
- scout/server/blueprints/panels/templates/panels/panel_pdf_simple.html +25 -18
- scout/server/blueprints/panels/views.py +9 -6
- scout/server/blueprints/variant/templates/variant/acmg.html +28 -24
- scout/server/blueprints/variant/templates/variant/gene_disease_relations.html +1 -3
- scout/server/blueprints/variant/templates/variant/utils.html +1 -1
- scout/server/blueprints/variant/utils.py +1 -0
- scout/server/blueprints/variant/views.py +5 -2
- scout/server/blueprints/variants/templates/variants/cancer-sv-variants.html +7 -11
- scout/server/blueprints/variants/templates/variants/components.html +55 -38
- scout/server/blueprints/variants/templates/variants/mei-variants.html +2 -6
- scout/server/blueprints/variants/templates/variants/str-variants.html +8 -2
- scout/server/blueprints/variants/templates/variants/sv-variants.html +4 -8
- scout/server/blueprints/variants/templates/variants/variants.html +23 -18
- scout/server/blueprints/variants/views.py +6 -0
- scout/utils/acmg.py +155 -28
- scout/utils/scout_requests.py +8 -13
- {scout_browser-4.89.2.dist-info → scout_browser-4.90.dist-info}/METADATA +1 -1
- {scout_browser-4.89.2.dist-info → scout_browser-4.90.dist-info}/RECORD +50 -49
- {scout_browser-4.89.2.dist-info → scout_browser-4.90.dist-info}/LICENSE +0 -0
- {scout_browser-4.89.2.dist-info → scout_browser-4.90.dist-info}/WHEEL +0 -0
- {scout_browser-4.89.2.dist-info → scout_browser-4.90.dist-info}/entry_points.txt +0 -0
- {scout_browser-4.89.2.dist-info → scout_browser-4.90.dist-info}/top_level.txt +0 -0
scout/constants/variant_tags.py
CHANGED
@@ -514,12 +514,67 @@ MOSAICISM_OPTIONS = {
|
|
514
514
|
}
|
515
515
|
|
516
516
|
VARIANTS_TARGET_FROM_CATEGORY = {
|
517
|
-
"sv": "variants.sv_variants",
|
518
517
|
"cancer": "variants.cancer_variants",
|
519
518
|
"cancer_sv": "variants.cancer_sv_variants",
|
519
|
+
"fusion": "variants.fusion_variants",
|
520
520
|
"mei": "variants.mei_variants",
|
521
|
+
"outlier": "omics_variants.outliers",
|
521
522
|
"snv": "variants.variants",
|
522
523
|
"str": "variants.str_variants",
|
523
|
-
"
|
524
|
-
|
524
|
+
"sv": "variants.sv_variants",
|
525
|
+
}
|
526
|
+
|
527
|
+
_FREEBAYES = {"id": "freebayes", "name": "Freebayes"}
|
528
|
+
_GATK = {"id": "gatk", "name": "GATK"}
|
529
|
+
_MANTA = {"id": "manta", "name": "Manta"}
|
530
|
+
_TIDDIT = {"id": "tiddit", "name": "TIDDIT"}
|
531
|
+
|
532
|
+
CALLERS = {
|
533
|
+
"snv": [
|
534
|
+
{"id": "bcftools", "name": "Bcftools"},
|
535
|
+
{"id": "deepvariant", "name": "DeepVariant"},
|
536
|
+
_FREEBAYES,
|
537
|
+
_GATK,
|
538
|
+
{"id": "samtools", "name": "SAMtools"},
|
539
|
+
],
|
540
|
+
"cancer": [
|
541
|
+
_FREEBAYES,
|
542
|
+
_GATK,
|
543
|
+
{"id": "mutect", "name": "MuTect"},
|
544
|
+
{"id": "pindel", "name": "Pindel"},
|
545
|
+
{"id": "tnscope", "name": "TNScope"},
|
546
|
+
{"id": "tnscope_umi", "name": "TNscope_UMI"},
|
547
|
+
{"id": "vardict", "name": "VarDict"},
|
548
|
+
],
|
549
|
+
"cancer_sv": [
|
550
|
+
{"id": "ascat", "name": "ASCAT"},
|
551
|
+
{"id": "cnvkit", "name": "CNVkit"},
|
552
|
+
{"id": "dellysv", "name": "DellySV"},
|
553
|
+
{"id": "dellycnv", "name": "DellyCNV"},
|
554
|
+
_GATK,
|
555
|
+
{"id": "igh_dux4", "name": "IGH-DUX4 detection"},
|
556
|
+
_MANTA,
|
557
|
+
_TIDDIT,
|
558
|
+
],
|
559
|
+
"mei": [{"id": "retroseq", "name": "RetroSeq"}],
|
560
|
+
"sv": [
|
561
|
+
{"id": "cnvnator", "name": "CNVnator"},
|
562
|
+
{"id": "cnvpytor", "name": "CNVpytor"},
|
563
|
+
{"id": "delly", "name": "Delly"},
|
564
|
+
_GATK,
|
565
|
+
{"id": "hificnv", "name": "HiFiCNV"},
|
566
|
+
_MANTA,
|
567
|
+
{"id": "severus", "name": "Severus"},
|
568
|
+
{"id": "sniffles", "name": "Sniffles"},
|
569
|
+
_TIDDIT,
|
570
|
+
],
|
571
|
+
"str": [
|
572
|
+
{"id": "expansionhunter", "name": "ExpansionHunter"},
|
573
|
+
{"id": "trgt", "name": "TRGT"},
|
574
|
+
],
|
575
|
+
"fusion": [
|
576
|
+
{"id": "arriba", "name": "Arriba"},
|
577
|
+
{"id": "fusioncatcher", "name": "FusionCatcher"},
|
578
|
+
{"id": "starfusion", "name": "STARfusion"},
|
579
|
+
],
|
525
580
|
}
|
scout/export/panel.py
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
import logging
|
3
|
+
from typing import List
|
3
4
|
|
5
|
+
from scout.adapter.mongo.base import MongoAdapter
|
4
6
|
from scout.constants import CHROMOSOME_INTEGERS, CHROMOSOMES
|
7
|
+
from scout.constants.panels import EXPORT_PANEL_FIELDS
|
5
8
|
|
6
9
|
LOG = logging.getLogger(__name__)
|
7
10
|
|
@@ -14,7 +17,6 @@ def export_panels(adapter, panels, versions=None, build="37"):
|
|
14
17
|
Args:
|
15
18
|
adapter(scout.adapter.MongoAdapter)
|
16
19
|
panels(iterable(str)): Iterable with panel ids
|
17
|
-
bed(bool): If lines should be bed formated
|
18
20
|
"""
|
19
21
|
if versions and (len(versions) != len(panels)):
|
20
22
|
raise SyntaxError("If version specify for each panel")
|
@@ -111,28 +113,30 @@ def export_panels(adapter, panels, versions=None, build="37"):
|
|
111
113
|
yield gene_line
|
112
114
|
|
113
115
|
|
114
|
-
def
|
116
|
+
def set_export_fields(panels: list[str]) -> list[tuple]:
|
117
|
+
"""Set the field that should be exported for one panel or a list of panels."""
|
118
|
+
|
119
|
+
if len(panels) == 1:
|
120
|
+
return EXPORT_PANEL_FIELDS
|
121
|
+
|
122
|
+
# if more than one panel is exported (from the CLI) - export only HGNC and symbol
|
123
|
+
return EXPORT_PANEL_FIELDS[:2]
|
124
|
+
|
125
|
+
|
126
|
+
def export_gene_panels(adapter: MongoAdapter, panels: List[str], version: float = None):
|
115
127
|
"""Export the genes of a gene panel
|
116
128
|
|
117
129
|
Takes a list of gene panel names and return the lines of the gene panels.
|
118
130
|
Unlike export_panels this function only export the genes and extra information,
|
119
131
|
not the coordinates.
|
120
132
|
|
121
|
-
Args:
|
122
|
-
adapter(MongoAdapter)
|
123
|
-
panels(list(str))
|
124
|
-
version(float): Version number, only works when one panel
|
125
|
-
|
126
133
|
Yields:
|
127
134
|
gene panel lines
|
128
135
|
"""
|
136
|
+
|
129
137
|
if version and len(panels) > 1:
|
130
138
|
raise SyntaxError("Version only possible with one panel")
|
131
139
|
|
132
|
-
bed_string = "{0}\t{1}\t{2}\t{3}\t{4}\t{5}"
|
133
|
-
|
134
|
-
headers = []
|
135
|
-
|
136
140
|
# Dictionary with hgnc ids as keys and panel gene information as value.
|
137
141
|
panel_geneobjs = dict()
|
138
142
|
|
@@ -141,29 +145,22 @@ def export_gene_panels(adapter, panels, version=None):
|
|
141
145
|
if not panel_obj:
|
142
146
|
LOG.warning("Panel %s could not be found", panel_id)
|
143
147
|
continue
|
148
|
+
panel_geneobjs.update({gene["hgnc_id"]: gene for gene in panel_obj.get("genes", [])})
|
144
149
|
|
145
|
-
|
146
|
-
panel_geneobjs[gene_obj["hgnc_id"]] = gene_obj
|
147
|
-
|
148
|
-
if len(panel_geneobjs) == 0:
|
150
|
+
if not panel_geneobjs:
|
149
151
|
return
|
150
152
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
)
|
155
|
-
|
156
|
-
for header in headers:
|
157
|
-
yield header
|
153
|
+
header = []
|
154
|
+
header.append("\t".join(fields[0] for fields in EXPORT_PANEL_FIELDS))
|
155
|
+
yield from header
|
158
156
|
|
159
|
-
for
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
)
|
169
|
-
yield gene_line
|
157
|
+
for gene_obj in panel_geneobjs.values():
|
158
|
+
gene_line_fields = [
|
159
|
+
(
|
160
|
+
",".join(gene_obj.get(gene_key, ""))
|
161
|
+
if isinstance(gene_obj.get(gene_key), list)
|
162
|
+
else str(gene_obj.get(gene_key, ""))
|
163
|
+
)
|
164
|
+
for _, gene_key in set_export_fields(panels=panels)
|
165
|
+
]
|
166
|
+
yield "\t".join(gene_line_fields)
|
scout/parse/panel.py
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
import logging
|
4
4
|
from datetime import datetime
|
5
|
-
from typing import Dict, Optional
|
5
|
+
from typing import Dict, List, Optional
|
6
6
|
|
7
7
|
from scout.constants import (
|
8
8
|
INCOMPLETE_PENETRANCE_MAP,
|
@@ -85,72 +85,63 @@ def get_hgnc_identifier(gene_info, id_type="hgnc_id"):
|
|
85
85
|
return None
|
86
86
|
|
87
87
|
|
88
|
-
def parse_gene(gene_info):
|
89
|
-
"""Parse a gene line with information from a panel file
|
88
|
+
def parse_gene(gene_info: dict) -> dict:
|
89
|
+
"""Parse a gene line with information from a panel file."""
|
90
90
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
'
|
98
|
-
|
99
|
-
|
100
|
-
'inheritance_models': list(str),
|
101
|
-
'mosaicism': bool,
|
102
|
-
'reduced_penetrance': bool,
|
103
|
-
'database_entry_version': str,
|
104
|
-
}
|
91
|
+
def get_alias_keys_value(alias_keys: list[str]) -> List[str]:
|
92
|
+
"""Collect list of strings from the alias keys present in gene_info."""
|
93
|
+
return [
|
94
|
+
item.strip()
|
95
|
+
for alias_key in alias_keys
|
96
|
+
if alias_key in gene_info
|
97
|
+
for item in gene_info[alias_key].strip('"').split(",")
|
98
|
+
if item
|
99
|
+
]
|
105
100
|
|
106
|
-
"""
|
107
101
|
gene = {}
|
108
102
|
|
103
|
+
# Parse hgnc_id and handle errors
|
109
104
|
hgnc_id = get_hgnc_identifier(gene_info, id_type="hgnc_id")
|
110
105
|
if hgnc_id is not None:
|
111
106
|
try:
|
112
107
|
hgnc_id = int(hgnc_id)
|
113
108
|
except ValueError:
|
114
|
-
raise SyntaxError("Invalid hgnc id: {
|
109
|
+
raise SyntaxError(f"Invalid hgnc id: {hgnc_id}")
|
115
110
|
|
116
111
|
gene["hgnc_id"] = hgnc_id
|
117
|
-
|
118
112
|
gene["hgnc_symbol"] = get_hgnc_identifier(gene_info, id_type="hgnc_symbol")
|
119
113
|
gene["identifier"] = hgnc_id or gene["hgnc_symbol"]
|
120
114
|
|
121
|
-
#
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
gene["transcripts"] = [
|
130
|
-
transcript.strip() for transcript in transcripts.split(",") if transcript
|
131
|
-
]
|
132
|
-
|
133
|
-
# Genetic disease models is a ','-separated list of manually curated
|
134
|
-
# inheritance patterns that are followed for a gene
|
135
|
-
models = ""
|
136
|
-
for field in PANEL_GENE_INFO_MODELS:
|
137
|
-
if field not in gene_info:
|
138
|
-
continue
|
139
|
-
models = gene_info[field].strip().strip('"')
|
115
|
+
# Add list values from alias keys
|
116
|
+
gene.update(
|
117
|
+
{
|
118
|
+
"disease_associated_transcripts": get_alias_keys_value(PANEL_GENE_INFO_TRANSCRIPTS),
|
119
|
+
"inheritance_models": get_alias_keys_value(PANEL_GENE_INFO_MODELS),
|
120
|
+
"custom_inheritance_models": get_alias_keys_value(["custom_inheritance_models"]),
|
121
|
+
}
|
122
|
+
)
|
140
123
|
|
141
|
-
#
|
142
|
-
|
143
|
-
gene["inheritance_models"] = [model.strip() for model in models.split(",") if model != ""]
|
124
|
+
# Remove empty keys
|
125
|
+
gene = {k: v for k, v in gene.items() if v}
|
144
126
|
|
145
|
-
#
|
146
|
-
gene
|
127
|
+
# Add boolean flags if they are True
|
128
|
+
gene.update(
|
129
|
+
{
|
130
|
+
key: True
|
131
|
+
for key in ["mosaicism", "reduced_penetrance"]
|
132
|
+
if gene_info.get(key) and gene_info.get(key) != ""
|
133
|
+
}
|
134
|
+
)
|
147
135
|
|
148
|
-
#
|
149
|
-
gene
|
136
|
+
# Add optional fields
|
137
|
+
gene.update(
|
138
|
+
{
|
139
|
+
key: gene_info[key]
|
140
|
+
for key in ["database_entry_version", "comment"]
|
141
|
+
if gene_info.get(key) and gene_info.get(key) != ""
|
142
|
+
}
|
143
|
+
)
|
150
144
|
|
151
|
-
# The database entry version is a way to track when a a gene was added or
|
152
|
-
# modified, optional
|
153
|
-
gene["database_entry_version"] = gene_info.get("database_entry_version")
|
154
145
|
return gene
|
155
146
|
|
156
147
|
|
@@ -127,6 +127,9 @@ def sashimi_igv(
|
|
127
127
|
@alignviewers_bp.route(
|
128
128
|
"/<institute_id>/<case_name>/<variant_id>/<chrom>/<start>/<stop>/igv", methods=["GET"]
|
129
129
|
) # from SV variant page, where you have to pass breakpoints coordinates
|
130
|
+
@alignviewers_bp.route(
|
131
|
+
"/<institute_id>/<case_name>/<chrom>/<start>/<stop>/igv", methods=["GET"]
|
132
|
+
) # from SMN variant page
|
130
133
|
def igv(
|
131
134
|
institute_id: str,
|
132
135
|
case_name: str,
|
@@ -20,6 +20,7 @@ from scout.constants import (
|
|
20
20
|
CASE_TAGS,
|
21
21
|
CUSTOM_CASE_REPORTS,
|
22
22
|
DATE_DAY_FORMATTER,
|
23
|
+
GENOME_REGION,
|
23
24
|
INHERITANCE_PALETTE,
|
24
25
|
MITODEL_HEADER,
|
25
26
|
MT_COV_STATS_HEADER,
|
@@ -282,11 +283,14 @@ def sma_case(store, institute_obj, case_obj):
|
|
282
283
|
|
283
284
|
_populate_case_individuals(case_obj)
|
284
285
|
|
286
|
+
case_has_alignments(case_obj)
|
287
|
+
|
285
288
|
data = {
|
286
289
|
"institute": institute_obj,
|
287
290
|
"case": case_obj,
|
288
291
|
"comments": store.events(institute_obj, case=case_obj, comments=True),
|
289
292
|
"events": _get_events(store, institute_obj, case_obj),
|
293
|
+
"region": GENOME_REGION[case_obj.get("genome_build", "38")],
|
290
294
|
}
|
291
295
|
return data
|
292
296
|
|
@@ -50,7 +50,7 @@
|
|
50
50
|
</div>
|
51
51
|
</div> <!-- end of div class row -->
|
52
52
|
|
53
|
-
<
|
53
|
+
<span class="d-flex">
|
54
54
|
{% if case.vcf_files.vcf_snv %}
|
55
55
|
<span class="me-3">
|
56
56
|
<form action="{{url_for('variants.variants', institute_id=institute._id, case_name=case.display_name) }}">
|
@@ -61,11 +61,19 @@
|
|
61
61
|
</span>
|
62
62
|
{% endif %}
|
63
63
|
{% if case.vcf_files.vcf_sv %}
|
64
|
-
<
|
65
|
-
<
|
66
|
-
|
67
|
-
|
68
|
-
|
64
|
+
<span class="me-3">
|
65
|
+
<form action="{{url_for('variants.sv_variants', institute_id=institute._id, case_name=case.display_name) }}">
|
66
|
+
<input type="hidden" id="hgnc_symbols" name="hgnc_symbols" value="SMN1, SMN2"></input>
|
67
|
+
<input type="hidden" id="gene_panels" name="gene_panels" value="['']"></input>
|
68
|
+
<button type="submit" class="btn btn-secondary btn-sm" target="_blank" rel="noopener" data-bs-toggle="tooltip" title="Structural variants view filtered for the genes SMN1 and SMN2">SVs</button></span>
|
69
|
+
</form>
|
70
|
+
</span>
|
71
|
+
{% endif %}
|
72
|
+
{% if case.bam_files %}
|
73
|
+
<span class="me-3"><a class="btn btn-secondary btn-sm text-white" href="{{url_for('alignviewers.igv', institute_id=case['owner'], case_name=case['display_name'], chrom=region['smn1']['chrom'], start=region['smn1']['start'], stop=region['smn1']['end'] )}}" target="_blank">IGV viewer SMN1</a></span>
|
74
|
+
<span class="me-3"><a class="btn btn-secondary btn-sm text-white" href="{{url_for('alignviewers.igv', institute_id=case['owner'], case_name=case['display_name'], chrom=region['smn2']['chrom'], start=region['smn2']['start'], stop=region['smn2']['end'] )}}" target="_blank">IGV viewer SMN2</a></span>
|
75
|
+
{% else %}
|
76
|
+
<span class="me-3 text-muted">BAM file(s) missing</span>
|
69
77
|
{% endif %}
|
70
78
|
</div>
|
71
79
|
|
@@ -90,16 +90,24 @@
|
|
90
90
|
<div href="#" class="bg-dark list-group-item text-white">
|
91
91
|
<div class="d-flex flex-row flex-fill bd-highlight">
|
92
92
|
<span class="menu-collapsed">Coverage (chanjo2)</span>
|
93
|
-
{{ chanjo2_report_form(institute, case, case.panel_names|join(', '), 'report', case.default_genes|join(','), "<span class='fa fa-link'></span>"|safe ) }} <!--chanjo2 report-->
|
93
|
+
{{ chanjo2_report_form(institute, case, case.panel_names|join(', '), 'report', case.default_genes|join(','), "<span class='fa fa-link' style='cursor: pointer;'></span>"|safe ) }} <!--chanjo2 report-->
|
94
94
|
</div>
|
95
95
|
</div>
|
96
|
+
{% if "38" in case.genome_build %}
|
97
|
+
<div href="#" class="bg-dark list-group-item text-white">
|
98
|
+
<div class="d-flex flex-row flex-fill bd-highlight">
|
99
|
+
<span class="menu-collapsed">MANE Coverage (chanjo2)</span>
|
100
|
+
{{ chanjo2_report_form(institute, case, case.panel_names|join(', '), 'mane_overview', case.default_genes|join(','), "<span class='fa fa-link' style='cursor: pointer;'></span>"|safe ) }} <!--chanjo2 MANE overview-->
|
101
|
+
</div>
|
102
|
+
</div>
|
103
|
+
{% endif %}
|
96
104
|
{% endif %}
|
97
105
|
{% if case.chanjo_coverage %}
|
98
106
|
<div href="#" class="bg-dark list-group-item text-white">
|
99
107
|
<div class="d-flex flex-row flex-fill bd-highlight">
|
100
108
|
<span class="menu-collapsed">Coverage</span>
|
101
109
|
<form method="POST" id="coverage_html" target="_blank" rel="noopener" action="{{ url_for('report.report', sample_id=case.individual_ids, level=institute.coverage_cutoff, panel_name=case.panel_names|join(', ')) }}">
|
102
|
-
<input type="hidden" name="gene_ids" value="{{ case.default_genes|join(',') }}"
|
110
|
+
<input type="hidden" name="gene_ids" value="{{ case.default_genes|join(',') }}"/>
|
103
111
|
<a href="javascript:;" onclick="document.getElementById('coverage_html').submit();">
|
104
112
|
<span class="fa fa-link"></span></a>
|
105
113
|
</form>
|
@@ -155,8 +155,13 @@
|
|
155
155
|
<div class="card">
|
156
156
|
<div class="card-header" id="heading_{{match_obj.match_oid}}">
|
157
157
|
<h2 class="mb-0">
|
158
|
-
<button class="btn btn-link collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#div_{{match_obj.match_oid}}" aria-expanded="false" aria-controls="collapseTwo">
|
158
|
+
<button class="btn btn-link collapsed" type="button" {% if match_obj.patients|length == 0 %} disabled {% endif %} data-bs-toggle="collapse" data-bs-target="#div_{{match_obj.match_oid}}" aria-expanded="false" aria-controls="collapseTwo">
|
159
159
|
Match {{match_obj.match_date.strftime('%Y-%m-%d %H:%M')}}
|
160
|
+
{% if match_obj.patients %}
|
161
|
+
<span class="badge rounded-pill bg-success ms-3">matches: {{match_obj.patients|length}}</span>
|
162
|
+
{% else %}
|
163
|
+
<span class="badge rounded-pill bg-secondary ms-3">No matches available</span>
|
164
|
+
{% endif %}
|
160
165
|
</button>
|
161
166
|
</h2>
|
162
167
|
</div>
|
@@ -177,14 +182,14 @@
|
|
177
182
|
{% for match_result in match_obj.patients %}
|
178
183
|
<tr class="{{ loop.cycle('odd', 'even') }}">
|
179
184
|
<td style="width: 5%" class="border-bottom-0"><span class="badge bg-primary rounded-pill">{{match_result.score.patient|round(4)}}</td>
|
180
|
-
<td style="width: 10%">{{match_result.node.label}}</td>
|
181
|
-
<td style="width: 15%">
|
185
|
+
<td style="width: 10%" class="text-body"><strong>{{match_result.node.label}}</strong></td>
|
186
|
+
<td style="width: 15%" class="text-body">
|
182
187
|
{% if "http" in match_result.patient_id %}
|
183
188
|
<a href="{{match_result.patient_id}}" target="_blank">link</a>
|
184
189
|
{% else %}
|
185
190
|
<strong>{{match_result.patient_id}}</strong></td>
|
186
191
|
{% endif %}
|
187
|
-
<td style="width: 20%" class="text-break">
|
192
|
+
<td style="width: 20%" class="text-break text-body">
|
188
193
|
{{match_result.patient.contact.name}}<br>
|
189
194
|
{% if "http" in match_result.patient.contact.href %}
|
190
195
|
<a href="{{match_result.patient.contact.href}}" target="_blank">contact link</a>
|
@@ -198,7 +203,7 @@
|
|
198
203
|
<br>{{match_result.patient.contact.email|replace("mailto:","")}}
|
199
204
|
{% endif %}
|
200
205
|
</td>
|
201
|
-
<td style="width: 35%">
|
206
|
+
<td style="width: 35%" class="text-body">
|
202
207
|
{% for feature in match_result.patient.features %}
|
203
208
|
<span data-bs-toggle="tooltip" title="{{feature.label or 'description not available'}}" class="badge bg-info">{{feature.label}}({{feature.id}})</span>
|
204
209
|
{% else %}
|
@@ -219,10 +224,10 @@
|
|
219
224
|
{% if match_result.patient.genomicFeatures%}
|
220
225
|
<tr class="{{ loop.cycle('odd', 'even') }}">
|
221
226
|
<td class="border-top-0"></td>
|
222
|
-
<td style="width: 20%"><strong>Gene/Variants:</strong></td>
|
227
|
+
<td style="width: 20%" class="text-body"><strong>Gene/Variants:</strong></td>
|
223
228
|
<td colspan="5">
|
224
229
|
{% for g_feat in match_result.patient.genomicFeatures %}
|
225
|
-
<div style="display: flex;">
|
230
|
+
<div style="display: flex;" class="text-body">
|
226
231
|
<div style="margin-left: 20px;"><strong>{{loop.index}}</strong></div>
|
227
232
|
<ul>
|
228
233
|
<li><strong>{{ g_feat.gene._geneName}}</strong>
|
@@ -10,7 +10,13 @@ from pymongo.cursor import Cursor
|
|
10
10
|
from werkzeug.datastructures import Headers, MultiDict
|
11
11
|
|
12
12
|
from scout.adapter.mongo.base import MongoAdapter
|
13
|
-
from scout.constants import
|
13
|
+
from scout.constants import (
|
14
|
+
CASE_STATUSES,
|
15
|
+
DATE_DAY_FORMATTER,
|
16
|
+
ID_PROJECTION,
|
17
|
+
PHENOTYPE_GROUPS,
|
18
|
+
VARIANTS_TARGET_FROM_CATEGORY,
|
19
|
+
)
|
14
20
|
from scout.server.blueprints.variant.utils import predictions, update_representative_gene
|
15
21
|
from scout.server.extensions import beacon, store
|
16
22
|
from scout.server.utils import institute_and_case, user_institutes
|
@@ -434,7 +440,7 @@ def cases(store, request, institute_id):
|
|
434
440
|
data["institute"] = institute_obj
|
435
441
|
|
436
442
|
name_query = request.form
|
437
|
-
limit = int(request.
|
443
|
+
limit = int(request.form.get("search_limit")) if request.form.get("search_limit") else 100
|
438
444
|
|
439
445
|
data["form"] = CaseFilterForm(request.form)
|
440
446
|
|
@@ -669,7 +675,7 @@ def export_gene_variants(
|
|
669
675
|
variant_line.append(variant.get("display_name")) # Position
|
670
676
|
variant_line.append(str(variant.get("rank_score", ""))) # Score
|
671
677
|
variant_genes = [
|
672
|
-
gene.get("hgnc_symbol", gene.get("hgnc_id")) for gene in variant.get("genes", [])
|
678
|
+
gene.get("hgnc_symbol", str(gene.get("hgnc_id"))) for gene in variant.get("genes", [])
|
673
679
|
]
|
674
680
|
variant_line.append(" | ".join(variant_genes)) # Genes
|
675
681
|
|
@@ -736,7 +742,8 @@ def gene_variants(store, pymongo_cursor, variant_count, page=1, per_page=50):
|
|
736
742
|
def filters(store, institute_id):
|
737
743
|
"""Retrieve all filters for an institute"""
|
738
744
|
filters = []
|
739
|
-
|
745
|
+
|
746
|
+
categories = VARIANTS_TARGET_FROM_CATEGORY.keys()
|
740
747
|
for category in categories:
|
741
748
|
category_filters = store.filters(institute_id, category)
|
742
749
|
filters.extend(category_filters)
|
@@ -29,7 +29,7 @@
|
|
29
29
|
<div class="container-float">
|
30
30
|
<div class="row" id="body-row"> <!--sidebar and main container are on the same row-->
|
31
31
|
<div class="col-12">
|
32
|
-
{{ variant_list_content(institute, causatives, acmg_map, callers) }}
|
32
|
+
{{ variant_list_content(institute, causatives, acmg_map, callers, inherit_palette) }}
|
33
33
|
</div>
|
34
34
|
</div> <!-- end of div id body-row -->
|
35
35
|
</div>
|
@@ -1,5 +1,5 @@
|
|
1
1
|
{% extends "layout.html" %}
|
2
|
-
{% from "variants/components.html" import frequency_cell_general, variant_funct_anno_cell, variant_gene_symbols_cell
|
2
|
+
{% from "variants/components.html" import frequency_cell_general, variant_funct_anno_cell, variant_gene_symbols_cell %}
|
3
3
|
{% from "utils.html" import comments_table %}
|
4
4
|
{% from "overview/institute_sidebar.html" import institute_actionbar %}
|
5
5
|
{% from "variants/utils.html" import pagination_footer, pagination_hidden_div %}
|
@@ -43,7 +43,6 @@
|
|
43
43
|
<th scope="col">Gene</th>
|
44
44
|
<th scope="col">Pop Freq</th>
|
45
45
|
<th scope="col">CADD</th>
|
46
|
-
<th scope="col">Region</th>
|
47
46
|
<th scope="col">Function</th>
|
48
47
|
</tr>
|
49
48
|
</thead>
|
@@ -56,16 +55,15 @@
|
|
56
55
|
{% endif %}
|
57
56
|
<td class="align-middle">{{ cell_rank(variant) }}</td>
|
58
57
|
<td class="align-middle">{{ pretty_link_no_gene(variant) }} </td>
|
59
|
-
<td class="align-middle">{{ variant_gene_symbols_cell(variant) }}</td>
|
58
|
+
<td class="align-middle">{{ variant_gene_symbols_cell(variant, inherit_palette) }}</td>
|
60
59
|
<td class="align-middle">{{ frequency_cell_general(variant) }}</td>
|
61
60
|
<td class="align-middle">{{ cell_cadd(variant) }}</td>
|
62
|
-
<td class="align-middle">{{ variant_region_anno_cell(variant) }}</td>
|
63
61
|
<td class="align-middle">{{ variant_funct_anno_cell(variant) }}</td>
|
64
62
|
</tr>
|
65
63
|
{% endfor %}
|
66
64
|
{% if form.hgnc_symbols.data == [] %}
|
67
65
|
<tr>
|
68
|
-
<td colspan=
|
66
|
+
<td colspan=6>
|
69
67
|
No variants to display
|
70
68
|
</td>
|
71
69
|
</tr>
|
@@ -311,7 +311,7 @@
|
|
311
311
|
{% endmacro %}
|
312
312
|
|
313
313
|
|
314
|
-
{% macro variant_list_content(institute, variants, acmg_map, callers) %}
|
314
|
+
{% macro variant_list_content(institute, variants, acmg_map, callers, inherit_palette) %}
|
315
315
|
<div class="card mt-3">
|
316
316
|
<div class="card-body overflow-auto">
|
317
317
|
<table id="variants_table" class="table display table-sm">
|
@@ -348,7 +348,7 @@
|
|
348
348
|
{% if variant.category == "fusion" %}
|
349
349
|
{{ fusion_variant_gene_symbols_cell(variant) }}
|
350
350
|
{% else %}
|
351
|
-
{{ variant_gene_symbols_cell(variant) }}
|
351
|
+
{{ variant_gene_symbols_cell(variant, inherit_palette) }}
|
352
352
|
{% endif %}
|
353
353
|
</td>
|
354
354
|
<td><!-- Variant link -->
|
@@ -58,7 +58,7 @@
|
|
58
58
|
{{validated_chart()}}
|
59
59
|
</div>
|
60
60
|
<div class="row">
|
61
|
-
<div class="col-12">{{ variant_list_content(institute, verified, acmg_map, callers) }}</div>
|
61
|
+
<div class="col-12">{{ variant_list_content(institute, verified, acmg_map, callers, inherit_palette) }}</div>
|
62
62
|
</div>
|
63
63
|
</div>
|
64
64
|
</div>
|
@@ -6,7 +6,14 @@ from flask import Blueprint, flash, jsonify, redirect, render_template, request
|
|
6
6
|
from flask_login import current_user
|
7
7
|
from pymongo import DESCENDING
|
8
8
|
|
9
|
-
from scout.constants import
|
9
|
+
from scout.constants import (
|
10
|
+
ACMG_COMPLETE_MAP,
|
11
|
+
ACMG_MAP,
|
12
|
+
CALLERS,
|
13
|
+
INHERITANCE_PALETTE,
|
14
|
+
VERBS_ICONS_MAP,
|
15
|
+
VERBS_MAP,
|
16
|
+
)
|
10
17
|
from scout.server.blueprints.variants.controllers import update_form_hgnc_symbols
|
11
18
|
from scout.server.extensions import beacon, loqusdb, store
|
12
19
|
from scout.server.utils import institute_and_case, jsonconverter, templated, user_institutes
|
@@ -63,11 +70,12 @@ def verified(institute_id):
|
|
63
70
|
verified_vars = controllers.verified_vars(institute_id)
|
64
71
|
verified_stats = controllers.verified_stats(institute_id, verified_vars)
|
65
72
|
return dict(
|
73
|
+
acmg_map={key: ACMG_COMPLETE_MAP[value] for key, value in ACMG_MAP.items()},
|
74
|
+
callers=CALLERS,
|
75
|
+
inherit_palette=INHERITANCE_PALETTE,
|
66
76
|
institute=institute_obj,
|
67
77
|
verified=verified_vars,
|
68
78
|
verified_stats=verified_stats,
|
69
|
-
acmg_map={key: ACMG_COMPLETE_MAP[value] for key, value in ACMG_MAP.items()},
|
70
|
-
callers=CALLERS,
|
71
79
|
)
|
72
80
|
|
73
81
|
|
@@ -76,10 +84,11 @@ def verified(institute_id):
|
|
76
84
|
def causatives(institute_id):
|
77
85
|
institute_obj = institute_and_case(store, institute_id)
|
78
86
|
return dict(
|
79
|
-
institute=institute_obj,
|
80
|
-
causatives=controllers.causatives(institute_obj, request),
|
81
87
|
acmg_map={key: ACMG_COMPLETE_MAP[value] for key, value in ACMG_MAP.items()},
|
82
88
|
callers=CALLERS,
|
89
|
+
causatives=controllers.causatives(institute_obj, request),
|
90
|
+
institute=institute_obj,
|
91
|
+
inherit_palette=INHERITANCE_PALETTE,
|
83
92
|
)
|
84
93
|
|
85
94
|
|
@@ -168,7 +177,14 @@ def gene_variants(institute_id):
|
|
168
177
|
store, results, result_size, page
|
169
178
|
) # decorated variant results, max 50 in a page
|
170
179
|
|
171
|
-
return dict(
|
180
|
+
return dict(
|
181
|
+
institute=institute_obj,
|
182
|
+
form=form,
|
183
|
+
inherit_palette=INHERITANCE_PALETTE,
|
184
|
+
page=page,
|
185
|
+
result_size=result_size,
|
186
|
+
**data,
|
187
|
+
)
|
172
188
|
|
173
189
|
|
174
190
|
# MOST OF THE CONTENT OF THIS ENDPOINT WILL BE REMOVED AND INCLUDED INTO THE BEACON EXTENSION UNDER SERVER/EXTENSIONS
|