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.
Files changed (52) hide show
  1. scout/adapter/mongo/case.py +20 -6
  2. scout/adapter/mongo/clinvar.py +7 -7
  3. scout/adapter/mongo/hgnc.py +7 -2
  4. scout/adapter/mongo/omics_variant.py +8 -0
  5. scout/adapter/mongo/variant_loader.py +6 -2
  6. scout/constants/__init__.py +1 -0
  7. scout/constants/file_types.py +1 -1
  8. scout/constants/igv_tracks.py +6 -2
  9. scout/constants/phenotype.py +1 -0
  10. scout/load/hpo.py +8 -2
  11. scout/server/blueprints/alignviewers/controllers.py +8 -6
  12. scout/server/blueprints/alignviewers/templates/alignviewers/igv_viewer.html +2 -0
  13. scout/server/blueprints/alignviewers/templates/alignviewers/utils.html +1 -1
  14. scout/server/blueprints/cases/controllers.py +56 -28
  15. scout/server/blueprints/cases/templates/cases/case_report.html +9 -88
  16. scout/server/blueprints/cases/templates/cases/matchmaker.html +1 -1
  17. scout/server/blueprints/cases/templates/cases/phenotype.html +1 -1
  18. scout/server/blueprints/cases/templates/cases/utils.html +27 -25
  19. scout/server/blueprints/cases/views.py +32 -33
  20. scout/server/blueprints/clinvar/controllers.py +18 -23
  21. scout/server/blueprints/clinvar/templates/clinvar/multistep_add_variant.html +0 -2
  22. scout/server/blueprints/diagnoses/controllers.py +4 -8
  23. scout/server/blueprints/diagnoses/templates/diagnoses/diagnoses.html +1 -1
  24. scout/server/blueprints/diagnoses/templates/diagnoses/disease_term.html +1 -1
  25. scout/server/blueprints/diagnoses/views.py +2 -2
  26. scout/server/blueprints/institutes/controllers.py +107 -73
  27. scout/server/blueprints/institutes/templates/overview/cases.html +8 -7
  28. scout/server/blueprints/login/controllers.py +2 -1
  29. scout/server/blueprints/login/views.py +5 -2
  30. scout/server/blueprints/omics_variants/views.py +2 -2
  31. scout/server/blueprints/panels/views.py +11 -2
  32. scout/server/blueprints/phenotypes/controllers.py +15 -2
  33. scout/server/blueprints/phenotypes/templates/phenotypes/hpo_terms.html +1 -1
  34. scout/server/blueprints/variant/controllers.py +10 -11
  35. scout/server/blueprints/variant/templates/variant/utils.html +1 -1
  36. scout/server/blueprints/variant/templates/variant/variant_details.html +68 -60
  37. scout/server/blueprints/variant/utils.py +25 -0
  38. scout/server/blueprints/variants/controllers.py +11 -42
  39. scout/server/blueprints/variants/templates/variants/cancer-variants.html +3 -3
  40. scout/server/blueprints/variants/templates/variants/indicators.html +18 -15
  41. scout/server/blueprints/variants/templates/variants/utils.html +1 -1
  42. scout/server/blueprints/variants/views.py +9 -8
  43. scout/server/config.py +3 -0
  44. scout/server/extensions/beacon_extension.py +7 -2
  45. scout/server/templates/bootstrap_global.html +11 -1
  46. scout/server/templates/layout.html +6 -1
  47. scout/server/utils.py +24 -3
  48. {scout_browser-4.100.2.dist-info → scout_browser-4.102.0.dist-info}/METADATA +1 -1
  49. {scout_browser-4.100.2.dist-info → scout_browser-4.102.0.dist-info}/RECORD +52 -52
  50. {scout_browser-4.100.2.dist-info → scout_browser-4.102.0.dist-info}/WHEEL +0 -0
  51. {scout_browser-4.100.2.dist-info → scout_browser-4.102.0.dist-info}/entry_points.txt +0 -0
  52. {scout_browser-4.100.2.dist-info → scout_browser-4.102.0.dist-info}/licenses/LICENSE +0 -0
@@ -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 _load_clinical_variants(self, case_obj: dict, build: str, update: bool = False):
932
- """Load variants in the order specified by CLINICAL_ORDERED_FILE_TYPE_MAP."""
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
- load_type_cat = set()
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
- load_type_cat.add((vcf_dict["variant_type"], vcf_dict["category"]))
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 load_type_cat:
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"],
@@ -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
- {"$set": {"updated_at": datetime.now()}},
403
- return_document=pymongo.ReturnDocument.AFTER,
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):
@@ -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(self, hgnc_identifier, build=None):
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 = case_obj["vcf_files"].get(vcf_file_key)
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)
@@ -78,6 +78,7 @@ from .indexes import ID_PROJECTION, INDEXES
78
78
  from .panels import PANELAPP_CONFIDENCE_EXCLUDE
79
79
  from .phenotype import (
80
80
  COHORT_TAGS,
81
+ HPO_LINK_URL,
81
82
  HPO_URL,
82
83
  HPOTERMS_URL,
83
84
  ORPHA_URLS,
@@ -1,6 +1,6 @@
1
1
  from collections import OrderedDict
2
2
 
3
- # Variants in Scout will be loadedfor a case in the same order as these ordered dictionaries
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"}),
@@ -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 = "https://igv.org/genomes/data/hg19/hg19_alias.tab"
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 = "https://igv.org/genomes/data/hg38/hg38_alias.tab"
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"
@@ -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 Dict, Iterable, Optional
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
- hgnc_id = gene_info["true"]
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 case_append_alignments, find_index
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
- if "38" in str(case_obj.get("genome_build", "37")) or chromosome == "M":
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.2.0/dist/igv.min.js" integrity="sha512-MHnbGQeONlQXyEs6PgiW2bhwywJW5IwUnRKfQKrPaVSrzopctBTU1VtOiEXMf/ZPBk47eFimlVRxdff+sdsyAg==" crossorigin="anonymous"></script>
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(store, case_obj, case_groups, case_group_label):
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: Dict) -> List[Dict]:
182
- """Return any partial causatives a case has, populated as causative objs.
183
- Args:
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": store.variant(var_id) or var_id,
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.get("genome_build", "38")],
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
- # Fetch the variant objects for suspects and causatives
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
- causatives = [
340
- store.variant(variant_id) or variant_id for variant_id in case_obj.get("causatives", [])
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
- # check for partial causatives and associated phenotypes
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"] = "http://hpo.jax.org/app/browse/term/{}".format(
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.get("genome_build")),
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(var_obj=var_obj, institute_obj=institute_obj, case_obj=case_obj)
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(var_obj: dict, institute_obj: dict, case_obj: dict) -> dict:
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(var_obj=var_obj, institute_obj=institute_obj, case_obj=case_obj)
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="https://hpo.jax.org/app/browse/term/{{pheno.phenotype_id}}" target="_blank">{{pheno.phenotype_id}})</a>
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
- <table id="panel-table" class="table table-sm" style="background-color: transparent">
596
- <thead>
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
- <table id="panel-table" class="table table-sm" style="background-color: transparent">
1078
- <thead>
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="http://hpo.jax.org/app/browse/term/{{hpo.id}}">
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/app/' %}
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>&nbsp;Phenotype terms (<a target="_blank" class="" href="{{ url }}" rel="noopener">HPO</a>)</h6>
197
197
  </div>