diff options
author | Frederick Muriuki Muriithi | 2022-02-26 08:11:09 +0300 |
---|---|---|
committer | Frederick Muriuki Muriithi | 2022-03-10 05:31:33 +0300 |
commit | 80b02d37f60d172be01bf8cd62bd84b406b1e0dd (patch) | |
tree | 50faa0ad3fc8d7e61e11ceb06d76248d62230b58 | |
parent | f733cf955ed5137c4a1a67860b26bbaf23650c83 (diff) | |
download | genenetwork2-partial_corr_ui_rework.tar.gz |
Use one-step process for the partial correlations computationspartial_corr_ui_rework
This commit gets rid of the multi-step partial correlations process
replacing it with a single-step process.
Summary of changes:
* wqflask/wqflask/collect.py: Add function to format the trait details
in a format that is usable for the partial correlations system.
* wqflask/wqflask/database.py: Provide function to create a connection
to the database
* wqflask/wqflask/partial_correlations_views.py: Rework the code to
enable the one-step process for the partial correlations
computations
* wqflask/wqflask/static/new/javascript/partial_correlations.js: Get
rid of code that supported the multi-step process
* wqflask/wqflask/templates/collections/view.html: Remove inconsistent
UI elements. Attach traits info in a form usable for the partial
correlations
* wqflask/wqflask/templates/partial_correlations.html: delete html
template
* wqflask/wqflask/templates/partial_correlations/pcorrs_error.html:
provide a html template to display errors in the partial
correlations computation process
* wqflask/wqflask/templates/partial_correlations/pcorrs_poll_results.html:
UI template to provide user with feedback as the computations
continue in the background
* wqflask/wqflask/templates/partial_correlations/pcorrs_results_presentation.html:
UI template to present the results of successful computation
* wqflask/wqflask/templates/partial_correlations/pcorrs_select_operations.html:
UI template to trigger the partial correlations computations
* wqflask/wqflask/templates/tool_buttons.html: Add the partial
correlations button to the template to ensure a consistent look and
feel
11 files changed, 762 insertions, 907 deletions
diff --git a/wqflask/wqflask/collect.py b/wqflask/wqflask/collect.py index 3475ae5d..815bb7c1 100644 --- a/wqflask/wqflask/collect.py +++ b/wqflask/wqflask/collect.py @@ -189,6 +189,30 @@ def delete_collection(): return redirect(url_for('list_collections')) +def trait_info_str(trait): + """Provide a string representation for given trait""" + def __trait_desc(trt): + if trait.dataset.type == "Geno": + return f"Marker: {trt.name}" + return trt.description_display or "N/A" + + def __symbol(trt): + return (trt.symbol or trt.abbreviation or "N/A")[:20] + + def __lrs(trt): + return ( + f"{float(trait.LRS_score_repr):0.3f}" if float(trait.LRS_score_repr) > 0 + else f"{trait.LRS_score_repr}") + + def __location(trt): + if hasattr(trt, "location_repr"): + return trt.location_repr + return None + + return "{}|||{}|||{}|||{}|||{}|||{:0.3f}|||{}|||{}".format( + trait.name, trait.dataset.name, __trait_desc(trait), __symbol(trait), + __location(trait), trait.mean, __lrs(trait), trait.LRS_location_repr) + @app.route("/collections/view") def view_collection(): params = request.args @@ -227,9 +251,10 @@ def view_collection(): if "json" in params: return json.dumps(json_version) else: - return render_template("collections/view.html", - **collection_info - ) + return render_template( + "collections/view.html", + trait_info_str=trait_info_str, + **collection_info) @app.route("/collections/change_name", methods=('POST',)) diff --git a/wqflask/wqflask/database.py b/wqflask/wqflask/database.py index 11f8d287..e485bcf1 100644 --- a/wqflask/wqflask/database.py +++ b/wqflask/wqflask/database.py @@ -1,10 +1,13 @@ # Module to initialize sqlalchemy with flask +import MySQLdb from sqlalchemy import create_engine from sqlalchemy.orm import scoped_session, sessionmaker from sqlalchemy.ext.declarative import declarative_base from utility.tools import SQL_URI +from flask import current_app + engine = create_engine(SQL_URI, encoding="latin1") @@ -16,3 +19,12 @@ Base.query = db_session.query_property() # Initialise the db Base.metadata.create_all(bind=engine) + + +def database_connection(): + """Returns a database connection""" + return MySQLdb.Connect( + db=current_app.config.get("DB_NAME"), + user=current_app.config.get("DB_USER"), + passwd=current_app.config.get("DB_PASS"), + host=current_app.config.get("DB_HOST")) diff --git a/wqflask/wqflask/partial_correlations_views.py b/wqflask/wqflask/partial_correlations_views.py index 6bc5efee..659b49e9 100644 --- a/wqflask/wqflask/partial_correlations_views.py +++ b/wqflask/wqflask/partial_correlations_views.py @@ -1,142 +1,31 @@ +import json +import math +import requests +from functools import reduce from typing import Union, Tuple -import MySQLdb -from gn3.db.traits import retrieve_trait_info -from flask import flash, request, current_app, render_template -from gn3.computations.partial_correlations import partial_correlations_entry +from flask import ( + flash, + request, + url_for, + redirect, + current_app, + render_template) from wqflask import app from utility.tools import GN_SERVER_URL +from wqflask.database import database_connection +from gn3.db.partial_correlations import traits_info -def parse_trait(trait_str: str) -> Union[dict, None]: - keys = ( - "name", "dataset", "symbol", "description", "location", "mean_expr", - "max_lrs", "data_hmac") - parts = tuple(part.strip() for part in trait_str.split(":::")) - if len(parts) == len(keys): - return dict(zip(keys, parts)) - return None - -def process_step_select_primary( - primary_trait: dict, control_traits: Tuple[dict, ...], - target_traits: Tuple[dict, ...], - traits_list: Tuple[dict, ...], corr_method: str) -> Tuple[ - str, dict, Tuple[dict, ...], Tuple[dict, ...], Tuple[dict, ...], - str]: - if primary_trait is None: - flash("You must select a primary trait", "alert-danger") - return ( - "select-primary", primary_trait, control_traits, target_traits, - traits_list, corr_method) - - return ( - "select-controls", primary_trait, control_traits, target_traits, - tuple( - trait for trait in traits_list - if trait["data_hmac"] != primary_trait["data_hmac"]), - corr_method) - -def process_step_select_controls( - primary_trait: dict, control_traits: Tuple[dict, ...], - target_traits: Tuple[dict, ...], - traits_list: Tuple[dict, ...], corr_method: str) -> Tuple[ - str, dict, Tuple[dict, ...], Tuple[dict, ...], Tuple[dict, ...], - str]: - if len(control_traits) == 0 or len(control_traits) > 3: - flash( - ("You must select a minimum of one control trait, up to a maximum " - "of three control traits."), - "alert-danger") - return ( - "select-controls", primary_trait, control_traits, target_traits, - traits_list, corr_method) - - hmacs =(primary_trait["data_hmac"],) + tuple( - trait["data_hmac"] for trait in control_traits) - return ( - "select-corr-method", primary_trait, control_traits, target_traits, - tuple( - trait for trait in traits_list if trait["data_hmac"] not in hmacs), - corr_method) - -def process_step_select_targets( - primary_trait: dict, control_traits: Tuple[dict, ...], - target_traits: Tuple[dict, ...], - traits_list: Tuple[dict, ...], corr_method: str) -> Tuple[ - str, dict, Tuple[dict, ...], Tuple[dict, ...], Tuple[dict, ...], - str]: - if len(target_traits) == 0: - flash( - "You must select at least one target trait.", "alert-danger") - return ( - "select-targets", primary_trait, control_traits, target_traits, - traits_list, corr_method) - - hmacs =(primary_trait["data_hmac"],) + tuple( - trait["data_hmac"] for trait in (control_traits + target_traits)) - return ( - "select-corr-method", primary_trait, control_traits, target_traits, - tuple( - trait for trait in traits_list if trait["data_hmac"] not in hmacs), - corr_method) - -def process_step_select_corr_method( - primary_trait: dict, control_traits: Tuple[dict, ...], - target_traits: Tuple[dict, ...], - traits_list: Tuple[dict, ...], corr_method: str) -> Tuple[ - str, dict, Tuple[dict, ...], Tuple[dict, ...], Tuple[dict, ...], - str]: - methods = ( - "genetic correlation, pearson's r", - "genetic correlation, spearman's rho", - "sgo literature correlation", - "tissue correlation, pearson's r", - "tissue correlation, spearman's rho") - if corr_method.lower() not in methods: - flash( - "Selected method is unknown.", "alert-danger") - return ( - "select-corr-method", primary_trait, control_traits, target_traits, - traits_list, corr_method) - - hmacs =(primary_trait["data_hmac"],) + tuple( - trait["data_hmac"] for trait in (control_traits + target_traits)) - return ( - "run-correlation", primary_trait, control_traits, target_traits, - tuple( - trait for trait in traits_list if trait["data_hmac"] not in hmacs), - corr_method) - -def process_step( - step: str, primary_trait: dict, control_traits: Tuple[dict, ...], - target_traits: Tuple[dict, ...], traits_list: Tuple[dict, ...], - corr_method: str) -> Tuple[ - str, dict, Tuple[dict, ...], Tuple[dict, ...], Tuple[dict, ...], - str]: - processor_functions = { - # "select-traits": lambda arg: arg, - "select-primary": process_step_select_primary, - "select-controls": process_step_select_controls, - "select-targets": process_step_select_targets, - "select-corr-method": process_step_select_corr_method - } - return processor_functions[(step or "select-primary")]( - primary_trait, control_traits, target_traits, traits_list, corr_method) - -def sequence_of_traits(trait_strs) -> Tuple[dict, ...]: - return tuple(filter( - lambda trt: trt is not None, - (parse_trait(tstr.strip()) for tstr in trait_strs))) - -def publish_target_dabases(conn, group, threshold): +def publish_target_databases(conn, groups, threshold): query = ( "SELECT PublishFreeze.FullName,PublishFreeze.Name " "FROM PublishFreeze, InbredSet " "WHERE PublishFreeze.InbredSetId = InbredSet.Id " - "AND InbredSet.Name = %(group)s " - "AND PublishFreeze.public > %(threshold)s") + f"AND InbredSet.Name IN ({', '.join(['%s'] * len(groups))}) " + "AND PublishFreeze.public > %s") with conn.cursor() as cursor: - cursor.execute(query, {"group": group, "threshold": threshold}) + cursor.execute(query, tuple(groups) + (threshold,)) res = cursor.fetchall() if res: return tuple( @@ -144,15 +33,15 @@ def publish_target_dabases(conn, group, threshold): return tuple() -def geno_target_databases(conn, group, threshold): +def geno_target_databases(conn, groups, threshold): query = ( "SELECT GenoFreeze.FullName,GenoFreeze.Name " "FROM GenoFreeze, InbredSet " "WHERE GenoFreeze.InbredSetId = InbredSet.Id " - "AND InbredSet.Name = %(group)s " - "AND GenoFreeze.public > %(threshold)s") + f"AND InbredSet.Name IN ({', '.join(['%s'] * len(groups))}) " + "AND GenoFreeze.public > %s") with conn.cursor() as cursor: - cursor.execute(query, {"group": group, "threshold": threshold}) + cursor.execute(query, tuple(groups) + (threshold,)) res = cursor.fetchall() if res: return tuple( @@ -160,27 +49,26 @@ def geno_target_databases(conn, group, threshold): return tuple() -def probeset_target_databases(conn, group, threshold): +def probeset_target_databases(conn, groups, threshold): query1 = "SELECT Id, Name FROM Tissue order by Name" - query2 = ( - "SELECT ProbeFreeze.TissueId, ProbeSetFreeze.FullName, ProbeSetFreeze.Name " - "FROM ProbeSetFreeze, ProbeFreeze, InbredSet " - "WHERE ProbeSetFreeze.ProbeFreezeId = ProbeFreeze.Id " - "AND ProbeFreeze.TissueId IN %(tissue_ids)s " - "AND ProbeSetFreeze.public > %(threshold)s " - "AND ProbeFreeze.InbredSetId = InbredSet.Id " - "AND InbredSet.Name like %(group)s " - "ORDER BY ProbeSetFreeze.CreateTime desc, ProbeSetFreeze.AvgId") with conn.cursor() as cursor: cursor.execute(query1) tissue_res = cursor.fetchall() if tissue_res: tissue_ids = tuple(row[0] for row in tissue_res) - cursor.execute( - query2,{ - "tissue_ids": tissue_ids, "group": f"{group}%%", - "threshold": threshold - }) + groups_clauses = ["InbredSet.Name like %s"] * len(groups) + query2 = ( + "SELECT ProbeFreeze.TissueId, ProbeSetFreeze.FullName, " + "ProbeSetFreeze.Name " + "FROM ProbeSetFreeze, ProbeFreeze, InbredSet " + "WHERE ProbeSetFreeze.ProbeFreezeId = ProbeFreeze.Id " + "AND ProbeFreeze.TissueId IN " + f"({', '.join(['%s'] * len(tissue_ids))}) " + "AND ProbeSetFreeze.public > %s " + "AND ProbeFreeze.InbredSetId = InbredSet.Id " + f"AND ({' OR '.join(groups_clauses)}) " + "ORDER BY ProbeSetFreeze.CreateTime desc, ProbeSetFreeze.AvgId") + cursor.execute(query2, tissue_ids + (threshold,) + tuple(groups)) db_res = cursor.fetchall() if db_res: databases = tuple( @@ -197,70 +85,201 @@ def probeset_target_databases(conn, group, threshold): return tuple() -def target_databases(conn, step, trait, threshold): +def target_databases(conn, traits, threshold): """ Retrieves the names of possible target databases from the database. """ - if step != "select-corr-method": - return None - - trait_info = retrieve_trait_info( - threshold, f"{trait['dataset']}::{trait['name']}", conn) - group = trait_info["group"] + trait_info = traits_info( + conn, threshold, + tuple(f"{trait['dataset']}::{trait['trait_name']}" for trait in traits)) + groups = tuple(set(row["db"]["group"] for row in trait_info)) return ( - publish_target_dabases(conn, group, threshold) + - geno_target_databases(conn, group, threshold) + - probeset_target_databases(conn, group, threshold)) + publish_target_databases(conn, groups, threshold) + + geno_target_databases(conn, groups, threshold) + + probeset_target_databases(conn, groups, threshold)) + +def primary_error(args): + if len(args["primary_trait"]) == 0 or len(args["primary_trait"]) > 1: + return { + **args, + "errors": (args.get("errors", tuple()) + + ("You must provide one, and only one primary trait",))} + return args + +def controls_error(args): + if len(args["control_traits"]) == 0 or len(args["control_traits"]) > 3: + return { + **args, + "errors": ( + args.get("errors", tuple()) + + (("You must provide at least one control trait, and a maximum " + "of three control traits"),))} + return args + +def target_db_error(args): + if not args["target_db"]: + return { + **args, + "errors": ( + args.get("errors", tuple()) + + ("The target database must be provided",))} + return args + +def method_error(args): + methods = ( + "genetic correlation, pearson's r", + "genetic correlation, spearman's rho", + "sgo literature correlation", + "tissue correlation, pearson's r", + "tissue correlation, spearman's rho") + if not args["method"] or args["method"].lower() not in methods: + return { + **args, + "errors": ( + args.get("errors", tuple()) + + ("Invalid correlation method provided",))} + return args -def pcorrelations(conn, values): - if values["step"] != "run-correlation": - return None +def criteria_error(args): + try: + int(args.get("criteria", "invalid")) + return args + except ValueError: + return { + **args, + "errors": ( + args.get("errors", tuple()) + + ("Invalid return number provided",))} - def trait_fullname(trait): - return f"{trait['dataset']}::{trait['name']}" +def errors(args): + return criteria_error(method_error(target_db_error(controls_error( + primary_error(args))))) - return partial_correlations_entry( - conn, trait_fullname(values["primary_trait"]), - tuple(trait_fullname(trait) for trait in values["control_traits"]), - values["method"], values["criteria"], values["target_db"]) +def __classify_args(acc, item): + if item[1].startswith("primary_"): + return { + **acc, + "primary_trait": (acc.get("primary_trait", tuple()) + (item,))} + if item[1].startswith("controls_"): + return {**acc, "control_traits": (acc.get("control_traits", tuple()) + (item,))} + if item[0] == "target_db": + return {**acc, "target_db": item[1]} + if item[0] == "method": + return {**acc, "method": item[1]} + if item[0] == "criteria": + return {**acc, "criteria": item[1]} + return acc + +def __build_args(raw_form, traits): + args = reduce(__classify_args, raw_form.items(), {}) + return { + **args, + "primary_trait": [ + item for item in traits if item["trait_name"] in + (name[1][8:] for name in args["primary_trait"])], + "control_traits": [ + item for item in traits if item["trait_name"] in + (name[1][9:] for name in args["control_traits"])] + } + +def parse_trait(trait_str): + return dict(zip( + ("trait_name", "dataset", "description", "symbol", "location", "mean", + "lrs", "lrs_location"), + trait_str.strip().split("|||"))) + +def response_error_message(response): + error_messages = { + 404: ("We could not connect to the API server at this time. " + "Try again later."), + 500: ("The API server experienced a problem. We will be working on a " + "fix. Please try again later.") + } + return error_messages.get( + response.status_code, + "General API server error!!") + +def render_error(error_message): + return render_template( + "partial_correlations/pcorrs_error.html", + message = error_message) + +def handle_200_response(response): + if response["status"] == "success": + return redirect( + url_for( + "poll_partial_correlation_results", + command_id=response["results"]), + code=303) + return render_error(response["results"]) + +def handle_response(response): + if response.status_code != 200: + return render_template( + "partial_correlations/pcorrs_error.html", + message = response_error_message(response)) + return handle_200_response(response.json()) @app.route("/partial_correlations", methods=["POST"]) def partial_correlations(): form = request.form - traits_list = tuple(filter( - lambda trt: trt is not None, - (parse_trait(tstr) for tstr in form.get("traits_list", "").split("|||")))) + traits = tuple( + parse_trait(trait) for trait in + form.get("trait_list").split(";;;")) - args_dict = dict(zip( - ("step", "primary_trait", "control_traits", "target_traits", - "traits_list", "method"), - process_step( - form.get("step", None), - parse_trait(form.get("primary_trait", "")), - sequence_of_traits( - form.getlist("control_traits[]") or - form.get("control_traits", "").split("|||")), - sequence_of_traits( - form.getlist("target_traits[]") or - form.get("target_traits", "").split("|||")), - sequence_of_traits(form.get("traits_list", "").split("|||")), - form.get("method")))) + if form.get("submit") == "Run Partial Correlations": + args = errors(__build_args(form, traits)) + if len(args.get("errors", [])) == 0: + post_data = { + **args, + "primary_trait": args["primary_trait"][0] + } + return handle_response(requests.post( + url=f"{GN_SERVER_URL}api/correlation/partial", + json=json.dumps(post_data))) - conn = MySQLdb.Connect( - db=current_app.config.get("DB_NAME"), - user=current_app.config.get("DB_USER"), - passwd=current_app.config.get("DB_PASS"), - host=current_app.config.get("DB_HOST")) - target_dbs = target_databases( - conn, args_dict["step"], args_dict["primary_trait"], 0) + for error in args["errors"]: + flash(error, "alert-danger") - if args_dict["step"] == "run-correlation": - args_dict = { - **args_dict, "target_db": form.get("target_db"), - "criteria": int(form.get("criteria", 500))} + with database_connection() as conn: + target_dbs = target_databases(conn, traits, threshold=0) + return render_template( + "partial_correlations/pcorrs_select_operations.html", + trait_list_str=form.get("trait_list"), + traits=traits, + target_dbs=target_dbs) - corr_results = pcorrelations(conn, args_dict) +def process_pcorrs_command_output(result): + if result["status"] == "success": + def __format_number(num): + if num is None or math.isnan(num): + return "" + if abs(num) <= 1.04E-4: + return f"{num:.2e}" + return f"{num:.5f}" - return render_template( - "partial_correlations.html", **args_dict, target_dbs=target_dbs, - corr_results=corr_results, part_corr_url=f"{GN_SERVER_URL}api/correlation/partial") + return render_template( + "partial_correlations/pcorrs_results_presentation.html", + primary=result["results"]["primary_trait"], + controls=result["results"]["control_traits"], + correlations=result["results"]["correlations"], + dataset_type=result["results"]["dataset_type"], + method=result["results"]["method"], + format_number=__format_number) + if result["status"] == "error": + return render_error( + "The partial correlations computation failed with an error") + +@app.route("/partial_correlations/<command_id>", methods=["GET"]) +def poll_partial_correlation_results(command_id): + response = requests.get( + url=f"{GN_SERVER_URL}api/async_commands/state/{command_id}") + if response.status_code == 200: + data = response.json() + if data["status"] == "error": + return render_error(response["result"]) + if data["status"] == "success": + return process_pcorrs_command_output(json.loads(data["result"])) + return render_template( + "partial_correlations/pcorrs_poll_results.html", + command_id = command_id) diff --git a/wqflask/wqflask/static/new/javascript/partial_correlations.js b/wqflask/wqflask/static/new/javascript/partial_correlations.js index 3bf2acc4..5de1204c 100644 --- a/wqflask/wqflask/static/new/javascript/partial_correlations.js +++ b/wqflask/wqflask/static/new/javascript/partial_correlations.js @@ -1,336 +1,26 @@ -/** - * This is, hopefully, a short-term stop-gap measure to get the system working - * and to get some feedback, even as better optimisation is done in the - * background to get better response/performance for the partial correlation - * computations - */ - -function key_value(keys, values) { - if(!(keys.length == values.length)) { - Error("The 'keys' and 'values' objects MUST be the same length"); - return null; - } - return values.reduce(function(accumulator, item, index) { - accumulator[keys[index]] = item; - return accumulator; - }, {}); -} - -function trait(trait_str) { - return key_value( - ["name", "dataset", "symbol", "description", "location", "mean_expr", - "max_lrs", "data_hmac"], - trait_str.split(":::")); -} - -function primary_trait() { - trait_string = document.querySelector( - "#partial-correlations-form input[name=primary_trait]").value; - return trait(trait_string); -} - -function control_traits() { - return document.querySelector( - "#partial-correlations-form input[name=control_traits]").value.split( - "|||").map(trait).filter(trait => !(trait === null)); -} - -function correlation_method() { - return document.querySelector( - "#partial-correlations-form select[name=method]").value; -} - -function criteria() { - return document.querySelector( - "#partial-correlations-form select[name=criteria]").value; -} - -function target_db() { - return document.querySelector( - "#partial-correlations-form select[name=target_db]").value; -} - -function partial_corr_request_data() { - return { - "primary_trait": primary_trait(), - "control_traits": control_traits(), - "method": correlation_method(), - "criteria": criteria(), - "target_db": target_db() - } -} - -function rho_or_r(method) { - if (method === "spearman") { - return "rho"; - } - return "r"; -} - -function format_number(num) { - if(num === null) { - return NaN; - } - if(Math.abs(num) <= 1.04e-4) { - return num.toExponential(2); - } - return num.toFixed(5); -} - -function display_publish_results(primary, controls, correlations, method) { - table = document.getElementById("part-corr-results-publish"); - table.setAttribute("style", "display: block;"); - table_body = document.querySelector("#part-corr-results-publish tbody"); - template_row = document.querySelector( - "#part-corr-results-publish tr.template-publish-results-row"); - correlations.forEach(function(item, index, arr) { - new_row = template_row.cloneNode(true); - new_row.setAttribute("class", "results-row"); - new_row.querySelector( - 'td[data-column-heading="Record"]').innerHTML = item["trait_name"]; - new_row.querySelector( - 'td[data-column-heading="Phenotype"]').innerHTML = ( - item["post_publication_description"]); - new_row.querySelector( - 'td[data-column-heading="Authors"]').innerHTML = item["authors"]; - new_row.querySelector( - 'td[data-column-heading="Year"]').innerHTML = item["year"]; - new_row.querySelector( - 'td[data-column-heading="N"]').innerHTML = item["noverlap"]; - new_row.querySelector( - `td[data-column-heading="Partial ${rho_or_r(method)}"]` - ).innerHTML = format_number(item["partial_corr"]); - new_row.querySelector( - `td[data-column-heading="p(partial ${rho_or_r(method)})"]` - ).innerHTML = format_number(item["partial_corr_p_value"]); - new_row.querySelector( - `td[data-column-heading="${rho_or_r(method)}"]` - ).innerHTML = format_number(item["corr"]); - new_row.querySelector( - `td[data-column-heading="p(${rho_or_r(method)})"]` - ).innerHTML = format_number(item["corr_p_value"]); - new_row.querySelector( - `td[data-column-heading="delta ${rho_or_r(method)}"]` - ).innerHTML = format_number(item["delta"]); - table_body.appendChild(new_row); - }); - table_body.removeChild(template_row); -} - -function display_geno_results(primary, controls, correlations, method) { - table = document.getElementById("part-corr-results-geno"); - table.setAttribute("style", "display: block;"); - table_body = document.querySelector("#part-corr-results-geno tbody"); - template_row = document.querySelector( - "#part-corr-results-geno tr.template-geno-results-row"); - correlations.forEach(function(item, index, arr) { - new_row = template_row.cloneNode(true); - new_row.setAttribute("class", "results-row"); - new_row.querySelector( - 'td[data-column-heading="Locus"]').innerHTML = item["trait_name"]; - new_row.querySelector( - 'td[data-column-heading="Chr"]').innerHTML = item["chr"]; - new_row.querySelector( - 'td[data-column-heading="Megabase"]').innerHTML = item["mb"]; - new_row.querySelector( - 'td[data-column-heading="N"]').innerHTML = item["noverlap"]; - new_row.querySelector( - `td[data-column-heading="Partial ${rho_or_r(method)}"]` - ).innerHTML = format_number(item["partial_corr"]); - new_row.querySelector( - `td[data-column-heading="p(partial ${rho_or_r(method)})"]` - ).innerHTML = format_number(item["partial_corr_p_value"]); - new_row.querySelector( - `td[data-column-heading="${rho_or_r(method)}"]` - ).innerHTML = format_number(item["corr"]); - new_row.querySelector( - `td[data-column-heading="p(${rho_or_r(method)})"]` - ).innerHTML = format_number(item["corr_p_value"]); - new_row.querySelector( - `td[data-column-heading="delta ${rho_or_r(method)}"]` - ).innerHTML = format_number(item["delta"]); - table_body.appendChild(new_row); - }); - table_body.removeChild(template_row); -} - -function display_probeset_results(primary, controls, correlations, method) { - table = document.getElementById("part-corr-results-probeset"); - table.setAttribute("style", "display: block;"); - table_body = document.querySelector("#part-corr-results-probeset tbody"); - template_row = document.querySelector( - "#part-corr-results-probeset tr.template-probeset-results-row"); - correlations.forEach(function(item, index, arr) { - new_row = template_row.cloneNode(true); - new_row.setAttribute("class", "results-row"); - new_row.querySelector( - 'td[data-column-heading="Record"]').innerHTML = item["trait_name"]; - new_row.querySelector( - 'td[data-column-heading="Gene ID"]').innerHTML = item["geneid"]; - new_row.querySelector( - 'td[data-column-heading="Homologene ID"]').innerHTML = item["homologeneid"]; - new_row.querySelector( - 'td[data-column-heading="Symbol"]').innerHTML = item["symbol"]; - new_row.querySelector( - 'td[data-column-heading="Description"]').innerHTML = item["description"]; - new_row.querySelector( - 'td[data-column-heading="Chr"]').innerHTML = item["chr"]; - new_row.querySelector( - 'td[data-column-heading="Megabase"]').innerHTML = item["mb"]; - new_row.querySelector( - 'td[data-column-heading="Mean Expr"]').innerHTML = item["mean_expr"]; - new_row.querySelector( - 'td[data-column-heading="N"]').innerHTML = item["noverlap"]; - new_row.querySelector( - `td[data-column-heading="Sample Partial ${rho_or_r(method)}"]` - ).innerHTML = format_number(item["partial_corr"] || NaN); - new_row.querySelector( - `td[data-column-heading="Sample p(partial ${rho_or_r(method)})"]` - ).innerHTML = format_number(item["partial_corr_p_value"] || NaN); - new_row.querySelector( - `td[data-column-heading="Sample ${rho_or_r(method)}"]` - ).innerHTML = format_number(item["corr"] || NaN); - new_row.querySelector( - `td[data-column-heading="Sample p(${rho_or_r(method)})"]` - ).innerHTML = format_number(item["corr_p_value"] || NaN); - new_row.querySelector( - `td[data-column-heading="delta ${rho_or_r(method)}"]` - ).innerHTML = format_number(item["delta"] || NaN); - new_row.querySelector( - `td[data-column-heading="Lit Corr"]` - ).innerHTML = format_number(item["l_corr"] || NaN); - new_row.querySelector( - `td[data-column-heading="Tissue ${rho_or_r(method)}"]` - ).innerHTML = format_number(item["tissue_corr"] || NaN); - new_row.querySelector( - `td[data-column-heading="Tissue p(${rho_or_r(method)})"]` - ).innerHTML = format_number(item["tissue_p_value"] || NaN); - table_body.appendChild(new_row); - }); - template_row.setAttribute("display", "none"); - /*table_body.removeChild(template_row);*/ -} - -function replace_r_with_rho(method) { - /* Mostly utility: Replace `r` with `rho` in the appropriate places */ - pattern = /\br\b/; - if(method == "spearman") { - results_div = document.getElementById("partial-correlation-results"); - headers = results_div.getElementsByTagName("th"); - for(let header of headers) { - header.innerHTML = header.innerHTML.replace(pattern, "rho"); - } - - cells = results_div.getElementsByTagName("td"); - for(let cell of cells) { - cell.setAttribute( - "data-column-heading", - cell.getAttribute( - "data-column-heading").replace(pattern, "rho")); - } +function selected_traits() { + traits = $("#trait_table input:checked").map(function() { + return $(this).attr("data-trait-info"); + }).get(); + if (traits.length == 0){ + num_traits = $("#trait_table input").length + if (num_traits <= 100){ + traits = $("#trait_table input").map(function() { + return $(this).attr("data-trait-info"); + }).get(); + } } -} - -function display_partial_corr_results(data, status, xhr) { - progress_indicator = document.getElementById( - "partial-correlations-progress-indicator").style.display = "none"; - console.log(data); - - replace_r_with_rho(data["results"]["method"]); - - display_functions = { - "Publish": display_publish_results, - "Geno": display_geno_results, - "ProbeSet": display_probeset_results - } - - display_functions[data["results"]["dataset_type"]]( - data["results"]["primary_traits"], - data["results"]["control_traits"], - data["results"]["correlations"], - data["results"]["method"]); - - initializePcorrTable(data["results"]["dataset_type"]); -} - -function display_partial_corr_error(xhr, status, error) { - document.getElementById( - "partial-correlations-progress-indicator").style.display = "none"; - error_element = document.getElementById("part-corr-error"); - panel = document.createElement("div"); - panel.setAttribute("class", "panel panel-danger"); - error_element.appendChild(panel); - - panel_header = document.createElement("div"); - panel_header.setAttribute("class", "panel-heading"); - panel_header.textContent = "Error: " + xhr.status; - panel.appendChild(panel_header); - - panel_body = document.createElement("div"); - panel_body.setAttribute("class", "panel-body"); - panel_body.textContent = xhr.statusText; - panel.appendChild(panel_body); - console.log(xhr) -} - -function send_data_and_process_results( - remote_url, request_data, success_fn, error_fn, indicator_id) { - document.getElementById(indicator_id).style.display = "block"; - $.ajax({ - type: "POST", - url: remote_url, - contentType: "application/json", - data: JSON.stringify(request_data), - dataType: "JSON", - success: success_fn, - error: error_fn - }); -} - -function initializePcorrTable(dataType){ - tableId = "part-corr-results-" + dataType.toLowerCase(); - if (dataType == "Publish") { - orderCol = 8; - } else if (dataType == "ProbeSet") { - orderCol = 12; - } else { - orderCol = 7; - } - - $('#' + tableId).dataTable( { - 'drawCallback': function( settings ) { - $('#' + tableId + ' tr').off().on("click", function(event) { - if (event.target.type !== 'checkbox' && event.target.tagName.toLowerCase() !== 'a') { - var obj =$(this).find('input'); - obj.prop('checked', !obj.is(':checked')); - } - if ($(this).hasClass("selected") && event.target.tagName.toLowerCase() !== 'a'){ - $(this).removeClass("selected") - } else if (event.target.tagName.toLowerCase() !== 'a') { - $(this).addClass("selected") - } - }); - }, - "order": [[orderCol, "asc" ]], - "sDom": "itir", - "iDisplayLength": -1, - "autoWidth": false, - "bDeferRender": true, - "bSortClasses": false, - "paging": false - } ); -} - -$("#partial-correlations-form").submit(function(e) { - e.preventDefault(); -}); - -$("#run-partial-corr-button").click(function(evt) { - send_data_and_process_results( - document.getElementById( - "run-partial-corr-button").getAttribute("data-url"), - partial_corr_request_data(), - display_partial_corr_results, - display_partial_corr_error, - "partial-correlations-progress-indicator"); + return traits +} + +$("#partial-correlations").on("click", function() { + // Submit the form to the `partial_correlations` endpoint + url = $(this).data("url") + traits = selected_traits(); + $("#trait_list").val(traits.reduce(function(acc, str) { + return acc.concat(";;;".concat(str)); + })); + $("input[name=tool_used]").val("Partial Correlation") + $("input[name=form_url]").val(url) + return submit_special(url) }) diff --git a/wqflask/wqflask/templates/collections/view.html b/wqflask/wqflask/templates/collections/view.html index f896471a..6f1a9680 100644 --- a/wqflask/wqflask/templates/collections/view.html +++ b/wqflask/wqflask/templates/collections/view.html @@ -67,22 +67,6 @@ </div> </form> - <form id="partial-correlations-form" - method="POST" - action="{{url_for('partial_correlations')}}"> - <input type="hidden" - id="collection_uuid" - value="{{uc.uc_id}}" /> - <input type="hidden" - name="traits_list" - value="{% for this_trait in trait_obs %}{{ this_trait.name }}:::{{ this_trait.dataset.name }}:::{{this_trait.symbol}}:::{{this_trait.description_display}}:::{{this_trait.location_repr}}:::{{this_trait.mean}}:::{{this_trait['LRS_location_repr']}}:::{{data_hmac('{}:{}'.format(this_trait.name, this_trait.dataset.name))}}|||{% endfor %}" /> - <button id="run-partial-correlations" - class="btn btn-primary" - title="Run partial correlations" - type="submit" style="margin-top: 10px;"> - Partial Correlations - </button> - </form> </div> <div> @@ -128,7 +112,13 @@ <tbody> {% for this_trait in trait_obs %} <TR id="trait:{{ this_trait.name }}:{{ this_trait.dataset.name }}"> - <TD align="center" style="padding: 0px;"><INPUT TYPE="checkbox" NAME="searchResult" class="checkbox trait_checkbox" VALUE="{{ data_hmac('{}:{}'.format(this_trait.name, this_trait.dataset.name)) }}"></TD> + <TD align="center" style="padding: 0px;"> + <input type="checkbox" + name="searchResult" + class="checkbox trait_checkbox" + value="{{data_hmac('{}:{}'.format(this_trait.name, this_trait.dataset.name))}}" + data-trait-info="{{trait_info_str(this_trait)}}"> + </TD> <TD data-export="{{ loop.index }}" align="right">{{ loop.index }}</TD> <TD title="{{ this_trait.dataset.fullname }}" data-export="{{ this_trait.dataset.fullname }}">{{ this_trait.dataset.fullname }}</TD> <TD data-export="{{ this_trait.name }}"> @@ -193,6 +183,9 @@ <script type="text/javascript" src="{{ url_for('js', filename='plotly/plotly.min.js') }}"></script> + <script type="text/javascript" + src="/static/new/javascript/partial_correlations.js"></script> + <script language="javascript" type="text/javascript"> $(document).ready( function () { diff --git a/wqflask/wqflask/templates/partial_correlations.html b/wqflask/wqflask/templates/partial_correlations.html deleted file mode 100644 index 0cf09afc..00000000 --- a/wqflask/wqflask/templates/partial_correlations.html +++ /dev/null @@ -1,355 +0,0 @@ -{%extends "base.html"%} - -{%block title%}Partial Correlations:{%endblock%} - -{%block css%} -<link rel="stylesheet" type="text/css" href="/static/new/css/partial_correlations.css" /> -<link rel="stylesheet" type="text/css" href="{{ url_for('css', filename='DataTables/css/jquery.dataTables.css') }}" /> -<link rel="stylesheet" type="text/css" href="/static/new/css/trait_list.css" /> -<link rel="stylesheet" type="text/css" href="/static/new/css/show_trait.css" /> -{%endblock%} - -{%block content%} -<div class="container"> -<form id="partial-correlations-form" - method="POST" - action="{{url_for('partial_correlations')}}"> - - <div id="main-form"> - {%with messages = get_flashed_messages(with_categories=true)%} - {%if messages:%} - <ul class=flashes> - {%for category, message in messages:%} - <li class="{{category}}">{{message}}</li> - {%endfor%} - </ul> - {%endif%} - {%endwith%} - - {%if step == "select-primary":%} - <p>Please select the primary trait (X)</p> - {%include "with-trait-items.html" %} - - <button type="submit" class="btn btn-primary"> - Next: Select Control Traits - </button> - {%endif%} - - - - {%if step == "select-controls":%} - - <p>Select a maximum of three (3) control traits (Z)</p> - {%include "with-trait-items.html" %} - - <button type="submit" class="btn btn-primary"> - Next: Select Target - </button> - {%endif%} - - - - {%if step == "select-targets":%} - <p>Select at least one target trait (Y)</p> - {%for trait in traits_list:%} - <div class="label-element-combo"> - <input type="checkbox" - name="target_traits[]" - value="{{trait['name']}}:::{{trait['dataset']}}:::{{trait['symbol']}}:::{{trait['description']}}:::{{trait['data_hmac']}}" - checked="checked" - id="trait_{{trait['data_hmac']}}" /> - <label for="trait_{{trait['data_hmac']}}"> - {{trait["name"]}} - {{trait["symbol"]}} - {{trait["description"]}} - </label> - </div> - {%endfor%} - <button type="submit" class="btn btn-primary"> - Next: Select Correlation Method - </button> - {%endif%} - - - - {%if step == "select-corr-method":%} - <div class="label-element-combo"> - <label for="target-db-input">Choose Database</label> - <select id="target-db-input" required="required" name="target_db"> - {%if target_dbs:%} - {%for item in target_dbs:%} - {%if "description" in item.keys():%} - <option value="{{item['value']}}">{{item['description']}}</option> - {%else:%} - {%for group, opts in item.items()%} - {%if opts | length > 0:%} - <optgroup label="{{group}} ------"> - {%for item2 in opts:%} - <option value="{{item2['value']}}">{{item2['description']}}</option> - {%endfor%} - </optgroup> - {%endif%} - {%endfor%} - {%endif%} - {%endfor%} - {%endif%} - </select> - </div> - - <div class="label-element-combo"> - <label for="corr-method-input">Compute</label> - <select id="corr-method-input" required="required" name="method"> - <option value="Genetic Correlation, Pearson's r"> - Genetic Correlation, Pearson's r</option> - <option value="Genetic Correlation, Spearman's rho"> - Genetic Correlation, Spearman's rho</option> - <option value="SGO Literature Correlation"> - SGO Literature Correlation</option> - <option value="Tissue Correlation, Pearson's r"> - Tissue Correlation, Pearson's r</option> - <option value="Tissue Correlation, Spearman's rho"> - Tissue Correlation, Spearman's rho</option> - </select> - </div> - - <div class="label-element-combo"> - <label for="criteria-input">Return</label> - <select id="criteria-input" required="required" name="criteria" size="1"> - <option value="100">top 100</option> - <option value="200">top 200</option> - <option value="500" selected="selected">top 500</option> - <option value="1000">top 1000</option> - <option value="2000">top 2000</option> - <option value="5000">top 5000</option> - <option value="10000">top 10000</option> - <option value="15000">top 15000</option> - <option value="20000">top 20000</option> - </select> - </div> - - <button id="run-partial-corr-button" - type="submit" - class="btn btn-primary" - data-url="{{part_corr_url}}"> - Run Partial Correlation - </button> - {%endif%} - - {%if step == "run-correlation":%} - <input type="hidden" name="selected_method" value="{{method}}" /> - <input type="hidden" name="selected_target_db" value="{{target_db}}" /> - <input type="hidden" name="selected_criteria" value="{{criteria}}" /> - - {{corr_results}} - {%endif%} - </div> - - <div id="form-display-area"> - <input type="hidden" name="step" id="step-indicator" value="{{step}}" /> - <input type="hidden" - name="traits_list" - value="{% for trait in traits_list %}{{trait['name']}}:::{{trait['dataset']}}:::{{trait['symbol']}}:::{{trait['description']}}:::{{trait['location']}}:::{{trait['mean_expr']}}:::{{trait['max_lrs']}}:::{{trait['data_hmac']}}|||{% endfor %}"> - - {%if primary_trait:%} - <input type="hidden" - name="primary_trait" - value="{{primary_trait['name']}}:::{{primary_trait['dataset']}}:::{{primary_trait['symbol']}}:::{{primary_trait['description']}}:::{{primary_trait['location']}}:::{{primary_trait['mean_expr']}}:::{{primary_trait['max_lrs']}}:::{{primary_trait['data_hmac']}}" - id="trait_{{primary_trait['data_hmac']}}" /> - - <div class="panel panel-info"> - <div class="panel-heading">Primary Trait (X)</div> - <div class="panel-body"> - {{primary_trait["name"]}} - - {{primary_trait["symbol"]}} - {{primary_trait["description"]}} - </div> - </div> - {%endif%} - - {%if target_traits:%} - <input type="hidden" - name="target_traits" - value="{%for trait in target_traits:%}{{trait['name']}}:::{{trait['dataset']}}:::{{trait['symbol']}}:::{{trait['description']}}:::{{trait['location']}}:::{{trait['mean_expr']}}:::{{trait['max_lrs']}}:::{{trait['data_hmac']}}|||{%endfor%}" /> - <div class="panel panel-info"> - <div class="panel-heading">Target Traits (Y)</div> - <div class="panel-body"> - <ul> - {%for trait in target_traits:%} - <li> - {{trait["name"]}} - {{trait["symbol"]}} - - {{trait["description"]}}</li> - {%endfor%} - </ul> - </div> - </div> - {%endif%} - - {%if control_traits:%} - <input type="hidden" - name="control_traits" - value="{%for trait in control_traits:%}{{trait['name']}}:::{{trait['dataset']}}:::{{trait['symbol']}}:::{{trait['description']}}:::{{trait['location']}}:::{{trait['mean_expr']}}:::{{trait['max_lrs']}}:::{{trait['data_hmac']}}|||{%endfor%}" /> - <div class="panel panel-info"> - <div class="panel-heading">Control Traits (Z)</div> - <div class="panel-body"> - <ul> - {%for trait in control_traits:%} - <li> - {{trait["name"]}} - {{trait["symbol"]}} - - {{trait["description"]}}</li> - {%endfor%} - </ul> - </div> - </div> - {%endif%} - </div> - -</form> - -<div id="partial-correlation-results"> - <span id="partial-correlations-progress-indicator" - style="display: {%if step == 'run-correlation':%}block{%else:%}none{%endif%};"> - <img src="/static/gif/waitAnima2.gif"> - </span> - <div id="part-corr-success"> - <table id="part-corr-results-publish" class="table-hover table-striped cell-border" style="display:none; float: left;"> - <thead> - <tr> - <th></th> - <th>Index</th> - <th>Record</th> - <th>Phenotype</th> - <th>Authors</th> - <th>Year</th> - <th>N</th> - <th>Partial {%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%}</th> - <th>p(partial {%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%})</th> - <th>{%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%}</th> - <th>p({%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%})</th> - <th>delta {%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%}</th> - </tr> - </thead> - - <tbody> - <tr class="template-publish-results-row"> - <td></td> - <td data-column-heading="Index"></td> - <td data-column-heading="Record"></td> - <td data-column-heading="Phenotype"></td> - <td data-column-heading="Authors"></td> - <td data-column-heading="Year"></td> - <td data-column-heading="N"></td> - <td data-column-heading="Partial {%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%}"> - </td> - <td data-column-heading="p(partial {%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%})"> - </td> - <td data-column-heading="{%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%}"> - </td> - <td data-column-heading="p({%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%})"> - </td> - <td data-column-heading="delta {%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%}"> - </td> - </tr> - </tbody> - </table> - - <table id="part-corr-results-geno" style="display:none;"> - <thead> - <tr> - <th></th> - <th>Index</th> - <th>Locus</th> - <th>Chr</th> - <th>Megabase</th> - <th>N</th> - <th>Partial {%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%}</th> - <th>p(partial {%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%})</th> - <th>{%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%}</th> - <th>p({%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%})</th> - <th>delta {%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%}</th> - </tr> - </thead> - - <tbody> - <tr class="template-geno-results-row"> - <td></td> - <td data-column-heading="Index"></td> - <td data-column-heading="Locus"></td> - <td data-column-heading="Chr"></td> - <td data-column-heading="Megabase"></td> - <td data-column-heading="N"></td> - <td data-column-heading="Partial {%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%}"> - </td> - <td data-column-heading="p(partial {%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%})"> - </td> - <td data-column-heading="{%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%}"> - </td> - <td data-column-heading="p({%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%})"> - </td> - <td data-column-heading="delta {%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%}"> - </td> - </tr> - </tbody> - </table> - - <table id="part-corr-results-probeset" style="display:none;"> - <thead> - <tr> - <th></th> - <th>Index</th> - <th>Record</th> - <th>Gene ID</th> - <th>Homologene ID</th> - <th>Symbol</th> - <th>Description</th> - <th>Chr</th> - <th>Megabase</th> - <th>Mean Expr</th> - <th>N</th> - <th>Sample Partial {%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%}</th> - <th>Sample p(partial {%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%})</th> - <th>Sample {%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%}</th> - <th>Sample p({%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%})</th> - <th>delta {%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%}</th> - <th>Lit Corr</th> - <th>Tissue {%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%}</th> - <th>Tissue p({%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%})</th> - </tr> - </thead> - - <tbody> - <tr class="template-probeset-results-row"> - <td></td> - <td data-column-heading="Index"></td> - <td data-column-heading="_"></td> - <td data-column-heading="Record"></td> - <td data-column-heading="Gene ID"></td> - <td data-column-heading="Homologene ID"></td> - <td data-column-heading="Symbol"></td> - <td data-column-heading="Description"></td> - <td data-column-heading="Chr"></td> - <td data-column-heading="Megabase"></td> - <td data-column-heading="Mean Expr"></td> - <td data-column-heading="N"></td> - <td data-column-heading="Sample Partial {%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%}"></td> - <td data-column-heading="Sample p(partial {%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%})"></td> - <td data-column-heading="Sample {%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%}"></td> - <td data-column-heading="Sample p({%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%})"></td> - <td data-column-heading="delta {%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%}"></td> - <td data-column-heading="Lit Corr"></td> - <td data-column-heading="Tissue {%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%}"></td> - <td data-column-heading="Tissue p({%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%})"></td> - </tr> - </tbody> - </table> - </div> - <div id="part-corr-error"> - </div> -</div> -</div> -{%endblock%} - -{%block js%} -{%if step == "select-corr-method":%} -<script type="text/javascript" - src="/static/new/javascript/partial_correlations.js"></script> -<script language="javascript" type="text/javascript" - src="{{ url_for('js', filename='DataTables/js/jquery.dataTables.min.js') }}"></script> -{%endif%} -{%endblock%} diff --git a/wqflask/wqflask/templates/partial_correlations/pcorrs_error.html b/wqflask/wqflask/templates/partial_correlations/pcorrs_error.html new file mode 100644 index 00000000..36847f57 --- /dev/null +++ b/wqflask/wqflask/templates/partial_correlations/pcorrs_error.html @@ -0,0 +1,54 @@ +{% extends "base.html" %} +{% block title %}Error: {{message}}{% endblock %} +{% block content %} +<!-- Start of body --> + +<div class="col-md-8"> +<div class="form-group has-error"> + <div class="control-label" for="inputError1"> + + <img src="/static/gif/error/{{ error_image }}"> + + <h1>ERROR</h1> + + <p> + This error is not what we wanted to see. Unfortunately errors + are part of all software systems and we need to resolve this + together. + </p> + <p> + <b>It is important to report this ERROR so we can fix it for everyone</b>. + </p> + + <p> + Report to the GeneNetwork team by recording the steps you take + to reproduce this ERROR. Next to those steps, copy-paste below + stack trace, either as + a <a href="https://github.com/genenetwork/genenetwork2/issues/new">new + issue</a> or E-mail this full page to one of the developers + directly. + </p> + </div> + + <p> + (GeneNetwork error: {{message[:128]}}) + </p> + + <p> + To check if this already a known issue, search the + <a href="https://github.com/genenetwork/genenetwork2/issues">issue + tracker</a>. + </p> + + <a href="#Stack" class="btn btn-default" data-toggle="collapse">Toggle full stack trace</a> + <div id="Stack" class="collapse"> + <pre> + GeneNetwork {{ version }} {% for line in stack %} {{ line }} + {% endfor %} + </pre> + </div> +</div> +</div> + + +{% endblock %} diff --git a/wqflask/wqflask/templates/partial_correlations/pcorrs_poll_results.html b/wqflask/wqflask/templates/partial_correlations/pcorrs_poll_results.html new file mode 100644 index 00000000..47acc294 --- /dev/null +++ b/wqflask/wqflask/templates/partial_correlations/pcorrs_poll_results.html @@ -0,0 +1,15 @@ +{%extends "base.html"%} + +{%block title%}Partial Correlations:{%endblock%} + +{%block css%} +<meta http-equiv="refresh" + content="10;URL=/partial_correlations/{{command_id}}"> +{%endblock%} + +{%block content%} + +<p>Computing partial correlations...</p> +<img src="/static/gif/waitAnima2.gif" + alt="Image indicating computation of partial correlations is ongoing" /> +{%endblock%} diff --git a/wqflask/wqflask/templates/partial_correlations/pcorrs_results_presentation.html b/wqflask/wqflask/templates/partial_correlations/pcorrs_results_presentation.html new file mode 100644 index 00000000..c109f24b --- /dev/null +++ b/wqflask/wqflask/templates/partial_correlations/pcorrs_results_presentation.html @@ -0,0 +1,249 @@ +{%extends "base.html"%} + +{%block title%}Partial Correlations:{%endblock%} + +{%block css%} +<link rel="stylesheet" type="text/css" href="/static/new/css/partial_correlations.css" /> +<link rel="stylesheet" type="text/css" href="{{ url_for('css', filename='DataTables/css/jquery.dataTables.css') }}" /> +<link rel="stylesheet" type="text/css" href="/static/new/css/trait_list.css" /> +<link rel="stylesheet" type="text/css" href="/static/new/css/show_trait.css" /> +{%endblock%} + +{%block content%} +<p> + <strong>Primary Trait</strong><br /><br /> + <a href="{{url_for( + 'show_trait_page', + trait_id=primary['trait_name'], + dataset=primary['dataset_name'])}}" + title="Link to trait data for trait {{primary['trait_name']}}"> + {{primary["dataset_type"]}}/{{primary["trait_name"]}} + [{{primary["symbol"] }} on Chr {{primary["chr"]}} @ {{primary["mb"]}}]: + {{primary["description"]}} + </a> --- FROM: {{primary["dataset_name"]}} +</p> +<p><strong>Control Traits</strong><br /><br /> + {%for trait in controls:%} + <a href="{{url_for( + 'show_trait_page', + trait_id=trait['trait_name'], + dataset=trait['dataset_name'])}}" + title="Link to trait data for trait {{trait['trait_name']}}"> + {{trait["dataset_type"]}}/{{trait["trait_name"]}} + [{{trait["symbol"] }} on Chr {{trait["chr"]}} @ {{trait["mb"]}}]: + {{trait["description"]}} + </a> --- FROM: {{trait["dataset_name"]}}<br /> + {%endfor%} +</p> + +<div id="partial-correlation-results"> + {%if dataset_type == "Publish":%} + <table id="part-corr-results-publish" + class="table-hover table-striped cell-border" + style="float: left;"> + <thead> + <tr> + <th></th> + <th>Index</th> + <th>Record</th> + <th>Phenotype</th> + <th>Authors</th> + <th>Year</th> + <th>N</th> + <th>Partial {%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%}</th> + <th>p(partial {%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%})</th> + <th>{%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%}</th> + <th>p({%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%})</th> + <th>delta {%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%}</th> + </tr> + </thead> + + <tbody> + {%for trait in correlations:%} + <tr class="results-row"> + <td></td> + <td data-column-heading="Index"></td> + <td data-column-heading="Record"> + <a href="{{url_for( + 'show_trait_page', + trait_id=trait['trait_name'], + dataset=trait['dataset_name'])}}" + title="Link to trait data for trait {{trait['trait_name']}}"> + {{trait["trait_name"]}} + </a> + </td> + <td data-column-heading="Phenotype"> + {{trait["post_publication_description"]}}</td> + <td data-column-heading="Authors">{{trait["authors"]}}</td> + <td data-column-heading="Year">{{trait["year"]}}</td> + <td data-column-heading="N">{{trait["noverlap"]}}</td> + <td data-column-heading="Partial {%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%}"> + {{format_number(trait.get("partial_corr"))}} + </td> + <td data-column-heading="p(partial {%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%})"> + {{format_number(trait.get("partial_corr_p_value"))}} + </td> + <td data-column-heading="{%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%}"> + {{format_number(trait.get("corr"))}} + </td> + <td data-column-heading="p({%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%})"> + {{format_number(trait.get("corr_p_value"))}} + </td> + <td data-column-heading="delta {%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%}"> + {{format_number(trait.get("delta"))}} + </td> + </tr> + {%endfor%} + </tbody> + </table> + {%endif%} + + {%if dataset_type == "Geno":%} + <table id="part-corr-results-geno" + class="table-hover table-striped cell-border" + style="float: left;"> + <thead> + <tr> + <th></th> + <th>Index</th> + <th>Locus</th> + <th>Chr</th> + <th>Megabase</th> + <th>N</th> + <th>Partial {%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%}</th> + <th>p(partial {%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%})</th> + <th>{%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%}</th> + <th>p({%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%})</th> + <th>delta {%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%}</th> + </tr> + </thead> + + <tbody> + {%for trait in correlations:%} + <tr class="results-row"> + <td></td> + <td data-column-heading="Index"></td> + <td data-column-heading="Locus"> + <a href="{{url_for( + 'show_trait_page', + trait_id=trait['trait_name'], + dataset=trait['dataset_name'])}}" + title="Link to trait data for trait {{trait['trait_name']}}"> + {{trait["trait_name"]}} + </a> + </td> + <td data-column-heading="Chr">{{trait["chr"]}}</td> + <td data-column-heading="Megabase">{{trait["mb"]}}</td> + <td data-column-heading="N">{{trait["noverlap"]}}</td> + <td data-column-heading="Partial {%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%}"> + {{format_number(trait.get("partial_corr"))}} + </td> + <td data-column-heading="p(partial {%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%})"> + {{format_number(trait.get("partial_corr_p_value"))}} + </td> + <td data-column-heading="{%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%}"> + {{format_number(trait.get("corr"))}} + </td> + <td data-column-heading="p({%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%})"> + {{format_number(trait.get("corr_p_value"))}} + </td> + <td data-column-heading="delta {%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%}"> + {{format_number(trait.get("delta"))}} + </td> + </tr> + {%endfor%} + </tbody> + </table> + {%endif%} + + {%if dataset_type == "ProbeSet":%} + <table id="part-corr-results-probeset" + class="table-hover table-striped cell-border" + style="float: left;"> + <thead> + <tr> + <th></th> + <th>Index</th> + <th>Record</th> + <th>Gene ID</th> + <th>Homologene ID</th> + <th>Symbol</th> + <th>Description</th> + <th>Chr</th> + <th>Megabase</th> + <th>Mean Expr</th> + <th>N</th> + <th>Sample Partial {%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%}</th> + <th>Sample p(partial {%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%})</th> + <th>Sample {%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%}</th> + <th>Sample p({%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%})</th> + <th>delta {%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%}</th> + <th>Lit Corr</th> + <th>Tissue {%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%}</th> + <th>Tissue p({%if "spearman" in (method | lower):%}rho{%else:%}r{%endif%})</th> + </tr> + </thead> + + <tbody> + {%for trait in correlations:%} + <tr class="results-row"> + <td></td> + <td data-column-heading="Index"></td> + <td data-column-heading="Record"> + <a href="{{url_for( + 'show_trait_page', + trait_id=trait['trait_name'], + dataset=trait['dataset_name'])}}" + title="Link to trait data for trait {{trait['trait_name']}}"> + {{trait["trait_name"]}} + </a> + </td> + <td data-column-heading="Gene ID">{{trait["geneid"]}}</td> + <td data-column-heading="Homologene ID">{{trait["homologeneid"]}}</td> + <td data-column-heading="Symbol">{{trait["symbol"]}}</td> + <td data-column-heading="Description">{{trait["description"]}}</td> + <td data-column-heading="Chr">{{trait["chr"]}}</td> + <td data-column-heading="Megabase">{{trait["mb"]}}</td> + <td data-column-heading="Mean Expr">{{trait["mean_expr"]}}</td> + <td data-column-heading="N">{{trait["noverlap"]}}</td> + <td data-column-heading="Sample Partial {%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%}"> + {{format_number(trait.get("partial_corr"))}} + </td> + <td data-column-heading="Sample p(partial {%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%})"> + {{format_number(trait.get("partial_corr_p_value"))}} + </td> + <td data-column-heading="Sample {%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%}"> + {{format_number(trait.get("corr"))}} + </td> + <td data-column-heading="Sample p({%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%})"> + {{format_number(trait.get("corr_p_value"))}} + </td> + <td data-column-heading="delta {%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%}"> + {{format_number(trait.get("delta"))}} + </td> + <td data-column-heading="Lit Corr"> + {{format_number(trait.get("l_corr"))}} + </td> + <td data-column-heading="Tissue {%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%}"> + {{format_number(trait.get("tissue_corr"))}} + </td> + <td data-column-heading="Tissue p({%if 'spearman' in (method | lower):%}rho{%else:%}r{%endif%})"> + {{format_number(trait.get("tissue_p_value"))}} + </td> + </tr> + {%endfor%} + </tbody> + </table> + {%endif%} + +</div> +{%endblock%} + +{%block js%} +{%if step == "select-corr-method":%} +<script type="text/javascript" + src="/static/new/javascript/partial_correlations.js"></script> +<script language="javascript" type="text/javascript" + src="{{ url_for('js', filename='DataTables/js/jquery.dataTables.min.js') }}"></script> +{%endif%} +{%endblock%} diff --git a/wqflask/wqflask/templates/partial_correlations/pcorrs_select_operations.html b/wqflask/wqflask/templates/partial_correlations/pcorrs_select_operations.html new file mode 100644 index 00000000..e541f31b --- /dev/null +++ b/wqflask/wqflask/templates/partial_correlations/pcorrs_select_operations.html @@ -0,0 +1,146 @@ +{%extends "base.html"%} + +{%block title%}Partial Correlations:{%endblock%} + +{%block css%} +<link rel="stylesheet" type="text/css" + href="{{url_for('css', filename='DataTables/css/jquery.dataTables.css')}}" /> +<link rel="stylesheet" type="text/css" + href="{{url_for('js', filename='DataTablesExtensions/buttonStyles/css/buttons.dataTables.min.css')}}"> +<link rel="stylesheet" type="text/css" href="/static/new/css/show_trait.css" /> +<link rel="stylesheet" type="text/css" href="/static/new/css/trait_list.css" /> +<link rel="stylesheet" type="text/css" + href="/static/new/css/partial_correlations.css" /> +{%endblock%} + +{%block content%} +<form id="pcorrs-form" + method="POST" + action="{{url_for('partial_correlations')}}"> + {%with messages = get_flashed_messages(with_categories=true)%} + {%if messages:%} + <ul class=flashes> + {%for category, message in messages:%} + <li class="{{category}}">{{message}}</li> + {%endfor%} + </ul> + {%endif%} + {%endwith%} + + <input type="hidden" value="{{trait_list_str}}" name="trait_list"> + <table id="pcorrs_traits_table" class="table-hover table-striped cell-border"> + <thead> + <tr> + <th>Primary (X)</th> + <th>Controls (Z)</th> + <th>Ignored</th> + <th>Dataset</th> + <th>Trait ID</th> + <th>Symbol</th> + <th>Description</th> + <th>Location</th> + <th>Mean</th> + <th>Max LRS</th> + <th>Max LRS Location Chr and Mb</th> + </tr> + </thead> + + <tbody> + {%for trait in traits:%} + <tr> + <td> + <input type="radio" name="trait_{{trait['trait_name']}}" + id="trait_{{trait['trait_name']}}" + value="primary_{{trait['trait_name']}}"> + </td> + <td> + <input type="radio" name="trait_{{trait['trait_name']}}" + id="trait_{{trait['trait_name']}}" + value="controls_{{trait['trait_name']}}"> + </td> + <td> + <input type="radio" name="trait_{{trait['trait_name']}}" + id="trait_{{trait['trait_name']}}" + value="ignored_{{trait['trait_name']}}" checked="checked"> + </td> + <td>{{trait.get("dataset", "_")}} + <td>{{trait.get("trait_name", "_")}}</td> + <td>{{trait.get("symbol", "_")}}</td> + <td>{{trait.get("description", "_")}}</td> + <td>{{trait.get("location", "_")}}</td> + <td>{{trait.get("mean", "_")}}</td> + <td>{{trait.get("lrs", "_")}}</td> + <td>{{trait.get("lrs_location", "_")}}</td> + </tr> + {%endfor%} + </tbody> + </table> + + <div class="form-group"> + <label for="corr-method-input" class="form-label">Compute</label> + <select id="corr-method-input" required="required" name="method" + class="form-control"> + <option value="Genetic Correlation, Pearson's r"> + Genetic Correlation, Pearson's r</option> + <option value="Genetic Correlation, Spearman's rho"> + Genetic Correlation, Spearman's rho</option> + <option value="SGO Literature Correlation"> + SGO Literature Correlation</option> + <option value="Tissue Correlation, Pearson's r"> + Tissue Correlation, Pearson's r</option> + <option value="Tissue Correlation, Spearman's rho"> + Tissue Correlation, Spearman's rho</option> + </select> + </div> + + <div class="form-group"> + <label for="target-db-input" class="form-label">Choose Database</label> + <select id="target-db-input" required="required" name="target_db" + class="form-control"> + {%if target_dbs:%} + {%for item in target_dbs:%} + {%if "description" in item.keys():%} + <option value="{{item['value']}}">{{item['description']}}</option> + {%else:%} + {%for group, opts in item.items()%} + {%if opts | length > 0:%} + <optgroup label="{{group}} ------"> + {%for item2 in opts:%} + <option value="{{item2['value']}}">{{item2['description']}}</option> + {%endfor%} + </optgroup> + {%endif%} + {%endfor%} + {%endif%} + {%endfor%} + {%endif%} + </select> + </div> + + <div class="form-group"> + <label for="criteria-input" class="form-label">Return</label> + <select id="criteria-input" required="required" name="criteria" size="1" + class="form-control"> + <option value="100">top 100</option> + <option value="200">top 200</option> + <option value="500" selected="selected">top 500</option> + <option value="1000">top 1000</option> + <option value="2000">top 2000</option> + <option value="5000">top 5000</option> + <option value="10000">top 10000</option> + <option value="15000">top 15000</option> + <option value="20000">top 20000</option> + </select> + </div> + + <button type="submit" class="btn btn-primary" name="submit" + value="Run Partial Correlations"> + Run Partial Correlations + </button> +</form> +{%endblock%} + +{%block js%} +<script type="text/javascript" + src="/static/new/javascript/partial_correlations.js"></script> +{%endblock%} diff --git a/wqflask/wqflask/templates/tool_buttons.html b/wqflask/wqflask/templates/tool_buttons.html index 3ee5be19..c3927495 100644 --- a/wqflask/wqflask/templates/tool_buttons.html +++ b/wqflask/wqflask/templates/tool_buttons.html @@ -33,3 +33,10 @@ <button id="comp_bar_chart" class="btn btn-primary submit_special" data-url="/comparison_bar_chart" title="Comparison Bar Chart" > Comparison Bar Chart </button> + +<button id="partial-correlations" + class="btn btn-primary submit_special" + data-url="{{url_for('partial_correlations')}}" + title="Run partial correlations with the selected traits"> + Partial Correlations +</button> |