scout-browser 4.85__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.
Files changed (76) hide show
  1. scout/__version__.py +1 -1
  2. scout/adapter/mongo/base.py +17 -14
  3. scout/adapter/mongo/case.py +20 -1
  4. scout/adapter/mongo/filter.py +36 -1
  5. scout/adapter/mongo/omics_variant.py +145 -0
  6. scout/adapter/mongo/query.py +13 -3
  7. scout/adapter/mongo/variant.py +10 -4
  8. scout/build/case.py +5 -0
  9. scout/build/variant/variant.py +1 -0
  10. scout/constants/__init__.py +3 -1
  11. scout/constants/case_tags.py +1 -0
  12. scout/constants/clinvar.py +1 -1
  13. scout/constants/file_types.py +31 -0
  14. scout/constants/filters.py +4 -0
  15. scout/constants/indexes.py +30 -13
  16. scout/constants/variant_tags.py +3 -0
  17. scout/demo/643594.clinical.mei.vcf.gz +0 -0
  18. scout/demo/643594.clinical.mei.vcf.gz.tbi +0 -0
  19. scout/demo/643594.config.yaml +4 -0
  20. scout/demo/drop/fraser_top_hits_clinical.tsv +5 -0
  21. scout/demo/drop/outrider_top_hits_clinical.tsv +10 -0
  22. scout/load/setup.py +4 -4
  23. scout/models/case/case_loading_models.py +25 -2
  24. scout/models/omics_variant.py +227 -0
  25. scout/parse/omics_variant/__init__.py +11 -0
  26. scout/parse/omics_variant/drop.py +19 -0
  27. scout/parse/variant/callers.py +6 -3
  28. scout/parse/variant/frequency.py +10 -2
  29. scout/server/app.py +4 -1
  30. scout/server/blueprints/alignviewers/controllers.py +35 -24
  31. scout/server/blueprints/alignviewers/templates/alignviewers/igv_sashimi_viewer.html +19 -15
  32. scout/server/blueprints/alignviewers/templates/alignviewers/igv_viewer.html +45 -5
  33. scout/server/blueprints/alignviewers/templates/alignviewers/utils.html +1 -1
  34. scout/server/blueprints/alignviewers/views.py +10 -2
  35. scout/server/blueprints/cases/controllers.py +3 -0
  36. scout/server/blueprints/cases/templates/cases/case.html +27 -9
  37. scout/server/blueprints/cases/templates/cases/case_report.html +2 -17
  38. scout/server/blueprints/cases/templates/cases/phenotype.html +8 -5
  39. scout/server/blueprints/cases/templates/cases/utils.html +26 -3
  40. scout/server/blueprints/clinvar/controllers.py +9 -3
  41. scout/server/blueprints/dashboard/controllers.py +44 -13
  42. scout/server/blueprints/dashboard/static/charts.js +46 -36
  43. scout/server/blueprints/dashboard/templates/dashboard/dashboard_general.html +2 -2
  44. scout/server/blueprints/institutes/forms.py +2 -0
  45. scout/server/blueprints/institutes/templates/overview/cases.html +6 -4
  46. scout/server/blueprints/institutes/templates/overview/gene_variants.html +40 -27
  47. scout/server/blueprints/institutes/templates/overview/institute_sidebar.html +1 -1
  48. scout/server/blueprints/institutes/views.py +5 -12
  49. scout/server/blueprints/omics_variants/__init__.py +1 -0
  50. scout/server/blueprints/omics_variants/controllers.py +122 -0
  51. scout/server/blueprints/omics_variants/templates/omics_variants/outliers.html +262 -0
  52. scout/server/blueprints/omics_variants/views.py +106 -0
  53. scout/server/blueprints/panels/controllers.py +1 -7
  54. scout/server/blueprints/panels/templates/panels/panels.html +12 -4
  55. scout/server/blueprints/panels/views.py +9 -11
  56. scout/server/blueprints/variant/templates/variant/buttons.html +7 -2
  57. scout/server/blueprints/variant/templates/variant/str-variant-reviewer.html +1 -1
  58. scout/server/blueprints/variant/templates/variant/utils.html +1 -1
  59. scout/server/blueprints/variant/utils.py +54 -103
  60. scout/server/blueprints/variant/views.py +1 -0
  61. scout/server/blueprints/variants/controllers.py +1 -4
  62. scout/server/blueprints/variants/forms.py +42 -0
  63. scout/server/blueprints/variants/templates/variants/utils.html +8 -4
  64. scout/server/blueprints/variants/views.py +28 -7
  65. scout/server/config.py +4 -0
  66. scout/server/extensions/clinvar_extension.py +7 -7
  67. scout/server/links.py +2 -2
  68. scout/server/templates/bootstrap_global.html +1 -4
  69. scout/server/templates/utils.html +3 -3
  70. scout/server/utils.py +4 -1
  71. {scout_browser-4.85.dist-info → scout_browser-4.86.dist-info}/METADATA +10 -10
  72. {scout_browser-4.85.dist-info → scout_browser-4.86.dist-info}/RECORD +76 -66
  73. {scout_browser-4.85.dist-info → scout_browser-4.86.dist-info}/WHEEL +1 -1
  74. {scout_browser-4.85.dist-info → scout_browser-4.86.dist-info}/LICENSE +0 -0
  75. {scout_browser-4.85.dist-info → scout_browser-4.86.dist-info}/entry_points.txt +0 -0
  76. {scout_browser-4.85.dist-info → scout_browser-4.86.dist-info}/top_level.txt +0 -0
scout/__version__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "4.85"
1
+ __version__ = "4.86"
@@ -45,6 +45,7 @@ from .index import IndexHandler
45
45
  from .institute import InstituteHandler
46
46
  from .managed_variant import ManagedVariantHandler
47
47
  from .matchmaker import MMEHandler
48
+ from .omics_variant import OmicsVariantHandler
48
49
  from .panel import PanelHandler
49
50
  from .phenomodel import PhenoModelHandler
50
51
  from .query import QueryHandler
@@ -57,27 +58,28 @@ LOG = logging.getLogger(__name__)
57
58
 
58
59
 
59
60
  class MongoAdapter(
60
- GeneHandler,
61
- CaseHandler,
61
+ ACMGHandler,
62
62
  CaseGroupHandler,
63
- InstituteHandler,
63
+ CaseHandler,
64
+ ClinVarHandler,
65
+ CytobandHandler,
66
+ DiagnosisHandler,
64
67
  EventHandler,
68
+ FilterHandler,
69
+ GeneHandler,
65
70
  HpoHandler,
66
- DiagnosisHandler,
67
- PanelHandler,
68
- QueryHandler,
69
- VariantHandler,
70
- UserHandler,
71
- ACMGHandler,
72
71
  IndexHandler,
73
- ClinVarHandler,
72
+ InstituteHandler,
74
73
  MMEHandler,
75
- TranscriptHandler,
76
- FilterHandler,
77
74
  ManagedVariantHandler,
78
- CytobandHandler,
75
+ OmicsVariantHandler,
76
+ PanelHandler,
79
77
  PhenoModelHandler,
78
+ QueryHandler,
80
79
  RankModelHandler,
80
+ TranscriptHandler,
81
+ UserHandler,
82
+ VariantHandler,
81
83
  ):
82
84
  """Adapter for communication with a Mongo database."""
83
85
 
@@ -108,9 +110,10 @@ class MongoAdapter(
108
110
  self.hpo_term_collection = database.hpo_term
109
111
  self.institute_collection = database.institute
110
112
  self.managed_variant_collection = database.managed_variant
113
+ self.omics_variant_collection = database.omics_variant
111
114
  self.panel_collection = database.gene_panel
112
- self.rank_model_collection = database.rank_model
113
115
  self.phenomodel_collection = database.phenomodel
116
+ self.rank_model_collection = database.rank_model
114
117
  self.transcript_collection = database.transcript
115
118
  self.user_collection = database.user
116
119
  self.variant_collection = database.variant
@@ -10,7 +10,7 @@ import pymongo
10
10
  from bson import ObjectId
11
11
 
12
12
  from scout.build.case import build_case
13
- from scout.constants import ACMG_MAP, FILE_TYPE_MAP, ID_PROJECTION
13
+ from scout.constants import ACMG_MAP, FILE_TYPE_MAP, ID_PROJECTION, OMICS_FILE_TYPE_MAP
14
14
  from scout.exceptions import ConfigError, IntegrityError
15
15
  from scout.parse.variant.ids import parse_document_id
16
16
  from scout.utils.algorithms import ui_score
@@ -834,6 +834,21 @@ class CaseHandler(object):
834
834
  if key in old_case:
835
835
  new_case[key] = old_case[key]
836
836
 
837
+ def _load_omics_variants(self, case_obj: dict, build: str, update: bool = False):
838
+ """Load omics variants. The OMICS FILE type dict contains all we need to
839
+ determine how to load variants (type, category etc)."""
840
+
841
+ for omics_file in OMICS_FILE_TYPE_MAP.keys():
842
+ if not case_obj["omics_files"].get(omics_file):
843
+ LOG.debug("didn't find %s for case, skipping", omics_file)
844
+ continue
845
+
846
+ if update:
847
+ LOG.debug("deleting %s omics variants for case", omics_file)
848
+ self.delete_omics_variants(case_id=case_obj["_id"], file_type=omics_file)
849
+
850
+ self.load_omics_variants(case_obj=case_obj, build=build, file_type=omics_file)
851
+
837
852
  def load_case(self, config_data: dict, update: bool = False, keep_actions: bool = True) -> dict:
838
853
  """Load a case into the database
839
854
 
@@ -930,6 +945,8 @@ class CaseHandler(object):
930
945
  except (IntegrityError, ValueError, ConfigError, KeyError) as error:
931
946
  LOG.warning(error)
932
947
 
948
+ self._load_omics_variants(case_obj, build=genome_build, update=update)
949
+
933
950
  if existing_case:
934
951
  self.update_case_data_sharing(old_case=existing_case, new_case=case_obj)
935
952
  case_obj["rerun_requested"] = False
@@ -1049,6 +1066,7 @@ class CaseHandler(object):
1049
1066
  "gene_fusion_report_research": case_obj.get("gene_fusion_report_research"),
1050
1067
  "genome_build": case_obj.get("genome_build", "37"),
1051
1068
  "has_meivariants": case_obj.get("has_meivariants"),
1069
+ "has_outliers": case_obj.get("has_outliers"),
1052
1070
  "has_strvariants": case_obj.get("has_strvariants"),
1053
1071
  "has_svvariants": case_obj.get("has_svvariants"),
1054
1072
  "individuals": case_obj["individuals"],
@@ -1057,6 +1075,7 @@ class CaseHandler(object):
1057
1075
  "mme_submission": case_obj.get("mme_submission"),
1058
1076
  "multiqc": case_obj.get("multiqc"),
1059
1077
  "multiqc_rna": case_obj.get("multiqc_rna"),
1078
+ "omics_files": case_obj.get("omics_files"),
1060
1079
  "panels": case_obj.get("panels", []),
1061
1080
  "phenotype_groups": case_obj.get("phenotype_groups"),
1062
1081
  "phenotype_terms": case_obj.get("phenotype_terms"),
@@ -1,8 +1,9 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  import logging
3
+ from typing import Optional
3
4
 
4
5
  from bson.objectid import ObjectId
5
- from flask import url_for
6
+ from flask import flash, url_for
6
7
  from pymongo.cursor import CursorType
7
8
  from werkzeug.datastructures import MultiDict
8
9
 
@@ -105,6 +106,40 @@ class FilterHandler(object):
105
106
 
106
107
  return filter_id
107
108
 
109
+ def unaudit_filter(self, audit_id: ObjectId, user_obj: dict):
110
+ """Removes an audit filter event with a new un-audit filter event."""
111
+
112
+ FILTER_SEARCH = {"_id": ObjectId(audit_id), "verb": "filter_audit"}
113
+
114
+ audit_event: Optional[dict] = self.event_collection.find_one(FILTER_SEARCH)
115
+ if audit_event is None:
116
+ return
117
+ if audit_event.get("user_id") != user_obj["email"]:
118
+ flash("You can't un-audit a filter audited by another user.", "warning")
119
+ return
120
+ institute_obj: Optional[dict] = self.institute(institute_id=audit_event.get("institute"))
121
+ case_obj: Optional[dict] = self.case(case_id=audit_event.get("case"))
122
+ if None in [institute_obj, case_obj]:
123
+ LOG.error(
124
+ f"An error occurred un-auditing filter: institute or case missing for audit event {audit_id}."
125
+ )
126
+ return
127
+
128
+ # Create un-audit event
129
+ self.create_event(
130
+ institute=institute_obj,
131
+ case=case_obj,
132
+ user=user_obj,
133
+ link=audit_event["link"],
134
+ category="case",
135
+ verb="filter_unaudit",
136
+ subject=audit_event["subject"],
137
+ level="global",
138
+ )
139
+
140
+ # Remove audit event
141
+ self.event_collection.delete_one(FILTER_SEARCH)
142
+
108
143
  def audit_filter(self, filter_id, institute_obj, case_obj, user_obj, category="snv", link=None):
109
144
  """Mark audit of filter for case in events.
110
145
  Audit filter leaves a voluntary log trail to answer questions like "did I really check for recessive variants"
@@ -0,0 +1,145 @@
1
+ import logging
2
+ from typing import Dict, Optional
3
+
4
+ from scout.constants import OMICS_FILE_TYPE_MAP
5
+ from scout.models.omics_variant import OmicsVariantLoader
6
+ from scout.parse.omics_variant import parse_omics_file
7
+
8
+ LOG = logging.getLogger(__name__)
9
+
10
+
11
+ class OmicsVariantHandler:
12
+ def delete_omics_variants(self, case_id: str, file_type: str):
13
+ """Delete OMICS variants for a case"""
14
+ omics_file_type = OMICS_FILE_TYPE_MAP.get(file_type)
15
+ category = omics_file_type["category"]
16
+ sub_category = omics_file_type["sub_category"]
17
+ variant_type = omics_file_type["variant_type"]
18
+
19
+ LOG.info(
20
+ "Deleting old %s %s %s OMICS variants.",
21
+ variant_type,
22
+ sub_category,
23
+ category,
24
+ )
25
+
26
+ query = {
27
+ "case_id": case_id,
28
+ "variant_type": variant_type,
29
+ "category": category,
30
+ "sub_category": sub_category,
31
+ }
32
+ result = self.omics_variant_collection.delete_many(query)
33
+
34
+ LOG.info("%s variants deleted", result.deleted_count)
35
+
36
+ def set_samples(self, case_obj: dict, omics_model: dict):
37
+ """Internal member function to connect individuals.
38
+ OMICS variants do not have a genotype as such."""
39
+
40
+ samples = []
41
+
42
+ for ind in case_obj.get("individuals"):
43
+ if omics_model["sampleID"] == ind.get("individual_id"):
44
+ sample = {
45
+ "sample_id": ind["individual_id"],
46
+ "display_name": ind["display_name"],
47
+ "genotype_call": "./1",
48
+ }
49
+ samples.append(sample)
50
+
51
+ omics_model["samples"] = samples
52
+
53
+ def set_genes(self, omics_model: dict):
54
+ """Internal member function to connect gene based on the hgnc_id / symbol / geneID given in outlier file.
55
+ We start with the case of having one hgnc_id.
56
+ """
57
+ hgnc_gene = self.hgnc_gene(omics_model["hgnc_ids"][0], omics_model["build"])
58
+ if hgnc_gene:
59
+ omics_model["genes"] = [hgnc_gene]
60
+
61
+ def load_omics_variants(self, case_obj: dict, file_type: str, build: Optional[str] = "37"):
62
+ """Load OMICS variants for a case"""
63
+
64
+ case_panels = case_obj.get("panels", [])
65
+ gene_to_panels = self.gene_to_panels(case_obj)
66
+
67
+ omics_file_type: dict = OMICS_FILE_TYPE_MAP.get(file_type)
68
+
69
+ nr_inserted = 0
70
+
71
+ file_handle = open(case_obj["omics_files"].get(file_type), "r")
72
+
73
+ for omics_info in parse_omics_file(file_handle, omics_file_type=omics_file_type):
74
+ omics_info["case_id"] = case_obj["_id"]
75
+ omics_info["build"] = "37" if "37" in build else "38"
76
+ omics_info["file_type"] = file_type
77
+ omics_info["institute"] = case_obj["owner"]
78
+ for key in ["category", "sub_category", "variant_type", "analysis_type"]:
79
+ omics_info[key] = omics_file_type[key]
80
+
81
+ omics_model = OmicsVariantLoader(**omics_info).model_dump(
82
+ by_alias=True, exclude_none=True
83
+ )
84
+
85
+ self.set_genes(omics_model)
86
+ self.set_samples(case_obj, omics_model)
87
+
88
+ # If case has gene panels, only add clinical variants with a matching gene
89
+ variant_genes = [gene["hgnc_id"] for gene in omics_model.get("genes", [])]
90
+ if (
91
+ omics_model["variant_type"] == "clinical"
92
+ and case_panels
93
+ and all(variant_gene not in gene_to_panels for variant_gene in variant_genes)
94
+ ):
95
+ continue
96
+
97
+ self.omics_variant_collection.insert_one(omics_model)
98
+ nr_inserted += 1
99
+
100
+ LOG.info("%s variants inserted", nr_inserted)
101
+
102
+ def omics_variant(self, variant_id: str, projection: Optional[Dict] = None):
103
+ """Return omics variant"""
104
+
105
+ return self.omics_variant_collection.find_one({"omics_variant_id": variant_id}, projection)
106
+
107
+ def omics_variants(
108
+ self,
109
+ case_id: str,
110
+ query=None,
111
+ category: str = "outlier",
112
+ nr_of_variants=50,
113
+ skip=0,
114
+ projection: Optional[Dict] = None,
115
+ build="37",
116
+ ):
117
+ """Return omics variants for a case, of a particular type (clinical, research) and category (outlier, ...)."""
118
+
119
+ if nr_of_variants == -1:
120
+ nr_of_variants = 0 # This will return all variants
121
+ else:
122
+ nr_of_variants = skip + nr_of_variants
123
+
124
+ query = self.build_query(case_id, query=query, category=category, build=build)
125
+ return self.omics_variant_collection.find(
126
+ query, projection, skip=skip, limit=nr_of_variants
127
+ )
128
+
129
+ def count_omics_variants(
130
+ self, case_id, query, variant_ids=None, category="outlier", build="37"
131
+ ):
132
+ """Returns number of variants
133
+
134
+ Arguments:
135
+ case_id(str): A string that represents the case
136
+ query(dict): A query dictionary
137
+
138
+ Returns:
139
+ integer
140
+ """
141
+
142
+ query = self.build_query(
143
+ case_id, query=query, variant_ids=variant_ids, category=category, build=build
144
+ )
145
+ return self.omics_variant_collection.count_documents(query)
@@ -1,6 +1,7 @@
1
1
  import logging
2
2
  import re
3
3
  from datetime import datetime, timedelta
4
+ from typing import Optional, Union
4
5
 
5
6
  from scout.constants import (
6
7
  CLINSIG_MAP,
@@ -76,7 +77,11 @@ class QueryHandler(object):
76
77
  return variants_query
77
78
 
78
79
  def build_variant_query(
79
- self, query=None, institute_ids=[], category="snv", variant_type=["clinical"]
80
+ self,
81
+ query: Optional[dict] = None,
82
+ institute_ids: Optional[list] = [],
83
+ category: Optional[Union[str, list]] = "snv",
84
+ variant_type: Optional[list] = ["clinical"],
80
85
  ):
81
86
  """Build a mongo query across multiple cases.
82
87
  Translate query options from a form into a complete mongo query dictionary.
@@ -93,7 +98,7 @@ class QueryHandler(object):
93
98
  Args:
94
99
  query(dict): A query dictionary for the database, from a query form.
95
100
  institute_ids: a list of institute _ids
96
- category(str): 'snv', 'sv', 'str' 'cancer_sv' or 'cancer'
101
+ category(str): 'snv', 'sv', 'str' 'cancer_sv' or 'cancer' OR a LIST(str) of the same
97
102
  variant_type(str): 'clinical' or 'research'
98
103
 
99
104
  Possible query dict keys:
@@ -112,7 +117,12 @@ class QueryHandler(object):
112
117
 
113
118
  mongo_variant_query["hgnc_symbols"] = {"$in": query["hgnc_symbols"]}
114
119
  mongo_variant_query["variant_type"] = {"$in": variant_type}
115
- mongo_variant_query["category"] = category
120
+
121
+ if not category:
122
+ category = "snv"
123
+ mongo_variant_query["category"] = (
124
+ {"$in": category} if isinstance(category, list) else category
125
+ )
116
126
 
117
127
  select_cases = None
118
128
  select_case_obj = None
@@ -206,7 +206,7 @@ class VariantHandler(VariantLoader):
206
206
 
207
207
  return result
208
208
 
209
- def count_variants(self, case_id, query, variant_ids, category):
209
+ def count_variants(self, case_id, query, variant_ids, category, build="37"):
210
210
  """Returns number of variants
211
211
 
212
212
  Arguments:
@@ -219,7 +219,9 @@ class VariantHandler(VariantLoader):
219
219
  integer
220
220
  """
221
221
 
222
- query = self.build_query(case_id, query=query, variant_ids=variant_ids, category=category)
222
+ query = self.build_query(
223
+ case_id, query=query, variant_ids=variant_ids, category=category, build=build
224
+ )
223
225
  return self.variant_collection.count_documents(query)
224
226
 
225
227
  def variant_update_field(self, variant_id: str, field_name: str, field_value: Any) -> dict:
@@ -237,6 +239,7 @@ class VariantHandler(VariantLoader):
237
239
  case_id=None,
238
240
  simple_id=None,
239
241
  variant_type="clinical",
242
+ projection=None,
240
243
  ):
241
244
  """Returns the specified variant.
242
245
 
@@ -264,7 +267,7 @@ class VariantHandler(VariantLoader):
264
267
  # search with a unique id
265
268
  query["_id"] = document_id
266
269
 
267
- variant_obj = self.variant_collection.find_one(query)
270
+ variant_obj = self.variant_collection.find_one(query, projection=projection)
268
271
  if not variant_obj:
269
272
  return variant_obj
270
273
  case_obj = self.case(
@@ -890,7 +893,10 @@ class VariantHandler(VariantLoader):
890
893
  }
891
894
  }
892
895
  pipeline = [match, group]
893
- results = self.variant_collection.aggregate(pipeline)
896
+ results = list(self.variant_collection.aggregate(pipeline))
897
+
898
+ omics_results = list(self.omics_variant_collection.aggregate(pipeline))
899
+ results.extend(omics_results)
894
900
 
895
901
  variants_by_type = {}
896
902
  for item in results:
scout/build/case.py CHANGED
@@ -285,6 +285,7 @@ def build_case(case_data, adapter):
285
285
  case_obj[report_key] = case_data.get(report_key)
286
286
 
287
287
  case_obj["vcf_files"] = case_data.get("vcf_files", {})
288
+ case_obj["omics_files"] = case_data.get("omics_files", {})
288
289
  case_obj["delivery_report"] = case_data.get("delivery_report")
289
290
 
290
291
  _populate_pipeline_info(case_obj, case_data)
@@ -297,6 +298,10 @@ def build_case(case_data, adapter):
297
298
 
298
299
  case_obj["has_meivariants"] = bool(case_obj["vcf_files"].get("vcf_mei"))
299
300
 
301
+ case_obj["has_outliers"] = bool(
302
+ case_obj["omics_files"].get("fraser") or case_obj["omics_files"].get("outrider")
303
+ )
304
+
300
305
  case_obj["is_migrated"] = False
301
306
 
302
307
  # What experiment is used, alternatives are rare (rare disease) or cancer
@@ -460,6 +460,7 @@ def add_frequencies(variant_obj, frequencies):
460
460
  variant_obj["thousand_genomes_frequency_right"] = call_safe(
461
461
  float, frequencies.get("thousand_g_right")
462
462
  )
463
+ variant_obj["colorsdb_af"] = call_safe(float, frequencies.get("colorsdb_af"))
463
464
 
464
465
  # Add the sv counts:
465
466
  variant_obj["clingen_cgh_benign"] = frequencies.get("clingen_benign")
@@ -45,11 +45,12 @@ from .disease_parsing import (
45
45
  MIMNR_PATTERN,
46
46
  OMIM_STATUS_MAP,
47
47
  )
48
- from .file_types import FILE_TYPE_MAP
48
+ from .file_types import FILE_TYPE_MAP, OMICS_FILE_TYPE_MAP
49
49
  from .filters import (
50
50
  CLINICAL_FILTER_BASE,
51
51
  CLINICAL_FILTER_BASE_CANCER,
52
52
  CLINICAL_FILTER_BASE_MEI,
53
+ CLINICAL_FILTER_BASE_OUTLIER,
53
54
  CLINICAL_FILTER_BASE_SV,
54
55
  )
55
56
  from .gene_tags import (
@@ -88,6 +89,7 @@ from .variant_tags import (
88
89
  GENETIC_MODELS_PALETTE,
89
90
  MANUAL_RANK_OPTIONS,
90
91
  MOSAICISM_OPTIONS,
92
+ OUTLIER_TYPES,
91
93
  SPIDEX_HUMAN,
92
94
  SPIDEX_LEVELS,
93
95
  SV_TYPES,
@@ -117,6 +117,7 @@ VERBS_MAP = {
117
117
  "dismiss_variant": "dismissed variant for",
118
118
  "filter_audit": "marked case audited with filter",
119
119
  "filter_stash": "stored a filter for",
120
+ "filter_unaudit": "un-audited a filter for",
120
121
  "manual_rank": "updated manual rank for",
121
122
  "mark_causative": "marked causative for",
122
123
  "mark_partial_causative": "mark partial causative for",
@@ -1,4 +1,4 @@
1
- CLINVAR_API_URL = "https://submit.ncbi.nlm.nih.gov/api/v1/submissions/"
1
+ CLINVAR_API_URL_DEFAULT = "https://submit.ncbi.nlm.nih.gov/api/v1/submissions/"
2
2
  PRECLINVAR_URL = "https://preclinvar.scilifelab.se"
3
3
 
4
4
  ASSERTION_METHOD = "ACMG Guidelines, 2015"
@@ -88,3 +88,34 @@ FILE_TYPE_MAP = {
88
88
  "load_priority": 50,
89
89
  },
90
90
  }
91
+
92
+ OMICS_FILE_TYPE_MAP = {
93
+ "fraser": {
94
+ "format": "tsv",
95
+ "analysis_type": "wts",
96
+ "category": "outlier",
97
+ "sub_category": "splicing",
98
+ "variant_type": "clinical",
99
+ },
100
+ "outrider": {
101
+ "format": "tsv",
102
+ "analysis_type": "wts",
103
+ "category": "outlier",
104
+ "sub_category": "expression",
105
+ "variant_type": "clinical",
106
+ },
107
+ "fraser_research": {
108
+ "format": "tsv",
109
+ "analysis_type": "wts",
110
+ "category": "outlier",
111
+ "sub_category": "splicing",
112
+ "variant_type": "research",
113
+ },
114
+ "outrider_research": {
115
+ "format": "tsv",
116
+ "analysis_type": "wts",
117
+ "category": "outlier",
118
+ "sub_category": "expression",
119
+ "variant_type": "research",
120
+ },
121
+ }
@@ -30,3 +30,7 @@ CLINICAL_FILTER_BASE_MEI = {
30
30
  "functional_annotations": SEVERE_SO_TERMS_SV,
31
31
  "swegen_freq": "0.02",
32
32
  }
33
+
34
+ CLINICAL_FILTER_BASE_OUTLIER = {
35
+ "variant_type": "clinical",
36
+ }
@@ -12,23 +12,48 @@ INDEXES = {
12
12
  IndexModel(
13
13
  [("build", ASCENDING), ("chromosome", ASCENDING)],
14
14
  name="build_chromosome",
15
- background=True,
16
15
  ),
17
16
  IndexModel(
18
17
  [("build", ASCENDING), ("hgnc_id", ASCENDING)],
19
18
  name="build_hgncid",
20
- background=True,
21
19
  ),
22
20
  IndexModel(
23
21
  [("build", ASCENDING), ("aliases", ASCENDING)],
24
22
  name="build_aliases",
25
- background=True,
26
23
  ),
27
24
  IndexModel(
28
25
  [("build", ASCENDING), ("hgnc_symbol", ASCENDING)],
29
26
  name="build_hgnc_symbol",
30
27
  ),
31
28
  ],
29
+ "omics_variant": [
30
+ IndexModel(
31
+ # Clear text variant id index
32
+ [
33
+ ("omics_variant_id", ASCENDING),
34
+ ],
35
+ name="omics_variant_id",
36
+ ),
37
+ IndexModel(
38
+ # Index for searching across cases for a change in given genes
39
+ [
40
+ ("hgnc_ids", ASCENDING),
41
+ ("sub_category", ASCENDING),
42
+ ("variant_type", ASCENDING),
43
+ ],
44
+ name="hgnc_ids_sub_category_variant_type",
45
+ ),
46
+ IndexModel(
47
+ # Filterish index
48
+ [
49
+ ("case_id", ASCENDING),
50
+ ("variant_type", ASCENDING),
51
+ ("sub_category", ASCENDING),
52
+ ("hgnc_ids", ASCENDING),
53
+ ],
54
+ name="case_id_variant_type_sub_category_hgnc_ids",
55
+ ),
56
+ ],
32
57
  "variant": [
33
58
  IndexModel(
34
59
  [
@@ -39,7 +64,6 @@ INDEXES = {
39
64
  ("hgnc_ids", ASCENDING),
40
65
  ],
41
66
  name="caseid_category_varianttype_variantrank_hgncids",
42
- background=True,
43
67
  ),
44
68
  IndexModel(
45
69
  [
@@ -49,8 +73,7 @@ INDEXES = {
49
73
  ("variant_type", ASCENDING),
50
74
  ],
51
75
  name="hgncsymbol_rankscore_category_varianttype",
52
- background=True,
53
- partialFilterExpression={"rank_score": {"$gt": 5}, "category": "snv"},
76
+ partialFilterExpression={"rank_score": {"$gte": 5}},
54
77
  ),
55
78
  IndexModel(
56
79
  [
@@ -59,7 +82,6 @@ INDEXES = {
59
82
  ("category", ASCENDING),
60
83
  ],
61
84
  name="variantid_caseid_category",
62
- background=True,
63
85
  ),
64
86
  IndexModel(
65
87
  [
@@ -69,7 +91,6 @@ INDEXES = {
69
91
  ("rank_score", ASCENDING),
70
92
  ],
71
93
  name="category_caseid_varianttype_rankscore",
72
- background=True,
73
94
  ),
74
95
  IndexModel(
75
96
  [
@@ -81,18 +102,16 @@ INDEXES = {
81
102
  ("end", ASCENDING),
82
103
  ],
83
104
  name="caseid_category_chromosome_start_end",
84
- background=True,
85
105
  ),
86
106
  IndexModel(
87
107
  [("variant_id", ASCENDING), ("institute", ASCENDING)],
88
108
  name="variant_id_institute",
89
- background=True,
90
109
  ),
91
110
  ],
92
111
  "hpo_term": [
93
112
  IndexModel([("description", ASCENDING)], name="description"),
94
113
  IndexModel([("description", TEXT)], default_language="english", name="description_text"),
95
- IndexModel([("hpo_number", ASCENDING)], name="number", background=True),
114
+ IndexModel([("hpo_number", ASCENDING)], name="number"),
96
115
  ],
97
116
  "event": [
98
117
  IndexModel(
@@ -115,14 +134,12 @@ INDEXES = {
115
134
  IndexModel(
116
135
  [("build", ASCENDING), ("hgnc_id", ASCENDING), ("length", DESCENDING)],
117
136
  name="hgncid_length",
118
- background=True,
119
137
  )
120
138
  ],
121
139
  "exon": [
122
140
  IndexModel(
123
141
  [("build", ASCENDING), ("hgnc_id", ASCENDING)],
124
142
  name="build_hgncid",
125
- background=True,
126
143
  )
127
144
  ],
128
145
  "case": [
@@ -37,6 +37,8 @@ FEATURE_TYPES = (
37
37
 
38
38
  SV_TYPES = ("ins", "del", "dup", "cnv", "inv", "bnd")
39
39
 
40
+ OUTLIER_TYPES = ("splicing", "expression")
41
+
40
42
  GENETIC_MODELS = (
41
43
  ("AR_hom", "Autosomal Recessive Homozygote"),
42
44
  ("AR_hom_dn", "Autosomal Recessive Homozygote De Novo"),
@@ -519,4 +521,5 @@ VARIANTS_TARGET_FROM_CATEGORY = {
519
521
  "snv": "variants.variants",
520
522
  "str": "variants.str_variants",
521
523
  "fusion": "variants.fusion_variants",
524
+ "outlier": "omics_variants.outliers",
522
525
  }
Binary file
Binary file
@@ -125,6 +125,10 @@ vcf_snv_research: scout/demo/643594.research.vcf.gz
125
125
  vcf_sv_research: scout/demo/643594.research.SV.vcf.gz
126
126
  vcf_mei_research: scout/demo/643594.research.mei.vcf.gz
127
127
 
128
+ omics_files:
129
+ fraser: scout/demo/drop/fraser_top_hits_clinical.tsv
130
+ outrider: scout/demo/drop/outrider_top_hits_clinical.tsv
131
+
128
132
  smn_tsv: scout/demo/643594.solo.smn.tsv
129
133
 
130
134
  madeline: scout/demo/madeline.xml