def cases(institute_id): """Display a list of cases for an institute.""" institute_obj = institute_and_case(store, institute_id) query = request.args.get("query") limit = 100 if request.args.get("limit"): limit = int(request.args.get("limit")) skip_assigned = request.args.get("skip_assigned") is_research = request.args.get("is_research") all_cases = store.cases( collaborator=institute_id, name_query=query, skip_assigned=skip_assigned, is_research=is_research, ) sort_by = request.args.get("sort") sort_order = request.args.get("order") or "asc" if sort_by: pymongo_sort = pymongo.ASCENDING if sort_order == "desc": pymongo_sort = pymongo.DESCENDING if sort_by == "analysis_date": all_cases.sort("analysis_date", pymongo_sort) elif sort_by == "track": all_cases.sort("track", pymongo_sort) elif sort_by == "status": all_cases.sort("status", pymongo_sort) LOG.debug("Prepare all cases") prioritized_cases = store.prioritized_cases(institute_id=institute_id) data = controllers.cases(store, all_cases, prioritized_cases, limit) data["sort_order"] = sort_order data["sort_by"] = sort_by data["nr_cases"] = store.nr_cases(institute_id=institute_id) sanger_unevaluated = controllers.get_sanger_unevaluated( store, institute_id, current_user.email) if len(sanger_unevaluated) > 0: data["sanger_unevaluated"] = sanger_unevaluated return dict(institute=institute_obj, skip_assigned=skip_assigned, is_research=is_research, query=query, **data)
def caselist(institute_id): """Search for cases for autocompletion""" query = request.args.get("query") if query is None: return abort(500) display_names = sorted([ case["display_name"] for case in store.cases(owner=institute_id, name_query="case:" + query) ]) json_terms = [{ "name": "{}".format(display_name) } for display_name in display_names] return jsonify(json_terms)
def cases(institute_id): """Display a list of cases for an institute.""" institute_obj = institute_and_case(store, institute_id) query = request.args.get('query') limit = 100 if request.args.get('limit'): limit = int(request.args.get('limit')) skip_assigned = request.args.get('skip_assigned') all_cases = store.cases(institute_id, name_query=query, skip_assigned=skip_assigned) data = controllers.cases(store, all_cases, limit) return dict(institute=institute_obj, skip_assigned=skip_assigned, query=query, **data)
def _populate_case_groups(store, case_obj, case_groups, case_group_label): """Case groups allow display of information about user linked cases together on one case. Notably variantS lists show shared annotations and alignment views show all alignments available for the group. Each case may belong to any of a list of groups. Groups have human readable labels that need to be fetched separately. Alignments for each case, that belongs to a group that the present case also belongs to, are added to the present case. Args: store(adapter.MongoAdapter) case_obj(models.Case) case_group(dict) - keys group ids, values list(case_ids) case_group_label(dict) - keys group ids, values case_group_labels(str) """ if case_obj.get("group"): for group in case_obj.get("group"): case_groups[group] = list(store.cases(group=group)) case_group_label[group] = store.case_group_label(group)
def cases(institute_id): """Display a list of cases for an institute.""" institute_obj = institute_and_case(store, institute_id) query = request.args.get('query') limit = 100 if request.args.get('limit'): limit = int(request.args.get('limit')) skip_assigned = request.args.get('skip_assigned') is_research = request.args.get('is_research') all_cases = store.cases(collaborator=institute_id, name_query=query, skip_assigned=skip_assigned, is_research=is_research) data = controllers.cases(store, all_cases, limit) sanger_unevaluated = controllers.get_sanger_unevaluated(store, institute_id, current_user.email) if len(sanger_unevaluated)> 0: data['sanger_unevaluated'] = sanger_unevaluated return dict(institute=institute_obj, skip_assigned=skip_assigned, is_research=is_research, query=query, **data)
def cases(institute_id): """Display a list of cases for an institute.""" institute_obj = institute_and_case(store, institute_id) query = request.args.get('query') limit = 500 if request.args.get('limit'): limit = int(request.args.get('limit')) skip_assigned = request.args.get('skip_assigned') is_research = request.args.get('is_research') all_cases = store.cases(collaborator=institute_id, name_query=query, skip_assigned=skip_assigned, is_research=is_research) LOG.info(type(all_cases)) sort_by = request.args.get('sort') if sort_by: if sort_by == 'analysis_date': all_cases.sort('analysis_date', pymongo.DESCENDING) elif sort_by == 'track': all_cases.sort('track', pymongo.ASCENDING) elif sort_by == 'status': all_cases.sort('status', pymongo.ASCENDING) LOG.debug("Prepare all cases") data = controllers.cases(store, all_cases, limit) sanger_unevaluated = controllers.get_sanger_unevaluated( store, institute_id, current_user.email) if len(sanger_unevaluated) > 0: data['sanger_unevaluated'] = sanger_unevaluated return dict(institute=institute_obj, skip_assigned=skip_assigned, is_research=is_research, query=query, **data)
def cases(store, request, institute_id): """Preprocess case objects. Add all the necessary information to display the 'cases' view Args: store(adapter.MongoAdapter) request(flask.request) request sent by browser to the api_institutes endpoint institute_id(str): An _id of an institute Returns: data(dict): includes the cases, how many there are and the limit. """ data = {"search_terms": CASE_SEARCH_TERMS} institute_obj = institute_and_case(store, institute_id) data["institute"] = institute_obj name_query = None if request.args.get("search_term"): name_query = "".join([ request.args.get("search_type"), re.escape(request.args["search_term"].strip()) ]) data["name_query"] = name_query limit = int(request.args.get("search_limit")) if request.args.get( "search_limit") else 100 skip_assigned = request.args.get("skip_assigned") data["form"] = populate_case_filter_form(request.args) data["skip_assigned"] = skip_assigned is_research = request.args.get("is_research") data["is_research"] = is_research prioritized_cases = store.prioritized_cases(institute_id=institute_id) all_cases = store.cases( collaborator=institute_id, name_query=name_query, skip_assigned=skip_assigned, is_research=is_research, ) all_cases = _sort_cases(data, request, all_cases) data["nr_cases"] = store.nr_cases(institute_id=institute_id) sanger_unevaluated = get_sanger_unevaluated(store, institute_id, current_user.email) if len(sanger_unevaluated) > 0: data["sanger_unevaluated"] = sanger_unevaluated case_groups = {status: [] for status in CASE_STATUSES} nr_cases = 0 # local function to add info to case obj def populate_case_obj(case_obj): analysis_types = set(ind["analysis_type"] for ind in case_obj["individuals"]) LOG.debug("Analysis types found in %s: %s", case_obj["_id"], ",".join(analysis_types)) if len(analysis_types) > 1: LOG.debug("Set analysis types to {'mixed'}") analysis_types = set(["mixed"]) case_obj["analysis_types"] = list(analysis_types) case_obj["assignees"] = [ store.user(user_email) for user_email in case_obj.get("assignees", []) ] # Check if case was re-runned analyses = case_obj.get("analyses", []) now = datetime.datetime.now() case_obj["is_rerun"] = (len(analyses) > 1 or analyses and analyses[0].get("date", now) < case_obj.get("analysis_date", now)) case_obj["clinvar_variants"] = store.case_to_clinVars(case_obj["_id"]) case_obj["display_track"] = TRACKS[case_obj.get("track", "rare")] return case_obj for nr_cases, case_obj in enumerate(all_cases.limit(limit), 1): case_obj = populate_case_obj(case_obj) case_groups[case_obj["status"]].append(case_obj) if prioritized_cases: extra_prioritized = 0 for case_obj in prioritized_cases: if any( group_obj.get("display_name") == case_obj.get( "display_name") for group_obj in case_groups[case_obj["status"]]): continue else: extra_prioritized += 1 case_obj = populate_case_obj(case_obj) case_groups[case_obj["status"]].append(case_obj) # extra prioritized cases are potentially shown in addition to the case query limit nr_cases += extra_prioritized data["cases"] = [(status, case_groups[status]) for status in CASE_STATUSES] data["found_cases"] = nr_cases data["limit"] = limit return data
def variants( user: str, case_id: str, status: list, older_than: int, analysis_type: list, rank_threshold: int, variants_threshold: int, keep_ctg: list, dry_run: bool, ) -> None: """Delete variants for one or more cases""" user_obj = store.user(user) if user_obj is None: click.echo(f"Could not find a user with email '{user}' in database") return total_deleted = 0 items_name = "deleted variants" if dry_run: click.echo("--------------- DRY RUN COMMAND ---------------") items_name = "estimated deleted variants" else: click.confirm("Variants are going to be deleted from database. Continue?", abort=True) case_query = store.build_case_query(case_id, status, older_than, analysis_type) # Estimate the average size of a variant document in database avg_var_size = store.collection_stats("variant").get("avgObjSize", 0) # in bytes # Get all cases where case_query applies n_cases = store.case_collection.count_documents(case_query) cases = store.cases(query=case_query) filters = ( f"Rank-score threshold:{rank_threshold}, case n. variants threshold:{variants_threshold}." ) click.echo("\t".join(DELETE_VARIANTS_HEADER)) for nr, case in enumerate(cases, 1): case_id = case["_id"] case_n_variants = store.variant_collection.count_documents({"case_id": case_id}) # Skip case if user provided a number of variants to keep and this number is less than total number of case variants if variants_threshold and case_n_variants < variants_threshold: continue # Get evaluated variants for the case that haven't been dismissed case_evaluated = store.evaluated_variants(case_id=case_id) evaluated_not_dismissed = [ variant["_id"] for variant in case_evaluated if "dismiss_variant" not in variant ] # Do not remove variants that are either pinned, causative or evaluated not dismissed variants_to_keep = ( case.get("suspects", []) + case.get("causatives", []) + evaluated_not_dismissed or [] ) variants_query = store.delete_variants_query( case_id, variants_to_keep, rank_threshold, keep_ctg ) if dry_run: # Just print how many variants would be removed for this case remove_n_variants = store.variant_collection.count_documents(variants_query) total_deleted += remove_n_variants click.echo( "\t".join( [ str(nr), str(n_cases), case["owner"], case["display_name"], case_id, case.get("track", ""), str(case["analysis_date"]), case.get("status", ""), str(case.get("is_research", "")), str(case_n_variants), str(remove_n_variants), ] ) ) continue # delete variants specified by variants_query result = store.variant_collection.delete_many(variants_query) click.echo(f"Deleted {result.deleted_count} / {case_n_variants} total variants") total_deleted += result.deleted_count click.echo( "\t".join( [ str(nr), str(n_cases), case["owner"], case["display_name"], case_id, case.get("track", ""), str(case["analysis_date"]), case.get("status", ""), str(case.get("is_research", "")), str(case_n_variants), str(result.deleted_count), ] ) ) # Create event in database institute_obj = store.institute(case["owner"]) with current_app.test_request_context("/cases"): url = url_for( "cases.case", institute_id=institute_obj["_id"], case_name=case["display_name"] ) store.remove_variants_event( institute=institute_obj, case=case, user=user_obj, link=url, content=filters ) click.echo(f"Total {items_name}: {total_deleted}") click.echo( f"Estimated space freed (GB): {round((total_deleted * avg_var_size) / BYTES_IN_ONE_GIGABYTE, 4)}" )
def index(): """Display a list of all user institutes.""" institute_objs = user_institutes(store, current_user) institutes_count = ((institute_obj, store.cases(collaborator=institute_obj['_id']).count()) for institute_obj in institute_objs if institute_obj) return dict(institutes=institutes_count)
def make_igv_tracks(case_obj, variant_id, chrom=None, start=None, stop=None): """Create a dictionary containing the required tracks for displaying IGV tracks for case or a group of cases Args: institute_id(str): institute _id case_obj(scout.models.Case) variant_id(str): _id of a variant chrom(str/None): requested chromosome [1-22], X, Y, [M-MT] start(int/None): start of the genomic interval to be displayed stop(int/None): stop of the genomic interval to be displayed Returns: display_obj(dict): A display object containing case name, list of genes, lucus and tracks """ display_obj = {} variant_obj = store.variant(document_id=variant_id) if variant_obj: # Set display locus start = start or variant_obj["position"] stop = stop or variant_obj["end"] chromosome = chrom or variant_obj.get("chromosome") chromosome = chromosome.replace("MT", "M") display_obj["locus"] = "chr{0}:{1}-{2}".format(chromosome, start, stop) else: chromosome = "All" # Set genome build for displaying alignments: if "38" in str(case_obj.get("genome_build", "37")) or chromosome == "M": build = "38" else: build = "37" # Set general tracks (Genes, Clinvar and ClinVar SNVs are shown according to user preferences) set_common_tracks(display_obj, build) # Build tracks for main case and all connected cases (cases grouped with main case) grouped_cases = [] for group in case_obj.get("group", []): group_cases = list(store.cases(group=group)) for case in group_cases: case_append_alignments( case) # Add track data to connected case dictionary grouped_cases.append(case) if not grouped_cases: # Display case individuals tracks only case_append_alignments( case_obj) # Add track data to main case dictionary grouped_cases.append(case_obj) # Set up bam/cram alignments for case group samples: set_sample_tracks(display_obj, grouped_cases, chromosome) # When chrom != MT, set up case-specific tracks (might be present according to the pipeline) if chrom != "M": set_case_specific_tracks(display_obj, case_obj) # Set up custom cloud public tracks, if available set_cloud_public_tracks(display_obj, build) display_obj["display_center_guide"] = True return display_obj