scout-browser 4.84__py3-none-any.whl → 4.86__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/base.py +17 -14
- scout/adapter/mongo/case.py +20 -1
- scout/adapter/mongo/cytoband.py +13 -0
- scout/adapter/mongo/filter.py +36 -1
- scout/adapter/mongo/hgnc.py +1 -1
- scout/adapter/mongo/omics_variant.py +145 -0
- scout/adapter/mongo/query.py +13 -3
- scout/adapter/mongo/variant.py +10 -4
- scout/build/case.py +5 -0
- scout/build/variant/variant.py +1 -0
- scout/commands/update/genes.py +9 -13
- scout/constants/__init__.py +3 -1
- scout/constants/case_tags.py +1 -0
- scout/constants/clinvar.py +1 -1
- scout/constants/file_types.py +31 -0
- scout/constants/filters.py +4 -0
- scout/constants/indexes.py +30 -13
- scout/constants/variant_tags.py +3 -0
- scout/demo/643594.clinical.mei.vcf.gz +0 -0
- scout/demo/643594.clinical.mei.vcf.gz.tbi +0 -0
- scout/demo/643594.config.yaml +4 -0
- scout/demo/drop/fraser_top_hits_clinical.tsv +5 -0
- scout/demo/drop/outrider_top_hits_clinical.tsv +10 -0
- scout/load/hgnc_gene.py +39 -6
- scout/load/setup.py +4 -4
- scout/models/case/case_loading_models.py +25 -2
- scout/models/omics_variant.py +227 -0
- scout/parse/hgnc.py +1 -0
- scout/parse/omics_variant/__init__.py +11 -0
- scout/parse/omics_variant/drop.py +19 -0
- scout/parse/variant/callers.py +6 -3
- scout/parse/variant/frequency.py +10 -2
- scout/parse/variant/transcript.py +1 -1
- scout/parse/variant/variant.py +10 -4
- scout/server/app.py +4 -1
- scout/server/blueprints/alignviewers/controllers.py +35 -24
- scout/server/blueprints/alignviewers/templates/alignviewers/igv_sashimi_viewer.html +19 -15
- scout/server/blueprints/alignviewers/templates/alignviewers/igv_viewer.html +45 -5
- scout/server/blueprints/alignviewers/templates/alignviewers/utils.html +1 -1
- scout/server/blueprints/alignviewers/views.py +10 -2
- scout/server/blueprints/cases/controllers.py +18 -1
- scout/server/blueprints/cases/templates/cases/case.html +28 -10
- scout/server/blueprints/cases/templates/cases/case_report.html +2 -17
- scout/server/blueprints/cases/templates/cases/collapsible_actionbar.html +1 -1
- scout/server/blueprints/cases/templates/cases/gene_panel.html +27 -41
- scout/server/blueprints/cases/templates/cases/phenotype.html +8 -5
- scout/server/blueprints/cases/templates/cases/utils.html +27 -4
- scout/server/blueprints/clinvar/controllers.py +9 -3
- scout/server/blueprints/dashboard/controllers.py +44 -13
- scout/server/blueprints/dashboard/static/charts.js +46 -36
- scout/server/blueprints/dashboard/templates/dashboard/dashboard_general.html +2 -2
- scout/server/blueprints/institutes/forms.py +2 -0
- scout/server/blueprints/institutes/templates/overview/cases.html +6 -4
- scout/server/blueprints/institutes/templates/overview/gene_variants.html +40 -27
- scout/server/blueprints/institutes/templates/overview/institute_sidebar.html +1 -1
- scout/server/blueprints/institutes/views.py +5 -12
- scout/server/blueprints/omics_variants/__init__.py +1 -0
- scout/server/blueprints/omics_variants/controllers.py +122 -0
- scout/server/blueprints/omics_variants/templates/omics_variants/outliers.html +262 -0
- scout/server/blueprints/omics_variants/views.py +106 -0
- scout/server/blueprints/panels/controllers.py +1 -7
- scout/server/blueprints/panels/templates/panels/panels.html +12 -4
- scout/server/blueprints/panels/views.py +9 -11
- scout/server/blueprints/variant/templates/variant/buttons.html +7 -2
- scout/server/blueprints/variant/templates/variant/str-variant-reviewer.html +1 -1
- scout/server/blueprints/variant/templates/variant/utils.html +1 -1
- scout/server/blueprints/variant/utils.py +54 -103
- scout/server/blueprints/variant/views.py +1 -0
- scout/server/blueprints/variants/controllers.py +1 -4
- scout/server/blueprints/variants/forms.py +42 -0
- scout/server/blueprints/variants/templates/variants/utils.html +8 -4
- scout/server/blueprints/variants/views.py +28 -7
- scout/server/config.py +4 -0
- scout/server/extensions/clinvar_extension.py +7 -7
- scout/server/links.py +2 -2
- scout/server/templates/bootstrap_global.html +1 -4
- scout/server/templates/utils.html +4 -4
- scout/server/utils.py +4 -1
- {scout_browser-4.84.dist-info → scout_browser-4.86.dist-info}/METADATA +11 -11
- {scout_browser-4.84.dist-info → scout_browser-4.86.dist-info}/RECORD +85 -75
- {scout_browser-4.84.dist-info → scout_browser-4.86.dist-info}/WHEEL +1 -1
- {scout_browser-4.84.dist-info → scout_browser-4.86.dist-info}/LICENSE +0 -0
- {scout_browser-4.84.dist-info → scout_browser-4.86.dist-info}/entry_points.txt +0 -0
- {scout_browser-4.84.dist-info → scout_browser-4.86.dist-info}/top_level.txt +0 -0
scout/parse/variant/variant.py
CHANGED
@@ -231,10 +231,7 @@ def parse_variant(
|
|
231
231
|
parsed_variant["revel_score"] = parsed_transcripts[0].get(
|
232
232
|
"revel_rankscore"
|
233
233
|
) # This is actually the value of REVEL_rankscore
|
234
|
-
|
235
|
-
parsed_variant["revel"] = parsed_transcripts[0].get(
|
236
|
-
"revel_raw_score"
|
237
|
-
) # This is actually the value of REVEL_score
|
234
|
+
parsed_variant["revel"] = get_highest_revel_score(parsed_transcripts)
|
238
235
|
|
239
236
|
###################### Add conservation ######################
|
240
237
|
parsed_variant["conservation"] = parse_conservations(variant, parsed_transcripts)
|
@@ -261,6 +258,15 @@ def parse_variant(
|
|
261
258
|
return parsed_variant
|
262
259
|
|
263
260
|
|
261
|
+
def get_highest_revel_score(parsed_transcripts: List[dict]) -> Optional[float]:
|
262
|
+
"""Retrieve the highest REVEL_score value from parsed variant transcripts."""
|
263
|
+
tx_revel_scores: List(float) = [
|
264
|
+
tx.get("revel_raw_score") for tx in parsed_transcripts if tx.get("revel_raw_score") != None
|
265
|
+
]
|
266
|
+
if tx_revel_scores:
|
267
|
+
return max(tx_revel_scores)
|
268
|
+
|
269
|
+
|
264
270
|
def get_genmod_key(case):
|
265
271
|
"""Gen genmod key
|
266
272
|
|
scout/server/app.py
CHANGED
@@ -7,7 +7,7 @@ from typing import Dict, Union
|
|
7
7
|
from urllib.parse import parse_qsl, unquote, urlsplit
|
8
8
|
|
9
9
|
import coloredlogs
|
10
|
-
from flask import Flask,
|
10
|
+
from flask import Flask, redirect, request, url_for
|
11
11
|
from flask_cors import CORS
|
12
12
|
from flask_login import current_user
|
13
13
|
from markdown import markdown as python_markdown
|
@@ -25,6 +25,7 @@ from .blueprints import (
|
|
25
25
|
institutes,
|
26
26
|
login,
|
27
27
|
managed_variants,
|
28
|
+
omics_variants,
|
28
29
|
panels,
|
29
30
|
phenomodels,
|
30
31
|
phenotypes,
|
@@ -98,6 +99,7 @@ def configure_extensions(app):
|
|
98
99
|
extensions.store.init_app(app)
|
99
100
|
extensions.login_manager.init_app(app)
|
100
101
|
extensions.mail.init_app(app)
|
102
|
+
extensions.clinvar_api.init_app(app)
|
101
103
|
|
102
104
|
if app.config.get("SQLALCHEMY_DATABASE_URI"):
|
103
105
|
extensions.chanjo_report.init_app(app)
|
@@ -177,6 +179,7 @@ def register_blueprints(app):
|
|
177
179
|
app.register_blueprint(diagnoses.omim_bp)
|
178
180
|
app.register_blueprint(institutes.overview)
|
179
181
|
app.register_blueprint(managed_variants.managed_variants_bp)
|
182
|
+
app.register_blueprint(omics_variants.omics_variants_bp)
|
180
183
|
|
181
184
|
|
182
185
|
def register_filters(app):
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
import logging
|
3
3
|
import os.path
|
4
|
-
from typing import Dict
|
4
|
+
from typing import Dict, Optional
|
5
5
|
|
6
6
|
from flask import flash, session
|
7
7
|
from flask_login import current_user
|
@@ -12,7 +12,7 @@ from scout.server.utils import case_append_alignments, find_index
|
|
12
12
|
from scout.utils.ensembl_rest_clients import EnsemblRestApiClient
|
13
13
|
|
14
14
|
LOG = logging.getLogger(__name__)
|
15
|
-
|
15
|
+
DEFAULT_TRACK_NAMES = ["Genes", "ClinVar", "ClinVar CNVs"]
|
16
16
|
|
17
17
|
|
18
18
|
def check_session_tracks(resource):
|
@@ -51,33 +51,39 @@ def set_session_tracks(display_obj: dict):
|
|
51
51
|
session["igv_tracks"] = session_tracks
|
52
52
|
|
53
53
|
|
54
|
-
def make_igv_tracks(
|
54
|
+
def make_igv_tracks(
|
55
|
+
case_obj: dict,
|
56
|
+
variant_id: str,
|
57
|
+
chrom: Optional[str] = None,
|
58
|
+
start: Optional[int] = None,
|
59
|
+
stop: Optional[int] = None,
|
60
|
+
) -> dict:
|
55
61
|
"""Create a dictionary containing the required tracks for displaying IGV tracks for case or a group of cases
|
56
62
|
|
57
63
|
Args:
|
58
|
-
institute_id
|
64
|
+
institute_id: institute _id
|
59
65
|
case_obj(scout.models.Case)
|
60
|
-
variant_id
|
61
|
-
chrom
|
62
|
-
start
|
63
|
-
stop
|
66
|
+
variant_id: _id of a variant
|
67
|
+
chrom: requested chromosome [1-22], X, Y, [M-MT]
|
68
|
+
start: start of the genomic interval to be displayed
|
69
|
+
stop: stop of the genomic interval to be displayed
|
64
70
|
|
65
71
|
Returns:
|
66
|
-
display_obj
|
72
|
+
display_obj: A display object containing case name, list of genes, locus and tracks
|
67
73
|
"""
|
68
74
|
display_obj = {}
|
69
75
|
variant_obj = store.variant(document_id=variant_id)
|
70
76
|
|
77
|
+
chromosome = "All"
|
71
78
|
if variant_obj:
|
72
79
|
# Set display locus
|
73
80
|
start = start or variant_obj["position"]
|
74
81
|
stop = stop or variant_obj["end"]
|
82
|
+
chrom = chrom or variant_obj.get("chromosome")
|
75
83
|
|
76
|
-
|
77
|
-
chromosome =
|
84
|
+
if all([start, stop, chrom]):
|
85
|
+
chromosome = chrom.replace("MT", "M")
|
78
86
|
display_obj["locus"] = "chr{0}:{1}-{2}".format(chromosome, start, stop)
|
79
|
-
else:
|
80
|
-
chromosome = "All"
|
81
87
|
|
82
88
|
# Set genome build for displaying alignments:
|
83
89
|
if "38" in str(case_obj.get("genome_build", "37")) or chromosome == "M":
|
@@ -115,20 +121,27 @@ def make_igv_tracks(case_obj, variant_id, chrom=None, start=None, stop=None):
|
|
115
121
|
return display_obj
|
116
122
|
|
117
123
|
|
118
|
-
def make_sashimi_tracks(
|
124
|
+
def make_sashimi_tracks(
|
125
|
+
case_obj: dict, variant_id: Optional[str] = None, omics_variant_id: Optional[str] = None
|
126
|
+
):
|
119
127
|
"""Create a dictionary containing the required tracks for a splice junction plot
|
128
|
+
If either a regular variant_id or an omics variant id is passed, set display to a particular locus.
|
129
|
+
Otherwise defaults to whole genome "All" view.
|
120
130
|
|
121
|
-
Args:
|
122
|
-
case_obj(scout.models.Case)
|
123
|
-
variant_id(str) _id of a variant
|
124
131
|
Returns:
|
125
|
-
display_obj(dict): A display object containing case name, list of genes,
|
132
|
+
display_obj(dict): A display object containing case name, list of genes, locus and tracks
|
126
133
|
"""
|
127
134
|
build = "38" # This feature is only available for RNA tracks in build 38
|
128
135
|
|
129
136
|
locus = "All"
|
137
|
+
variant_obj = None
|
138
|
+
|
130
139
|
if variant_id:
|
131
140
|
variant_obj = store.variant(document_id=variant_id)
|
141
|
+
if omics_variant_id:
|
142
|
+
variant_obj = store.omics_variant(variant_id=omics_variant_id)
|
143
|
+
|
144
|
+
if variant_obj:
|
132
145
|
locus = make_locus_from_variant(variant_obj, case_obj, build)
|
133
146
|
|
134
147
|
display_obj = {"locus": locus, "tracks": []}
|
@@ -234,9 +247,9 @@ def set_common_tracks(display_obj, build):
|
|
234
247
|
# Set up IGV tracks that are common for all cases:
|
235
248
|
display_obj["reference_track"] = HUMAN_REFERENCE[build] # Human reference is always present
|
236
249
|
|
237
|
-
# if user settings for igv tracks exist -> use these settings, otherwise display
|
250
|
+
# if user settings for igv tracks exist -> use these settings, otherwise display default tracks ---> Genes, ClinVar and ClinVar CNVs
|
238
251
|
custom_tracks_names = (
|
239
|
-
user_obj.get("igv_tracks") if "igv_tracks" in user_obj else
|
252
|
+
user_obj.get("igv_tracks") if "igv_tracks" in user_obj else DEFAULT_TRACK_NAMES
|
240
253
|
)
|
241
254
|
|
242
255
|
display_obj["custom_tracks"] = []
|
@@ -300,7 +313,6 @@ def set_config_custom_tracks(display_obj: dict, build: str):
|
|
300
313
|
"""Set up custom public or private tracks stored in a cloud bucket or locally. These tracks were those specified in the Scout config file.
|
301
314
|
Respect user's preferences."""
|
302
315
|
user_obj = store.user(email=current_user.email)
|
303
|
-
custom_tracks_names = user_obj.get("igv_tracks")
|
304
316
|
|
305
317
|
config_custom_tracks = []
|
306
318
|
|
@@ -308,8 +320,7 @@ def set_config_custom_tracks(display_obj: dict, build: str):
|
|
308
320
|
build_tracks = config_igv_tracks.tracks.get(build, [])
|
309
321
|
for track in build_tracks:
|
310
322
|
# Do not display track if user doesn't want to see it
|
311
|
-
if
|
312
|
-
|
313
|
-
config_custom_tracks.append(track)
|
323
|
+
if "igv_tracks" not in user_obj or track["name"] in user_obj.get("igv_tracks"):
|
324
|
+
config_custom_tracks.append(track)
|
314
325
|
if config_custom_tracks:
|
315
326
|
display_obj["config_custom_tracks"] = config_custom_tracks
|
@@ -79,6 +79,7 @@
|
|
79
79
|
type: 'wig',
|
80
80
|
format: "bigwig",
|
81
81
|
url: "{{ url_for('alignviewers.remote_static', file=track.coverage_wig) }}",
|
82
|
+
height: 500,
|
82
83
|
},
|
83
84
|
{
|
84
85
|
type: 'spliceJunctions',
|
@@ -88,24 +89,27 @@
|
|
88
89
|
labelUniqueReadCount: true,
|
89
90
|
url: "{{ url_for('alignviewers.remote_static', file=track.splicej_bed) }}",
|
90
91
|
indexURL: "{{ url_for('alignviewers.remote_static', file=track.splicej_bed_index) }}",
|
91
|
-
minUniquelyMappedReads: 1
|
92
|
+
minUniquelyMappedReads: 1,
|
93
|
+
height: 500,
|
92
94
|
},
|
93
95
|
]
|
94
96
|
}, // end of sashimi track with data
|
95
|
-
{
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
97
|
+
{% if custom_tracks|selectattr("name","equalto", "Genes")|list|length > 0 %}
|
98
|
+
{ // genes track
|
99
|
+
name: geneTrack.name,
|
100
|
+
type: geneTrack.type,
|
101
|
+
format: geneTrack.format,
|
102
|
+
sourceType: geneTrack.sourceType,
|
103
|
+
url: geneTrack.url,
|
104
|
+
indexURL: geneTrack.indexURL,
|
105
|
+
displayMode: geneTrack.displayMode,
|
106
|
+
visibilityWindow: 300000000,
|
107
|
+
height: 100,
|
108
|
+
searchable: true,
|
109
|
+
order: {{counter.loop}},
|
110
|
+
infoURL: "https://www.ncbi.nlm.nih.gov/gene/?term=$$"
|
111
|
+
}, // end of genes track
|
112
|
+
{% endif %}
|
109
113
|
{% endif %}
|
110
114
|
{% endfor %}
|
111
115
|
] // end of tracks
|
@@ -14,14 +14,11 @@
|
|
14
14
|
<link rel="stylesheet" type="text/css"
|
15
15
|
href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/themes/smoothness/jquery-ui.css"/>
|
16
16
|
|
17
|
-
<!-- Font Awesome CSS -->
|
18
|
-
<link rel="stylesheet" type="text/css"
|
19
|
-
href="https://maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css"/>
|
20
|
-
|
21
17
|
<!-- jQuery JS -->
|
22
18
|
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
|
23
19
|
<script type="text/javascript"
|
24
20
|
src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js"></script>
|
21
|
+
|
25
22
|
{{ igv_script() }}
|
26
23
|
</head>
|
27
24
|
|
@@ -30,6 +27,11 @@
|
|
30
27
|
</body>
|
31
28
|
|
32
29
|
<script type="text/javascript">
|
30
|
+
|
31
|
+
var outLinks = {
|
32
|
+
COSV: "https://cancer.sanger.ac.uk/cosmic/search?q=", // COSMIC variant search
|
33
|
+
};
|
34
|
+
|
33
35
|
$(document).ready(function () {
|
34
36
|
var div = $("#igvDiv")[0],
|
35
37
|
options = {
|
@@ -146,7 +148,45 @@
|
|
146
148
|
{% endfor %}
|
147
149
|
]
|
148
150
|
};
|
149
|
-
igv.createBrowser(div, options)
|
151
|
+
igv.createBrowser(div, options)
|
152
|
+
.then(function (browser) {
|
153
|
+
browser.on('trackclick', function (track, popoverData) {
|
154
|
+
|
155
|
+
var markup = "<table class=\"igv-popover-table\">";
|
156
|
+
|
157
|
+
// Don't show a pop-over when there's no data.
|
158
|
+
if (!popoverData || !popoverData.length) {
|
159
|
+
return false;
|
160
|
+
}
|
161
|
+
|
162
|
+
popoverData.forEach(function (nameValue) {
|
163
|
+
|
164
|
+
if (nameValue.name) {
|
165
|
+
|
166
|
+
var value = nameValue.value;
|
167
|
+
for (var key in outLinks) {
|
168
|
+
if (nameValue.value.toString().startsWith(key) && nameValue.name.toLowerCase() === 'name') {
|
169
|
+
value = '<a href="' + outLinks[key] + value + '" target="_blank" rel="noopener noreferrer">' + nameValue.value + '</a>';
|
170
|
+
}
|
171
|
+
}
|
172
|
+
|
173
|
+
markup += "<tr><td class=\"igv-popover-td\">"
|
174
|
+
+ "<span class=\"igv-popover-name\">" + nameValue.name + "</span> "
|
175
|
+
+ "<span class=\"igv-popover-value\">" + value + "</span>"
|
176
|
+
+ "</td></tr>";
|
177
|
+
}
|
178
|
+
else {
|
179
|
+
// not a name/value pair
|
180
|
+
markup += "<tr><td>" + nameValue.toString() + "</td></tr>";
|
181
|
+
}
|
182
|
+
});
|
183
|
+
|
184
|
+
markup += "</table>";
|
185
|
+
|
186
|
+
// By returning a string from the trackclick handler we're asking IGV to use our custom HTML in its pop-over.
|
187
|
+
return markup;
|
188
|
+
});
|
189
|
+
});
|
150
190
|
});
|
151
191
|
</script>
|
152
192
|
|
@@ -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@
|
4
|
+
<script src="https://cdn.jsdelivr.net/npm/igv@3.0.1/dist/igv.min.js"></script>
|
5
5
|
{% endmacro %}
|
@@ -91,7 +91,15 @@ def remote_static():
|
|
91
91
|
@alignviewers_bp.route(
|
92
92
|
"/<institute_id>/<case_name>/<variant_id>/igv-splice-junctions", methods=["GET"]
|
93
93
|
)
|
94
|
-
|
94
|
+
@alignviewers_bp.route(
|
95
|
+
"/<institute_id>/<case_name>/outliers/<omics_variant_id>/igv-splice-junctions", methods=["GET"]
|
96
|
+
)
|
97
|
+
def sashimi_igv(
|
98
|
+
institute_id: str,
|
99
|
+
case_name: str,
|
100
|
+
variant_id: Optional[str] = None,
|
101
|
+
omics_variant_id: Optional[str] = None,
|
102
|
+
):
|
95
103
|
"""Visualize splice junctions on igv.js sashimi-like viewer for one or more individuals of a case.
|
96
104
|
wiki: https://github.com/igvteam/igv.js/wiki/Splice-Junctions
|
97
105
|
"""
|
@@ -99,7 +107,7 @@ def sashimi_igv(institute_id, case_name, variant_id=None):
|
|
99
107
|
store, institute_id, case_name
|
100
108
|
) # This function takes care of checking if user is authorized to see resource
|
101
109
|
|
102
|
-
display_obj = controllers.make_sashimi_tracks(case_obj, variant_id)
|
110
|
+
display_obj = controllers.make_sashimi_tracks(case_obj, variant_id, omics_variant_id)
|
103
111
|
controllers.set_session_tracks(display_obj)
|
104
112
|
|
105
113
|
response = Response(render_template("alignviewers/igv_sashimi_viewer.html", **display_obj))
|
@@ -64,6 +64,7 @@ JSON_HEADERS = {
|
|
64
64
|
COVERAGE_REPORT_TIMEOUT = 20
|
65
65
|
|
66
66
|
PANEL_PROJECTION = {"version": 1, "display_name": 1, "genes": 1}
|
67
|
+
PANEL_HIDDEN_PROJECTION = {"version": 1, "display_name": 1, "hidden": 1}
|
67
68
|
|
68
69
|
|
69
70
|
def phenomizer_diseases(hpo_ids, case_obj, p_value_treshold=1):
|
@@ -339,6 +340,8 @@ def case(
|
|
339
340
|
|
340
341
|
case_obj["default_genes"] = _get_default_panel_genes(store, case_obj)
|
341
342
|
|
343
|
+
_set_panel_removed(store, case_obj)
|
344
|
+
|
342
345
|
for hpo_term in itertools.chain(
|
343
346
|
case_obj.get("phenotype_groups") or [], case_obj.get("phenotype_terms") or []
|
344
347
|
):
|
@@ -449,6 +452,9 @@ def case(
|
|
449
452
|
"gens_info": gens.connection_settings(case_obj.get("genome_build")),
|
450
453
|
"display_rerunner": rerunner.connection_settings.get("display", False),
|
451
454
|
"hide_matching": hide_matching,
|
455
|
+
"audits": store.case_events_by_verb(
|
456
|
+
category="case", institute=institute_obj, case=case_obj, verb="filter_audit"
|
457
|
+
),
|
452
458
|
}
|
453
459
|
|
454
460
|
return data
|
@@ -479,6 +485,18 @@ def _limit_genes_on_default_panels(default_genes: list, limit_genes: list) -> li
|
|
479
485
|
return list(default_genes_set.intersection(limit_genes_set))
|
480
486
|
|
481
487
|
|
488
|
+
def _set_panel_removed(store: MongoAdapter, case_obj: dict) -> list:
|
489
|
+
"""Flag panel on list removed if the latest panel version is marked hidden."""
|
490
|
+
|
491
|
+
for panel_info in case_obj.get("panels", []):
|
492
|
+
latest_panel = store.gene_panel(
|
493
|
+
panel_info["panel_name"], projection=PANEL_HIDDEN_PROJECTION
|
494
|
+
)
|
495
|
+
panel_info["removed"] = (
|
496
|
+
latest_panel.get("hidden", False) if latest_panel is not None else False
|
497
|
+
)
|
498
|
+
|
499
|
+
|
482
500
|
def _get_default_panel_genes(store: MongoAdapter, case_obj: dict) -> list:
|
483
501
|
"""Get unique genes on case default panels.
|
484
502
|
|
@@ -510,7 +528,6 @@ def _get_default_panel_genes(store: MongoAdapter, case_obj: dict) -> list:
|
|
510
528
|
projection=PANEL_PROJECTION,
|
511
529
|
)
|
512
530
|
latest_panel = store.gene_panel(panel_name, projection=PANEL_PROJECTION)
|
513
|
-
panel_info["removed"] = False if latest_panel is None else latest_panel.get("hidden", False)
|
514
531
|
if not panel_obj:
|
515
532
|
panel_obj = latest_panel
|
516
533
|
if not panel_obj:
|
@@ -1,7 +1,7 @@
|
|
1
1
|
{% extends "layout.html" %}
|
2
2
|
{% from "cases/collapsible_actionbar.html" import action_bar, research_modal, reanalysis_modal %}
|
3
3
|
{% from "utils.html" import comments_panel, activity_panel, pedigree_panel %}
|
4
|
-
{% from "cases/utils.html" import causatives_list, suspects_list, remove_form, matching_causatives, matching_managed_variants, beacon_modal, matchmaker_modal %}
|
4
|
+
{% from "cases/utils.html" import causatives_list, suspects_list, remove_form, matching_causatives, matching_managed_variants, beacon_modal, matchmaker_modal, filter_audits %}
|
5
5
|
{% from "cases/individuals_table.html" import cancer_individuals_table, individuals_table %}
|
6
6
|
{% from "cases/phenotype.html" import hpo_item, cohort_panel, diagnosis_phenotypes, phenotype_groups_panel, add_phenotype_terms_panel, hpo_panel %}
|
7
7
|
{% from "cases/gene_panel.html" import genepanels_table, hpo_genelist_panel %}
|
@@ -119,8 +119,16 @@
|
|
119
119
|
</div>
|
120
120
|
</div>
|
121
121
|
|
122
|
+
<div class="row ms-1">
|
122
123
|
{{ matching_variants() }}
|
123
124
|
|
125
|
+
{% if audits | count_cursor > 0 %}
|
126
|
+
<div class="card panel-default col-4 ms-5 me-1">
|
127
|
+
{{ filter_audits(audits, true) }}
|
128
|
+
</div>
|
129
|
+
{% endif %}
|
130
|
+
</div>
|
131
|
+
|
124
132
|
<div class="card panel-default" >
|
125
133
|
<div class="row">
|
126
134
|
<div class="col">{{ causatives_list(causatives, partial_causatives, evaluated_variants, institute, case, manual_rank_options, cancer_tier_options) }}</div>
|
@@ -258,6 +266,9 @@
|
|
258
266
|
{% if case.vcf_files.vcf_fusion %}
|
259
267
|
<a class="btn btn-dark btn-sm text-white" href="{{ url_for('variants.fusion_variants', institute_id=institute._id, case_name=case.display_name, variant_type='clinical') }}">Clinical fusion variants</a>
|
260
268
|
{% endif %}
|
269
|
+
{% if case.has_outliers %}
|
270
|
+
<a class="btn btn-dark btn-sm text-white" href="{{ url_for('omics_variants.outliers', institute_id=institute._id, case_name=case.display_name, variant_type='clinical') }}">Clinical WTS outliers</a>
|
271
|
+
{% endif %}
|
261
272
|
</div>
|
262
273
|
</div>
|
263
274
|
</div>
|
@@ -352,7 +363,7 @@
|
|
352
363
|
<a href="{{ url_for('cases.case', institute_id=grouped_case.owner, case_name=grouped_case.display_name) }}">{{ grouped_case.display_name }}</a>
|
353
364
|
|
354
365
|
<a href="{{ url_for('cases.remove_case_group', institute_id=institute._id, case_name=grouped_case.display_name, case_group=group_id) }}" class="btn btn-link btn-sm">
|
355
|
-
<span class="fa fa-
|
366
|
+
<span class="fa fa-times text-dark"></span></a>
|
356
367
|
|
357
368
|
</div>
|
358
369
|
{% endfor %}
|
@@ -537,9 +548,9 @@
|
|
537
548
|
{% endmacro %}
|
538
549
|
|
539
550
|
{% macro matching_variants() %}
|
540
|
-
<div class="card mt-3">
|
541
|
-
<div class="
|
542
|
-
<div class="col-
|
551
|
+
<div class="card mt-3 col-7">
|
552
|
+
<div class="mt-0">
|
553
|
+
<div class="col-md-7">
|
543
554
|
<div data-bs-toggle='tooltip' class="panel-heading" title="Check if there are any variants in this case
|
544
555
|
marked as causative in another case for this institute, or are on the managed variants list.">
|
545
556
|
<strong>
|
@@ -554,27 +565,27 @@
|
|
554
565
|
{% if hide_matching == false %}
|
555
566
|
{% if other_causatives|length > 0 %}
|
556
567
|
<div class="row mt-0 ms-3">
|
557
|
-
<div class="col-
|
568
|
+
<div class="col-md-7">{{ matching_causatives(other_causatives, institute, case) }}</div>
|
558
569
|
</div>
|
559
570
|
{% endif %}
|
560
571
|
{% if default_other_causatives|length > 0%}
|
561
572
|
<div class="row mt-0 ms-3">
|
562
|
-
<div class="col-
|
573
|
+
<div class="col-md-7">{{ matching_causatives(default_other_causatives, institute, case, default=True) }}</div>
|
563
574
|
</div>
|
564
575
|
{% endif %}
|
565
576
|
{% if managed_variants|length > 0%}
|
566
577
|
<div class="row mt-0 ms-3">
|
567
|
-
<div class="col-
|
578
|
+
<div class="col-md-7">{{ matching_managed_variants(managed_variants, institute, case) }}</div>
|
568
579
|
</div>
|
569
580
|
{% endif %}
|
570
581
|
{% if default_managed_variants|length > 0%}
|
571
582
|
<div class="row mt-0 ms-3">
|
572
|
-
<div class="col-
|
583
|
+
<div class="col-md-7">{{ matching_managed_variants(default_managed_variants, institute, case, default=True) }}</div>
|
573
584
|
</div>
|
574
585
|
{% endif %}
|
575
586
|
{% if other_causatives|length == 0 and default_other_causatives|length == 0 and managed_variants|length == 0 and default_managed_variants|length == 0%}
|
576
587
|
<div class="row mt-0 ms-3">
|
577
|
-
<div class="col-
|
588
|
+
<div class="col-md-7">No matching causatives or managed variants found</div>
|
578
589
|
</div>
|
579
590
|
{% endif %}
|
580
591
|
{% endif %}
|
@@ -772,5 +783,12 @@ $('#collapse-icon').addClass('fa-angle-double-left');
|
|
772
783
|
$('[data-bs-toggle=sidebar-collapse]').click(function() {
|
773
784
|
SidebarCollapse();
|
774
785
|
});
|
786
|
+
|
787
|
+
function dynamicPhenotypeCheck(source){
|
788
|
+
var checkboxes = document.getElementsByName('hpo_id');
|
789
|
+
for(var i=0, n=checkboxes.length;i<n;i++) {
|
790
|
+
checkboxes[i].checked = source.checked;
|
791
|
+
}
|
792
|
+
}
|
775
793
|
</script>
|
776
794
|
{% endblock %}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
{% from "cases/utils.html" import variant_transcripts %}
|
1
|
+
{% from "cases/utils.html" import variant_transcripts, filter_audits %}
|
2
2
|
{% from "utils.html" import comments_table, variant_related_comments_table %}
|
3
3
|
{% from "variants/components.html" import fusion_variants_header, default_fusion_variant_cells %}
|
4
4
|
|
@@ -266,22 +266,7 @@
|
|
266
266
|
{% if audits | count_cursor > 0 %}
|
267
267
|
<tr>
|
268
268
|
<td colspan=2>
|
269
|
-
|
270
|
-
<thead>
|
271
|
-
<tr>
|
272
|
-
<th>Filters marked audited for case</th>
|
273
|
-
</tr>
|
274
|
-
</thead>
|
275
|
-
<tbody>
|
276
|
-
{% set audit_query = namespace() %}
|
277
|
-
{% for audit in audits %}
|
278
|
-
{% set audit_query = audit.link|url_args %}
|
279
|
-
<tr>
|
280
|
-
<td><strong>{{ audit.subject }} ({{audit_query.variant_type if audit_query.variant_type else "type unavailable -"}} {{ audit_query.category if audit_query.category else "category unavailable"}})</strong> was marked checked by {{ audit.user_name }} on {{audit.created_at.strftime('%Y-%m-%d')}}.</td>
|
281
|
-
</tr>
|
282
|
-
{% endfor %}
|
283
|
-
</tbody>
|
284
|
-
</table>
|
269
|
+
{{filter_audits(audits)}}
|
285
270
|
</td>
|
286
271
|
</tr>
|
287
272
|
{% endif %}
|
@@ -247,7 +247,7 @@
|
|
247
247
|
{% else %}
|
248
248
|
<button type="submit" name="action" value="DELETE" class="btn btn-warning btn-xs form-control">
|
249
249
|
{% endif %}
|
250
|
-
<span class="fa fa-
|
250
|
+
<span class="fa fa-times"></span>
|
251
251
|
{{ user.name }}
|
252
252
|
</button>
|
253
253
|
</form>
|