aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md3
-rw-r--r--.github/workflows/main.yml48
-rw-r--r--README.md11
-rw-r--r--api_readme.md155
-rw-r--r--doc/docker-container.org89
-rw-r--r--test/requests/main_web_functionality.py2
-rw-r--r--wqflask/tests/base/test_trait.py4
-rw-r--r--wqflask/utility/redis_tools.py118
-rw-r--r--wqflask/wqflask/__init__.py21
-rw-r--r--wqflask/wqflask/db_info.py127
-rw-r--r--wqflask/wqflask/marker_regression/run_mapping.py12
-rw-r--r--wqflask/wqflask/static/new/css/marker_regression.css4
-rw-r--r--wqflask/wqflask/static/new/javascript/search_results.js22
-rw-r--r--wqflask/wqflask/templates/base.html4
-rw-r--r--wqflask/wqflask/templates/gsearch_gene.html16
-rw-r--r--wqflask/wqflask/templates/gsearch_pheno.html17
-rw-r--r--wqflask/wqflask/templates/info_page.html92
-rw-r--r--wqflask/wqflask/templates/mapping_results.html139
-rw-r--r--wqflask/wqflask/templates/search_result_page.html15
-rw-r--r--wqflask/wqflask/templates/tutorials.html1
-rw-r--r--wqflask/wqflask/user_login.py4
-rw-r--r--wqflask/wqflask/views.py62
22 files changed, 765 insertions, 201 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 789d6a57..7d7e34a5 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -26,7 +26,8 @@ If applicable, add screenshots to help explain your problem.
**Environment setup (please complete the following information):**
- OS: [e.g. Linux]
-- Racket Version [e.g. v7.6]
+- Guix Version (optional)
+- [Anything else you think is relevant]
**Additional context**
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 00000000..2fd9a886
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,48 @@
+name: tests
+
+# Run actions when pushing to the testing branch or when you create a
+# PR against it
+on:
+ push:
+ branches: [ testing ]
+ pull_request:
+ branches: [ testing ]
+
+jobs:
+ unittest:
+ runs-on: ubuntu-latest
+ container: bonfacekilz/python2-genenetwork2:latest
+
+ steps:
+ # First start with mariadb set then checkout. The checkout gives
+ # the mysqld enough time to start
+ - name: Set up mariadb
+ run: |
+ mysql_install_db --user=mysql --datadir=/usr/local/mysql
+ # Wait for the mysqld_safe process to start
+ mysqld_safe --user=mysql --datadir=/usr/local/mysql &
+
+ # Use v1 of checkout since v2 fails
+ - name: Checkout Project
+ uses: actions/checkout@v1
+
+ # Redis is required by some of the tests 6379
+ - name: Start Redis
+ run: |
+ /gn2-profile/bin/screen -dmLS redisconn /gn2-profile/bin/redis-server
+
+ # Redis is required by some of the tests 6379
+ - name: Bootstrap tables
+ run: |
+ mysql -u root -e "SHOW DATABASES;"
+ mysql -u root -e "CREATE DATABASE db_webqtl_s;"
+ mysql -u root -e "CREATE USER 'gn2'@'localhost' IDENTIFIED BY 'mysql_password';"
+ mysql -u root -e "GRANT ALL PRIVILEGES ON *.* TO 'gn2'@'localhost';FLUSH PRIVILEGES;"
+
+ - name: Run the unit tests
+ run: |
+ env GN2_PROFILE=/gn2-profile \
+ TMPDIR=/tmp SERVER_PORT=5004 \
+ WEBSERVER_MODE=DEBUG LOG_LEVEL=DEBUG \
+ GENENETWORK_FILES=/genotype_files/ bin/genenetwork2 \
+ etc/default_settings.py -c -m unittest discover -v
diff --git a/README.md b/README.md
index 46264252..cd35defb 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
[![DOI](https://zenodo.org/badge/5591/genenetwork/genenetwork2.svg)](https://zenodo.org/badge/latestdoi/5591/genenetwork/genenetwork2) [![JOSS](http://joss.theoj.org/papers/10.21105/joss.00025/status.svg)](http://joss.theoj.org/papers/10.21105/joss.00025)
+[![Actions Status](https://github.com/genenetwork/genenetwork2/workflows/tests/badge.svg)](https://github.com/genenetwork/genenetwork2/actions)
# GeneNetwork
@@ -42,9 +43,17 @@ Also mariadb and redis need to be running, see
## Testing
To have tests pass, the redis and mariadb instance should be running, because of
-asserts sprinkled in the code base(these will be removed in due time).
+asserts sprinkled in the code base.
+
+Right now, the only tests running in CI are unittests. Please make
+sure the existing unittests are green when submitting a PR.
+
+See
+[./bin/genenetwork2](https://github.com/genenetwork/genenetwork2/blob/testing/doc/docker-container.org)
+for more details.
#### Mechanical Rob
+
We are building 'Mechanical Rob' automated testing using Python
[requests](https://github.com/genenetwork/genenetwork2/tree/testing/test/requests)
which can be run with:
diff --git a/api_readme.md b/api_readme.md
new file mode 100644
index 00000000..96e8b246
--- /dev/null
+++ b/api_readme.md
@@ -0,0 +1,155 @@
+# API Query Documentation #
+---
+# Fetching Dataset/Trait info/data #
+---
+## Fetch Species List ##
+
+To get a list of species with data available in GN (and their associated names and ids):
+```
+curl http://gn2-zach.genenetwork.org/api/v_pre1/species
+[ { "FullName": "Mus musculus", "Id": 1, "Name": "mouse", "TaxonomyId": 10090 }, ... { "FullName": "Populus trichocarpa", "Id": 10, "Name": "poplar", "TaxonomyId": 3689 } ]
+```
+
+Or to get a single species info:
+```
+curl http://gn2-zach.genenetwork.org/api/v_pre1/species/mouse
+```
+OR
+```
+curl http://gn2-zach.genenetwork.org/api/v_pre1/species/mouse.json
+```
+
+*For all queries where the last field is a user-specified name/ID, there will be the option to append a file format type. Currently there is only JSON (and it will default to JSON if none is provided), but other formats will be added later*
+
+## Fetch Groups/RISets ##
+
+This query can optionally filter by species:
+
+```
+curl http://gn2-zach.genenetwork.org/api/v_pre1/groups (for all species)
+```
+OR
+```
+curl http://gn2-zach.genenetwork.org/api/v_pre1/mouse/groups (for just mouse groups/RISets)
+[ { "DisplayName": "BXD", "FullName": "BXD RI Family", "GeneticType": "riset", "Id": 1, "MappingMethodId": "1", "Name": "BXD", "SpeciesId": 1, "public": 2 }, ... { "DisplayName": "AIL LGSM F34 and F39-43 (GBS)", "FullName": "AIL LGSM F34 and F39-43 (GBS)", "GeneticType": "intercross", "Id": 72, "MappingMethodId": "2", "Name": "AIL-LGSM-F34-F39-43-GBS", "SpeciesId": 1, "public": 2 } ]
+```
+
+## Fetch Genotypes for Group/RISet ##
+```
+curl http://gn2-zach.genenetwork.org/api/v_pre1/genotypes/BXD
+```
+Returns a CSV file with metadata in the first few rows, sample/strain names as columns, and markers as rows. Currently only works for genotypes we have stored in .geno files; I'll add the option to download BIMBAM files soon.
+
+## Fetch Datasets ##
+```
+curl http://gn2-zach.genenetwork.org/api/v_pre1/datasets/bxd
+```
+OR
+```
+curl http://gn2-zach.genenetwork.org/api/v_pre1/datasets/mouse/bxd
+[ { "AvgID": 1, "CreateTime": "Fri, 01 Aug 2003 00:00:00 GMT", "DataScale": "log2", "FullName": "UTHSC/ETHZ/EPFL BXD Liver Polar Metabolites Extraction A, CD Cohorts (Mar 2017) log2", "Id": 1, "Long_Abbreviation": "BXDMicroArray_ProbeSet_August03", "ProbeFreezeId": 3, "ShortName": "Brain U74Av2 08/03 MAS5", "Short_Abbreviation": "Br_U_0803_M", "confidentiality": 0, "public": 0 }, ... { "AvgID": 3, "CreateTime": "Tue, 14 Aug 2018 00:00:00 GMT", "DataScale": "log2", "FullName": "EPFL/LISP BXD CD Liver Affy Mouse Gene 1.0 ST (Aug18) RMA", "Id": 859, "Long_Abbreviation": "EPFLMouseLiverCDRMAApr18", "ProbeFreezeId": 181, "ShortName": "EPFL/LISP BXD CD Liver Affy Mouse Gene 1.0 ST (Aug18) RMA", "Short_Abbreviation": "EPFLMouseLiverCDRMA0818", "confidentiality": 0, "public": 1 } ]
+```
+(I added the option to specify species just in case we end up with the same group name across multiple species at some point, though it's currently unnecessary)
+
+## Fetch Sample Data for Dataset ##
+```
+curl http://gn2-zach.genenetwork.org/api/v_pre1/sample_data/HSNIH-PalmerPublish.csv
+```
+
+Returns a CSV file with sample/strain names as the columns and trait IDs as rows
+
+## Fetch Individual Dataset Info ##
+### For mRNA Assay/"ProbeSet" ###
+
+```
+curl http://gn2-zach.genenetwork.org/api/v_pre1/dataset/HC_M2_0606_P
+```
+OR
+```
+curl http://gn2-zach.genenetwork.org/api/v_pre1/dataset/bxd/HC_M2_0606_P```
+{ "confidential": 0, "data_scale": "log2", "dataset_type": "mRNA expression", "full_name": "Hippocampus Consortium M430v2 (Jun06) PDNN", "id": 112, "name": "HC_M2_0606_P", "public": 2, "short_name": "Hippocampus M430v2 BXD 06/06 PDNN", "tissue": "Hippocampus mRNA", "tissue_id": 9 }
+```
+(This also has the option to specify group/riset)
+
+### For "Phenotypes" (basically non-mRNA Expression; stuff like weight, sex, etc) ###
+For these traits, the query fetches publication info and takes the group and phenotype 'ID' as input. For example:
+```
+curl http://gn2-zach.genenetwork.org/api/v_pre1/dataset/bxd/10001
+{ "dataset_type": "phenotype", "description": "Central nervous system, morphology: Cerebellum weight, whole, bilateral in adults of both sexes [mg]", "id": 10001, "name": "CBLWT2", "pubmed_id": 11438585, "title": "Genetic control of the mouse cerebellum: identification of quantitative trait loci modulating size and architecture", "year": "2001" }
+```
+
+## Fetch Sample Data for Single Trait ##
+```
+curl http://gn2-zach.genenetwork.org/api/v_pre1/sample_data/HC_M2_0606_P/1436869_at
+[ { "data_id": 23415463, "sample_name": "129S1/SvImJ", "sample_name_2": "129S1/SvImJ", "se": 0.123, "value": 8.201 }, { "data_id": 23415463, "sample_name": "A/J", "sample_name_2": "A/J", "se": 0.046, "value": 8.413 }, { "data_id": 23415463, "sample_name": "AKR/J", "sample_name_2": "AKR/J", "se": 0.134, "value": 8.856 }, ... ]
+```
+
+## Fetch Trait Info (Name, Description, Location, etc) ##
+### For mRNA Expression/"ProbeSet" ###
+```
+curl http://gn2-zach.genenetwork.org/api/v_pre1/trait/HC_M2_0606_P/1436869_at
+{ "additive": -0.214087568058076, "alias": "HHG1; HLP3; HPE3; SMMCI; Dsh; Hhg1", "chr": "5", "description": "sonic hedgehog (hedgehog)", "id": 99602, "locus": "rs8253327", "lrs": 12.7711275309832, "mb": 28.457155, "mean": 9.27909090909091, "name": "1436869_at", "p_value": 0.306, "se": null, "symbol": "Shh" }
+```
+
+### For "Phenotypes" ###
+For phenotypes this just gets the max LRS, its location, and additive effect (as calculated by qtlreaper)
+
+Since each group/riset only has one phenotype "dataset", this query takes either the group/riset name or the group/riset name + "Publish" (for example "BXDPublish", which is the dataset name in the DB) as input
+```
+curl http://gn2-zach.genenetwork.org/api/v_pre1/trait/BXD/10001
+{ "additive": 2.39444435069444, "id": 4, "locus": "rs48756159", "lrs": 13.4974911471087 }
+```
+
+---
+
+# Analyses #
+---
+## Mapping ##
+Currently two mapping tools can be used - GEMMA and R/qtl. qtlreaper will be added later with Christian Fischer's RUST implementation - https://github.com/chfi/rust-qtlreaper
+
+Each method's query takes the following parameters respectively (more will be added):
+### GEMMA ###
+* trait_id (*required*) - ID for trait being mapped
+* db (*required*) - DB name for trait above (Short_Abbreviation listed when you query for datasets)
+* use_loco - Whether to use LOCO (leave one chromosome out) method (default = false)
+* maf - minor allele frequency (default = 0.01)
+
+Example query:
+```
+curl http://gn2-zach.genenetwork.org/api/v_pre1/mapping?trait_id=10015&db=BXDPublish&method=gemma&use_loco=true
+```
+
+### R/qtl ###
+(See the R/qtl guide for information on some of these options - http://www.rqtl.org/manual/qtl-manual.pdf)
+* trait_id (*required*) - ID for trait being mapped
+* db (*required*) - DB name for trait above (Short_Abbreviation listed when you query for datasets)
+* rqtl_method - hk (default) | ehk | em | imp | mr | mr-imp | mr-argmax ; Corresponds to the "method" option for the R/qtl scanone function.
+* rqtl_model - normal (default) | binary | 2-part | np ; corresponds to the "model" option for the R/qtl scanone function
+* num_perm - number of permutations; 0 by default
+* control_marker - Name of marker to use as control; this relies on the user knowing the name of the marker they want to use as a covariate
+* interval_mapping - Whether to use interval mapping; "false" by default
+* pair_scan - *NYI*
+
+Example query:
+```
+curl http://gn2-zach.genenetwork.org/api/v_pre1/mapping?trait_id=1418701_at&db=HC_M2_0606_P&method=rqtl&num_perm=100
+```
+
+Some combinations of methods/models may not make sense. The R/qtl manual should be referred to for any questions on its use (specifically the scanone function in this case)
+
+## Calculate Correlation ##
+Currently only Sample and Tissue correlations are implemented
+
+This query currently takes the following parameters (though more will be added):
+* trait_id (*required*) - ID for trait used for correlation
+* db (*required*) - DB name for the trait above (this is the Short_Abbreviation listed when you query for datasets)
+* target_db (*required*) - Target DB name to be correlated against
+* type - sample (default) | tissue
+* method - pearson (default) | spearman
+* return - Number of results to return (default = 500)
+
+Example query:
+```
+curl http://gn2-zach.genenetwork.org/api/v_pre1/correlation?trait_id=1427571_at&db=HC_M2_0606_P&target_db=BXDPublish&type=sample&return_count=100
+[ { "#_strains": 6, "p_value": 0.004804664723032055, "sample_r": -0.942857142857143, "trait": 20511 }, { "#_strains": 6, "p_value": 0.004804664723032055, "sample_r": -0.942857142857143, "trait": 20724 }, { "#_strains": 12, "p_value": 1.8288943424888848e-05, "sample_r": -0.9233615170820528, "trait": 13536 }, { "#_strains": 7, "p_value": 0.006807187408935392, "sample_r": 0.8928571428571429, "trait": 10157 }, { "#_strains": 7, "p_value": 0.006807187408935392, "sample_r": -0.8928571428571429, "trait": 20392 }, ... ]
+```
diff --git a/doc/docker-container.org b/doc/docker-container.org
new file mode 100644
index 00000000..ec91824a
--- /dev/null
+++ b/doc/docker-container.org
@@ -0,0 +1,89 @@
+#+TITLE: Genenetwork2 Dockerized
+
+* Table of Contents :TOC:
+- [[#introduction][Introduction]]
+- [[#creating-the-docker-images][Creating the Docker Images]]
+- [[#pushing-to-dockerhub][Pushing to DockerHub]]
+
+* Introduction
+
+The CI(Continuous Integration) system for Genenetwork2 uses [[https://github.com/features/actions][Github
+Actions]]. As such, it's important to have a way to run tests using
+facilities provided by GUIX in a reproducible way. This project
+leverages GUIX to generate a docker container from which the unittests
+are ran from.
+
+Find instructions on how to set docker up inside GUIX [[https://github.com/pjotrp/guix-notes/blob/master/CONTAINERS.org#run-docker][here]]. This
+document will not get into that. It's assumed that you have a working
+docker setup.
+
+The rest of this document outlines how the docker container used in
+the CI builds was created.
+
+* Creating the Docker Images
+
+The general idea is that GUIX is used to generate a set of binaries,
+which will be added to a base mariaDB image.
+
+First create the gn2 tar archive by running:
+
+#+begin_src sh
+# For the Python 2 version:
+env GUIX_PACKAGE_PATH="/home/bonface/projects/guix-bioinformatics:/home/bonface/projects/guix-past/modules" \
+ ./pre-inst-env guix pack --no-grafts\
+ -S /gn2-profile=/ \
+ screen genenetwork2
+
+# For the Python 3 version:
+env GUIX_PACKAGE_PATH="/home/bonface/projects/guix-bioinformatics:/home/bonface/projects/guix-past/modules" \
+ ./pre-inst-env guix pack --no-grafts\
+ -S /gn2-profile=/ \
+ screen python3-genenetwork2
+ #+end_src
+
+The output will look something similar to:
+
+: /gnu/store/x3m77vwaqcwba24p5s4lrb7w2ii16lj9-tarball-pack.tar.gz
+
+Now create a folder from which will host the following dockerfile. You
+can name this file Dockerfile. Note that mariadb is the base image
+since it already has mariadb installed for us.
+
+#+begin_src conf :mkdirp yes :tangle ~/docker/Dockerfile
+FROM mariadb:latest
+
+COPY ./gn2.tar.gz /tmp/gn2.tar.gz
+RUN tar -xzf /tmp/gn2.tar.gz -C / && rm -f /tmp/gn2.tar.gz && \
+ mkdir -p /usr/local/mysql /genotype_files/genotype/json
+#+end_src
+
+Build the image(Note the fullstop at the end):
+
+: sudo docker build -t python2-genenetwork2:latest -f Dockerfile .
+
+To load the image interactively you've just created:
+
+: docker run -ti "python2-genenetwork2:latest" bash
+
+Assuming you have a docker instance running, you could always run
+commands in it e.g:
+
+: docker run "python2-genenetwork2:latest" python --version
+
+* Pushing to DockerHub
+
+We use DockerHub to store the docker images from which we use on our
+CI environment using Github Actions.
+
+To push to dockerhub, first get the image name by running =docker
+images=. Push to dockerhub using a command similar to:
+
+: docker push bonfacekilz/python2-genenetwork2:latest
+
+Right now, we have 2 images on DockerHub:
+
+- https://hub.docker.com/repository/docker/bonfacekilz/python2-genenetwork2:
+ Contains the python2 version of gn2. Don't use this. Please use the
+ python3 image!
+- https://hub.docker.com/repository/docker/bonfacekilz/python3-genenetwork2:
+ Contains the python3 version of gn2.
diff --git a/test/requests/main_web_functionality.py b/test/requests/main_web_functionality.py
index cefb8b8c..28033ad5 100644
--- a/test/requests/main_web_functionality.py
+++ b/test/requests/main_web_functionality.py
@@ -18,7 +18,7 @@ def check_search_page(host):
search_terms_or="",
search_terms_and="MEAN=(15 16) LRS=(23 46)")
result = requests.get(host+"/search", params=data)
- found = result.text.find("records were found.")
+ found = result.text.find("records were found")
assert(found >= 0)
assert(result.status_code == 200)
print("OK")
diff --git a/wqflask/tests/base/test_trait.py b/wqflask/tests/base/test_trait.py
index d333458a..9c3154f3 100644
--- a/wqflask/tests/base/test_trait.py
+++ b/wqflask/tests/base/test_trait.py
@@ -93,6 +93,6 @@ class TestRetrieveTraitInfo(unittest.TestCase):
test_trait = retrieve_trait_info(trait=mock_trait,
dataset=mock_dataset)
self.assertEqual(test_trait.abbreviation,
- "ファイルを画面毎に見て行くには、次のコマンドを使います。")
+ "ファイルを画面毎に見て行くには、次のコマンドを使います。".decode('utf-8'))
self.assertEqual(test_trait.authors,
- "Jane Doe かいと")
+ "Jane Doe かいと".decode('utf-8'))
diff --git a/wqflask/utility/redis_tools.py b/wqflask/utility/redis_tools.py
index 4aba2b70..d855a7fa 100644
--- a/wqflask/utility/redis_tools.py
+++ b/wqflask/utility/redis_tools.py
@@ -2,23 +2,21 @@ import uuid
import simplejson as json
import datetime
-import redis # used for collections
-
-import logging
-
-from flask import (render_template, flash)
-
-from utility import hmac
+import redis # used for collections
+from utility.hmac import hmac_creation
from utility.logger import getLogger
logger = getLogger(__name__)
+
def get_redis_conn():
Redis = redis.StrictRedis(port=6379)
return Redis
+
Redis = get_redis_conn()
+
def is_redis_available():
try:
Redis.ping()
@@ -26,6 +24,7 @@ def is_redis_available():
return False
return True
+
def get_user_id(column_name, column_value):
user_list = Redis.hgetall("users")
key_list = []
@@ -36,6 +35,7 @@ def get_user_id(column_name, column_value):
return None
+
def get_user_by_unique_column(column_name, column_value):
item_details = None
@@ -50,9 +50,11 @@ def get_user_by_unique_column(column_name, column_value):
return item_details
+
def get_users_like_unique_column(column_name, column_value):
- """
- Like previous function, but this only checks if the input is a subset of a field and can return multiple results
+ """Like previous function, but this only checks if the input is a
+ subset of a field and can return multiple results
+
"""
matched_users = []
@@ -72,7 +74,6 @@ def get_users_like_unique_column(column_name, column_value):
return matched_users
-# def search_users_by_unique_column(column_name, column_value):
def set_user_attribute(user_id, column_name, column_value):
user_info = json.loads(Redis.hget("users", user_id))
@@ -80,6 +81,7 @@ def set_user_attribute(user_id, column_name, column_value):
Redis.hset("users", user_id, json.dumps(user_info))
+
def get_user_collections(user_id):
collections = None
collections = Redis.hget("collections", user_id)
@@ -89,22 +91,27 @@ def get_user_collections(user_id):
else:
return []
+
def save_user(user, user_id):
Redis.hset("users", user_id, json.dumps(user))
+
def save_collections(user_id, collections_ob):
Redis.hset("collections", user_id, collections_ob)
+
def save_verification_code(user_email, code):
Redis.hset("verification_codes", code, user_email)
+
def check_verification_code(code):
email_address = None
user_details = None
email_address = Redis.hget("verification_codes", code)
if email_address:
- user_details = get_user_by_unique_column('email_address', email_address)
+ user_details = get_user_by_unique_column(
+ 'email_address', email_address)
if user_details:
return user_details
else:
@@ -112,10 +119,12 @@ def check_verification_code(code):
else:
return None
+
def get_user_groups(user_id):
- #ZS: Get the groups where a user is an admin or a member and return lists corresponding to those two sets of groups
- admin_group_ids = [] #ZS: Group IDs where user is an admin
- user_group_ids = [] #ZS: Group IDs where user is a regular user
+ # ZS: Get the groups where a user is an admin or a member and
+ # return lists corresponding to those two sets of groups
+ admin_group_ids = [] # ZS: Group IDs where user is an admin
+ user_group_ids = [] # ZS: Group IDs where user is a regular user
groups_list = Redis.hgetall("groups")
for key in groups_list:
try:
@@ -140,6 +149,7 @@ def get_user_groups(user_id):
return admin_groups, user_groups
+
def get_group_info(group_id):
group_json = Redis.hget("groups", group_id)
group_info = None
@@ -148,6 +158,7 @@ def get_group_info(group_id):
return group_info
+
def get_group_by_unique_column(column_name, column_value):
""" Get group by column; not sure if there's a faster way to do this """
@@ -156,7 +167,8 @@ def get_group_by_unique_column(column_name, column_value):
all_group_list = Redis.hgetall("groups")
for key in all_group_list:
group_info = json.loads(all_group_list[key])
- if column_name == "admins" or column_name == "members": #ZS: Since these fields are lists, search in the list
+ # ZS: Since these fields are lists, search in the list
+ if column_name == "admins" or column_name == "members":
if column_value in group_info[column_name]:
matched_groups.append(group_info)
else:
@@ -165,9 +177,11 @@ def get_group_by_unique_column(column_name, column_value):
return matched_groups
+
def get_groups_like_unique_column(column_name, column_value):
- """
- Like previous function, but this only checks if the input is a subset of a field and can return multiple results
+ """Like previous function, but this only checks if the input is a
+ subset of a field and can return multiple results
+
"""
matched_groups = []
@@ -176,7 +190,8 @@ def get_groups_like_unique_column(column_name, column_value):
if column_name != "group_id":
for key in group_list:
group_info = json.loads(group_list[key])
- if column_name == "admins" or column_name == "members": #ZS: Since these fields are lists, search in the list
+ # ZS: Since these fields are lists, search in the list
+ if column_name == "admins" or column_name == "members":
if column_value in group_info[column_name]:
matched_groups.append(group_info)
else:
@@ -188,13 +203,15 @@ def get_groups_like_unique_column(column_name, column_value):
return matched_groups
-def create_group(admin_user_ids, member_user_ids = [], group_name = "Default Group Name"):
+
+def create_group(admin_user_ids, member_user_ids=[],
+ group_name="Default Group Name"):
group_id = str(uuid.uuid4())
new_group = {
- "id" : group_id,
+ "id": group_id,
"admins": admin_user_ids,
- "members" : member_user_ids,
- "name" : group_name,
+ "members": member_user_ids,
+ "name": group_name,
"created_timestamp": datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p'),
"changed_timestamp": datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p')
}
@@ -203,8 +220,9 @@ def create_group(admin_user_ids, member_user_ids = [], group_name = "Default Gro
return new_group
+
def delete_group(user_id, group_id):
- #ZS: If user is an admin of a group, remove it from the groups hash
+ # ZS: If user is an admin of a group, remove it from the groups hash
group_info = get_group_info(group_id)
if user_id in group_info["admins"]:
Redis.hdel("groups", group_id)
@@ -212,9 +230,15 @@ def delete_group(user_id, group_id):
else:
None
-def add_users_to_group(user_id, group_id, user_emails = [], admins = False): #ZS "admins" is just to indicate whether the users should be added to the groups admins or regular users set
+
+# ZS "admins" is just to indicate whether the users should be added to
+# the groups admins or regular users set
+def add_users_to_group(user_id, group_id, user_emails=[], admins=False):
group_info = get_group_info(group_id)
- if user_id in group_info["admins"]: #ZS: Just to make sure that the user is an admin for the group, even though they shouldn't be able to reach this point unless they are
+ # ZS: Just to make sure that the user is an admin for the group,
+ # even though they shouldn't be able to reach this point unless
+ # they are
+ if user_id in group_info["admins"]:
if admins:
group_users = set(group_info["admins"])
else:
@@ -229,25 +253,36 @@ def add_users_to_group(user_id, group_id, user_emails = [], admins = False): #ZS
else:
group_info["members"] = list(group_users)
- group_info["changed_timestamp"] = datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p')
+ group_info["changed_timestamp"] = datetime.datetime.utcnow().strftime(
+ '%b %d %Y %I:%M%p')
Redis.hset("groups", group_id, json.dumps(group_info))
return group_info
else:
return None
-def remove_users_from_group(user_id, users_to_remove_ids, group_id, user_type = "members"): #ZS: User type is because I assume admins can remove other admins
+
+# ZS: User type is because I assume admins can remove other admins
+def remove_users_from_group(user_id,
+ users_to_remove_ids,
+ group_id,
+ user_type="members"):
group_info = get_group_info(group_id)
if user_id in group_info["admins"]:
users_to_remove_set = set(users_to_remove_ids)
- if user_type == "admins" and user_id in users_to_remove_set: #ZS: Make sure an admin can't remove themselves from a group, since I imagine we don't want groups to be able to become admin-less
+ # ZS: Make sure an admin can't remove themselves from a group,
+ # since I imagine we don't want groups to be able to become
+ # admin-less
+ if user_type == "admins" and user_id in users_to_remove_set:
users_to_remove_set.remove(user_id)
group_users = set(group_info[user_type])
group_users -= users_to_remove_set
group_info[user_type] = list(group_users)
- group_info["changed_timestamp"] = datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p')
+ group_info["changed_timestamp"] = datetime.datetime.utcnow().strftime(
+ '%b %d %Y %I:%M%p')
Redis.hset("groups", group_id, json.dumps(group_info))
+
def change_group_name(user_id, group_id, new_name):
group_info = get_group_info(group_id)
if user_id in group_info["admins"]:
@@ -257,22 +292,28 @@ def change_group_name(user_id, group_id, new_name):
else:
return None
+
def get_resources():
resource_list = Redis.hgetall("resources")
return resource_list
+
def get_resource_id(dataset, trait_id=None):
resource_id = False
if dataset.type == "Publish":
if trait_id:
- resource_id = hmac.hmac_creation("{}:{}:{}".format('dataset-publish', dataset.id, trait_id))
+ resource_id = hmac_creation("{}:{}:{}".format(
+ 'dataset-publish', dataset.id, trait_id))
elif dataset.type == "ProbeSet":
- resource_id = hmac.hmac_creation("{}:{}".format('dataset-probeset', dataset.id))
+ resource_id = hmac_creation(
+ "{}:{}".format('dataset-probeset', dataset.id))
elif dataset.type == "Geno":
- resource_id = hmac.hmac_creation("{}:{}".format('dataset-geno', dataset.id))
+ resource_id = hmac_creation(
+ "{}:{}".format('dataset-geno', dataset.id))
return resource_id
+
def get_resource_info(resource_id):
resource_info = Redis.hget("resources", resource_id)
if resource_info:
@@ -280,17 +321,23 @@ def get_resource_info(resource_id):
else:
return None
+
def add_resource(resource_info, update=True):
if 'trait' in resource_info['data']:
- resource_id = hmac.hmac_creation('{}:{}:{}'.format(str(resource_info['type']), str(resource_info['data']['dataset']), str(resource_info['data']['trait'])))
+ resource_id = hmac_creation('{}:{}:{}'.format(
+ str(resource_info['type']), str(
+ resource_info['data']['dataset']),
+ str(resource_info['data']['trait'])))
else:
- resource_id = hmac.hmac_creation('{}:{}'.format(str(resource_info['type']), str(resource_info['data']['dataset'])))
+ resource_id = hmac_creation('{}:{}'.format(
+ str(resource_info['type']), str(resource_info['data']['dataset'])))
if update or not Redis.hexists("resources", resource_id):
Redis.hset("resources", resource_id, json.dumps(resource_info))
return resource_info
+
def add_access_mask(resource_id, group_id, access_mask):
the_resource = get_resource_info(resource_id)
the_resource['group_masks'][group_id] = access_mask
@@ -299,8 +346,9 @@ def add_access_mask(resource_id, group_id, access_mask):
return the_resource
+
def change_resource_owner(resource_id, new_owner_id):
- the_resource= get_resource_info(resource_id)
+ the_resource = get_resource_info(resource_id)
the_resource['owner_id'] = new_owner_id
Redis.delete("resource")
diff --git a/wqflask/wqflask/__init__.py b/wqflask/wqflask/__init__.py
index e73f833f..d484e525 100644
--- a/wqflask/wqflask/__init__.py
+++ b/wqflask/wqflask/__init__.py
@@ -10,13 +10,24 @@ logging.basicConfig(level=logging.INFO)
app = Flask(__name__)
-app.config.from_envvar('GN2_SETTINGS') # See http://flask.pocoo.org/docs/config/#configuring-from-files
+# See http://flask.pocoo.org/docs/config/#configuring-from-files
# Note no longer use the badly named WQFLASK_OVERRIDES (nyi)
-
+app.config.from_envvar('GN2_SETTINGS')
app.jinja_env.globals.update(
- undefined = jinja2.StrictUndefined,
- numify = formatting.numify
-)
+ undefined=jinja2.StrictUndefined,
+ numify=formatting.numify)
from wqflask.api import router
+from wqflask import group_manager
+from wqflask import resource_manager
+from wqflask import search_results
+from wqflask import export_traits
+from wqflask import gsearch
+from wqflask import update_search_results
+from wqflask import docs
+from wqflask import news
+from wqflask import db_info
+from wqflask import user_login
+from wqflask import user_session
+
import wqflask.views
diff --git a/wqflask/wqflask/db_info.py b/wqflask/wqflask/db_info.py
new file mode 100644
index 00000000..f04e38bf
--- /dev/null
+++ b/wqflask/wqflask/db_info.py
@@ -0,0 +1,127 @@
+import httplib, urllib2
+import re
+
+from flask import Flask, g
+
+from utility.logger import getLogger
+logger = getLogger(__name__ )
+
+class InfoPage(object):
+ def __init__(self, start_vars):
+ self.info = None
+ self.gn_accession_id = None
+ if 'gn_accession_id' in start_vars:
+ self.gn_accession_id = start_vars['gn_accession_id']
+ self.info_page_name = start_vars['info_page_name']
+
+ self.get_info()
+ self.get_datasets_list()
+
+ def get_info(self, create=False):
+ query_base = ("SELECT InfoPageName, GN_AccesionId, Species.MenuName, Species.TaxonomyId, Tissue.Name, InbredSet.Name, " +
+ "GeneChip.GeneChipName, GeneChip.GeoPlatform, AvgMethod.Name, Datasets.DatasetName, Datasets.GeoSeries, " +
+ "Datasets.PublicationTitle, DatasetStatus.DatasetStatusName, Datasets.Summary, Datasets.AboutCases, " +
+ "Datasets.AboutTissue, Datasets.AboutDataProcessing, Datasets.Acknowledgment, Datasets.ExperimentDesign, " +
+ "Datasets.Contributors, Datasets.Citation, Datasets.Notes, Investigators.FirstName, Investigators.LastName, " +
+ "Investigators.Address, Investigators.City, Investigators.State, Investigators.ZipCode, Investigators.Country, " +
+ "Investigators.Phone, Investigators.Email, Investigators.Url, Organizations.OrganizationName, " +
+ "InvestigatorId, DatasetId, DatasetStatusId, Datasets.AboutPlatform, InfoFileTitle, Specifics " +
+ "FROM InfoFiles " +
+ "LEFT JOIN Species USING (SpeciesId) " +
+ "LEFT JOIN Tissue USING (TissueId) " +
+ "LEFT JOIN InbredSet USING (InbredSetId) " +
+ "LEFT JOIN GeneChip USING (GeneChipId) " +
+ "LEFT JOIN AvgMethod USING (AvgMethodId) " +
+ "LEFT JOIN Datasets USING (DatasetId) " +
+ "LEFT JOIN Investigators USING (InvestigatorId) " +
+ "LEFT JOIN Organizations USING (OrganizationId) " +
+ "LEFT JOIN DatasetStatus USING (DatasetStatusId) WHERE ")
+
+ if self.gn_accession_id:
+ final_query = query_base + "GN_AccesionId = {}".format(self.gn_accession_id)
+ results = g.db.execute(final_query).fetchone()
+ if self.info_page_name and not results:
+ final_query = query_base + "InfoPageName={}".format(self.info_page_name)
+ elif self.info_page_name:
+ final_query = query_base + "InfoPageName={}".format(self.info_page_name)
+ results = g.db.execute(final_query).fetchone()
+ else:
+ raise 'No correct parameter found'
+
+ if results:
+ self.info = process_query_results(results)
+
+ if (not results or len(results) < 1) and self.info_page_name and create:
+ insert_sql = "INSERT INTO InfoFiles SET InfoFiles.InfoPageName={}".format(self.info_page_name)
+ return self.get_info()
+
+ if not self.gn_accession_id and self.info:
+ self.gn_accession_id = self.info['accession_id']
+ if not self.info_page_name and self.info:
+ self.info_page_name = self.info['info_page_name']
+
+ def get_datasets_list(self):
+ self.filelist = []
+ try:
+ response = urllib2.urlopen("http://datafiles.genenetwork.org/download/GN%s" % self.gn_accession_id)
+ data = response.read()
+
+ matches = re.findall(r"<tr>.+?</tr>", data, re.DOTALL)
+ for i, match in enumerate(matches):
+ if i == 0:
+ continue
+ cells = re.findall(r"<td.+?>.+?</td>", match, re.DOTALL)
+ full_filename = re.search(r"<a href=\"(.+?)\"", cells[1], re.DOTALL).group(1).strip()
+ filename = full_filename.split("/")[-1]
+ filesize = re.search(r">(.+?)<", cells[2]).group(1).strip()
+ filedate = "N/A" #ZS: Since we can't get it for now
+
+ self.filelist.append([filename, filedate, filesize])
+ except Exception, e:
+ pass
+
+def process_query_results(results):
+ info_ob = {
+ 'info_page_name': results[0],
+ 'accession_id': results[1],
+ 'menu_name': results[2],
+ 'taxonomy_id': results[3],
+ 'tissue_name': results[4],
+ 'group_name': results[5],
+ 'gene_chip_name': results[6],
+ 'geo_platform': results[7],
+ 'avg_method_name': results[8],
+ 'dataset_name': results[9],
+ 'geo_series': results[10],
+ 'publication_title': results[11],
+ 'dataset_status_name': results[12],
+ 'dataset_summary': results[13],
+ 'about_cases': results[14],
+ 'about_tissue': results[15],
+ 'about_data_processing': results[16],
+ 'acknowledgement': results[17],
+ 'experiment_design': results[18],
+ 'contributors': results[19],
+ 'citation': results[20],
+ 'notes': results[21],
+ 'investigator_firstname': results[22],
+ 'investigator_lastname': results[23],
+ 'investigator_address': results[24],
+ 'investigator_city': results[25],
+ 'investigator_state': results[26],
+ 'investigator_zipcode': results[27],
+ 'investigator_country': results[28],
+ 'investigator_phone': results[29],
+ 'investigator_email': results[30],
+ 'investigator_url': results[31],
+ 'organization_name': results[32],
+ 'investigator_id': results[33],
+ 'dataset_id': results[34],
+ 'dataset_status_is': results[35],
+ 'about_platform': results[36],
+ 'info_file_title': results[37],
+ 'specifics': results[38]
+ }
+
+ return info_ob
+ \ No newline at end of file
diff --git a/wqflask/wqflask/marker_regression/run_mapping.py b/wqflask/wqflask/marker_regression/run_mapping.py
index c606cf53..f42d2315 100644
--- a/wqflask/wqflask/marker_regression/run_mapping.py
+++ b/wqflask/wqflask/marker_regression/run_mapping.py
@@ -399,9 +399,7 @@ class RunMapping(object):
rs = marker['name'],
pos = this_ps
)
- #if 'p_value' in marker:
- # logger.debug("P EXISTS:", marker['p_value'])
- #else:
+
if 'lrs_value' in marker and marker['lrs_value'] > 0:
browser_marker['p_wald'] = 10**-(marker['lrs_value']/4.61)
elif 'lod_score' in marker and marker['lod_score'] > 0:
@@ -414,7 +412,13 @@ class RunMapping(object):
if marker['chr'] > 0 or marker['chr'] == "X" or marker['chr'] == "X/Y":
if marker['chr'] > highest_chr or marker['chr'] == "X" or marker['chr'] == "X/Y":
highest_chr = marker['chr']
- if ('lod_score' in list(marker.keys())) or ('lrs_value' in list(marker.keys())):
+ if ('lod_score' in marker.keys()) or ('lrs_value' in marker.keys()):
+ if 'Mb' in marker.keys():
+ marker['display_pos'] = "Chr" + str(marker['chr']) + ": " + "{:.3f}".format(marker['Mb'])
+ elif 'cM' in marker.keys():
+ marker['display_pos'] = "Chr" + str(marker['chr']) + ": " + "{:.3f}".format(marker['cM'])
+ else:
+ marker['display_pos'] = "N/A"
self.qtl_results.append(marker)
with Bench("Exporting Results"):
diff --git a/wqflask/wqflask/static/new/css/marker_regression.css b/wqflask/wqflask/static/new/css/marker_regression.css
index f1a26a83..e0a5ceea 100644
--- a/wqflask/wqflask/static/new/css/marker_regression.css
+++ b/wqflask/wqflask/static/new/css/marker_regression.css
@@ -62,6 +62,10 @@ table.dataTable tbody td {
padding: 4px 20px 2px 10px;
}
+table.dataTable tbody tr.selected {
+ background-color: #ffee99;
+}
+
table.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {
border-top: 1px solid #ccc;
border-right: 1px solid #ccc;
diff --git a/wqflask/wqflask/static/new/javascript/search_results.js b/wqflask/wqflask/static/new/javascript/search_results.js
index 4e87d67a..685d6291 100644
--- a/wqflask/wqflask/static/new/javascript/search_results.js
+++ b/wqflask/wqflask/static/new/javascript/search_results.js
@@ -259,14 +259,16 @@ $(function() {
let naturalAsc = $.fn.dataTableExt.oSort["natural-ci-asc"]
let naturalDesc = $.fn.dataTableExt.oSort["natural-ci-desc"]
+ let na_equivalent_vals = ["N/A", "--", ""]; //ZS: Since there are multiple values that should be treated the same as N/A
+
function sort_NAs(a, b, sort_function){
- if (a === "N/A" && b === "N/A") {
+ if ( na_equivalent_vals.includes(a) && na_equivalent_vals.includes(b)) {
return 0;
}
- if (a === "N/A"){
+ if (na_equivalent_vals.includes(a)){
return 1
}
- if (b === "N/A") {
+ if (na_equivalent_vals.includes(b)) {
return -1;
}
return sort_function(a, b)
@@ -281,4 +283,18 @@ $(function() {
}
});
+ $.fn.dataTable.ext.order['dom-checkbox'] = function ( settings, col )
+ {
+ return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
+ return $('input', td).prop('checked') ? '1' : '0';
+ } );
+ };
+
+ $.fn.dataTable.ext.order['dom-inner-text'] = function ( settings, col )
+ {
+ return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
+ return $(td).text();
+ } );
+ }
+
}); \ No newline at end of file
diff --git a/wqflask/wqflask/templates/base.html b/wqflask/wqflask/templates/base.html
index 50562200..e6802cc4 100644
--- a/wqflask/wqflask/templates/base.html
+++ b/wqflask/wqflask/templates/base.html
@@ -4,7 +4,9 @@
<head>
<meta charset="utf-8">
- <title>{% block title %}{% endblock %}</title>
+
+ <title>{% block title %}{% endblock %} GeneNetwork 2</title>
+
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" type="image/png" sizes="64x64" href="/static/new/images/CITGLogo.png">
diff --git a/wqflask/wqflask/templates/gsearch_gene.html b/wqflask/wqflask/templates/gsearch_gene.html
index 478d6f5f..d2c78d65 100644
--- a/wqflask/wqflask/templates/gsearch_gene.html
+++ b/wqflask/wqflask/templates/gsearch_gene.html
@@ -59,20 +59,6 @@
</script>
<script type="text/javascript" charset="utf-8">
- $.fn.dataTable.ext.order['dom-checkbox'] = function ( settings, col )
- {
- return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
- return $('input', td).prop('checked') ? '1' : '0';
- } );
- };
-
- $.fn.dataTable.ext.order['dom-inner-text'] = function ( settings, col )
- {
- return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
- return $(td).text();
- } );
- }
-
$(document).ready( function () {
$('#trait_table tr').click(function(event) {
@@ -252,7 +238,7 @@
'sDom': "pitirp",
'autoWidth': true,
'iDisplayLength': 500,
- 'deferRender': true,
+ 'deferRender': false,
'paging': true,
'orderClasses': true,
'processing': true,
diff --git a/wqflask/wqflask/templates/gsearch_pheno.html b/wqflask/wqflask/templates/gsearch_pheno.html
index eb998d15..c44231f3 100644
--- a/wqflask/wqflask/templates/gsearch_pheno.html
+++ b/wqflask/wqflask/templates/gsearch_pheno.html
@@ -59,20 +59,6 @@
</script>
<script type="text/javascript" charset="utf-8">
- $.fn.dataTable.ext.order['dom-checkbox'] = function ( settings, col )
- {
- return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
- return $('input', td).prop('checked') ? '1' : '0';
- } );
- };
-
- $.fn.dataTable.ext.order['dom-inner-text'] = function ( settings, col )
- {
- return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
- return $(td).text();
- } );
- }
-
$(document).ready( function () {
$('#trait_table tr').click(function(event) {
@@ -172,6 +158,7 @@
'title': "Record",
'type': "natural",
'data': null,
+ 'orderDataType': "dom-inner-text",
'render': function(data, type, row, meta) {
return '<a target="_blank" href="/show_trait?trait_id=' + data.name + '&dataset=' + data.dataset + '">' + data.display_name + '</a>'
}
@@ -252,7 +239,7 @@
'order': [[1, "asc" ]],
'sDom': "pitirp",
'autoWidth': false,
- 'deferRender': true,
+ 'deferRender': false,
'iDisplayLength': 500,
'paging': true,
'orderClasses': true,
diff --git a/wqflask/wqflask/templates/info_page.html b/wqflask/wqflask/templates/info_page.html
new file mode 100644
index 00000000..d8b7d74c
--- /dev/null
+++ b/wqflask/wqflask/templates/info_page.html
@@ -0,0 +1,92 @@
+{% extends "base.html" %}
+{% block title %}Policies{% endblock %}
+{% block content %}
+
+<h1 id="parent-fieldname-title">Data Set Group: {{ info.dataset_name }}
+<!--<a href="/infoshare/manager/member-studies-edit.html?DatasetId=%s"><img src="/images/modify.gif" alt="modify this page" border="0" valign="middle"></a>-->
+<span style="color:red;">{{ info.info_page_name }}</span>
+</h1>
+<table border="0" width="100%">
+<tr>
+<td valign="top" width="50%">
+<table name="info_table" cellSpacing=0 cellPadding=5 width=100% border=0>
+ <tr><td><b>Data Set:</b> {{ info.info_file_title }} <!--<a href="/infoshare/manager/member-infofile-edit.html?GN_AccesionId=%s"><img src="/images/modify.gif" alt="modify this page" border="0" valign="middle"></a>--></td></tr>
+ <tr><td><b>GN Accession:</b> GN{{ gn_accession_id }}</td></tr>
+ <tr><td><b>GEO Series:</b> <a href="http://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc={{ info.geo_series }}" target="_blank">{{ info.geo_series }}</a></td></tr>
+ <tr><td><b>Title:</b> {{ info.publication_title }}</td></tr>
+ <tr><td><b>Organism:</b> <a href="http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?mode=Info&id={{ info.taxonomy_id }}" target="_blank">{{ info.menu_name }}</a></td></tr>
+ <tr><td><b>Group:</b> {{ info.group_name }}</td></tr>
+ <tr><td><b>Tissue:</b> {{ info.tissue_name }}</td></tr>
+ <tr><td><b>Dataset Status:</b> {{ info.dataset_status_name }}</td></tr>
+ <tr><td><b>Platforms:</b> <a href="http://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc={{ info.geo_platform }}" target="_blank">{{ info.gene_chip_name }}</a></td></tr>
+ <tr><td><b>Normalization:</b> {{ info.avg_method_name }}</td></tr>
+</table>
+</td>
+<td valign="top" width="50%">
+<table border="0" width="100%">
+ <tr>
+ <td><b>Contact Information</b></td>
+ </tr>
+ <tr>
+ <td>
+ {{ info.investigator_first_name }} {{ info.inveestigator_last_name }}<br>
+ {{ info.organization_name }} <br>
+ {{ info.investigator_address }}<br>
+ {{ info.investigator_city }}, {{ info.investigator_state }} {{ info.investigator_zipcode }} {{ info.investigator_country }}<br>
+ Tel. {{ info.investigator_phone }}<br>
+ {{ info.investigator_email }}<br>
+ <a href="{{ info.investigator_url }}" target="_blank">Website</a>
+ </td>
+ </tr>
+
+<tr>
+ <td><b>Download datasets and supplementary data files</b></td>
+</tr>
+<tr>
+ <td>
+ <ul style="line-height: 160%">
+ {% for file in filelist %}
+ <li><a href="http://datafiles.genenetwork.org/download/GN{{ gn_accession_id }}/{{ file[0] }}">{{ file[0] }} ({{ file[2] }})</a></li>
+ {% endfor %}
+ </ul>
+ </td>
+</tr>
+
+<tr><td>
+</td></tr>
+
+</table>
+</td>
+</tr>
+</table>
+<HR>
+<p>
+<table name="info_table" width="100%" border="0" cellpadding="5" cellspacing="0">
+<tr><td><span style="font-size:115%%;font-weight:bold;">Specifics of this Data Set:</span></td></tr>
+ <tr><td> {{ info.specifics|safe }}<br><br></td></tr>
+<tr><td><span style="font-size:115%%;font-weight:bold;">Summary:</span></td></tr>
+ <tr><td> {{ info.dataset_summary|safe }}<br><br></td></tr>
+<tr><td><span style="font-size:115%; font-weight:bold;">About the cases used to generate this set of data:</span></td></tr>
+ <tr><td> {{ info.about_cases|safe }}<br><br></td></tr>
+<tr><td><span style="font-size:115%; font-weight:bold;">About the tissue used to generate this set of data:</span></td></tr>
+ <tr><td> {{ info.about_tissue|safe }}<br><br></td></tr>
+ <tr><td><span style="font-size:115%; font-weight:bold;">About the array platform:</span></td></tr>
+ <tr><td> {{ info.about_platform|safe }}<br><br></td></tr>
+<tr><td><span style="font-size:115%; font-weight:bold;">About data values and data processing:</span></td></tr>
+ <tr><td> {{ info.about_data_processing|safe }}<br><br></td></tr>
+<tr><td><span style="font-size:115%; font-weight:bold;">Notes:</span></td></tr>
+ <tr><td> {{ info.notes|safe }}<br><br></td></tr>
+<tr><td><span style="font-size:115%; font-weight:bold;">Experiment Type:</span></td></tr>
+ <tr><td> {{ info.experiment_design|safe }}<br><br></td></tr>
+<tr><td><span style="font-size:115%; font-weight:bold;">Contributor:</span></td></tr>
+ <tr><td> {{ info.contributors|safe }}<br><br></td></tr>
+<tr><td><span style="font-size:115%; font-weight:bold;">Citation:</span></td></tr>
+ <tr><td> {{ info.citation|safe }}<br><br></td></tr>
+<tr><td><span style="font-size:115%; font-weight:bold;">Data source acknowledgment:</span></td></tr>
+ <tr><td> {{ info.acknowledgement|safe }}<br><br></td></tr>
+<tr><td><span style="font-size:115%; font-weight:bold;">Study Id:</span></td></tr>
+ <tr><td> {{ info.dataset_id }}<br><br></td></tr>
+</table>
+</p>
+
+{% endblock %} \ No newline at end of file
diff --git a/wqflask/wqflask/templates/mapping_results.html b/wqflask/wqflask/templates/mapping_results.html
index 8edda548..41d760c0 100644
--- a/wqflask/wqflask/templates/mapping_results.html
+++ b/wqflask/wqflask/templates/mapping_results.html
@@ -228,71 +228,61 @@
<button class="btn btn-success" id="add" disabled><span class="glyphicon glyphicon-plus-sign"></span> Add</button>
<br />
<br />
- <div id="table_container" style="width:{% if 'additive' in trimmed_markers[0] %}500{% else %}470{% endif %}px;">
- <table id="trait_table" class="table-hover table-striped cell-border dataTable no-footer">
- <thead>
- <tr>
- <th></th>
- <th>Row</th>
- <th>Marker</th>
- <th>{{ LRS_LOD }}</th>
- <th>Chr</th>
- {% if plotScale != "physic" %}
- <th>cM</th>
- {% else %}
- <th align="right">Mb</th>
- {% endif %}
- {% if 'additive' in trimmed_markers[0] %}
- <th>Add Eff</th>
- {% endif %}
- {% if 'dominance' in trimmed_markers[0] and dataset.group.genetic_type != "riset" %}
- <th>Dom Eff</th>
- {% endif %}
- </tr>
- </thead>
- <tbody>
- {% for marker in trimmed_markers %}
- <tr>
- <td align="center" style="padding: 1px 0px 1px 0px;">
- <input type="checkbox" name="selectCheck"
- class="checkbox trait_checkbox"
- value="{{ data_hmac('{}:{}Geno'.format(marker.name, dataset.group.name)) }}">
- </td>
- <td align="right">{{ loop.index }}</td>
- <td>{% if geno_db_exists == "True" %}<a href="/show_trait?trait_id={{ marker.name }}&dataset={{ dataset.group.name }}Geno">{{ marker.name }}</a>{% else %}{{ marker.name }}{% endif %}</td>
- {% if LRS_LOD == "LOD" or LRS_LOD == "-log(p)" %}
- {% if 'lod_score' in marker %}
- <td align="right">{{ '%0.2f' | format(marker.lod_score|float) }}</td>
- {% else %}
- <td align="right">{{ '%0.2f' | format(marker.lrs_value|float / 4.61) }}</td>
- {% endif %}
- {% else %}
- {% if 'lod_score' in marker %}
- <td align="right">{{ '%0.2f' | format(marker.lod_score|float * 4.61) }}</td>
- {% else %}
- <td align="right">{{ '%0.2f' | format(marker.lrs_value|float) }}</td>
- {% endif %}
- {% endif %}
- <td align="right">{{marker.chr}}</td>
- {% if plotScale != "physic" %}
- {% if 'cM' in marker %}
- <td align="right">{{ '%0.3f' | format(marker.cM|float) }}</td>
- {% else %}
- <td align="right">{{ '%0.3f' | format(marker.Mb|float) }}</td>
- {% endif %}
- {% else %}
- <td align="right">{{ '%0.6f' | format(marker.Mb|float) }}</td>
- {% endif %}
- {% if 'additive' in marker %}
- <td align="right">{{ '%0.3f' | format(marker.additive|float) }}</td>
- {% endif %}
- {% if 'dominance' in marker and dataset.group.genetic_type != "riset" %}
- <td align="right">{{ '%0.2f' | format(marker.dominance|float) }}</td>
- {% endif %}
- </tr>
- {% endfor %}
- </tbody>
- </table>
+ <div id="table_container" style="width:{% if 'additive' in trimmed_markers[0] %}600{% else %}550{% endif %}px;">
+ <table id="trait_table" class="table-hover table-striped cell-border dataTable no-footer">
+ <thead>
+ <tr>
+ <th></th>
+ <th>Row</th>
+ <th>Marker</th>
+ {% if LRS_LOD == "-log(p)" %}
+ <th>–log(p)</th>
+ {% else %}
+ <th>{{ LRS_LOD }}</th>
+ {% endif %}
+ <th>Position ({% if plotScale == "physic" %}Mb{% else %}cM{% endif %})</th>
+ {% if 'additive' in trimmed_markers[0] %}
+ <th>Add Eff</th>
+ {% endif %}
+ {% if 'dominance' in trimmed_markers[0] and dataset.group.genetic_type != "riset" %}
+ <th>Dom Eff</th>
+ {% endif %}
+ </tr>
+ </thead>
+ <tbody>
+ {% for marker in trimmed_markers %}
+ <tr>
+ <td align="center" style="padding: 1px 0px 1px 0px;">
+ <input type="checkbox" name="selectCheck"
+ class="checkbox trait_checkbox"
+ value="{{ data_hmac('{}:{}Geno'.format(marker.name, dataset.group.name)) }}">
+ </td>
+ <td align="right">{{ loop.index }}</td>
+ <td>{% if geno_db_exists == "True" %}<a href="/show_trait?trait_id={{ marker.name }}&dataset={{ dataset.group.name }}Geno">{{ marker.name }}</a>{% else %}{{ marker.name }}{% endif %}</td>
+ {% if LRS_LOD == "LOD" or LRS_LOD == "-log(p)" %}
+ {% if 'lod_score' in marker %}
+ <td align="right">{{ '%0.2f' | format(marker.lod_score|float) }}</td>
+ {% else %}
+ <td align="right">{{ '%0.2f' | format(marker.lrs_value|float / 4.61) }}</td>
+ {% endif %}
+ {% else %}
+ {% if 'lod_score' in marker %}
+ <td align="right">{{ '%0.2f' | format(marker.lod_score|float * 4.61) }}</td>
+ {% else %}
+ <td align="right">{{ '%0.2f' | format(marker.lrs_value|float) }}</td>
+ {% endif %}
+ {% endif %}
+ <td align="right">{{ marker.display_pos }}</td>
+ {% if 'additive' in marker %}
+ <td align="right">{{ '%0.3f' | format(marker.additive|float) }}</td>
+ {% endif %}
+ {% if 'dominance' in marker and dataset.group.genetic_type != "riset" %}
+ <td align="right">{{ '%0.2f' | format(marker.dominance|float) }}</td>
+ {% endif %}
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
</div>
</div>
{% elif selectedChr != -1 and plotScale =="physic" and (dataset.group.species == 'mouse' or dataset.group.species == 'rat') %}
@@ -362,8 +352,7 @@
"columns": [
{ "type": "natural", "width": "5%" },
{ "type": "natural", "width": "8%" },
- { "type": "natural", "width": "25%" },
- { "type": "natural" },
+ { "type": "natural", "width": "20%" },
{ "type": "natural" },
{ "type": "natural" }{% if 'additive' in qtlresults[0] %},
{ "type": "natural" }{% endif %}{% if 'dominance' in qtlresults[0] and dataset.group.genetic_type != "riset" %},
@@ -395,16 +384,16 @@
$('td', row).eq(9).attr("align", "right");
},
"columns": [
- { "bSortable": false},
- { "type": "natural" },
- { "type": "natural" },
- { "type": "natural" },
- { "type": "natural" },
- { "type": "natural" },
- { "type": "natural" },
- { "type": "natural" },
+ { "orderDataType": "dom-checkbox" },
+ { "type": "natural"},
+ { "type": "natural" , "orderDataType": "dom-inner-text" },
+ { "type": "natural" , "orderDataType": "dom-inner-text" },
+ { "type": "natural" , "orderDataType": "dom-inner-text" },
{ "type": "natural" },
{ "type": "natural" },
+ { "type": "natural-minus-na" },
+ { "type": "natural-minus-na" },
+ { "type": "natural-minus-na" , "orderDataType": "dom-inner-text" },
{ "type": "natural" }
],
"columnDefs": [ {
diff --git a/wqflask/wqflask/templates/search_result_page.html b/wqflask/wqflask/templates/search_result_page.html
index 53373b41..282e752d 100644
--- a/wqflask/wqflask/templates/search_result_page.html
+++ b/wqflask/wqflask/templates/search_result_page.html
@@ -174,21 +174,6 @@
</script>
<script type="text/javascript" charset="utf-8">
-
- $.fn.dataTable.ext.order['dom-checkbox'] = function ( settings, col )
- {
- return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
- return $('input', td).prop('checked') ? '1' : '0';
- } );
- };
-
- $.fn.dataTable.ext.order['dom-inner-text'] = function ( settings, col )
- {
- return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
- return $(td).text();
- } );
- }
-
$(document).ready( function () {
$('#trait_table tr').click(function(event) {
diff --git a/wqflask/wqflask/templates/tutorials.html b/wqflask/wqflask/templates/tutorials.html
index 3e6ef01c..f9d12ba5 100644
--- a/wqflask/wqflask/templates/tutorials.html
+++ b/wqflask/wqflask/templates/tutorials.html
@@ -15,3 +15,4 @@ and initial mapping results for Rat GWAS P50 as implemented in GeneNetwork.org</
</TR></TABLE>
{% endblock %}
+
diff --git a/wqflask/wqflask/user_login.py b/wqflask/wqflask/user_login.py
index 28d58712..cb2edbc5 100644
--- a/wqflask/wqflask/user_login.py
+++ b/wqflask/wqflask/user_login.py
@@ -451,7 +451,9 @@ def register_user(params):
user_details['confirmed'] = 1
user_details['registration_info'] = basic_info()
- save_user(user_details, user_details['user_id'])
+
+ if len(errors) == 0:
+ save_user(user_details, user_details['user_id'])
return errors
diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py
index 7e0b1c40..7fdc62e5 100644
--- a/wqflask/wqflask/views.py
+++ b/wqflask/wqflask/views.py
@@ -27,14 +27,7 @@ import array
import sqlalchemy
from wqflask import app
from flask import g, Response, request, make_response, render_template, send_from_directory, jsonify, redirect, url_for, send_file
-from wqflask import group_manager
-from wqflask import resource_manager
-from wqflask import search_results
-from wqflask import export_traits
-from wqflask import gsearch
-from wqflask import update_search_results
-from wqflask import docs
-from wqflask import news
+
from wqflask.submit_bnw import get_bnw_input
from base.data_set import create_dataset, DataSet # Used by YAML in marker_regression
from wqflask.show_trait import show_trait
@@ -51,6 +44,12 @@ from wqflask.correlation import corr_scatter_plot
from wqflask.wgcna import wgcna_analysis
from wqflask.ctl import ctl_analysis
from wqflask.snp_browser import snp_browser
+from wqflask.search_results import SearchResultPage
+from wqflask.export_traits import export_search_results_csv
+from wqflask.gsearch import GSearch
+from wqflask.update_search_results import GSearch as UpdateGSearch
+from wqflask.docs import Docs
+from wqflask.db_info import InfoPage
from utility import temp_data
from utility.tools import SQL_URI, TEMPDIR, USE_REDIS, USE_GN_SERVER, GN_SERVER_URL, GN_VERSION, JS_TWITTER_POST_FETCHER_PATH, JS_GUIX_PATH, CSS_PATH
@@ -64,9 +63,6 @@ from utility.benchmark import Bench
from pprint import pformat as pf
-from wqflask import user_login
-from wqflask import user_session
-
from wqflask import collect
from wqflask.database import db_session
@@ -213,7 +209,7 @@ def search_page():
logger.info("Skipping Redis cache (USE_REDIS=False)")
logger.info("request.args is", request.args)
- the_search = search_results.SearchResultPage(request.args)
+ the_search = SearchResultPage(request.args)
result = the_search.__dict__
valid_search = result['search_term_exists']
@@ -229,7 +225,7 @@ def search_page():
@app.route("/gsearch", methods=('GET',))
def gsearchact():
logger.info(request.url)
- result = gsearch.GSearch(request.args).__dict__
+ result = GSearch(request.args).__dict__
type = request.args['type']
if type == "gene":
return render_template("gsearch_gene.html", **result)
@@ -240,7 +236,7 @@ def gsearchact():
def gsearch_updating():
logger.info("REQUEST ARGS:", request.values)
logger.info(request.url)
- result = update_search_results.GSearch(request.args).__dict__
+ result = UpdateGSearch(request.args).__dict__
return result['results']
# type = request.args['type']
# if type == "gene":
@@ -253,7 +249,7 @@ def docedit():
logger.info(request.url)
try:
if g.user_session.record['user_email_address'] == "zachary.a.sloan@gmail.com" or g.user_session.record['user_email_address'] == "labwilliams@gmail.com":
- doc = docs.Docs(request.args['entry'], request.args)
+ doc = Docs(request.args['entry'], request.args)
return render_template("docedit.html", **doc.__dict__)
else:
return "You shouldn't be here!"
@@ -269,7 +265,7 @@ def generated_file(filename):
@app.route("/help")
def help():
logger.info(request.url)
- doc = docs.Docs("help", request.args)
+ doc = Docs("help", request.args)
return render_template("docs.html", **doc.__dict__)
@app.route("/wgcna_setup", methods=('POST',))
@@ -304,54 +300,54 @@ def ctl_results():
@app.route("/news")
def news():
- doc = docs.Docs("news", request.args)
+ doc = Docs("news", request.args)
return render_template("docs.html", **doc.__dict__)
@app.route("/references")
def references():
- doc = docs.Docs("references", request.args)
+ doc = Docs("references", request.args)
return render_template("docs.html", **doc.__dict__)
#return render_template("reference.html")
@app.route("/intro")
def intro():
- doc = docs.Docs("intro", request.args)
+ doc = Docs("intro", request.args)
return render_template("docs.html", **doc.__dict__)
@app.route("/policies")
def policies():
- doc = docs.Docs("policies", request.args)
+ doc = Docs("policies", request.args)
#return render_template("policies.html")
return render_template("docs.html", **doc.__dict__)
@app.route("/links")
def links():
- #doc = docs.Docs("links", request.args)
+ #doc = Docs("links", request.args)
#return render_template("docs.html", **doc.__dict__)
return render_template("links.html")
@app.route("/tutorials")
def tutorials():
- #doc = docs.Docs("links", request.args)
+ #doc = Docs("links", request.args)
#return render_template("docs.html", **doc.__dict__)
return render_template("tutorials.html")
@app.route("/credits")
def credits():
- #doc = docs.Docs("links", request.args)
+ #doc = Docs("links", request.args)
#return render_template("docs.html", **doc.__dict__)
return render_template("credits.html")
@app.route("/environments")
def environments():
- doc = docs.Docs("environments", request.args)
+ doc = Docs("environments", request.args)
return render_template("docs.html", **doc.__dict__)
#return render_template("environments.html", **doc.__dict__)
@app.route("/update_text", methods=('POST',))
def update_page():
docs.update_text(request.form)
- doc = docs.Docs(request.form['entry_type'], request.form)
+ doc = Docs(request.form['entry_type'], request.form)
return render_template("docs.html", **doc.__dict__)
@app.route("/submit_trait")
@@ -366,7 +362,7 @@ def create_temp_trait():
#template_vars = submit_trait.SubmitTrait(request.form)
- doc = docs.Docs("links")
+ doc = Docs("links")
return render_template("links.html", **doc.__dict__)
#return render_template("show_trait.html", **template_vars.__dict__)
@@ -421,7 +417,7 @@ def export_traits_csv():
logger.info("In export_traits_csv")
logger.info("request.form:", request.form)
logger.info(request.url)
- file_list = export_traits.export_search_results_csv(request.form)
+ file_list = export_search_results_csv(request.form)
if len(file_list) > 1:
now = datetime.datetime.now()
@@ -904,12 +900,24 @@ def snp_browser_page():
return render_template("snp_browser.html", **template_vars.__dict__)
+@app.route("/db_info", methods=('GET',))
+def db_info_page():
+ template_vars = InfoPage(request.args)
+
+ return render_template("info_page.html", **template_vars.__dict__)
+
@app.route("/tutorial/WebQTLTour", methods=('GET',))
def tutorial_page():
#ZS: Currently just links to GN1
logger.info(request.url)
return redirect("http://gn1.genenetwork.org/tutorial/WebQTLTour/")
+@app.route("/tutorial/security", methods=('GET',))
+def security_tutorial_page():
+ #ZS: Currently just links to GN1
+ logger.info(request.url)
+ return render_template("admin/security_help.html")
+
@app.route("/submit_bnw", methods=('POST',))
def submit_bnw():
logger.info(request.url)