diff options
63 files changed, 811 insertions, 547 deletions
@@ -1 +1 @@ -2.0 +2.10-pre1 diff --git a/bin/genenetwork2 b/bin/genenetwork2 index d926d6a1..889401fd 100755 --- a/bin/genenetwork2 +++ b/bin/genenetwork2 @@ -1,53 +1,93 @@ #! /bin/bash # -# This will run the GN2 server (with default settings if none supplied). Pass in -# your own settings file, e.g. +# This will run the GN2 server (with default settings if none +# supplied). Pass in your own settings file, e.g. # # ./bin/genenetwork2 ~/my_settings.py # +# But better is to retain the defaults and override them with +# JSON file (see the deploy docs). +# +# ./bin/genenetwork2 ~/my_overrides.json +# # To run a maintenance script with settings (instead of the webserver) add that with # a -c switch, e.g. # -# ./bin/genenetwork2 ~/my_settings.py -c ./wqflask/maintenance/gen_select_dataset.py +# ./bin/genenetwork2 ~/my_overrides.json -c ./wqflask/maintenance/gen_select_dataset.py # # Environment settings can be used to preconfigure as well as a # settings.py file. +# +# GN2_BASE_PATH is base directory of wqflask source code +# SCRIPT=$(readlink -f "$0") -GN2_BASE_PATH=$(dirname $(dirname "$SCRIPT")) +GN2_BASE_DIR=$(dirname $(dirname "$SCRIPT")) -GN2_GUIX_PATH=$GN2_BASE_PATH/lib/python2.7/site-packages/genenetwork2-2.0-py2.7.egg -if [ -d $GN2_GUIX_PATH ]; then - echo GN2 is running from GUIX - GN2_BASE_PATH=$GN2_GUIX_PATH -fi -echo $GN2_BASE_PATH +echo GN2_BASE_DIR=$GN2_BASE_DIR -# Handle settings parameter + +# Handle settings parameter (can be .py or .json) settings=$1 -if [ -z $settings ]; then - # get default - settings=$GN2_BASE_PATH/etc/default_settings.py +ext="${settings##*.}" +if [ -z "$settings" -o "$ext" = "json" -o "$ext" = "JSON" ]; then + overrides=$settings + settings=$GN2_BASE_DIR/etc/default_settings.py else shift fi if [ ! -e $settings ]; then - echo "ERROR: can not locate settings file - pass it in the command line" - exit 1 + GUIX_ETC=$GN2_BASE_DIR/lib/python2.7/site-packages/genenetwork2-2.0-py2.7.egg + if [ -d $GUIX_ETC ]; then + echo INFO: GN2 is actually running from GNU Guix + else + echo "ERROR: can not locate settings file - pass it in the command line" + exit 1 + fi +fi +export WQFLASK_SETTINGS=$settings # Python +export WQFLASK_OVERRIDES=$overrides # JSON + +echo WQFLASK_SETTINGS=$settings +echo WQFLASK_OVERRIDES=$overrides + +# ---- Checks and balances +if [ -z $GUIX_ETC ]; then + if [ -z $GN2_PROFILE ] ; then + echo "WARNING: GN2_PROFILE has not been set - I hope you know what you are doing" + else + export PYTHONPATH=$GN2_PROFILE/lib/python2.7/site-packages + export R_LIBS_SITE=$GN2_PROFILE/site-library + export GUIX_GTK3_PATH="$GN2_PROFILE/lib/gtk-3.0" + export GI_TYPELIB_PATH="$GN2_PROFILE/lib/girepository-1.0" + export XDG_DATA_DIRS="$GN2_PROFILE/share" + export GIO_EXTRA_MODULES="$GN2_PROFILE/lib/gio/modules" + fi + if [ -z $PYTHONPATH ] ; then + echo "WARNING PYTHONPATH has not been set" + fi + if [ ! -d $R_LIBS_SITE ] ; then + echo "ERROR: R_LIBS_SITE has not been set correctly (we only allow one path)" + echo "Paste in the output of, for example," + echo "guix package -p /usr/local/guix-profiles/gn2-staging --search-paths" + exit 1 + fi fi -export WQFLASK_SETTINGS=$settings # We may change this one: -export PYTHONPATH=$GN2_BASE_PATH/wqflask:$PYTHONPATH +export PYTHONPATH=$GN2_BASE_DIR/wqflask:$PYTHONPATH # TEMPDIR defaults to /tmp if nothing else if [ -z $TEMPDIR ]; then TEMPDIR="/tmp" fi +set|grep $GN2_PROFILE +set|grep TEMPDIR + # Now handle command parameter -c -if [ $1 = '-c' ] ; then - cd $GN2_BASE_PATH/wqflask +if [ "$1" = '-c' ] ; then + cd $GN2_BASE_DIR/wqflask cmd=${2#wqflask/} echo PYTHONPATH=$PYTHONPATH echo RUNNING COMMAND $cmd @@ -61,6 +101,6 @@ dbfilename gn2.rdb " | redis-server - & # Start the flask server running GN2 -cd $GN2_BASE_PATH/wqflask +cd $GN2_BASE_DIR/wqflask echo "Starting with $settings" /usr/bin/env python runserver.py diff --git a/bin/test-website b/bin/test-website index b693bd60..c9a72a5e 100755 --- a/bin/test-website +++ b/bin/test-website @@ -15,6 +15,10 @@ If you are using the small deployment database you can use ./bin/test-website --skip -n +To run all tests + + ./bin/test-website --all + To run individual tests on localhost you can do ruby -Itest -Itest/lib test/lib/mapping.rb --name="/Mapping/" diff --git a/test/data/input/mapping/1435395_s_at_HC_M2_0606_P.json b/test/data/input/mapping/1435395_s_at_HC_M2_0606_P.json index 15428553..195c16e4 100644 --- a/test/data/input/mapping/1435395_s_at_HC_M2_0606_P.json +++ b/test/data/input/mapping/1435395_s_at_HC_M2_0606_P.json @@ -1,142 +1,245 @@ { "temp_uuid" : "unknown", -"maf" : "0.01", -"control_marker" : "mCV24506226", -"dataset" : "HC_M2_0606_P", - "do_control" : "false", - "maf" : "0.01", - "manhattan_plot" : "False", - "mapmethod_rqtl_geno" : "em", - "mapmodel_rqtl_geno" : "normal", - "method" : "rqtl_geno", - "num_bootstrap" : "2000", - "num_perm" : "", - "pair_scan" : "false", - "suggestive" : "0", - "trait_id" : "1433387_at", - "value:129S1/SvImJ" : "6.920", - "value:A/J" : "7.437", - "value:AKR/J" : "7.550", - "value:B6D2F1" : "7.742", - "value:BALB/cByJ" : "6.613", - "value:BALB/cJ" : "6.664", - "value:BXD1" : "6.749", - "value:BXD100" : "x", - "value:BXD101" : "x", - "value:BXD102" : "x", - "value:BXD103" : "x", - "value:BXD11" : "7.398", - "value:BXD12" : "7.073", - "value:BXD13" : "8.191", - "value:BXD14" : "x", - "value:BXD15" : "7.406", - "value:BXD16" : "6.890", - "value:BXD18" : "x", - "value:BXD19" : "6.980", - "value:BXD2" : "7.248", - "value:BXD20" : "7.554", - "value:BXD21" : "7.316", - "value:BXD22" : "7.327", - "value:BXD23" : "7.605", - "value:BXD24" : "7.306", - "value:BXD24a" : "x", - "value:BXD25" : "x", - "value:BXD27" : "7.800", - "value:BXD28" : "7.023", - "value:BXD29" : "7.518", - "value:BXD30" : "x", - "value:BXD31" : "7.301", - "value:BXD32" : "7.161", - "value:BXD33" : "7.140", - "value:BXD34" : "8.180", - "value:BXD35" : "x", - "value:BXD36" : "x", - "value:BXD37" : "x", - "value:BXD38" : "7.350", - "value:BXD39" : "6.976", - "value:BXD40" : "7.411", - "value:BXD41" : "x", - "value:BXD42" : "7.050", - "value:BXD43" : "6.866", - "value:BXD44" : "7.246", - "value:BXD45" : "7.576", - "value:BXD48" : "7.108", - "value:BXD48a" : "7.192", - "value:BXD49" : "x", - "value:BXD5" : "6.771", - "value:BXD50" : "7.528", - "value:BXD51" : "7.408", - "value:BXD52" : "x", - "value:BXD53" : "x", - "value:BXD54" : "x", - "value:BXD55" : "6.720", - "value:BXD56" : "x", - "value:BXD59" : "x", - "value:BXD6" : "7.372", - "value:BXD60" : "7.178", - "value:BXD61" : "7.198", - "value:BXD62" : "7.618", - "value:BXD63" : "7.076", - "value:BXD64" : "6.576", - "value:BXD65" : "7.046", - "value:BXD65a" : "7.046", - "value:BXD65b" : "7.385", - "value:BXD66" : "7.108", - "value:BXD67" : "7.342", - "value:BXD68" : "7.668", - "value:BXD69" : "7.310", - "value:BXD70" : "7.278", - "value:BXD71" : "x", - "value:BXD72" : "x", - "value:BXD73" : "7.342", - "value:BXD73a" : "7.841", - "value:BXD74" : "7.298", - "value:BXD75" : "7.133", - "value:BXD76" : "7.448", - "value:BXD77" : "7.014", - "value:BXD78" : "x", - "value:BXD79" : "7.916", - "value:BXD8" : "7.148", - "value:BXD81" : "x", - "value:BXD83" : "7.322", - "value:BXD84" : "7.298", - "value:BXD85" : "7.243", - "value:BXD86" : "7.719", - "value:BXD87" : "7.145", - "value:BXD88" : "x", - "value:BXD89" : "7.162", - "value:BXD9" : "6.708", - "value:BXD90" : "7.497", - "value:BXD91" : "x", - "value:BXD93" : "7.558", - "value:BXD94" : "6.817", - "value:BXD95" : "x", - "value:BXD98" : "7.753", - "value:BXD99" : "8.076", - "value:C3H/HeJ" : "7.536", - "value:C57BL/6ByJ" : "6.940", - "value:C57BL/6J" : "7.309", - "value:CAST/EiJ" : "8.796", - "value:CXB1" : "6.430", - "value:CXB10" : "6.958", - "value:CXB11" : "6.182", - "value:CXB12" : "6.432", - "value:CXB13" : "6.388", - "value:CXB2" : "7.687", - "value:CXB3" : "6.312", - "value:CXB4" : "6.453", - "value:CXB5" : "6.959", - "value:CXB6" : "7.022", - "value:CXB7" : "6.334", - "value:CXB8" : "6.790", - "value:CXB9" : "6.545", - "value:D2B6F1" : "7.615", - "value:DBA/2J" : "7.816", - "value:KK/HlJ" : "8.035", - "value:LG/J" : "7.594", - "value:NOD/ShiLtJ" : "8.220", - "value:NZO/HlLtJ" : "7.629", - "value:PWD/PhJ" : "6.320", - "value:PWK/PhJ" : "7.235", - "value:WSB/EiJ" : "7.650" -} + "control_marker": "NES13033186", + "dataset": "HC_M2_0606_P", + "do_control": "false", + "maf": "0.01", + "manhattan_plot": "False", + "mapmethod_rqtl_geno": "em", + "mapmodel_rqtl_geno": "normal", + "method": "rqtl_geno", + "num_bootstrap": "2000", + "num_perm": "", + "pair_scan": "false", + "suggestive": "0", + "trait_id": "1435395_s_at", + "value:129S1/SvImJ": "15.468", + "value:A/J": "15.230", + "value:AKR/J": "15.798", + "value:B6D2F1": "15.575", + "value:BALB/cByJ": "15.138", + "value:BALB/cJ": "15.222", + "value:BXD1": "15.034", + "value:BXD100": "x", + "value:BXD101": "x", + "value:BXD102": "x", + "value:BXD104": "x", + "value:BXD105": "x", + "value:BXD106": "x", + "value:BXD107": "x", + "value:BXD108": "x", + "value:BXD109": "x", + "value:BXD11": "15.364", + "value:BXD110": "x", + "value:BXD111": "x", + "value:BXD112": "x", + "value:BXD113": "x", + "value:BXD114": "x", + "value:BXD115": "x", + "value:BXD116": "x", + "value:BXD117": "x", + "value:BXD119": "x", + "value:BXD12": "14.992", + "value:BXD120": "x", + "value:BXD121": "x", + "value:BXD122": "x", + "value:BXD123": "x", + "value:BXD124": "x", + "value:BXD125": "x", + "value:BXD126": "x", + "value:BXD127": "x", + "value:BXD128": "x", + "value:BXD128a": "x", + "value:BXD13": "15.290", + "value:BXD130": "x", + "value:BXD131": "x", + "value:BXD132": "x", + "value:BXD133": "x", + "value:BXD134": "x", + "value:BXD135": "x", + "value:BXD136": "x", + "value:BXD137": "x", + "value:BXD138": "x", + "value:BXD139": "x", + "value:BXD14": "x", + "value:BXD141": "x", + "value:BXD142": "x", + "value:BXD144": "x", + "value:BXD145": "x", + "value:BXD146": "x", + "value:BXD147": "x", + "value:BXD148": "x", + "value:BXD149": "x", + "value:BXD15": "15.188", + "value:BXD150": "x", + "value:BXD151": "x", + "value:BXD152": "x", + "value:BXD153": "x", + "value:BXD154": "x", + "value:BXD155": "x", + "value:BXD156": "x", + "value:BXD157": "x", + "value:BXD16": "15.340", + "value:BXD160": "x", + "value:BXD161": "x", + "value:BXD162": "x", + "value:BXD165": "x", + "value:BXD168": "x", + "value:BXD169": "x", + "value:BXD170": "x", + "value:BXD171": "x", + "value:BXD172": "x", + "value:BXD173": "x", + "value:BXD174": "x", + "value:BXD175": "x", + "value:BXD176": "x", + "value:BXD177": "x", + "value:BXD178": "x", + "value:BXD18": "x", + "value:BXD180": "x", + "value:BXD181": "x", + "value:BXD183": "x", + "value:BXD184": "x", + "value:BXD186": "x", + "value:BXD187": "x", + "value:BXD188": "x", + "value:BXD189": "x", + "value:BXD19": "15.144", + "value:BXD190": "x", + "value:BXD191": "x", + "value:BXD192": "x", + "value:BXD193": "x", + "value:BXD194": "x", + "value:BXD195": "x", + "value:BXD196": "x", + "value:BXD197": "x", + "value:BXD198": "x", + "value:BXD199": "x", + "value:BXD2": "15.538", + "value:BXD20": "15.194", + "value:BXD200": "x", + "value:BXD201": "x", + "value:BXD202": "x", + "value:BXD203": "x", + "value:BXD204": "x", + "value:BXD205": "x", + "value:BXD206": "x", + "value:BXD207": "x", + "value:BXD208": "x", + "value:BXD209": "x", + "value:BXD21": "15.088", + "value:BXD210": "x", + "value:BXD211": "x", + "value:BXD212": "x", + "value:BXD213": "x", + "value:BXD214": "x", + "value:BXD215": "x", + "value:BXD216": "x", + "value:BXD217": "x", + "value:BXD218": "x", + "value:BXD219": "x", + "value:BXD22": "15.499", + "value:BXD220": "x", + "value:BXD23": "14.988", + "value:BXD24": "15.562", + "value:BXD24a": "x", + "value:BXD25": "x", + "value:BXD27": "15.598", + "value:BXD28": "15.510", + "value:BXD29": "15.041", + "value:BXD30": "x", + "value:BXD31": "14.834", + "value:BXD32": "15.245", + "value:BXD33": "15.466", + "value:BXD34": "15.302", + "value:BXD35": "x", + "value:BXD36": "x", + "value:BXD37": "x", + "value:BXD38": "15.131", + "value:BXD39": "15.430", + "value:BXD40": "15.488", + "value:BXD41": "x", + "value:BXD42": "14.878", + "value:BXD43": "15.542", + "value:BXD44": "15.417", + "value:BXD45": "14.910", + "value:BXD48": "15.487", + "value:BXD48a": "15.328", + "value:BXD49": "x", + "value:BXD5": "15.622", + "value:BXD50": "15.435", + "value:BXD51": "15.183", + "value:BXD52": "x", + "value:BXD53": "x", + "value:BXD54": "x", + "value:BXD55": "14.928", + "value:BXD56": "x", + "value:BXD59": "x", + "value:BXD6": "15.366", + "value:BXD60": "15.502", + "value:BXD61": "15.622", + "value:BXD62": "15.198", + "value:BXD63": "15.238", + "value:BXD64": "15.572", + "value:BXD65": "15.485", + "value:BXD65a": "15.284", + "value:BXD65b": "15.318", + "value:BXD66": "15.406", + "value:BXD67": "15.509", + "value:BXD68": "15.552", + "value:BXD69": "15.667", + "value:BXD70": "15.104", + "value:BXD71": "x", + "value:BXD72": "x", + "value:BXD73": "15.210", + "value:BXD73a": "15.223", + "value:BXD73b": "x", + "value:BXD74": "15.666", + "value:BXD75": "15.554", + "value:BXD76": "15.234", + "value:BXD77": "15.613", + "value:BXD78": "x", + "value:BXD79": "15.124", + "value:BXD8": "15.548", + "value:BXD81": "x", + "value:BXD83": "15.512", + "value:BXD84": "15.426", + "value:BXD85": "15.252", + "value:BXD86": "15.457", + "value:BXD87": "15.320", + "value:BXD88": "x", + "value:BXD89": "15.316", + "value:BXD9": "15.669", + "value:BXD90": "15.348", + "value:BXD91": "x", + "value:BXD93": "15.602", + "value:BXD94": "15.360", + "value:BXD95": "x", + "value:BXD98": "15.421", + "value:BXD99": "15.534", + "value:C3H/HeJ": "15.398", + "value:C57BL/6ByJ": "15.702", + "value:C57BL/6J": "15.281", + "value:CAST/EiJ": "15.890", + "value:CXB1": "15.774", + "value:CXB10": "15.518", + "value:CXB11": "15.922", + "value:CXB12": "15.753", + "value:CXB13": "15.608", + "value:CXB2": "15.320", + "value:CXB3": "15.492", + "value:CXB4": "15.541", + "value:CXB5": "15.353", + "value:CXB6": "15.454", + "value:CXB7": "15.547", + "value:CXB8": "15.496", + "value:CXB9": "15.880", + "value:D2B6F1": "15.265", + "value:DBA/2J": "15.287", + "value:KK/HlJ": "15.303", + "value:LG/J": "15.285", + "value:NOD/ShiLtJ": "15.348", + "value:NZO/HlLtJ": "15.028", + "value:PWD/PhJ": "15.535", + "value:PWK/PhJ": "15.382", + "value:WSB/EiJ": "15.424"} diff --git a/test/lib/mapping.rb b/test/lib/mapping.rb index 4c8ff632..d6a3cd7b 100644 --- a/test/lib/mapping.rb +++ b/test/lib/mapping.rb @@ -19,7 +19,7 @@ describe MappingTest do json["method"] = "pylmm" # p json page = @agent.post(URI.encode(url), json) - # Unpacking the page is slow - but the run is enough as a test + # Unpacking the page is slow - somehow - but the run is enough as a test # form = page.forms_with("marker_regression")[0] # form.fields.select { |fld| fld.name == 'dataset' }.first.value.must_equal 'HC_M2_0606_P' # form.fields.select { |fld| fld.name == 'value:BXD1' }.first.value.must_equal '6.749' @@ -37,7 +37,7 @@ describe MappingTest do ({'Content-Type' => 'application/x-www-form-urlencoded'})) form = page.forms_with("marker_regression")[0] form.fields.select { |fld| fld.name == 'dataset' }.first.value.must_equal 'HC_M2_0606_P' - form.fields.select { |fld| fld.name == 'value:BXD1' }.first.value.must_equal '6.749' + form.fields.select { |fld| fld.name == 'value:BXD1' }.first.value.must_equal "15.034" end end @@ -50,7 +50,7 @@ describe MappingTest do page = @agent.post(URI.encode(url), json) form = page.forms_with("marker_regression")[0] form.fields.select { |fld| fld.name == 'dataset' }.first.value.must_equal 'HC_M2_0606_P' - form.fields.select { |fld| fld.name == 'value:BXD1' }.first.value.must_equal '6.749' + form.fields.select { |fld| fld.name == 'value:BXD1' }.first.value.must_equal "15.034" end end diff --git a/wqflask/base/data_set.py b/wqflask/base/data_set.py index 1b4e1195..8bd5bfb9 100644 --- a/wqflask/base/data_set.py +++ b/wqflask/base/data_set.py @@ -107,7 +107,7 @@ Publish or ProbeSet. E.g. else: new_type = "ProbeSet" self.datasets[short_dataset_name] = new_type - logger.info("datasets",self.datasets) + logger.debug("datasets",self.datasets) def __call__(self, name): return self.datasets[name] diff --git a/wqflask/base/trait.py b/wqflask/base/trait.py index 900e050c..32032ba7 100644 --- a/wqflask/base/trait.py +++ b/wqflask/base/trait.py @@ -363,7 +363,7 @@ class GeneralTrait(object): FROM Homologene, Species, InbredSet WHERE - Homologene.GeneId =%s AND + Homologene.GeneId ='%s' AND InbredSet.Name = '%s' AND InbredSet.SpeciesId = Species.Id AND Species.TaxonomyId = Homologene.TaxonomyId diff --git a/wqflask/base/webqtlCaseData.py b/wqflask/base/webqtlCaseData.py index 8df9939e..2f88f778 100644 --- a/wqflask/base/webqtlCaseData.py +++ b/wqflask/base/webqtlCaseData.py @@ -16,8 +16,6 @@ # Contact Drs. Robert W. Williams and Xiaodong Zhou (2010) # at rwilliams@uthsc.edu and xzhou15@uthsc.edu # -# -# # This module is used by GeneNetwork project (www.genenetwork.org) # # Created by GeneNetwork Core Team 2010/08/10 diff --git a/wqflask/maintenance/__init__.py b/wqflask/maintenance/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/wqflask/maintenance/__init__.py diff --git a/wqflask/runserver.py b/wqflask/runserver.py index 12ec904e..0342b7ad 100644 --- a/wqflask/runserver.py +++ b/wqflask/runserver.py @@ -16,34 +16,37 @@ GREEN = '\033[92m' BOLD = '\033[1m' ENDC = '\033[0m' -logger.info("GN2 is running. Visit %shttp://localhost:5003/%s" % (BLUE,ENDC)) - import os app.config['SECRET_KEY'] = os.urandom(24) -from utility.tools import WEBSERVER_MODE +from utility.tools import WEBSERVER_MODE,get_setting_int + +port = get_setting_int("SERVER_PORT") + +logger.info("GN2 is running. Visit %shttp://localhost:%s/%s" % (BLUE,port,ENDC)) werkzeug_logger = logging.getLogger('werkzeug') if WEBSERVER_MODE == 'DEBUG': app.run(host='0.0.0.0', - port=app.config['SERVER_PORT'], + port=port, debug=True, - use_debugger=True, + use_debugger=False, threaded=False, + processes=0, use_reloader=True) elif WEBSERVER_MODE == 'DEV': werkzeug_logger.setLevel(logging.WARNING) app.run(host='0.0.0.0', - port=app.config['SERVER_PORT'], + port=port, debug=False, use_debugger=False, threaded=False, processes=0, use_reloader=True) -else: #production mode +else: # staging/production modes app.run(host='0.0.0.0', - port=app.config['SERVER_PORT'], + port=port, debug=False, use_debugger=False, threaded=True, diff --git a/wqflask/utility/helper_functions.py b/wqflask/utility/helper_functions.py index 149ee553..377f6b26 100644 --- a/wqflask/utility/helper_functions.py +++ b/wqflask/utility/helper_functions.py @@ -5,19 +5,21 @@ from base import data_set from base.species import TheSpecies from wqflask import user_manager +import logging +logger = logging.getLogger(__name__ ) def get_species_dataset_trait(self, start_vars): #assert type(read_genotype) == type(bool()), "Expecting boolean value for read_genotype" self.dataset = data_set.create_dataset(start_vars['dataset']) - print("After creating dataset") + logger.debug("After creating dataset") self.species = TheSpecies(dataset=self.dataset) - print("After creating species") + logger.debug("After creating species") self.this_trait = GeneralTrait(dataset=self.dataset, name=start_vars['trait_id'], cellid=None, get_qtl_info=True) - print("After creating trait") + logger.debug("After creating trait") #if read_genotype: #self.dataset.group.read_genotype_file() @@ -27,7 +29,7 @@ def get_species_dataset_trait(self, start_vars): def get_trait_db_obs(self, trait_db_list): if isinstance(trait_db_list, basestring): trait_db_list = trait_db_list.split(",") - + self.trait_list = [] for trait in trait_db_list: data, _separator, hmac = trait.rpartition(':') @@ -38,4 +40,4 @@ def get_trait_db_obs(self, trait_db_list): trait_ob = GeneralTrait(dataset=dataset_ob, name=trait_name, cellid=None) - self.trait_list.append((trait_ob, dataset_ob))
\ No newline at end of file + self.trait_list.append((trait_ob, dataset_ob)) diff --git a/wqflask/utility/logger.py b/wqflask/utility/logger.py index ddc0ea82..b873e16f 100644 --- a/wqflask/utility/logger.py +++ b/wqflask/utility/logger.py @@ -31,6 +31,7 @@ import string from inspect import isfunction from pprint import pformat as pf from inspect import stack +import datetime from utility.tools import LOG_LEVEL, LOG_LEVEL_DEBUG, LOG_SQL, LOG_FORMAT @@ -66,7 +67,10 @@ LOG_LEVEL_DEBUG (NYI). def error(self,*args): """Call logging.error for multiple args""" - self.collect(self.logger.error,*args) + now = datetime.datetime.utcnow() + time_str = now.strftime('%H:%M:%S UTC %Y%m%d') + l = [time_str]+list(args) + self.collect(self.logger.error,*l) def infof(self,*args): """Call logging.info for multiple args lazily""" diff --git a/wqflask/utility/tools.py b/wqflask/utility/tools.py index 22779739..23d6fb62 100644 --- a/wqflask/utility/tools.py +++ b/wqflask/utility/tools.py @@ -3,6 +3,7 @@ import os import sys +import json from wqflask import app @@ -10,6 +11,8 @@ from wqflask import app import logging logger = logging.getLogger(__name__ ) +OVERRIDES = {} + def get_setting(command_id,guess=None): """Resolve a setting from the environment or the global settings in app.config, with valid_path is a function checking whether the @@ -45,13 +48,15 @@ def get_setting(command_id,guess=None): logger.debug("Looking for "+command_id+"\n") command = value(os.environ.get(command_id)) if command is None or command == "": - # ---- Check whether setting exists in app - command = value(app.config.get(command_id)) + command = OVERRIDES.get(command_id) if command is None: - command = value(guess) - if command is None or command == "": - print command - raise Exception(command_id+' setting unknown or faulty (update default_settings.py?).') + # ---- Check whether setting exists in app + command = value(app.config.get(command_id)) + if command is None: + command = value(guess) + if command is None or command == "": + # print command + raise Exception(command_id+' setting unknown or faulty (update default_settings.py?).') logger.debug("Set "+command_id+"="+str(command)) return command @@ -169,18 +174,20 @@ def show_settings(): log_level = getattr(logging, LOG_LEVEL.upper()) logging.basicConfig(level=log_level) + logger.info(OVERRIDES) logger.info(BLUE+"Mr. Mojo Risin 2"+ENDC) - print "runserver.py: ****** The webserver has the following configuration ******" + print "runserver.py: ****** Webserver configuration ******" keylist = app.config.keys() keylist.sort() for k in keylist: try: - print("%s %s%s%s%s" % (k,BLUE,BOLD,get_setting(k),ENDC)) + print("%s: %s%s%s%s" % (k,BLUE,BOLD,get_setting(k),ENDC)) except: - print("%s %s%s%s%s" % (k,GREEN,BOLD,app.config[k],ENDC)) + print("%s: %s%s%s%s" % (k,GREEN,BOLD,app.config[k],ENDC)) # Cached values +HOME = get_setting('HOME') WEBSERVER_MODE = get_setting('WEBSERVER_MODE') GN_SERVER_URL = get_setting('GN_SERVER_URL') SQL_URI = get_setting('SQL_URI') @@ -199,3 +206,18 @@ PYLMM_COMMAND = pylmm_command() GEMMA_COMMAND = gemma_command() PLINK_COMMAND = plink_command() TEMPDIR = tempdir() + +from six import string_types + +if os.environ.get('WQFLASK_OVERRIDES'): + jsonfn = get_setting('WQFLASK_OVERRIDES') + logger.error("WQFLASK_OVERRIDES: %s" % jsonfn) + with open(jsonfn) as data_file: + overrides = json.load(data_file) + for k in overrides: + cmd = overrides[k] + if isinstance(cmd, string_types): + OVERRIDES[k] = eval(cmd) + else: + OVERRIDES[k] = cmd + logger.debug(OVERRIDES) diff --git a/wqflask/wqflask/__init__.py b/wqflask/wqflask/__init__.py index af271d02..2188ce17 100644 --- a/wqflask/wqflask/__init__.py +++ b/wqflask/wqflask/__init__.py @@ -14,11 +14,7 @@ app = Flask(__name__) app.config.from_object('cfg.default_settings') # Get the defaults from cfg.default_settings app.config.from_envvar('WQFLASK_SETTINGS') # See http://flask.pocoo.org/docs/config/#configuring-from-files - -logger.debug("System path is") -logger.debug(sys.path) -logger.debug("App.config is") -logger.debug(app.config) +# Note we also use WQFLASK_OVERRIDES app.jinja_env.globals.update( undefined = jinja2.StrictUndefined, diff --git a/wqflask/wqflask/collect.py b/wqflask/wqflask/collect.py index 7e7aba89..81d03d6c 100644 --- a/wqflask/wqflask/collect.py +++ b/wqflask/wqflask/collect.py @@ -164,7 +164,7 @@ class UserCollection(object): if not uc: return create_new("Default") else: - uc = model.UserCollection.query.get(params['existing_collection']) + uc = model.UserCollection.query.get(params['existing_collection'].split(":")[0]) members = list(uc.members_as_set()) #set(json.loads(uc.members)) len_before = len(members) @@ -218,7 +218,6 @@ def collections_add(): anon_collections = user_manager.AnonUser().get_collections() collection_names = [] for collection in anon_collections: - print("COLLECTION:", collection) collection_names.append({'id':collection['id'], 'name':collection['name']}) return render_template("collections/add.html", traits = traits, @@ -229,21 +228,17 @@ def collections_add(): @app.route("/collections/new") def collections_new(): params = request.args - #print("request.args in collections_new are:", params) - - collection_name = params['new_collection'] - if "anonymous_add" in params: - AnonCollection(name=collection_name).add_traits(params, "Default") - return redirect(url_for('view_collection')) if "sign_in" in params: return redirect(url_for('login')) if "create_new" in params: print("in create_new") + collection_name = params['new_collection'] return create_new(collection_name) elif "add_to_existing" in params: print("in add to existing") + collection_name = params['existing_collection'].split(":")[1] if g.user_session.logged_in: return UserCollection().add_traits(params, collection_name) else: @@ -251,7 +246,6 @@ def collections_new(): ac.add_traits(params) return redirect(url_for('view_collection', collection_id=ac.id)) else: - print("ELSE") CauseAnError @@ -288,7 +282,6 @@ def create_new(collection_name): ac = AnonCollection(collection_name) ac.changed_timestamp = datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p') ac.add_traits(params) - print("Collection ID:", ac.id) return redirect(url_for('view_collection', collection_id=ac.id)) @app.route("/collections/list") @@ -367,7 +360,6 @@ def view_collection(): uc_id = params['uc_id'] uc = model.UserCollection.query.get(uc_id) traits = json.loads(uc.members) - print("traits are:", traits) else: user_collections = json.loads(Redis.get(user_manager.AnonUser().key)) this_collection = {} @@ -384,7 +376,6 @@ def view_collection(): json_version = [] for atrait in traits: - print("atrait is:", atrait) name, dataset_name = atrait.split(':') trait_ob = trait.GeneralTrait(name=name, dataset_name=dataset_name) @@ -393,8 +384,6 @@ def view_collection(): json_version.append(trait_ob.jsonable()) - print("trait_obs:", trait_obs) - if "uc_id" in params: collection_info = dict(trait_obs=trait_obs, uc = uc) diff --git a/wqflask/wqflask/marker_regression/marker_regression.py b/wqflask/wqflask/marker_regression/marker_regression.py index d7c78db0..37ee42a7 100644 --- a/wqflask/wqflask/marker_regression/marker_regression.py +++ b/wqflask/wqflask/marker_regression/marker_regression.py @@ -35,7 +35,7 @@ from utility import helper_functions from utility import Plot, Bunch from utility import temp_data from utility.benchmark import Bench -from wqflask.marker_regression import gemma_mapping +from wqflask.marker_regression import gemma_mapping, rqtl_mapping from utility.tools import locate, locate_ignore_error, PYLMM_COMMAND, GEMMA_COMMAND, PLINK_COMMAND, TEMPDIR from utility.external import shell @@ -169,7 +169,10 @@ class MarkerRegression(object): self.model = start_vars['mapmodel_rqtl_geno'] if start_vars['pair_scan'] == "true": self.pair_scan = True - results = self.run_rqtl_geno() + if self.permCheck and self.num_perm > 0: + perm_output, self.suggestive, self.significant, results = rqtl_mapping.run_rqtl_geno(self.vals, self.dataset, self.method, self.model, self.permCheck, self.num_perm, self.do_control, self.control_marker, self.manhattan_plot, self.pair_scan) + else: + results = rqtl_mapping.run_rqtl_geno(self.vals, self.dataset, self.method, self.model, self.permCheck, self.num_perm, self.do_control, self.control_marker, self.manhattan_plot, self.pair_scan) elif self.mapping_method == "reaper": if "startMb" in start_vars: #ZS: Check if first time page loaded, so it can default to ON if "additiveCheck" in start_vars: @@ -202,12 +205,12 @@ class MarkerRegression(object): elif self.mapping_method == "plink": results = self.run_plink() elif self.mapping_method == "pylmm": - print("RUNNING PYLMM") + logger.debug("RUNNING PYLMM") if self.num_perm > 0: self.run_permutations(str(temp_uuid)) results = self.gen_data(str(temp_uuid)) else: - print("RUNNING NOTHING") + logger.debug("RUNNING NOTHING") if self.pair_scan == True: self.qtl_results = [] @@ -261,9 +264,9 @@ class MarkerRegression(object): #Need to convert the QTL objects that qtl reaper returns into a json serializable dictionary for index, qtl in enumerate(self.qtl_results): #if index<40: - # print("lod score is:", qtl['lod_score']) + # logger.debug("lod score is:", qtl['lod_score']) if qtl['chr'] == highest_chr and highest_chr != "X" and highest_chr != "X/Y": - #print("changing to X") + #logger.debug("changing to X") self.json_data['chr'].append("X") else: self.json_data['chr'].append(str(qtl['chr'])) @@ -281,7 +284,7 @@ class MarkerRegression(object): self.json_data['chrnames'].append([self.species.chromosomes.chromosomes[key].name, self.species.chromosomes.chromosomes[key].mb_length]) chromosome_mb_lengths[key] = self.species.chromosomes.chromosomes[key].mb_length - # print("json_data:", self.json_data) + # logger.debug("json_data:", self.json_data) self.js_data = dict( result_score_type = self.score_type, @@ -309,7 +312,7 @@ class MarkerRegression(object): self.dataset.group.name, self.dataset.group.name, self.dataset.group.name) - #print("gemma_command:" + gemma_command) + #logger.debug("gemma_command:" + gemma_command) os.system(gemma_command) @@ -331,7 +334,7 @@ class MarkerRegression(object): included_markers.append(line.split("\t")[1]) p_values.append(float(line.split("\t")[10])) #p_values[line.split("\t")[1]] = float(line.split("\t")[10]) - #print("p_values: ", p_values) + #logger.debug("p_values: ", p_values) return included_markers, p_values def gen_pheno_txt_file(self): @@ -353,200 +356,13 @@ class MarkerRegression(object): count, p_values = self.parse_rqtl_output(plink_output_filename) - def geno_to_rqtl_function(self): # TODO: Need to figure out why some genofiles have the wrong format and don't convert properly - - ro.r(""" - trim <- function( x ) { gsub("(^[[:space:]]+|[[:space:]]+$)", "", x) } - - getGenoCode <- function(header, name = 'unk'){ - mat = which(unlist(lapply(header,function(x){ length(grep(paste('@',name,sep=''), x)) })) == 1) - return(trim(strsplit(header[mat],':')[[1]][2])) - } - - GENOtoCSVR <- function(genotypes = '%s', out = 'cross.csvr', phenotype = NULL, sex = NULL, verbose = FALSE){ - header = readLines(genotypes, 40) # Assume a geno header is not longer than 40 lines - toskip = which(unlist(lapply(header, function(x){ length(grep("Chr\t", x)) })) == 1)-1 # Major hack to skip the geno headers - - genocodes <- c(getGenoCode(header, 'mat'), getGenoCode(header, 'het'), getGenoCode(header, 'pat')) # Get the genotype codes - type <- getGenoCode(header, 'type') - genodata <- read.csv(genotypes, sep='\t', skip=toskip, header=TRUE, na.strings=getGenoCode(header,'unk'), colClasses='character', comment.char = '#') - cat('Genodata:', toskip, " ", dim(genodata), genocodes, '\n') - if(is.null(phenotype)) phenotype <- runif((ncol(genodata)-4)) # If there isn't a phenotype, generate a random one - if(is.null(sex)) sex <- rep('m', (ncol(genodata)-4)) # If there isn't a sex phenotype, treat all as males - outCSVR <- rbind(c('Pheno', '', '', phenotype), # Phenotype - c('sex', '', '', sex), # Sex phenotype for the mice - cbind(genodata[,c('Locus','Chr', 'cM')], genodata[, 5:ncol(genodata)])) # Genotypes - write.table(outCSVR, file = out, row.names=FALSE, col.names=FALSE,quote=FALSE, sep=',') # Save it to a file - require(qtl) - cross = read.cross(file=out, 'csvr', genotypes=genocodes) # Load the created cross file using R/qtl read.cross - if(type == 'riset') cross <- convert2riself(cross) # If its a RIL, convert to a RIL in R/qtl - return(cross) - } - """ % (self.dataset.group.name + ".geno")) - - def run_rqtl_geno(self): - self.geno_to_rqtl_function() - - ## Get pointers to some common R functions - r_library = ro.r["library"] # Map the library function - r_c = ro.r["c"] # Map the c function - r_sum = ro.r["sum"] # Map the sum function - plot = ro.r["plot"] # Map the plot function - postscript = ro.r["postscript"] # Map the postscript function - png = ro.r["png"] # Map the png function - dev_off = ro.r["dev.off"] # Map the device off function - - print(r_library("qtl")) # Load R/qtl - - ## Get pointers to some R/qtl functions - scanone = ro.r["scanone"] # Map the scanone function - scantwo = ro.r["scantwo"] # Map the scantwo function - calc_genoprob = ro.r["calc.genoprob"] # Map the calc.genoprob function - read_cross = ro.r["read.cross"] # Map the read.cross function - write_cross = ro.r["write.cross"] # Map the write.cross function - GENOtoCSVR = ro.r["GENOtoCSVR"] # Map the local GENOtoCSVR function - - crossname = self.dataset.group.name - genofilelocation = locate(crossname + ".geno", "genotype") - crossfilelocation = TMPDIR + crossname + ".cross" - - #print("Conversion of geno to cross at location:", genofilelocation, " to ", crossfilelocation) - - cross_object = GENOtoCSVR(genofilelocation, crossfilelocation) # TODO: Add the SEX if that is available - - if self.manhattan_plot: - cross_object = calc_genoprob(cross_object) - else: - cross_object = calc_genoprob(cross_object, step=1, stepwidth="max") - - cross_object = self.add_phenotype(cross_object, self.sanitize_rqtl_phenotype()) # Add the phenotype - - # for debug: write_cross(cross_object, "csvr", "test.csvr") - - # Scan for QTLs - covar = self.create_covariates(cross_object) # Create the additive covariate matrix - - if self.pair_scan: - if self.do_control == "true": # If sum(covar) > 0 we have a covariate matrix - print("Using covariate"); result_data_frame = scantwo(cross_object, pheno = "the_pheno", addcovar = covar, model=self.model, method=self.method, n_cluster = 16) - else: - print("No covariates"); result_data_frame = scantwo(cross_object, pheno = "the_pheno", model=self.model, method=self.method, n_cluster = 16) - - #print("Pair scan results:", result_data_frame) - - self.pair_scan_filename = webqtlUtil.genRandStr("scantwo_") + ".png" - png(file=TEMPDIR+self.pair_scan_filename) - plot(result_data_frame) - dev_off() - - return self.process_pair_scan_results(result_data_frame) - - else: - if self.do_control == "true": - print("Using covariate"); result_data_frame = scanone(cross_object, pheno = "the_pheno", addcovar = covar, model=self.model, method=self.method) - else: - print("No covariates"); result_data_frame = scanone(cross_object, pheno = "the_pheno", model=self.model, method=self.method) - - if self.num_perm > 0 and self.permCheck == "ON": # Do permutation (if requested by user) - if self.do_control == "true": - perm_data_frame = scanone(cross_object, pheno_col = "the_pheno", addcovar = covar, n_perm = self.num_perm, model=self.model, method=self.method) - else: - perm_data_frame = scanone(cross_object, pheno_col = "the_pheno", n_perm = self.num_perm, model=self.model, method=self.method) - - self.process_rqtl_perm_results(perm_data_frame) # Functions that sets the thresholds for the webinterface - - return self.process_rqtl_results(result_data_frame) - - def add_phenotype(self, cross, pheno_as_string): - ro.globalenv["the_cross"] = cross - ro.r('the_cross$pheno <- cbind(pull.pheno(the_cross), the_pheno = '+ pheno_as_string +')') - return ro.r["the_cross"] - - def create_covariates(self, cross): - ro.globalenv["the_cross"] = cross - ro.r('genotypes <- pull.geno(the_cross)') # Get the genotype matrix - userinputS = self.control_marker.replace(" ", "").split(",") # TODO: sanitize user input, Never Ever trust a user - covariate_names = ', '.join('"{0}"'.format(w) for w in userinputS) - #print("Marker names of selected covariates:", covariate_names) - ro.r('covnames <- c(' + covariate_names + ')') - ro.r('covInGeno <- which(covnames %in% colnames(genotypes))') - ro.r('covnames <- covnames[covInGeno]') - ro.r("cat('covnames (purged): ', covnames,'\n')") - ro.r('covariates <- genotypes[,covnames]') # Get the covariate matrix by using the marker name as index to the genotype file - #print("R/qtl matrix of covariates:", ro.r["covariates"]) - return ro.r["covariates"] - - def sanitize_rqtl_phenotype(self): - pheno_as_string = "c(" - for i, val in enumerate(self.vals): - if val == "x": - if i < (len(self.vals) - 1): - pheno_as_string += "NA," - else: - pheno_as_string += "NA" - else: - if i < (len(self.vals) - 1): - pheno_as_string += str(val) + "," - else: - pheno_as_string += str(val) - pheno_as_string += ")" - return pheno_as_string - - def process_pair_scan_results(self, result): - pair_scan_results = [] - - result = result[1] - output = [tuple([result[j][i] for j in range(result.ncol)]) for i in range(result.nrow)] - #print("R/qtl scantwo output:", output) - - for i, line in enumerate(result.iter_row()): - marker = {} - marker['name'] = result.rownames[i] - marker['chr1'] = output[i][0] - marker['Mb'] = output[i][1] - marker['chr2'] = int(output[i][2]) - pair_scan_results.append(marker) - - #print("pair_scan_results:", pair_scan_results) - - return pair_scan_results - - def process_rqtl_results(self, result): # TODO: how to make this a one liner and not copy the stuff in a loop - qtl_results = [] - - output = [tuple([result[j][i] for j in range(result.ncol)]) for i in range(result.nrow)] - #print("R/qtl scanone output:", output) - - for i, line in enumerate(result.iter_row()): - marker = {} - marker['name'] = result.rownames[i] - marker['chr'] = output[i][0] - marker['Mb'] = output[i][1] - marker['lod_score'] = output[i][2] - qtl_results.append(marker) - - return qtl_results - - def process_rqtl_perm_results(self, results): - perm_vals = [] - for line in str(results).split("\n")[1:(self.num_perm+1)]: - #print("R/qtl permutation line:", line.split()) - perm_vals.append(float(line.split()[1])) - - self.perm_output = perm_vals - self.suggestive = np.percentile(np.array(perm_vals), 67) - self.significant = np.percentile(np.array(perm_vals), 95) - - return self.suggestive, self.significant - - def run_plink(self): plink_output_filename = webqtlUtil.genRandStr("%s_%s_"%(self.dataset.group.name, self.this_trait.name)) self.gen_pheno_txt_file_plink(pheno_filename = plink_output_filename) plink_command = PLINK_COMMAND + ' --noweb --ped %s/%s.ped --no-fid --no-parents --no-sex --no-pheno --map %s/%s.map --pheno %s%s.txt --pheno-name %s --maf %s --missing-phenotype -9999 --out %s%s --assoc ' % (PLINK_PATH, self.dataset.group.name, PLINK_PATH, self.dataset.group.name, TMPDIR, plink_output_filename, self.this_trait.name, self.maf, TMPDIR, plink_output_filename) - print("plink_command:", plink_command) + logger.debug("plink_command:", plink_command) os.system(plink_command) @@ -554,11 +370,11 @@ class MarkerRegression(object): #for marker in self.dataset.group.markers.markers: # if marker['name'] not in included_markers: - # print("marker:", marker) + # logger.debug("marker:", marker) # self.dataset.group.markers.markers.remove(marker) # #del self.dataset.group.markers.markers[marker] - print("p_values:", pf(p_values)) + logger.debug("p_values:", pf(p_values)) self.dataset.group.markers.add_pvalues(p_values) @@ -825,7 +641,7 @@ class MarkerRegression(object): top_lod_scores = [] - #print("self.num_perm:", self.num_perm) + #logger.debug("self.num_perm:", self.num_perm) for permutation in range(self.num_perm): @@ -870,10 +686,10 @@ class MarkerRegression(object): if p_value < lowest_p_value: lowest_p_value = p_value - #print("lowest_p_value:", lowest_p_value) + #logger.debug("lowest_p_value:", lowest_p_value) top_lod_scores.append(-math.log10(lowest_p_value)) - #print("top_lod_scores:", top_lod_scores) + #logger.debug("top_lod_scores:", top_lod_scores) self.suggestive = np.percentile(top_lod_scores, 67) self.significant = np.percentile(top_lod_scores, 95) @@ -881,14 +697,13 @@ class MarkerRegression(object): def gen_data(self, temp_uuid): """Generates p-values for each marker""" - - print("self.vals is:", self.vals) + logger.debug("self.vals is:", self.vals) pheno_vector = np.array([(val == "x" or val == "") and np.nan or float(val) for val in self.vals]) #lmm_uuid = str(uuid.uuid4()) key = "pylmm:input:" + temp_uuid - print("key is:", pf(key)) + logger.debug("key is:", pf(key)) #with Bench("Loading cache"): # result = Redis.get(key) @@ -897,7 +712,7 @@ class MarkerRegression(object): #p_values = self.trim_results(p_values) else: - print("NOW CWD IS:", os.getcwd()) + logger.debug("NOW CWD IS:", os.getcwd()) genotype_data = [marker['genotypes'] for marker in self.dataset.group.markers.markers] no_val_samples = self.identify_empty_samples() @@ -905,9 +720,9 @@ class MarkerRegression(object): genotype_matrix = np.array(genotype_data).T - #print("pheno_vector: ", pf(pheno_vector)) - #print("genotype_matrix: ", pf(genotype_matrix)) - #print("genotype_matrix.shape: ", pf(genotype_matrix.shape)) + #logger.debug("pheno_vector: ", pf(pheno_vector)) + #logger.debug("genotype_matrix: ", pf(genotype_matrix)) + #logger.debug("genotype_matrix.shape: ", pf(genotype_matrix.shape)) #params = {"pheno_vector": pheno_vector, # "genotype_matrix": genotype_matrix, @@ -915,8 +730,8 @@ class MarkerRegression(object): # "refit": False, # "temp_data": tempdata} - # print("genotype_matrix:", str(genotype_matrix.tolist())) - # print("pheno_vector:", str(pheno_vector.tolist())) + # logger.debug("genotype_matrix:", str(genotype_matrix.tolist())) + # logger.debug("pheno_vector:", str(pheno_vector.tolist())) params = dict(pheno_vector = pheno_vector.tolist(), genotype_matrix = genotype_matrix.tolist(), @@ -929,14 +744,14 @@ class MarkerRegression(object): ) json_params = json.dumps(params) - #print("json_params:", json_params) + #logger.debug("json_params:", json_params) Redis.set(key, json_params) Redis.expire(key, 60*60) - print("before printing command") + logger.debug("before printing command") command = PYLMM_COMMAND + ' --key {} --species {}'.format(key, "other") - print("command is:", command) - print("after printing command") + logger.debug("command is:", command) + logger.debug("after printing command") shell(command) @@ -946,7 +761,7 @@ class MarkerRegression(object): json_results = Redis.blpop("pylmm:results:" + temp_uuid, 45*60) results = json.loads(json_results[1]) p_values = [float(result) for result in results['p_values']] - #print("p_values:", p_values[:10]) + #logger.debug("p_values:", p_values[:10]) #p_values = self.trim_results(p_values) t_stats = results['t_stats'] @@ -957,7 +772,7 @@ class MarkerRegression(object): # refit=False, # temp_data=tempdata #) - #print("p_values:", p_values) + #logger.debug("p_values:", p_values) self.dataset.group.markers.add_pvalues(p_values) @@ -966,7 +781,7 @@ class MarkerRegression(object): return self.dataset.group.markers.markers def trim_results(self, p_values): - print("len_p_values:", len(p_values)) + logger.debug("len_p_values:", len(p_values)) if len(p_values) > 500: p_values.sort(reverse=True) trimmed_values = p_values[:500] @@ -985,7 +800,7 @@ class MarkerRegression(object): kinship_matrix = np.fromfile(open(file_base + '.kin','r'),sep=" ") kinship_matrix.resize((len(plink_input.indivs),len(plink_input.indivs))) - print("Before creating params") + logger.debug("Before creating params") params = dict(pheno_vector = pheno_vector.tolist(), covariate_matrix = covariate_matrix.tolist(), @@ -998,18 +813,18 @@ class MarkerRegression(object): timestamp = datetime.datetime.now().isoformat(), ) - print("After creating params") + logger.debug("After creating params") json_params = json.dumps(params) Redis.set(key, json_params) Redis.expire(key, 60*60) - print("Before creating the command") + logger.debug("Before creating the command") command = PYLMM_COMMAND+' --key {} --species {}'.format(key, "human") - print("command is:", command) + logger.debug("command is:", command) os.system(command) @@ -1032,7 +847,7 @@ class MarkerRegression(object): return p_values, t_stats def get_lod_score_cutoff(self): - print("INSIDE GET LOD CUTOFF") + logger.debug("INSIDE GET LOD CUTOFF") high_qtl_count = 0 for marker in self.dataset.group.markers.markers: if marker['lod_score'] > 1: diff --git a/wqflask/wqflask/marker_regression/rqtl_mapping.py b/wqflask/wqflask/marker_regression/rqtl_mapping.py new file mode 100644 index 00000000..93bf717c --- /dev/null +++ b/wqflask/wqflask/marker_regression/rqtl_mapping.py @@ -0,0 +1,193 @@ +import rpy2.robjects as ro
+import numpy as np
+
+from base.webqtlConfig import TMPDIR
+from utility import webqtlUtil
+from utility.tools import locate, TEMPDIR
+
+def run_rqtl_geno(vals, dataset, method, model, permCheck, num_perm, do_control, control_marker, manhattan_plot, pair_scan):
+ geno_to_rqtl_function(dataset)
+
+ ## Get pointers to some common R functions
+ r_library = ro.r["library"] # Map the library function
+ r_c = ro.r["c"] # Map the c function
+ r_sum = ro.r["sum"] # Map the sum function
+ plot = ro.r["plot"] # Map the plot function
+ postscript = ro.r["postscript"] # Map the postscript function
+ png = ro.r["png"] # Map the png function
+ dev_off = ro.r["dev.off"] # Map the device off function
+
+ print(r_library("qtl")) # Load R/qtl
+
+ ## Get pointers to some R/qtl functions
+ scanone = ro.r["scanone"] # Map the scanone function
+ scantwo = ro.r["scantwo"] # Map the scantwo function
+ calc_genoprob = ro.r["calc.genoprob"] # Map the calc.genoprob function
+ read_cross = ro.r["read.cross"] # Map the read.cross function
+ write_cross = ro.r["write.cross"] # Map the write.cross function
+ GENOtoCSVR = ro.r["GENOtoCSVR"] # Map the local GENOtoCSVR function
+
+ crossname = dataset.group.name
+ genofilelocation = locate(crossname + ".geno", "genotype")
+ crossfilelocation = TMPDIR + crossname + ".cross"
+
+ #print("Conversion of geno to cross at location:", genofilelocation, " to ", crossfilelocation)
+
+ cross_object = GENOtoCSVR(genofilelocation, crossfilelocation) # TODO: Add the SEX if that is available
+
+ if manhattan_plot:
+ cross_object = calc_genoprob(cross_object)
+ else:
+ cross_object = calc_genoprob(cross_object, step=1, stepwidth="max")
+
+ cross_object = add_phenotype(cross_object, sanitize_rqtl_phenotype(vals)) # Add the phenotype
+
+ # for debug: write_cross(cross_object, "csvr", "test.csvr")
+
+ # Scan for QTLs
+ covar = create_covariates(control_marker, cross_object) # Create the additive covariate matrix
+
+ if pair_scan:
+ if do_control == "true": # If sum(covar) > 0 we have a covariate matrix
+ print("Using covariate"); result_data_frame = scantwo(cross_object, pheno = "the_pheno", addcovar = covar, model=model, method=method, n_cluster = 16)
+ else:
+ print("No covariates"); result_data_frame = scantwo(cross_object, pheno = "the_pheno", model=model, method=method, n_cluster = 16)
+
+ #print("Pair scan results:", result_data_frame)
+
+ pair_scan_filename = webqtlUtil.genRandStr("scantwo_") + ".png"
+ png(file=TEMPDIR+pair_scan_filename)
+ plot(result_data_frame)
+ dev_off()
+
+ return process_pair_scan_results(result_data_frame)
+ else:
+ if do_control == "true":
+ print("Using covariate"); result_data_frame = scanone(cross_object, pheno = "the_pheno", addcovar = covar, model=model, method=method)
+ else:
+ print("No covariates"); result_data_frame = scanone(cross_object, pheno = "the_pheno", model=model, method=method)
+
+ if num_perm > 0 and permCheck == "ON": # Do permutation (if requested by user)
+ if do_control == "true":
+ perm_data_frame = scanone(cross_object, pheno_col = "the_pheno", addcovar = covar, n_perm = num_perm, model=model, method=method)
+ else:
+ perm_data_frame = scanone(cross_object, pheno_col = "the_pheno", n_perm = num_perm, model=model, method=method)
+
+ perm_output, suggestive, significant = process_rqtl_perm_results(num_perm, perm_data_frame) # Functions that sets the thresholds for the webinterface
+ return perm_output, suggestive, significant, process_rqtl_results(result_data_frame)
+ else:
+ return process_rqtl_results(result_data_frame)
+
+def geno_to_rqtl_function(dataset): # TODO: Need to figure out why some genofiles have the wrong format and don't convert properly
+
+ ro.r("""
+ trim <- function( x ) { gsub("(^[[:space:]]+|[[:space:]]+$)", "", x) }
+
+ getGenoCode <- function(header, name = 'unk'){
+ mat = which(unlist(lapply(header,function(x){ length(grep(paste('@',name,sep=''), x)) })) == 1)
+ return(trim(strsplit(header[mat],':')[[1]][2]))
+ }
+
+ GENOtoCSVR <- function(genotypes = '%s', out = 'cross.csvr', phenotype = NULL, sex = NULL, verbose = FALSE){
+ header = readLines(genotypes, 40) # Assume a geno header is not longer than 40 lines
+ toskip = which(unlist(lapply(header, function(x){ length(grep("Chr\t", x)) })) == 1)-1 # Major hack to skip the geno headers
+
+ genocodes <- c(getGenoCode(header, 'mat'), getGenoCode(header, 'het'), getGenoCode(header, 'pat')) # Get the genotype codes
+ type <- getGenoCode(header, 'type')
+ genodata <- read.csv(genotypes, sep='\t', skip=toskip, header=TRUE, na.strings=getGenoCode(header,'unk'), colClasses='character', comment.char = '#')
+ cat('Genodata:', toskip, " ", dim(genodata), genocodes, '\n')
+ if(is.null(phenotype)) phenotype <- runif((ncol(genodata)-4)) # If there isn't a phenotype, generate a random one
+ if(is.null(sex)) sex <- rep('m', (ncol(genodata)-4)) # If there isn't a sex phenotype, treat all as males
+ outCSVR <- rbind(c('Pheno', '', '', phenotype), # Phenotype
+ c('sex', '', '', sex), # Sex phenotype for the mice
+ cbind(genodata[,c('Locus','Chr', 'cM')], genodata[, 5:ncol(genodata)])) # Genotypes
+ write.table(outCSVR, file = out, row.names=FALSE, col.names=FALSE,quote=FALSE, sep=',') # Save it to a file
+ require(qtl)
+ cross = read.cross(file=out, 'csvr', genotypes=genocodes) # Load the created cross file using R/qtl read.cross
+ if(type == 'riset') cross <- convert2riself(cross) # If its a RIL, convert to a RIL in R/qtl
+ return(cross)
+ }
+ """ % (dataset.group.name + ".geno"))
+
+def add_phenotype(cross, pheno_as_string):
+ ro.globalenv["the_cross"] = cross
+ ro.r('the_cross$pheno <- cbind(pull.pheno(the_cross), the_pheno = '+ pheno_as_string +')')
+ return ro.r["the_cross"]
+
+def create_covariates(control_marker, cross):
+ ro.globalenv["the_cross"] = cross
+ ro.r('genotypes <- pull.geno(the_cross)') # Get the genotype matrix
+ userinputS = control_marker.replace(" ", "").split(",") # TODO: sanitize user input, Never Ever trust a user
+ covariate_names = ', '.join('"{0}"'.format(w) for w in userinputS)
+ #print("Marker names of selected covariates:", covariate_names)
+ ro.r('covnames <- c(' + covariate_names + ')')
+ ro.r('covInGeno <- which(covnames %in% colnames(genotypes))')
+ ro.r('covnames <- covnames[covInGeno]')
+ ro.r("cat('covnames (purged): ', covnames,'\n')")
+ ro.r('covariates <- genotypes[,covnames]') # Get the covariate matrix by using the marker name as index to the genotype file
+ #print("R/qtl matrix of covariates:", ro.r["covariates"])
+ return ro.r["covariates"]
+
+def sanitize_rqtl_phenotype(vals):
+ pheno_as_string = "c("
+ for i, val in enumerate(vals):
+ if val == "x":
+ if i < (len(vals) - 1):
+ pheno_as_string += "NA,"
+ else:
+ pheno_as_string += "NA"
+ else:
+ if i < (len(vals) - 1):
+ pheno_as_string += str(val) + ","
+ else:
+ pheno_as_string += str(val)
+ pheno_as_string += ")"
+ return pheno_as_string
+
+def process_pair_scan_results(result):
+ pair_scan_results = []
+
+ result = result[1]
+ output = [tuple([result[j][i] for j in range(result.ncol)]) for i in range(result.nrow)]
+ #print("R/qtl scantwo output:", output)
+
+ for i, line in enumerate(result.iter_row()):
+ marker = {}
+ marker['name'] = result.rownames[i]
+ marker['chr1'] = output[i][0]
+ marker['Mb'] = output[i][1]
+ marker['chr2'] = int(output[i][2])
+ pair_scan_results.append(marker)
+
+ #print("pair_scan_results:", pair_scan_results)
+
+ return pair_scan_results
+
+def process_rqtl_perm_results(num_perm, results):
+ perm_vals = []
+ for line in str(results).split("\n")[1:(num_perm+1)]:
+ #print("R/qtl permutation line:", line.split())
+ perm_vals.append(float(line.split()[1]))
+
+ perm_output = perm_vals
+ suggestive = np.percentile(np.array(perm_vals), 67)
+ significant = np.percentile(np.array(perm_vals), 95)
+ print("SIGNIFICANT:", significant)
+
+ return perm_output, suggestive, significant
+
+def process_rqtl_results(result): # TODO: how to make this a one liner and not copy the stuff in a loop
+ qtl_results = []
+
+ output = [tuple([result[j][i] for j in range(result.ncol)]) for i in range(result.nrow)]
+ #print("R/qtl scanone output:", output)
+
+ for i, line in enumerate(result.iter_row()):
+ marker = {}
+ marker['name'] = result.rownames[i]
+ marker['chr'] = output[i][0]
+ marker['Mb'] = output[i][1]
+ marker['lod_score'] = output[i][2]
+ qtl_results.append(marker)
+
+ return qtl_results
\ No newline at end of file diff --git a/wqflask/wqflask/static/gif/error/Wild-Type-Mouse.gif b/wqflask/wqflask/static/gif/error/Wild-Type-Mouse.gif Binary files differnew file mode 100644 index 00000000..2c68b5ee --- /dev/null +++ b/wqflask/wqflask/static/gif/error/Wild-Type-Mouse.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-aliens-29.gif b/wqflask/wqflask/static/gif/error/animated-gifs-aliens-29.gif Binary files differnew file mode 100644 index 00000000..e9d38277 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-aliens-29.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-angels-04.gif b/wqflask/wqflask/static/gif/error/animated-gifs-angels-04.gif Binary files differnew file mode 100644 index 00000000..94e11847 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-angels-04.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-cats-016.gif b/wqflask/wqflask/static/gif/error/animated-gifs-cats-016.gif Binary files differnew file mode 100644 index 00000000..7e6ec9a3 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-cats-016.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-cats-031.gif b/wqflask/wqflask/static/gif/error/animated-gifs-cats-031.gif Binary files differnew file mode 100644 index 00000000..af7ef655 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-cats-031.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-cell-phones-03.gif b/wqflask/wqflask/static/gif/error/animated-gifs-cell-phones-03.gif Binary files differnew file mode 100644 index 00000000..89c79ddf --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-cell-phones-03.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-cell-phones-16.gif b/wqflask/wqflask/static/gif/error/animated-gifs-cell-phones-16.gif Binary files differnew file mode 100644 index 00000000..7530d180 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-cell-phones-16.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-computers-13.gif b/wqflask/wqflask/static/gif/error/animated-gifs-computers-13.gif Binary files differnew file mode 100644 index 00000000..afb05c62 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-computers-13.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-computers-28.gif b/wqflask/wqflask/static/gif/error/animated-gifs-computers-28.gif Binary files differnew file mode 100644 index 00000000..f5b4a563 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-computers-28.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-computers-32.gif b/wqflask/wqflask/static/gif/error/animated-gifs-computers-32.gif Binary files differnew file mode 100644 index 00000000..7258e594 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-computers-32.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-computers-42.gif b/wqflask/wqflask/static/gif/error/animated-gifs-computers-42.gif Binary files differnew file mode 100644 index 00000000..ed1f8722 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-computers-42.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-computers-60.gif b/wqflask/wqflask/static/gif/error/animated-gifs-computers-60.gif Binary files differnew file mode 100644 index 00000000..f58d69f1 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-computers-60.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-computers-64.gif b/wqflask/wqflask/static/gif/error/animated-gifs-computers-64.gif Binary files differnew file mode 100644 index 00000000..5d5b4fdf --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-computers-64.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-computers-65.gif b/wqflask/wqflask/static/gif/error/animated-gifs-computers-65.gif Binary files differnew file mode 100644 index 00000000..b4b10845 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-computers-65.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-computers-72.gif b/wqflask/wqflask/static/gif/error/animated-gifs-computers-72.gif Binary files differnew file mode 100644 index 00000000..e60cb4fe --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-computers-72.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-computers-74.gif b/wqflask/wqflask/static/gif/error/animated-gifs-computers-74.gif Binary files differnew file mode 100644 index 00000000..bd7b72f3 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-computers-74.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-computers-75.gif b/wqflask/wqflask/static/gif/error/animated-gifs-computers-75.gif Binary files differnew file mode 100644 index 00000000..916d6b33 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-computers-75.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-construction-sites-038.gif b/wqflask/wqflask/static/gif/error/animated-gifs-construction-sites-038.gif Binary files differnew file mode 100644 index 00000000..0ec782c4 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-construction-sites-038.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-dogs-04.gif b/wqflask/wqflask/static/gif/error/animated-gifs-dogs-04.gif Binary files differnew file mode 100644 index 00000000..9515c18a --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-dogs-04.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-dogs-14.gif b/wqflask/wqflask/static/gif/error/animated-gifs-dogs-14.gif Binary files differnew file mode 100644 index 00000000..f1e2e1f5 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-dogs-14.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-dogs-18.gif b/wqflask/wqflask/static/gif/error/animated-gifs-dogs-18.gif Binary files differnew file mode 100644 index 00000000..572849d5 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-dogs-18.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-dogs-47.gif b/wqflask/wqflask/static/gif/error/animated-gifs-dogs-47.gif Binary files differnew file mode 100644 index 00000000..d808c9ee --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-dogs-47.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-dogs-50.gif b/wqflask/wqflask/static/gif/error/animated-gifs-dogs-50.gif Binary files differnew file mode 100644 index 00000000..9865ee45 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-dogs-50.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-lava-lamps-01.gif b/wqflask/wqflask/static/gif/error/animated-gifs-lava-lamps-01.gif Binary files differnew file mode 100644 index 00000000..ee9c113d --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-lava-lamps-01.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-mice-02.gif b/wqflask/wqflask/static/gif/error/animated-gifs-mice-02.gif Binary files differnew file mode 100644 index 00000000..5ca2ee5c --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-mice-02.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-mice-09.gif b/wqflask/wqflask/static/gif/error/animated-gifs-mice-09.gif Binary files differnew file mode 100644 index 00000000..7cb361e4 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-mice-09.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-mice-24.gif b/wqflask/wqflask/static/gif/error/animated-gifs-mice-24.gif Binary files differnew file mode 100644 index 00000000..96a26450 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-mice-24.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-smileys-063.gif b/wqflask/wqflask/static/gif/error/animated-gifs-smileys-063.gif Binary files differnew file mode 100644 index 00000000..62de166c --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-smileys-063.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-smileys-068.gif b/wqflask/wqflask/static/gif/error/animated-gifs-smileys-068.gif Binary files differnew file mode 100644 index 00000000..3550e978 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-smileys-068.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-smileys-134.gif b/wqflask/wqflask/static/gif/error/animated-gifs-smileys-134.gif Binary files differnew file mode 100644 index 00000000..954ab614 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-smileys-134.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-smileys-211.gif b/wqflask/wqflask/static/gif/error/animated-gifs-smileys-211.gif Binary files differnew file mode 100644 index 00000000..596174d7 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-smileys-211.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-smileys-234.gif b/wqflask/wqflask/static/gif/error/animated-gifs-smileys-234.gif Binary files differnew file mode 100644 index 00000000..5aba636b --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-smileys-234.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-stickmen-001.gif b/wqflask/wqflask/static/gif/error/animated-gifs-stickmen-001.gif Binary files differnew file mode 100644 index 00000000..7896ff1f --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-stickmen-001.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-stickmen-002.gif b/wqflask/wqflask/static/gif/error/animated-gifs-stickmen-002.gif Binary files differnew file mode 100644 index 00000000..89da6441 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-stickmen-002.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-stickmen-005.gif b/wqflask/wqflask/static/gif/error/animated-gifs-stickmen-005.gif Binary files differnew file mode 100644 index 00000000..b7887630 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-stickmen-005.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-stickmen-012.gif b/wqflask/wqflask/static/gif/error/animated-gifs-stickmen-012.gif Binary files differnew file mode 100644 index 00000000..f6697d02 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-stickmen-012.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-stickmen-056.gif b/wqflask/wqflask/static/gif/error/animated-gifs-stickmen-056.gif Binary files differnew file mode 100644 index 00000000..2b2496a4 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-stickmen-056.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-stickmen-059.gif b/wqflask/wqflask/static/gif/error/animated-gifs-stickmen-059.gif Binary files differnew file mode 100644 index 00000000..f2188656 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-stickmen-059.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-stickmen-060.gif b/wqflask/wqflask/static/gif/error/animated-gifs-stickmen-060.gif Binary files differnew file mode 100644 index 00000000..aa8f7bd3 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-stickmen-060.gif diff --git a/wqflask/wqflask/static/gif/error/animated-gifs-stickmen-069.gif b/wqflask/wqflask/static/gif/error/animated-gifs-stickmen-069.gif Binary files differnew file mode 100644 index 00000000..473212e4 --- /dev/null +++ b/wqflask/wqflask/static/gif/error/animated-gifs-stickmen-069.gif diff --git a/wqflask/wqflask/templates/collections/add.html b/wqflask/wqflask/templates/collections/add.html index 47b87d73..d45aa015 100644 --- a/wqflask/wqflask/templates/collections/add.html +++ b/wqflask/wqflask/templates/collections/add.html @@ -25,7 +25,7 @@ <select name="existing_collection" class="form-control"> {% for col in collections %} - <option value="{{ col.id }}">{{ col.name }}</option> + <option value="{{ col.id }}:{{ col.name }}">{{ col.name }}</option> {% endfor %} </select> <br /> diff --git a/wqflask/wqflask/templates/ctl_setup.html b/wqflask/wqflask/templates/ctl_setup.html index 9c0d7bea..51553322 100644 --- a/wqflask/wqflask/templates/ctl_setup.html +++ b/wqflask/wqflask/templates/ctl_setup.html @@ -1,65 +1,70 @@ {% extends "base.html" %} -{% block title %}WCGNA analysis{% endblock %} +{% block title %}CTL analysis{% endblock %} {% block content %} <!-- Start of body --> <div class="container"> + {% if request.form['trait_list'].split(",")|length < 2 %} + <div class="alert alert-danger" role="alert"> + <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> + <span class="sr-only">Error:</span> + <h2>Too few traits as input</h2> + Please make sure you select enough traits to perform CTL. Your collection needs to contain at least 2 different traits. You provided {{request.form['trait_list'].split(',')|length}} traits as input. + </div> + {% else %} <h1>CTL analysis parameters</h1> - {{(request.form['trait_list'].split(',')|length -1)}} phenotypes as input + {{(request.form['trait_list'].split(',')|length -1)}} traits as input -<form action="/ctl_results" method="post" class="form-horizontal"> - <input type="hidden" name="trait_list" id="trait_list" value= "{{request.form['trait_list']}}"> + <form action="/ctl_results" method="post" class="form-horizontal"> + <input type="hidden" name="trait_list" id="trait_list" value= "{{request.form['trait_list']}}"> + <div class="dropdown"> + <label for="Strategy">Strategy</label> + <div class="col-sm-10"> + <select name="strategy" id="strategy"> + <option value="Exact">Exact</option> + <option value="Full">Full</option> + <option value="Pairwise">Pairwise</option> + </select> + </div> + </div> - <div class="dropdown"> - <label for="Strategy">Strategy</label> - <div class="col-sm-10"> - <select name="strategy" id="strategy"> - <option value="Exact">Exact</option> - <option value="Full">Full</option> - <option value="Pairwise">Pairwise</option> - </select> - </div> - </div> + <div class="dropdown"> + <label for="Permutations">Number of permutation (Used when strategy is Full or Pairwise)</label> + <div class="col-sm-10"> + <select name="nperm" id="nperm"> + <option value="100">100</option> + <option value="1000" selected="selected">1000</option> + <option value="10000">10000</option> + </select> + </div> + </div> - <div class="dropdown"> - <label for="Permutations">Number of permutation (Used when strategy is Full or Pairwise)</label> - <div class="col-sm-10"> - <select name="nperm" id="nperm"> - <option value="100">100</option> - <option value="1000" selected="selected">1000</option> - <option value="10000">10000</option> - </select> - </div> - </div> - - <div class="dropdown"> - <label for="Coefficient">Type of correlation coefficient</label> - <div class="col-sm-10"> - <select name="parametric" id="parametric"> - <option value="False">Spearman</option> - <option value="True">Pearson</option> - </select> - </div> - </div> - - - <div class="dropdown"> - <label for="Significance">Significance level</label> - <div class="col-sm-10"> - <select name="significance" id="significance"> - <option value="0.1">0.1</option> - <option value="0.05" selected="selected">0.05</option> - <option value="0.001">0.001</option> - </select> - </div> - </div> - <br> - <div class="form-group"> - <div class="col-sm-10"> - <input type="submit" class="btn btn-primary" value="Run CTL using these settings" /> - </div> - </div> + <div class="dropdown"> + <label for="Coefficient">Type of correlation coefficient</label> + <div class="col-sm-10"> + <select name="parametric" id="parametric"> + <option value="False">Spearman</option> + <option value="True">Pearson</option> + </select> + </div> + </div> + <div class="dropdown"> + <label for="Significance">Significance level</label> + <div class="col-sm-10"> + <select name="significance" id="significance"> + <option value="0.1">0.1</option> + <option value="0.05" selected="selected">0.05</option> + <option value="0.001">0.001</option> + </select> + </div> + </div> + <br> + <div class="form-group"> + <div class="col-sm-10"> + <input type="submit" class="btn btn-primary" value="Run CTL using these settings" /> + </div> + </div> </form> - +{% endif %} </div> {% endblock %} diff --git a/wqflask/wqflask/templates/error.html b/wqflask/wqflask/templates/error.html new file mode 100644 index 00000000..7ab2bf2f --- /dev/null +++ b/wqflask/wqflask/templates/error.html @@ -0,0 +1,61 @@ +{% 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> + + <pre> + {{ stack[0] }} + {{ message }} (error) + {{ stack[-3] }} + {{ stack[-2] }} + </pre> + + <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> + {% for line in stack %} {{ line }} + {% endfor %} + </pre> + </div> +</div> +</div> + + +{% endblock %} diff --git a/wqflask/wqflask/templates/show_trait_mapping_tools.html b/wqflask/wqflask/templates/show_trait_mapping_tools.html index 3d9c2521..0f293942 100644 --- a/wqflask/wqflask/templates/show_trait_mapping_tools.html +++ b/wqflask/wqflask/templates/show_trait_mapping_tools.html @@ -2,7 +2,7 @@ {% if (use_pylmm_rqtl and dataset.group.species != "human") or use_plink_gemma %} <div class="col-xs-4"> <div class="tabbable"> <!-- Only required for left/right tabs --> - + <ul class="nav nav-pills"> {% if use_pylmm_rqtl and not use_plink_gemma and dataset.group.species != "human" %} <li class="active"> @@ -61,7 +61,7 @@ No </label> </div> - </div> + </div> <!-- <div class="mapping_method_fields form-group"> @@ -75,7 +75,7 @@ <div class="mapping_method_fields form-group"> <label style="text-align:left;" class="col-xs-12 control-label">Display Additive Effect</label> - <div class="col-xs-12 controls" id="display_additive_effect"> + <div class="col-xs-12 controls" id="display_additive_effect"> <label class="radio-inline"> <input type="radio" name="display_additive" id="display_additive" value="yes" checked=""> Yes @@ -90,8 +90,8 @@ <div class="mapping_method_fields form-group"> - <label style="text-align:left;" class="col-xs-12 control-label">Marker Regr.</label> - <div class="col-xs-12 controls"> + <label style="text-align:left;" class="col-xs-3 control-label">Marker<br>Regression</label> + <div style="margin-left: 20px;" class="col-xs-4 controls"> <label class="radio-inline"> <input type="radio" name="manhattan_plot_reaper" value="True"> Yes @@ -146,7 +146,7 @@ <div class="mapping_method_fields form-group"> <label style="text-align:left;" class="col-xs-12 control-label">Manhattan Plot</label> - <div class="col-xs-12 controls"> + <div class="col-xs-12 controls"> <label class="radio-inline"> <input type="radio" name="manhattan_plot_pylmm" value="True"> Yes @@ -167,7 +167,7 @@ </div> </div> <div class="tab-pane" id="rqtl_geno"> - + <div style="margin-top: 20px" class="form-horizontal"> <div class="mapping_method_fields form-group"> <label for="mapping_permutations" class="col-xs-3 control-label">Permutations</label> @@ -226,7 +226,7 @@ <div class="mapping_method_fields form-group"> <label style="text-align:left;" class="col-xs-12 control-label">Pair Scan</label> - <div class="col-xs-12 controls"> + <div class="col-xs-12 controls"> <label class="radio-inline"> <input type="radio" name="pair_scan" value="true"> Yes @@ -240,7 +240,7 @@ <div class="mapping_method_fields form-group"> <label style="text-align:left;" class="col-xs-12 control-label">Manhattan Plot</label> - <div class="col-xs-12 controls"> + <div class="col-xs-12 controls"> <label class="radio-inline"> <input type="radio" name="manhattan_plot_rqtl" value="True"> Yes @@ -272,7 +272,7 @@ </div> </div> </div> - + <div class="form-group"> <label for="plink_compute" class="col-xs-1 control-label"></label> <div style="margin-left:20px;" class="col-xs-4 controls"> @@ -282,7 +282,7 @@ </div> </div> </div> - + <div class="tab-pane" id="gemma"> <div style="padding: 20px" class="form-horizontal"> <div class="mapping_method_fields form-group"> @@ -292,7 +292,7 @@ </div> </div> </div> - + <div class="form-group"> <label for="gemma_compute" class="col-xs-1 control-label"></label> <div style="margin-left:20px;" class="col-xs-4 controls"> @@ -301,12 +301,12 @@ </button> </div> </div> - </div> + </div> {% endif %} </div> </div> </div> - <div class="col-xs-6"> + <div class="col-xs-6"> <dl> <dt>Interval Mapping</dt> <dd>Interval mapping is a process in which the statistical significance of a hypothetical QTL is evaluated at regular points across a chromosome, even in the absence of explicit genotype data at those points.</dd> diff --git a/wqflask/wqflask/templates/wgcna_setup.html b/wqflask/wqflask/templates/wgcna_setup.html index b4a5730d..c5461497 100644 --- a/wqflask/wqflask/templates/wgcna_setup.html +++ b/wqflask/wqflask/templates/wgcna_setup.html @@ -4,49 +4,46 @@ {% block content %} <!-- Start of body --> <h1> WGCNA analysis parameters</h1> <div class="container"> - {% if request.form['trait_list'].split(",")|length <= 4 %} - - <div class="alert alert-danger" role="alert"> - <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> - <span class="sr-only">Error:</span> - <h2> - Too few phenotypes as input - </h2> - Please make sure you select enough phenotypes / genes to perform WGCNA, your collection needs to contain at least 4 different phenotypes. You provided {{request.form['trait_list'].split(',')|length}} phenotypes as input - </div> - {% else %} - <form action="/wgcna_results" method="post" class="form-horizontal"> - <input type="hidden" name="trait_list" id="trait_list" value= "{{request.form['trait_list']}}"> - <div class="form-group"> - <label for="SoftThresholds"> Soft threshold: </label> - <div class="col-sm-10"> - <input type="text" class="form-inline" name="SoftThresholds" id="SoftThresholds" value="1,2,3,4,5,6,7,8,9"> - </div> - </div> - <div class="form-group"> - <label for="MinModuleSize"> Minimum module size: </label> - <div class="col-sm-10"> - <input type="text" class="form-inline" name="MinModuleSize" id="MinModuleSize" value="30"> - </div> - </div> - <div class="form-group"> - <label for="TOMtype"> TOMtype: </label> - <div class="col-sm-10"> - <input type="text" class="form-inline" name="TOMtype" id="TOMtype" value="unsigned"> - </div> - </div> - <div class="form-group"> - <label for="mergeCutHeight"> mergeCutHeight: </label> - <div class="col-sm-10"> - <input type="text" class="form-inline" name="mergeCutHeight" id="mergeCutHeight" value="0.25"> - </div> - </div> - <div class="form-group"> - <div class="col-sm-10"> - <input type="submit" class="btn btn-primary" value="Run WGCNA using these settings" /> - </div> - </div> - </form> - {% endif %} + {% if request.form['trait_list'].split(",")|length < 4 %} + <div class="alert alert-danger" role="alert"> + <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> + <span class="sr-only">Error:</span> + <h2>Too few phenotypes as input</h2> + Please make sure you select enough phenotypes / genes to perform WGCNA. Your collection needs to contain at least 4 different phenotypes. You provided {{request.form['trait_list'].split(',')|length}} phenotypes as input. + </div> + {% else %} + <form action="/wgcna_results" method="post" class="form-horizontal"> + <input type="hidden" name="trait_list" id="trait_list" value= "{{request.form['trait_list']}}"> + <div class="form-group"> + <label for="SoftThresholds"> Soft threshold: </label> + <div class="col-sm-10"> + <input type="text" class="form-inline" name="SoftThresholds" id="SoftThresholds" value="1,2,3,4,5,6,7,8,9"> + </div> + </div> + <div class="form-group"> + <label for="MinModuleSize"> Minimum module size: </label> + <div class="col-sm-10"> + <input type="text" class="form-inline" name="MinModuleSize" id="MinModuleSize" value="30"> + </div> + </div> + <div class="form-group"> + <label for="TOMtype"> TOMtype: </label> + <div class="col-sm-10"> + <input type="text" class="form-inline" name="TOMtype" id="TOMtype" value="unsigned"> + </div> + </div> + <div class="form-group"> + <label for="mergeCutHeight"> mergeCutHeight: </label> + <div class="col-sm-10"> + <input type="text" class="form-inline" name="mergeCutHeight" id="mergeCutHeight" value="0.25"> + </div> + </div> + <div class="form-group"> + <div class="col-sm-10"> + <input type="submit" class="btn btn-primary" value="Run WGCNA using these settings" /> + </div> + </div> + </form> + {% endif %} </div> {% endblock %} diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py index 7061e0f1..33fab84d 100644 --- a/wqflask/wqflask/views.py +++ b/wqflask/wqflask/views.py @@ -4,6 +4,11 @@ from __future__ import absolute_import, division, print_function +import traceback # for error page +import os # for error gifs +import random # for random error gif +import datetime # for errors +import time # for errors import sys import csv import xlsxwriter @@ -26,7 +31,7 @@ import base64 import array import sqlalchemy from wqflask import app -from flask import g, Response, request, render_template, send_from_directory, jsonify, redirect +from flask import g, Response, request, make_response, render_template, send_from_directory, jsonify, redirect from wqflask import search_results from wqflask import gsearch from wqflask import update_search_results @@ -58,6 +63,8 @@ from wqflask import user_manager from wqflask import collect from wqflask.database import db_session +import werkzeug + import utility.logger logger = utility.logger.getLogger(__name__ ) @@ -82,6 +89,31 @@ def shutdown_session(exception=None): # from wqflask import tracer # tracer.turn_on() +@app.errorhandler(Exception) +def handle_bad_request(e): + err_msg = str(e) + logger.error(err_msg) + logger.error(request.url) + # get the stack trace and send it to the logger + exc_type, exc_value, exc_traceback = sys.exc_info() + logger.error(traceback.format_exc()) + now = datetime.datetime.utcnow() + time_str = now.strftime('%l:%M%p UTC %b %d, %Y') + formatted_lines = [request.url + " ("+time_str+")"]+traceback.format_exc().splitlines() + + # Handle random animations + # Use a cookie to have one animation on refresh + animation = request.cookies.get(err_msg[:32]) + if not animation: + list = [fn for fn in os.listdir("./wqflask/static/gif/error") if fn.endswith(".gif") ] + animation = random.choice(list) + + resp = make_response(render_template("error.html",message=err_msg,stack=formatted_lines,error_image=animation)) + + # logger.error("Set cookie %s with %s" % (err_msg, animation)) + resp.set_cookie(err_msg[:32],animation) + return resp + @app.route("/") def index_page(): logger.info("Sending index_page") |