diff options
author | Sam Ockman | 2012-05-24 02:18:20 -0400 |
---|---|---|
committer | Sam Ockman | 2012-05-24 02:18:20 -0400 |
commit | 527bb0459cf488e5021696e326dc10d28ecdd74c (patch) | |
tree | 097e013d6a876fe0a6e178ff6defa813faa4af93 | |
parent | aa915612d2ff98f1e31d2ec38e8054382ef75dd9 (diff) | |
download | genenetwork2-527bb0459cf488e5021696e326dc10d28ecdd74c.tar.gz |
Trying to get stuff working under new structure
41 files changed, 8275 insertions, 0 deletions
diff --git a/wqflask/base/GeneralObject.py b/wqflask/base/GeneralObject.py new file mode 100755 index 00000000..311c9e22 --- /dev/null +++ b/wqflask/base/GeneralObject.py @@ -0,0 +1,71 @@ +# Copyright (C) University of Tennessee Health Science Center, Memphis, TN. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Affero General Public License for more details. +# +# This program is available from Source Forge: at GeneNetwork Project +# (sourceforge.net/projects/genenetwork/). +# +# 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 +# +# Last updated by GeneNetwork Core Team 2010/10/20 + +class GeneralObject: + """ + Base class to define an Object. + a = [Spam(1, 4), Spam(9, 3), Spam(4,6)] + a.sort(lambda x, y: cmp(x.eggs, y.eggs)) + """ + + def __init__(self, *args, **kw): + self.contents = list(args) + for name, value in kw.items(): + setattr(self, name, value) + + def __setitem__(self, key, value): + setattr(self, key, value) + + def __getitem__(self, key): + return getattr(self, key) + + def __getattr__(self, key): + if key in self.__dict__.keys(): + return self.__dict__[key] + else: + return eval("self.__dict__.%s" % key) + + def __len__(self): + return len(self.__dict__) - 1 + + def __str__(self): + s = '' + for key in self.__dict__.keys(): + if key != 'contents': + s += '%s = %s\n' % (key,self.__dict__[key]) + return s + + def __repr__(self): + s = '' + for key in self.__dict__.keys(): + s += '%s = %s\n' % (key,self.__dict__[key]) + return s + + def __cmp__(self,other): + return len(self.__dict__.keys()).__cmp__(len(other.__dict__.keys())) + + + diff --git a/wqflask/base/JinjaPage.py b/wqflask/base/JinjaPage.py new file mode 100644 index 00000000..07e485b1 --- /dev/null +++ b/wqflask/base/JinjaPage.py @@ -0,0 +1,28 @@ +import logging +logging.basicConfig(filename="/tmp/gn_log", level=logging.INFO) +_log = logging.getLogger("search") + +from pprint import pformat as pf + +import templatePage + +from utility import formatting + +import jinja2 +JinjaEnv = jinja2.Environment(loader=jinja2.FileSystemLoader('/gnshare/gn/web/webqtl/templates')) +JinjaEnv.globals['numify'] = formatting.numify + + +class JinjaPage(templatePage.templatePage): + """Class derived from our regular templatePage, but uses Jinja2 instead. + + When converting pages from Python generated templates, change the base class from templatePage + to JinjaPage + + """ + + + def write(self): + """We override the base template write so we can use Jinja2.""" + _log.info(pf(self.__dict__)) + return self.jtemplate.render(**self.__dict__) diff --git a/wqflask/base/__init__.py b/wqflask/base/__init__.py new file mode 100755 index 00000000..e69de29b --- /dev/null +++ b/wqflask/base/__init__.py diff --git a/wqflask/base/admin.py b/wqflask/base/admin.py new file mode 100755 index 00000000..a04df2da --- /dev/null +++ b/wqflask/base/admin.py @@ -0,0 +1,88 @@ +# Copyright (C) University of Tennessee Health Science Center, Memphis, TN. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Affero General Public License for more details. +# +# This program is available from Source Forge: at GeneNetwork Project +# (sourceforge.net/projects/genenetwork/). +# +# 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 +# +# Last updated by GeneNetwork Core Team 2010/10/20 + + + + + +#XZ, 04/02/2009: we should put this into database. + + +###LIST of databases used into gene name query + + +ADMIN_search_dbs = { + 'rat': {'PERITONEAL FAT': ['FT_2A_0605_Rz'], + 'KIDNEY': ['KI_2A_0405_Rz'], + 'ADRENAL GLAND': ['HXB_Adrenal_1208'], + 'HEART': ['HXB_Heart_1208'] + }, + 'mouse': {'CEREBELLUM': ['CB_M_0305_R'], + 'STRIATUM': ['SA_M2_0905_R', 'SA_M2_0405_RC', 'UTHSC_1107_RankInv', 'Striatum_Exon_0209'], + 'HIPPOCAMPUS': ['HC_M2_0606_R', 'UMUTAffyExon_0209_RMA'], + 'WHOLE BRAIN': ['BR_M2_1106_R', 'IBR_M_0106_R', 'BRF2_M_0805_R', 'UCLA_BHF2_BRAIN_0605'], + 'LIVER': ['LV_G_0106_B', 'UCLA_BHF2_LIVER_0605'], + 'EYE': ['Eye_M2_0908_R'], + 'HEMATOPOIETIC STEM CELLS': ['HC_U_0304_R'], + 'KIDNEY': ['MA_M2_0806_R'], + 'MAMMARY TUMORS': ['MA_M_0704_R', 'NCI_Agil_Mam_Tum_RMA_0409'], + 'PREFRONTAL CORTEX': ['VCUSal_1206_R'], + 'SPLEEN': ['IoP_SPL_RMA_0509'], + 'NUCLEUS ACCUMBENS': ['VCUSalo_1007_R'], + 'NEOCORTEX': ['HQFNeoc_0208_RankInv'], + 'ADIPOSE': ['UCLA_BHF2_ADIPOSE_0605'], + 'RETINA': ['Illum_Retina_BXD_RankInv0410'] + }, + 'human': { + 'LYMPHOBLAST B CELL': ['Human_1008', 'UT_CEPH_RankInv0909'], + 'WHOLE BRAIN': ['GSE5281_F_RMA0709', 'GSE15222_F_RI_0409'] + } + } + + +###LIST of tissue alias + +ADMIN_tissue_alias = {'CEREBELLUM': ['Cb'], + 'STRIATUM': ['Str'], + 'HIPPOCAMPUS': ['Hip'], + 'WHOLE BRAIN': ['Brn'], + 'LIVER': ['Liv'], + 'EYE': ['Eye'], + 'PERITONEAL FAT': ['Fat'], + 'HEMATOPOIETIC STEM CELLS': ['Hsc'], + 'KIDNEY': ['Kid'], + 'ADRENAL GLAND': ['Adr'], + 'HEART': ['Hea'], + 'MAMMARY TUMORS': ['Mam'], + 'PREFRONTAL CORTEX': ['Pfc'], + 'SPLEEN': ['Spl'], + 'NUCLEUS ACCUMBENS': ['Nac'], + 'NEOCORTEX': ['Ctx'], + 'ADIPOSE': ['Wfat'], + 'RETINA': ['Ret'] + } + + diff --git a/wqflask/base/cgiData.py b/wqflask/base/cgiData.py new file mode 100755 index 00000000..57416060 --- /dev/null +++ b/wqflask/base/cgiData.py @@ -0,0 +1,70 @@ +# Copyright (C) University of Tennessee Health Science Center, Memphis, TN. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Affero General Public License for more details. +# +# This program is available from Source Forge: at GeneNetwork Project +# (sourceforge.net/projects/genenetwork/). +# +# 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 +# +# Last updated by GeneNetwork Core Team 2010/10/20 + +######################################### +#convert Field storage object to Dict object +#in order to be able to saved into a session file +######################################### + +class cgiData(dict): + '''convert Field storage object to Dict object + Filed storage object cannot be properly dumped + ''' + + def __init__(self, field_storage=None): + + if not field_storage: + field_storage={} + + for key in field_storage.keys(): + temp = field_storage.getlist(key) + if len(temp) > 1: + temp = map(self.toValue, temp) + elif len(temp) == 1: + temp = self.toValue(temp[0]) + else: + temp = None + self[key]= temp + + def toValue(self, obj): + '''fieldstorge returns different type of objects, \ + need to convert to string or None''' + try: + return obj.value + except: + return "" + + def getvalue(self, k, default= None): + try: + return self[k] + except: + return default + + getfirst = getvalue + + + + diff --git a/wqflask/base/cookieData.py b/wqflask/base/cookieData.py new file mode 100755 index 00000000..4b7c9046 --- /dev/null +++ b/wqflask/base/cookieData.py @@ -0,0 +1,52 @@ +# Copyright (C) University of Tennessee Health Science Center, Memphis, TN. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Affero General Public License for more details. +# +# This program is available from Source Forge: at GeneNetwork Project +# (sourceforge.net/projects/genenetwork/). +# +# 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 +# +# Last updated by GeneNetwork Core Team 2010/10/20 + +######################################### +#convert mod_python object to Dict object +#in order to be able to be pickled +######################################### + +class cookieData(dict): + 'convert mod python Cookie object to Dict object' + + def __init__(self, cookies=None): + + if not cookies: + cookies={} + + for key in cookies.keys(): + self[key.lower()]= cookies[key].value + + def getvalue(self, k, default= None): + try: + return self[k.lower()] + except: + return default + + getfirst = getvalue + + + diff --git a/wqflask/base/footer.py b/wqflask/base/footer.py new file mode 100755 index 00000000..6f92fdf8 --- /dev/null +++ b/wqflask/base/footer.py @@ -0,0 +1,6 @@ +import webqtlConfig + +footer_html = open(webqtlConfig.HTMLPATH + 'footer.html', 'r').read() +footer = footer_html.replace('%"','%%"') + +footer_string = footer.replace('<!-- %s -->', '%s') diff --git a/wqflask/base/header.py b/wqflask/base/header.py new file mode 100755 index 00000000..b6136b51 --- /dev/null +++ b/wqflask/base/header.py @@ -0,0 +1,6 @@ +import webqtlConfig + +header_string = open(webqtlConfig.HTMLPATH + 'header.html', 'r').read() +header_string = header_string.replace("\\'", "'") +header_string = header_string.replace('%"','%%"') +header_string = header_string.replace('<!-- %s -->', '%s')
\ No newline at end of file diff --git a/wqflask/base/indexBody.py b/wqflask/base/indexBody.py new file mode 100755 index 00000000..aa67dffa --- /dev/null +++ b/wqflask/base/indexBody.py @@ -0,0 +1,290 @@ +index_body_string = """ +<TD vAlign=top width="40%" align="left" height=10 bgColor=#eeeeee> + <p style="font-size:18px;font-family:verdana;color:black"><B> Select and Search</B> + <Form METHOD="POST" ACTION="/webqtl/main.py" ENCTYPE="multipart/form-data" NAME="SEARCHFORM"> + + <TABLE width="100%"> + + <!-- SPECIES SELECTION --> + <TR> + <TD align=right height="35" style="font-size:14px;font-family:verdana;color:black" width="16%"> + <B>Species:</B> + </TD> + + <TD width="3%"> + </TD> + + <TD NOWRAP width="85%" align="left"> + <DIV Id="menu0"> + <Select NAME="species" size=1 id="species" onchange="fillOptions('species');"> + </Select> + </DIV> + </TD> + </TR> + + <!-- GROUP SELECTION --> + + <TR> + + <TD align="right" height="35" style="font-size:14px;font-family:verdana;color:black"> + <B>Group:</B> + </TD> + + <TD width="3%"> + </TD> + + <TD NOWRAP width="85%" align="left"> + <DIV Id="menu1"> + + <Select NAME="cross" size=1 id="cross" onchange="fillOptions('cross');"> + </Select> + <input type="button" class="button" value=" Info " onCLick="javascript:crossinfo();"> + </DIV> + </TD> + </TR> + + + <!-- TYPE SELECTION --> + + <TR> + + <TD align=right height=35 style="font-size:14px;font-family:verdana;color:black"> + <B>Type:</B> + </TD> + + <TD width="3%"> + </TD> + <TD NOWRAP width="85%" align="left"> + <DIV Id="menu2"> + <Select NAME="tissue" size=1 id="tissue" onchange="fillOptions('tissue');"> + + </Select> + </DIV> + </TD> + </TR> + + + <!-- DATABASE SELECTION --> + <TR> + <TD align=right height=35 style="font-size:14px;font-family:verdana;color:black"> + <B>Database:</B> + </TD> + + <TD width="3%"> + </TD> + + <TD NOWRAP width="85%" align="left"> + <DIV Id="menu3"> + <Select NAME="database" size=1 id="database"> + </Select> + <input type="button" class="button" value=" Info " onCLick="javascript:databaseinfo();"> + </DIV> + + </TD> + </TR> + + <!-- USER HELP --> + <TR> + <TD align=right height=20 width="10%"> + </TD> + <TD width="3%"> + </TD> + + <TD align="left" width="85%"> + <P class="fs12"> Databases marked with <B>**</B> suffix are not public yet. + <BR> Access requires <A HREF="/account.html" target="_blank" class="fs14"><small>user login</small></A>.</P> + </TD> + </TR> + + +<!-- GET ANY SEARCH --> + <TR> + <TD align=right height=35 NOWRAP="on" style="font-size:14px;font-family:verdana;color:black" width="10%"> + <B>Get Any:</B> + </TD> + + <TD width="3%"> + </TD> + + <TD NOWRAP width="85%" align="left"> + + <input id="tfor" name="ORkeyword" style="width:420px; background-color:white; font-family:verdana; font-size:14px" type="text" maxlength="500"> + </TD> + </TR> + + + +<!-- GET ANY HELP --> + <TR> + <TD align=right height=20 width="10%"> + </TD> + <TD width="3%"> + + </TD> + <TD width="85%" align="left"> + <P class="fs12"> Enter terms, genes, ID numbers in the <B>Get Any</B> field. + <BR> Use <B>*</B> or <B>?</B> wildcards (Cyp*a?, synap*). + <BR> Use <B>Combined</B> for terms such as <I>tyrosine kinase</I>.</P> + + </TD> + </TR> + + + +<!-- COMBINED SEARCH --> + + <TR> + <TD align=right height=35 NOWRAP="on" STYLE="font-size:14px;font-family:verdana;color:black" width="10%"> + <B>Combined:</B> + </TD> + + <TD width="3%"> + </TD> + + <TD NOWRAP width="85%" align="left"> + <input id="tfand" NAME="ANDkeyword" STYLE="width:420px; background-color:white; font-family:verdana; font-size:14px" type="text" maxlength="500"> + <input name="matchwhole" type="hidden" value="ON"> + </TD> + </TR> + + + +<!-- SEARCH, MAKE DEFAULT, ADVANCED SEARCH --> + + <TR ALIGN="center"> + <TD width="3%"> + </TD> + <TD width="3%"> + </TD> + <TD ALIGN="left" HEIGHT="40" COLSPAN=3> + <INPUT id="btsearch" TYPE="Submit" CLASS="button" STYLE="font-size:12px" VALUE=" Search "> + <INPUT TYPE="button" CLASS="button" STYLE="font-size:12px" VALUE=" Make Default " onClick = "setDefault(this.form);"> + <INPUT TYPE="button" CLASS="button" STYLE="font-size:12px" VALUE=" Advanced Search " onClick="javascript:window.open('/index3.html', '_self');"> + + </TD> + </TR> + </TABLE> + <INPUT TYPE="hidden" NAME="FormID" VALUE="searchResult"> + <INPUT TYPE="hidden" NAME="RISet" VALUE="BXD"> + <SCRIPT SRC="/javascript/selectDatasetMenu.js"></SCRIPT> + </FORM> + </CENTER> + + + + + +<!-- QUICK HELP --> + +<P><LEFT> ______________________________________________________ + +<P STYLE="font-size:13px;font-family:verdana;color:black"><B> + +Quick HELP Examples and </B> +<A HREF="http://www.genenetwork.org/index4.html" target="_blank" class="fs14"><B> + User's Guide</B></A></P> + +</CENTER style="font-size:12px;font-family:verdana;color:black"> + You can also use advanced commands. Copy these simple examples +<BR> into the <B>Get Any</B> or <B>Combined</B> search fields: +<UL style="font-size:12px;font-family:verdana;color:black"> + +<LI><B><I>POSITION=(chr1 25 30)</I></B> finds genes, markers, or transcripts on chromosome 1 between 25 and 30 Mb. + +<LI><B><I>MEAN=(15 16) LRS=(23 46)</I></B> in the <B>Combined</B> field finds highly expressed genes (15 to 16 log2 units) AND with peak <A HREF="http://www.genenetwork.org/glossary.html#L" target="_blank" class="fs14"><small>LRS</small></A> linkage between 23 and 46. + + +<LI><B><I>RIF=mitochondrial</I></B> searches RNA databases for <A HREF="http://www.ncbi.nlm.nih.gov/projects/GeneRIF/GeneRIFhelp.html" target="_blank" class="fs14"><small>GeneRIF</small></A> links. + +<LI><B><I>WIKI=nicotine</I></B> searches <A HREF="http://www.genenetwork.org/webqtl/main.py?FormID=geneWiki" target="_blank" class="fs14"><small>GeneWiki</small></A> for genes that you or other users have annotated with the word <I>nicotine</I>. + +<LI><B><I>GO:0045202</I></B> searches for synapse-associated genes listed in the <A HREF="http://www.godatabase.org/cgi-bin/amigo/go.cgi" target="_blank" class="fs14"><small>Gene Ontology</small></A>. + + +<LI><B><I>GO:0045202 LRS=(9 99 Chr4 122 155) cisLRS=(9 999 10)</I> </B><BR> in <B>Combined</B> finds synapse-associated genes with <A HREF="http://www.genenetwork.org/glossary.html#E" target="_blank" class="fs14"><small>cis eQTL</small></A> on Chr 4 from 122 and 155 Mb with LRS scores between 9 and 999. + +<LI><B><I>RIF=diabetes LRS=(9 999 Chr2 100 105) transLRS=(9 999 10)</I> </B><BR> in <B>Combined</B> finds diabetes-associated transcripts with peak <A HREF="http://www.genenetwork.org/glossary.html#E" target="_blank" class="fs14"><small>trans eQTLs</small></A> on Chr 2 between 100 and 105 Mb with LRS scores between 9 and 999. + + +</UL> +</DIR> + </TD> +<!-- END OF FIND SELECTOR PULL-DOWN PANEL (LEFT SIDE) --> + +<!-- START OF TOP RIGHT PANEL --> + +<TD vAlign=top width="40%" bgColor=#FFFFFF> + <p style="font-size:15px;font-family:verdana;color:black"><B>Websites Affiliated with GeneNetwork</B></p> + <p style="font-size:12px;font-family:verdana;color:black"> + <ul> + <li><a href="http://ucscbrowser.genenetwork.org/" target="_blank">Genome Browser</a> at UTHSC</li> + <li><a href="http://galaxy.genenetwork.org/" target="_blank">Galaxy</a> at UTHSC</li> + <li>GeneNetwork at <a href="http://ec2.genenetwork.org/" target="_blank">Amazon Cloud (EC2)</a></li> + <li>GeneNetwork Source Codes at <a href="http://sourceforge.net/projects/genenetwork/" target="_blank">SourceForge</a></li> + </ul> + </p> + <P>____________________________ + + <p style="font-size:15px;font-family:verdana;color:black"><B>Getting Started</B> </p> + <OL style="font-size:12px;font-family:verdana;color:black"> + <LI>Select <B>Species</B> (or select All) + <LI>Select <B>Group</B> (a specific sample) + <LI>Select <B>Type</B> of data: + <UL> + <LI>Phenotype (traits) + <LI>Genotype (markers) + <LI>Expression (mRNAs) + </UL> + <LI>Select a <B>Database</B> + <LI>Enter search terms in the <B>Get Any</B> or <B>Combined</B> field: words, genes, ID numbers, probes, advanced search commands + <LI>Click on the <B>Search</B> button + <LI>Optional: Use the <B>Make Default</B> button to save your preferences + </OL> + + <P>____________________________ + +<p style="font-size:14px;font-family:verdana;color:black"><B>How to Use GeneNetwork</B> + + <BLOCKQUOTE> + <p style="font-size:12px;font-family:verdana;color:black">Take a 20-40 minute GeneNetwork <A HREF="http://www.genenetwork.org/tutorial/WebQTLTour/" target="_blank" class="fs14"><small>Tour</small></A> that includes screen shots and typical steps in the analysis.</P> + </BLOCKQUOTE> + <BLOCKQUOTE> + <p style="font-size:12px;font-family:verdana;color:black">For information about resources and methods, select the <img src="http://www.genenetwork.org/images/upload/Info.png" alt="INFO" border= 0 valign="middle"> buttons.</P> + + + +<p style="font-size:12px;font-family:verdana;color:black">Try the <A HREF="http://alexandria.uthsc.edu/" target="_blank" class="fs14"><small>Workstation</small></A> site to explore data and features that are being implemented.</P> + + +<p style="font-size:12px;font-family:verdana;color:black">Review the <A HREF="/conditionsofUse.html" target="_blank" class="fs14"><small>Conditions</small></A> and <A HREF="/statusandContact.html" target="_blank" class="fs14"><small>Contacts</small></A> pages for information on the status of data sets and advice on their use and citation.</P> + + + </BLOCKQUOTE> + + + + <p style="font-size:14px;font-family:verdana;color:black"><B>Mirror and Development Sites</B></P> + + <UL> + <LI><A HREF="http://www.genenetwork.org/" target="_blank" style="font-size:12px;font-family:verdana;color:blue">Main GN site at UTHSC</A> (main site) + <LI><A HREF="http://www.genenetwork.waimr.uwa.edu.au/" target="_blank" style="font-size:12px;font-family:verdana;color:blue">Australia at the UWA</A> + <LI><A HREF="http://gn.genetics.ucla.edu/" target="_blank" style="font-size:12px;font-family:verdana;color:blue">California at UCLA</A> + <LI><A HREF="http://genenetwork.helmholtz-hzi.de/" target="_blank" style="font-size:12px;font-family:verdana;color:blue">Germany at the HZI</A> + <LI><A HREF="https://genenetwork.hubrecht.eu/" target="_blank" style="font-size:12px;font-family:verdana;color:blue">Netherlands at the Hubrecht</A> (Development) + <LI><A HREF="http://xzhou3.memphis.edu/" target="_blank" style="font-size:12px;font-family:verdana;color:blue">Memphis at the U of M</A> + <LI><A HREF="http://webqtl.bic.nus.edu.sg/" target="_blank" style="font-size:12px;font-family:verdana;color:blue">Singapore at the NUS</A> + <LI><A HREF="http://genenetwork.epfl.ch/" target="_blank" style="font-size:12px;font-family:verdana;color:blue">Switzerland at the EPFL</A> + </UL> + + + <p style="font-size:14px;font-family:verdana;color:black"><B>History and Archive</B> + + <BLOCKQUOTE> + <p style="font-size:12px;font-family:verdana;color:black">GeneNetwork's <A HREF="http://artemis.uthsc.edu" target="_blank" class="fs14"><small>Time Machine</small></A> links to earlier versions that correspond to specific publication dates.</P> + + </BLOCKQUOTE> + + +</P> + </TD> +""" diff --git a/wqflask/base/myCookie.py b/wqflask/base/myCookie.py new file mode 100755 index 00000000..db5320df --- /dev/null +++ b/wqflask/base/myCookie.py @@ -0,0 +1,55 @@ +# Copyright (C) University of Tennessee Health Science Center, Memphis, TN. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Affero General Public License for more details. +# +# This program is available from Source Forge: at GeneNetwork Project +# (sourceforge.net/projects/genenetwork/). +# +# 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 +# +# Last updated by GeneNetwork Core Team 2010/10/20 + +######################################### +## python cookie and mod python cookie are +## not compatible +######################################### + +class myCookie(dict): + 'define my own cookie' + + def __init__(self, name="", value="", expire = None, path="/"): + self['name']= name + self['value']= value + self['expire']= expire + self['path']= path + + def __getattr__(self, key): + if key in self.keys(): + return self[key] + else: + return None + + def __nonzero__ (self): + if self['name']: + return 1 + else: + return 0 + + + + diff --git a/wqflask/base/sessionData.py b/wqflask/base/sessionData.py new file mode 100755 index 00000000..01555f87 --- /dev/null +++ b/wqflask/base/sessionData.py @@ -0,0 +1,53 @@ +# Copyright (C) University of Tennessee Health Science Center, Memphis, TN. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Affero General Public License for more details. +# +# This program is available from Source Forge: at GeneNetwork Project +# (sourceforge.net/projects/genenetwork/). +# +# 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 +# +# Last updated by GeneNetwork Core Team 2010/10/20 + +######################################### +#convert mod_python object to Dict object +#in order to be able to be pickled +######################################### + +class sessionData(dict): + 'convert mod python Session object to Dict object' + + def __init__(self, mod_python_session=None): + + if not mod_python_session: + mod_python_session = {} + + for key in mod_python_session.keys(): + self[key]= mod_python_session[key] + + + def getvalue(self, k, default= None): + try: + return self[k] + except: + return default + + getfirst = getvalue + + + diff --git a/wqflask/base/template.py b/wqflask/base/template.py new file mode 100755 index 00000000..85bd86df --- /dev/null +++ b/wqflask/base/template.py @@ -0,0 +1,123 @@ +# Copyright (C) University of Tennessee Health Science Center, Memphis, TN. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Affero General Public License for more details. +# +# This program is available from Source Forge: at GeneNetwork Project +# (sourceforge.net/projects/genenetwork/). +# +# 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 +# +# Last updated by GeneNetwork Core Team 2010/10/20 + +template = """ +<?XML VERSION="1.0" ENCODING="UTF-8"> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<HTML> +<HEAD> +<TITLE>%s</TITLE> + +<META http-equiv=Content-Type content="text/html; charset=iso-8859-1"> +<META NAME="keywords" CONTENT="genetics, bioinformatics, genome, phenome, gene expression, complex trait analysis, gene mapping, SNP, quantitative trait locus QTL, expression eQTL, WebQTL, Traitnet, Traitnetwork, personalized medicine"> +<META NAME="description" CONTENT ="GeneNetwork is a free scientific web resource used to study relationships between differences in genes, environmental factors, phenotypes, and disease risk." > +<META NAME="author" CONTENT ="GeneNetwork developers" > +<META NAME="geo.placename" CONTENT ="Memphis, TN" > +<META NAME="geo.region" CONTENT="US-TN"> +%s +<LINK REL="stylesheet" TYPE="text/css" HREF='/css/general.css'> +<LINK REL="stylesheet" TYPE="text/css" HREF='/css/menu.css'> +<link rel="stylesheet" media="all" type="text/css" href="/css/tabbed_pages.css" /> +<LINK REL="apple-touch-icon" href="/images/ipad_icon3.png" /> +<link type="text/css" href='/css/custom-theme/jquery-ui-1.8.12.custom.css' rel='Stylesheet' /> +<link type="text/css" href='/css/tab_style.css' rel='Stylesheet' /> + +<script type="text/javascript" src="/javascript/jquery-1.5.2.min.js"></script> +<SCRIPT SRC="/javascript/webqtl.js"></SCRIPT> +<SCRIPT SRC="/javascript/dhtml.js"></SCRIPT> +<SCRIPT SRC="/javascript/tablesorter.js"></SCRIPT> +<SCRIPT SRC="/javascript/jqueryFunction.js"></SCRIPT> +<script src="/javascript/tabbed_pages.js" type="text/javascript"></script> +<script src="/javascript/jquery-ui-1.8.12.custom.min.js" type="text/javascript"></script> +%s + +<script type="text/javascript"> + var _gaq = _gaq || []; + _gaq.push(['_setAccount', 'UA-3782271-1']); + _gaq.push(['_trackPageview']); + (function() { + var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; + ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; + var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); + })(); +</script> +</HEAD> +<BODY bottommargin="2" leftmargin="2" rightmargin="2" topmargin="2" text=#000000 bgColor=#ffffff %s> +%s +<TABLE cellSpacing=5 cellPadding=4 width="100%%" border=0> + <TBODY> + <!-- Start of header --> + <TR> + %s + </TR> + <!-- End of header --> + + <!-- Start of body --> + <TR> + <TD bgColor=#eeeeee class="solidBorder"> + <Table width= "100%%" cellSpacing=0 cellPadding=5> + <TR> + %s + </TR> + </TABLE> + </TD> + </TR> + <!-- End of body --> + + <!-- Start of footer --> + <TR> + <TD align=center bgColor=#ddddff class="solidBorder"> + <TABLE width="90%%">%s</table> + </td> + </TR> + <!-- End of footer --> +</TABLE> + +<!-- menu script itself. you should not modify this file --> +<script language="JavaScript" src="/javascript/menu_new.js"></script> +<!-- items structure. menu hierarchy and links are stored there --> +<script language="JavaScript" src="/javascript/menu_items.js"></script> +<!-- files with geometry and styles structures --> +<script language="JavaScript" src="/javascript/menu_tpl.js"></script> +<script language="JavaScript"> + <!--// + // Note where menu initialization block is located in HTML document. + // Don't try to position menu locating menu initialization block in + // some table cell or other HTML element. Always put it before </body> + // each menu gets two parameters (see demo files) + // 1. items structure + // 2. geometry structure + new menu (MENU_ITEMS, MENU_POS); + // make sure files containing definitions for these variables are linked to the document + // if you got some javascript error like "MENU_POS is not defined", then you've made syntax + // error in menu_tpl.js file or that file isn't linked properly. + + // also take a look at stylesheets loaded in header in order to set styles + //--> +</script> +</BODY> +</HTML> +""" diff --git a/wqflask/base/templatePage.py b/wqflask/base/templatePage.py new file mode 100755 index 00000000..4dece24a --- /dev/null +++ b/wqflask/base/templatePage.py @@ -0,0 +1,222 @@ +# Copyright (C) University of Tennessee Health Science Center, Memphis, TN. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Affero General Public License for more details. +# +# This program is available from Source Forge: at GeneNetwork Project +# (sourceforge.net/projects/genenetwork/). +# +# 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 +# +# Last updated by GeneNetwork Core Team 2010/10/20 + +#templatePage.py +# +#--Genenetwork generates a lot of pages; this file is the generic version of them, defining routines they all use. +# +#Classes: +#templatePage +# +#Functions (of templatePage): +#__init__(...) -- class constructor, allows a more specific template to be used in addition to templatePage +#__str__(self) -- returns the object's elements as a tuple +#__del__(self) -- closes the current connection to MySQL, if there is one +#write -- explained below +#writefile -- explained below +#openMysql(self) -- opens a MySQL connection and stores the resulting cursor in the object's cursor variable +#updMysql(self) -- same as openMysql +#error -- explained below +#session -- explained below + + +import socket +import time +import shutil +import MySQLdb +import os + +from htmlgen import HTMLgen2 as HT + +import template +import webqtlConfig +import header +import footer +from utility import webqtlUtil + + + +class templatePage: + + contents = ['title','basehref','js1','js2', 'layer', 'header', 'body', 'footer'] + + # you can pass in another template here if you want + def __init__(self, fd=None, template=template.template): + + # initiate dictionary + self.starttime = time.time() + self.dict = {} + self.template = template + + for item in self.contents: + self.dict[item] = "" + + self.dict['basehref'] = "" #webqtlConfig.BASEHREF + self.cursor = None + + self.cookie = [] #XZ: list to hold cookies (myCookie object) being changed + self.content_type = 'text/html' + self.content_disposition = '' + self.redirection = '' + self.debug = '' + self.attachment = '' + + #XZ: Holding data (new data or existing data being changed) that should be saved to session. The data must be picklable!!! + self.session_data_changed = {} + + self.userName = 'Guest' + self.privilege = 'guest' + if fd.input_session_data.has_key('user'): + self.userName = fd.input_session_data['user'] + if fd.input_session_data.has_key('privilege'): + self.privilege = fd.input_session_data['privilege'] + + def __str__(self): + + #XZ: default setting + thisUserName = self.userName + thisPrivilege = self.privilege + #XZ: user may just go through login or logoff page + if self.session_data_changed.has_key('user'): + thisUserName = self.session_data_changed['user'] + if self.session_data_changed.has_key('privilege'): + thisPrivilege = self.session_data_changed['privilege'] + + if thisUserName == 'Guest': + userInfo = 'Welcome! <a href=/account.html><U>Login</U></a>' + else: + userInfo = 'Hi, %s! <a href=/webqtl/main.py?FormID=userLogoff><U>Logout</U></a>' % thisUserName + + reload(header) + self.dict['header'] = header.header_string % userInfo + + serverInfo = "It took %2.3f second(s) for %s to generate this page" % (time.time()-self.starttime, socket.getfqdn()) + reload(footer) + self.dict['footer'] = footer.footer_string % serverInfo + + slist = [] + for item in self.contents: + slist.append(self.dict[item]) + return self.template % tuple(slist) + + + def __del__(self): + if self.cursor: + self.cursor.close() + + def write(self): + 'return string representation of this object' + + if self.cursor: + self.cursor.close() + + return str(self) + + def writeFile(self, filename): + 'save string representation of this object into a file' + if self.cursor: + self.cursor.close() + + try: + 'it could take a long time to generate the file, save to .tmp first' + fp = open(os.path.join(webqtlConfig.TMPDIR, filename+'.tmp'), 'wb') + fp.write(str(self)) + fp.close() + path_tmp = os.path.join(webqtlConfig.TMPDIR, filename+'.tmp') + path_html = os.path.join(webqtlConfig.TMPDIR, filename) + shutil.move(path_tmp,path_html) + except: + pass + + def openMysql(self): + try: + self.con = MySQLdb.Connect(db=webqtlConfig.DB_NAME,host=webqtlConfig.MYSQL_SERVER, \ + user=webqtlConfig.DB_USER,passwd=webqtlConfig.DB_PASSWD) + self.cursor = self.con.cursor() + return 1 + except: + heading = "Connect MySQL Server" + detail = ["Can't connect to MySQL server on '"+ webqtlConfig.MYSQL_SERVER+"':100061. \ + The server may be down at this time"] + self.error(heading=heading,detail=detail,error="Error 2003") + return 0 + + def updMysql(self): + try: + self.con = MySQLdb.Connect(db=webqtlConfig.DB_UPDNAME,host=webqtlConfig.MYSQL_UPDSERVER, \ + user=webqtlConfig.DB_UPDUSER,passwd=webqtlConfig.DB_UPDPASSWD) + self.cursor = self.con.cursor() + return 1 + except: + heading = "Connect MySQL Server" + detail = ["update: Can't connect to MySQL server on '"+ webqtlConfig.MYSQL_UPDSERVER+"':100061. \ + The server may be down at this time "] + self.error(heading=heading,detail=detail,error="Error 2003") + return 0 + + def error(self,heading="",intro=[],detail=[],title="Error",error="Error"): + 'generating a WebQTL style error page' + Heading = HT.Paragraph(heading) + Heading.__setattr__("class","title") + + Intro = HT.Blockquote() + if intro: + for item in intro: + Intro.append(item) + else: + Intro.append(HT.Strong('Sorry!'),' Error occurred while processing\ + your request.', HT.P(),'The nature of the error generated is as\ + follows:') + + Detail = HT.Blockquote() + Detail.append(HT.Span("%s : " % error,Class="fwb cr")) + if detail: + Detail2 = HT.Blockquote() + for item in detail: + Detail2.append(item) + Detail.append(HT.Italic(Detail2)) + + #Detail.__setattr__("class","subtitle") + TD_LR = HT.TD(height=200,width="100%",bgColor='#eeeeee',valign="top") + TD_LR.append(Heading,Intro,Detail) + self.dict['body'] = str(TD_LR) + self.dict['title'] = title + + def session(self,mytitle="",myHeading=""): + 'generate a auto-refreshing temporary html file(waiting page)' + self.filename = webqtlUtil.generate_session() + self.dict['title'] = mytitle + self.dict['basehref'] = webqtlConfig.REFRESHSTR % (webqtlConfig.CGIDIR, self.filename) + "" #webqtlConfig.BASEHREF + + TD_LR = HT.TD(align="center", valign="middle", height=200,width="100%", bgColor='#eeeeee') + Heading = HT.Paragraph(myHeading, Class="fwb fs16 cr") + # NL, 07/27/2010. variable 'PROGRESSBAR' has been moved from templatePage.py to webqtlUtil.py; + TD_LR.append(Heading, HT.BR(), webqtlUtil.PROGRESSBAR) + self.dict['body'] = TD_LR + self.writeFile(self.filename + '.html') + return self.filename + + diff --git a/wqflask/base/webqtlCaseData.py b/wqflask/base/webqtlCaseData.py new file mode 100755 index 00000000..4df32ca4 --- /dev/null +++ b/wqflask/base/webqtlCaseData.py @@ -0,0 +1,54 @@ +# Copyright (C) University of Tennessee Health Science Center, Memphis, TN. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Affero General Public License for more details. +# +# This program is available from Source Forge: at GeneNetwork Project +# (sourceforge.net/projects/genenetwork/). +# +# 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 +# +# Last updated by GeneNetwork Core Team 2010/10/20 + +class webqtlCaseData: + """ + one case data in one trait + """ + + val = None #Trait Value + var = None #Trait Variance + N = None #Number of individuals + + def __init__(self, val=val, var=var, N=N): + self.val = val + self.var = var + self.N = N + + def __str__(self): + str = "" + if self.val != None: + str += "value=%2.3f" % self.val + if self.var != None: + str += " variance=%2.3f" % self.var + if self.N != None: + str += " ndata=%d" % self.N + return str + + __repr__ = __str__ + + + diff --git a/wqflask/base/webqtlConfig.py b/wqflask/base/webqtlConfig.py new file mode 100755 index 00000000..755595e0 --- /dev/null +++ b/wqflask/base/webqtlConfig.py @@ -0,0 +1,73 @@ +from webqtlConfigLocal import * +#########################################' +# Environment Variables - public +######################################### + +#Debug Level +#1 for debug, mod python will reload import each time +DEBUG = 1 + +#USER privilege +USERDICT = {'guest':1,'user':2, 'admin':3, 'root':4} + +#minimum number of informative strains +KMININFORMATIVE = 5 + +#maximum number of traits for interval mapping +MULTIPLEMAPPINGLIMIT = 11 + +#maximum number of traits for correlation +MAXCORR = 100 + +#Daily download limit from one IP +DAILYMAXIMUM = 1000 + +#maximum LRS value +MAXLRS = 460.0 + +#temporary data life span +MAXLIFE = 86400 + +#MINIMUM Database public value +PUBLICTHRESH = 0 + +#NBCI address +NCBI_LOCUSID = "http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?db=gene&cmd=Retrieve&dopt=Graphics&list_uids=%s" +UCSC_REFSEQ = "http://genome.cse.ucsc.edu/cgi-bin/hgGene?db=%s&hgg_gene=%s&hgg_chrom=chr%s&hgg_start=%s&hgg_end=%s" +GENBANK_ID = "http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?db=Nucleotide&cmd=search&doptcmdl=DocSum&term=%s" +OMIM_ID = "http://www.ncbi.nlm.nih.gov/omim/%s" +UNIGEN_ID = "http://www.ncbi.nlm.nih.gov/UniGene/clust.cgi?ORG=%s&CID=%s" +HOMOLOGENE_ID = "http://www.ncbi.nlm.nih.gov/sites/entrez?Db=homologene&Cmd=DetailsSearch&Term=%s" +PUBMEDLINK_URL = "http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?cmd=Retrieve&db=PubMed&list_uids=%s&dopt=Abstract" +UCSC_POS = "http://genome.ucsc.edu/cgi-bin/hgTracks?clade=mammal&org=%s&db=%s&position=chr%s:%s-%s&pix=800&Submit=submit" +UCSC_BLAT = 'http://genome.ucsc.edu/cgi-bin/hgBlat?org=%s&db=%s&type=0&sort=0&output=0&userSeq=%s' +UTHSC_BLAT = 'http://ucscbrowser.genenetwork.org/cgi-bin/hgBlat?org=%s&db=%s&type=0&sort=0&output=0&userSeq=%s' +UCSC_GENOME = "http://genome.ucsc.edu/cgi-bin/hgTracks?db=%s&position=chr%s:%d-%d&hgt.customText=http://web2qtl.utmem.edu:88/snp/chr%s" +ENSEMBLE_BLAT = 'http://www.ensembl.org/Mus_musculus/featureview?type=AffyProbe&id=%s' +DBSNP = 'http://www.ncbi.nlm.nih.gov/SNP/snp_ref.cgi?type=rs&rs=%s' +UCSC_RUDI_TRACK_URL = " http://genome.cse.ucsc.edu/cgi-bin/hgTracks?org=%s&db=%s&hgt.customText=http://gbic.biol.rug.nl/~ralberts/tracks/%s/%s" +GENOMEBROWSER_URL="http://ucscbrowser.genenetwork.org/cgi-bin/hgTracks?clade=mammal&org=Mouse&db=mm9&position=%s&hgt.suggest=&pix=800&Submit=submit" +ENSEMBLETRANSCRIPT_URL="http://useast.ensembl.org/Mus_musculus/Lucene/Details?species=Mus_musculus;idx=Transcript;end=1;q=%s" + +SECUREDIR = GNROOT + 'secure/' +COMMON_LIB = GNROOT + 'support/admin' +HTMLPATH = GNROOT + 'web/' +IMGDIR = HTMLPATH +'image/' +IMAGESPATH = HTMLPATH + 'images/' +UPLOADPATH = IMAGESPATH + 'upload/' +TMPDIR = '/tmp/' +GENODIR = HTMLPATH + 'genotypes/' +GENO_ARCHIVE_DIR = GENODIR + 'archive/' +TEXTDIR = HTMLPATH + 'ProbeSetFreeze_DataMatrix/' +CMDLINEDIR = HTMLPATH + 'webqtl/cmdLine/' +ChangableHtmlPath = GNROOT + 'web/' + +SITENAME = 'GN' +PORTADDR = "http://132.192.47.32" +BASEHREF = '<base href="http://132.192.47.32/">' +INFOPAGEHREF = '/dbdoc/%s.html' +GLOSSARYFILE = "/glossary.html" +CGIDIR = '/webqtl/' #XZ: The variable name 'CGIDIR' should be changed to 'PYTHONDIR' +SCRIPTFILE = 'main.py' +REFRESHSTR = '<meta http-equiv="refresh" content="5;url=%s' + SCRIPTFILE +'?sid=%s">' +REFRESHDIR = '%s' + SCRIPTFILE +'?sid=%s' diff --git a/wqflask/base/webqtlConfigLocal.py b/wqflask/base/webqtlConfigLocal.py new file mode 100755 index 00000000..35da73c2 --- /dev/null +++ b/wqflask/base/webqtlConfigLocal.py @@ -0,0 +1,19 @@ +#########################################' +# Environment Variables - private +######################################### + +MYSQL_SERVER = 'localhost' +DB_NAME = 'db_webqtl' +DB_USER = 'webqtlupd' +DB_PASSWD = 'zhou&yan@ut' + +MYSQL_UPDSERVER = 'localhost' +DB_UPDNAME = 'db_webqtl' +DB_UPDUSER = 'webqtlupd' +DB_UPDPASSWD = 'zhou&yan@ut' + +GNROOT = '/gnshare/gn/' +PythonPath = '/usr/bin/python' +PIDDLE_FONT_PATH = '/usr/lib/python2.4/site-packages/piddle/truetypefonts/' + +TEXTUI=1 # XZ: This is to protect GN production server. If set to 0, no text UI is allowed. diff --git a/wqflask/base/webqtlDataset.py b/wqflask/base/webqtlDataset.py new file mode 100755 index 00000000..da1b8601 --- /dev/null +++ b/wqflask/base/webqtlDataset.py @@ -0,0 +1,160 @@ +# Copyright (C) University of Tennessee Health Science Center, Memphis, TN. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Affero General Public License for more details. +# +# This program is available from Source Forge: at GeneNetwork Project +# (sourceforge.net/projects/genenetwork/). +# +# 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 +# +# Last updated by GeneNetwork Core Team 2010/10/20 + +from htmlgen import HTMLgen2 as HT + +import webqtlConfig + + + +class webqtlDataset: + """ + Database class defines a database in webqtl, can be either Microarray, + Published phenotype, genotype, or user input database(temp) + """ + + def __init__(self, dbName, cursor=None): + + assert dbName + self.id = 0 + self.name = '' + self.type = '' + self.riset = '' + self.cursor = cursor + + #temporary storage + if dbName.find('Temp') >= 0: + self.searchfield = ['name','description'] + self.disfield = ['name','description'] + self.type = 'Temp' + self.id = 1 + self.fullname = 'Temporary Storage' + self.shortname = 'Temp' + elif dbName.find('Publish') >= 0: + self.searchfield = ['name','post_publication_description','abstract','title','authors'] + self.disfield = ['name','pubmed_id', + 'pre_publication_description', 'post_publication_description', 'original_description', + 'pre_publication_abbreviation', 'post_publication_abbreviation', + 'lab_code', 'submitter', 'owner', 'authorized_users', + 'authors','title','abstract', 'journal','volume','pages','month', + 'year','sequence', 'units', 'comments'] + self.type = 'Publish' + elif dbName.find('Geno') >= 0: + self.searchfield = ['name','chr'] + self.disfield = ['name','chr','mb', 'source2', 'sequence'] + self.type = 'Geno' + else: #ProbeSet + self.searchfield = ['name','description','probe_target_description', + 'symbol','alias','genbankid','unigeneid','omim', + 'refseq_transcriptid','probe_set_specificity', 'probe_set_blat_score'] + self.disfield = ['name','symbol','description','probe_target_description', + 'chr','mb','alias','geneid','genbankid', 'unigeneid', 'omim', + 'refseq_transcriptid','blatseq','targetseq','chipid', 'comments', + 'strand_probe','strand_gene','probe_set_target_region', + 'probe_set_specificity', 'probe_set_blat_score','probe_set_blat_mb_start', + 'probe_set_blat_mb_end', 'probe_set_strand', + 'probe_set_note_by_rw', 'flag'] + self.type = 'ProbeSet' + self.name = dbName + if self.cursor and self.id == 0: + self.retrieveName() + + def __str__(self): + return self.name + + __repr__ = __str__ + + + def getRISet(self): + assert self.cursor + if self.type == 'Publish': + query = ''' + SELECT + InbredSet.Name, InbredSet.Id + FROM + InbredSet, PublishFreeze + WHERE + PublishFreeze.InbredSetId = InbredSet.Id AND + PublishFreeze.Name = "%s" + ''' % self.name + elif self.type == 'Geno': + query = ''' + SELECT + InbredSet.Name, InbredSet.Id + FROM + InbredSet, GenoFreeze + WHERE + GenoFreeze.InbredSetId = InbredSet.Id AND + GenoFreeze.Name = "%s" + ''' % self.name + elif self.type == 'ProbeSet': + query = ''' + SELECT + InbredSet.Name, InbredSet.Id + FROM + InbredSet, ProbeSetFreeze, ProbeFreeze + WHERE + ProbeFreeze.InbredSetId = InbredSet.Id AND + ProbeFreeze.Id = ProbeSetFreeze.ProbeFreezeId AND + ProbeSetFreeze.Name = "%s" + ''' % self.name + else: + return "" + self.cursor.execute(query) + RISet, RIID = self.cursor.fetchone() + if RISet == 'BXD300': + RISet = "BXD" + self.riset = RISet + self.risetid = RIID + return RISet + + + def retrieveName(self): + assert self.id == 0 and self.cursor + query = ''' + SELECT + Id, Name, FullName, ShortName + FROM + %sFreeze + WHERE + public > %d AND + (Name = "%s" OR FullName = "%s" OR ShortName = "%s") + '''% (self.type, webqtlConfig.PUBLICTHRESH, self.name, self.name, self.name) + try: + self.cursor.execute(query) + self.id,self.name,self.fullname,self.shortname=self.cursor.fetchone() + except: + raise KeyError, `self.name`+' doesn\'t exist.' + + + def genHTML(self, Class='c0dd'): + return HT.Href(text = HT.Span('%s Database' % self.fullname, Class= "fwb " + Class), + url= webqtlConfig.INFOPAGEHREF % self.name,target="_blank") + + + + + diff --git a/wqflask/base/webqtlFormData.py b/wqflask/base/webqtlFormData.py new file mode 100755 index 00000000..84e41cae --- /dev/null +++ b/wqflask/base/webqtlFormData.py @@ -0,0 +1,289 @@ +# Copyright (C) University of Tennessee Health Science Center, Memphis, TN. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Affero General Public License for more details. +# +# This program is available from Source Forge: at GeneNetwork Project +# (sourceforge.net/projects/genenetwork/). +# +# 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 +# +# Last updated by GeneNetwork Core Team 2010/10/20 + +from mod_python import Cookie +import string +import os + +import reaper + +import webqtlConfig +import cookieData +import sessionData +from cgiData import cgiData +from webqtlCaseData import webqtlCaseData +from utility import webqtlUtil + + + +class webqtlFormData: + 'Represents data from a WebQTL form page, needed to generate the next page' + attrs = ('formID','RISet','genotype','strainlist','allstrainlist', + 'suggestive','significance','submitID','identification', 'enablevariance', + 'nperm','nboot','email','incparentsf1','genotype_1','genotype_2','traitInfo') + + #XZ: Attention! All attribute values must be picklable! + + def __init__(self, req = None, mod_python_session=None, FieldStorage_formdata=None): + + for item in self.attrs: + setattr(self,item, None) + + try: + self.remote_ip = req.connection.remote_ip + except: + self.remote_ip = '1.2.3.4' + + if req and req.headers_in.has_key('referer'): + self.refURL = req.headers_in['referer'] + else: + self.refURL = None + + + self.cookies = cookieData.cookieData(Cookie.get_cookies(req)) #XZ: dictionary type. To hold values transfered from mod_python Cookie. + + #XZ: dictionary type. To hold values transfered from mod_python Session object. We assume that it is always picklable. + self.input_session_data = sessionData.sessionData( mod_python_session ) + + #XZ: FieldStorage_formdata may contain item that can't be pickled. Must convert to picklable data. + self.formdata = cgiData( FieldStorage_formdata ) + + #get Form ID + self.formID = self.formdata.getfirst('FormID') + + #get rest of the attributes + if self.formID: + for item in self.attrs: + value = self.formdata.getfirst(item) + if value != None: + setattr(self,item,string.strip(value)) + + self.ppolar = "" + self.mpolar = "" + if self.RISet: + try: + # NL, 07/27/2010. ParInfo has been moved from webqtlForm.py to webqtlUtil.py; + f1, f12, self.mpolar, self.ppolar = webqtlUtil.ParInfo[self.RISet] + except: + f1 = f12 = self.mpolar = self.ppolar = None + + try: + self.nperm = int(self.nperm) + self.nboot = int(self.nboot) + except: + self.nperm = 2000 #XZ: Rob asked to change the default value to 2000 + self.nboot = 2000 #XZ: Rob asked to change the default value to 2000 + + if self.allstrainlist: + self.allstrainlist = map(string.strip, string.split(self.allstrainlist)) + #self.readGenotype() + #self.readData() + + if self.RISet == 'BXD300': + self.RISet = 'BXD' + else: + pass + + def __str__(self): + rstr = '' + for item in self.attrs: + if item != 'genotype': + rstr += '%s:%s\n' % (item,str(getattr(self,item))) + return rstr + + + def readGenotype(self): + 'read genotype from .geno file' + if self.RISet == 'BXD300': + self.RISet = 'BXD' + else: + pass + assert self.RISet + #genotype_1 is Dataset Object without parents and f1 + #genotype_2 is Dataset Object with parents and f1 (not for intercross) + self.genotype_1 = reaper.Dataset() + self.genotype_1.read(os.path.join(webqtlConfig.GENODIR, self.RISet + '.geno')) + try: + # NL, 07/27/2010. ParInfo has been moved from webqtlForm.py to webqtlUtil.py; + _f1, _f12, _mat, _pat = webqtlUtil.ParInfo[self.RISet] + except: + _f1 = _f12 = _mat = _pat = None + + self.genotype_2 =self.genotype_1 + if self.genotype_1.type == "riset" and _mat and _pat: + self.genotype_2 = self.genotype_1.add(Mat=_mat, Pat=_pat) #, F1=_f1) + + #determine default genotype object + if self.incparentsf1 and self.genotype_1.type != "intercross": + self.genotype = self.genotype_2 + else: + self.incparentsf1 = 0 + self.genotype = self.genotype_1 + self.strainlist = list(self.genotype.prgy) + self.f1list = self.parlist = [] + if _f1 and _f12: + self.f1list = [_f1, _f12] + if _mat and _pat: + self.parlist = [_mat, _pat] + + def readData(self, strainlst=[], incf1=[]): + 'read user input data or from trait data and analysis form' + + if not self.genotype: + self.readGenotype() + if not strainlst: + if incf1: + strainlst = self.f1list + self.strainlist + else: + strainlst = self.strainlist + + + traitfiledata = self.formdata.getfirst('traitfile') + traitpastedata = self.formdata.getfirst('traitpaste') + variancefiledata = self.formdata.getfirst('variancefile') + variancepastedata = self.formdata.getfirst('variancepaste') + Nfiledata = self.formdata.getfirst('Nfile') + + + if traitfiledata: + tt = string.split(traitfiledata) + vals = map(webqtlUtil.StringAsFloat, tt) + elif traitpastedata: + tt = string.split(traitpastedata) + vals = map(webqtlUtil.StringAsFloat, tt) + else: + vals = map(self.FormDataAsFloat, strainlst) + + if len(vals) < len(strainlst): + vals += [None]*(len(strainlst) - len(vals)) + elif len(vals) > len(strainlst): + vals = vals[:len(strainlst)] + else: + pass + + + if variancefiledata: + tt = string.split(variancefiledata) + vars = map(webqtlUtil.StringAsFloat, tt) + elif variancepastedata: + tt = string.split(variancepastedata) + vars = map(webqtlUtil.StringAsFloat, tt) + else: + vars = map(self.FormVarianceAsFloat, strainlst) + + if len(vars) < len(strainlst): + vars += [None]*(len(strainlst) - len(vars)) + elif len(vars) > len(strainlst): + vars = vars[:len(strainlst)] + else: + pass + + if Nfiledata: + tt = string.split(Nfiledata) + nstrains = map(webqtlUtil.IntAsFloat, tt) + if len(nstrains) < len(strainlst): + nstrains += [None]*(len(strainlst) - len(nstrains)) + else: + nstrains = map(self.FormNAsFloat, strainlst) + + ##vals, vars, nstrains is obsolete + self.allTraitData = {} + for i, _strain in enumerate(strainlst): + if vals[i] != None: + self.allTraitData[_strain] = webqtlCaseData(vals[i], vars[i], nstrains[i]) + + + + def informativeStrains(self, strainlst=[], incVars = 0): + '''if readData was called, use this to output the informative strains + (strain with values)''' + if not strainlst: + strainlst = self.strainlist + strains = [] + vals = [] + vars = [] + for _strain in strainlst: + if self.allTraitData.has_key(_strain): + _val, _var = self.allTraitData[_strain].val, self.allTraitData[_strain].var + if _val != None: + if incVars: + if _var != None: + strains.append(_strain) + vals.append(_val) + vars.append(_var) + else: + strains.append(_strain) + vals.append(_val) + vars.append(None) + return strains, vals, vars, len(strains) + + + + def FormDataAsFloat(self, key): + try: + return float(self.formdata.getfirst(key)) + except: + return None + + + def FormVarianceAsFloat(self, key): + try: + return float(self.formdata.getfirst('V' + key)) + except: + return None + + def FormNAsFloat(self, key): + try: + return int(self.formdata.getfirst('N' + key)) + except: + return None + + def Sample(self): + 'Create some dummy data for testing' + self.RISet = 'BXD' + self.incparentsf1 = 'on' + #self.display = 9.2 + #self.significance = 16.1 + self.readGenotype() + self.identification = 'BXD : Coat color example by Lu Lu, et al' + #self.readGenotype() + #self.genotype.ReadMM('AXBXAforQTL') + #self.strainlist = map((lambda x, y='': '%s%s' % (y,x)), self.genotype.prgy) + #self.strainlist.sort() + self.allTraitData = {'BXD29': webqtlCaseData(3), 'BXD28': webqtlCaseData(2), + 'BXD25': webqtlCaseData(2), 'BXD24': webqtlCaseData(2), 'BXD27': webqtlCaseData(2), + 'BXD21': webqtlCaseData(1), 'BXD20': webqtlCaseData(4), 'BXD23': webqtlCaseData(4), + 'BXD22': webqtlCaseData(3), 'BXD14': webqtlCaseData(4), 'BXD15': webqtlCaseData(2), + 'BXD16': webqtlCaseData(3), 'BXD11': webqtlCaseData(4), 'BXD12': webqtlCaseData(3), + 'BXD13': webqtlCaseData(2), 'BXD18': webqtlCaseData(3), 'BXD19': webqtlCaseData(3), + 'BXD38': webqtlCaseData(3), 'BXD39': webqtlCaseData(3), 'BXD36': webqtlCaseData(2), + 'BXD34': webqtlCaseData(4), 'BXD35': webqtlCaseData(4), 'BXD32': webqtlCaseData(4), + 'BXD33': webqtlCaseData(3), 'BXD30': webqtlCaseData(1), 'BXD31': webqtlCaseData(4), + 'DBA/2J': webqtlCaseData(1), 'BXD8': webqtlCaseData(3), 'BXD9': webqtlCaseData(1), + 'BXD6': webqtlCaseData(3), 'BXD5': webqtlCaseData(3), 'BXD2': webqtlCaseData(4), + 'BXD1': webqtlCaseData(1), 'C57BL/6J': webqtlCaseData(4), 'B6D2F1': webqtlCaseData(4), + 'BXD42': webqtlCaseData(4), 'BXD40': webqtlCaseData(3)} + diff --git a/wqflask/base/webqtlTrait.py b/wqflask/base/webqtlTrait.py new file mode 100755 index 00000000..f5051e45 --- /dev/null +++ b/wqflask/base/webqtlTrait.py @@ -0,0 +1,581 @@ +import string + +from htmlgen import HTMLgen2 as HT + +import webqtlConfig +from webqtlCaseData import webqtlCaseData +from webqtlDataset import webqtlDataset +from dbFunction import webqtlDatabaseFunction +from utility import webqtlUtil + + +class webqtlTrait: + """ + Trait class defines a trait in webqtl, can be either Microarray, + Published phenotype, genotype, or user input trait + """ + + def __init__(self, cursor = None, **kw): + self.cursor = cursor + self.db = None # database object + self.name = '' # Trait ID, ProbeSet ID, Published ID, etc. + self.cellid = '' + self.identification = 'un-named trait' + self.riset = '' + self.haveinfo = 0 + self.sequence = '' # Blat sequence, available for ProbeSet + self.data = {} + for name, value in kw.items(): + if self.__dict__.has_key(name): + setattr(self, name, value) + elif name == 'fullname': + name2 = value.split("::") + if len(name2) == 2: + self.db, self.name = name2 + elif len(name2) == 3: + self.db, self.name, self.cellid = name2 + else: + raise KeyError, `value` + ' parameter format error.' + else: + raise KeyError, `name`+' not a valid parameter for this class.' + + if self.db and type(self.db) == type("1"): + assert self.cursor + self.db = webqtlDataset(self.db, self.cursor) + + #if self.db == None, not from a database + if self.db: + if self.db.type == "Temp": + self.cursor.execute(''' + SELECT + InbredSet.Name + FROM + InbredSet, Temp + WHERE + Temp.InbredSetId = InbredSet.Id AND + Temp.Name = "%s" + ''' % self.name) + self.riset = self.cursor.fetchone()[0] + else: + self.riset = self.db.getRISet() + + # + # In ProbeSet, there are maybe several annotations match one sequence + # so we need use sequence(BlatSeq) as the identification, when we update + # one annotation, we update the others who match the sequence also. + # + # Hongqiang Li, 3/3/2008 + # + + #XZ, 05/08/2009: This block is not neccessary. We can add 'BlatSeq' into disfield. + # The variable self.sequence should be changed to self.BlatSeq + # It also should be changed in other places where it are used. + + if self.db: + if self.db.type == 'ProbeSet': + query = ''' + SELECT + ProbeSet.BlatSeq + FROM + ProbeSet, ProbeSetFreeze, ProbeSetXRef + WHERE + ProbeSet.Id=ProbeSetXRef.ProbeSetId and + ProbeSetFreeze.Id = ProbeSetXRef.ProbeSetFreezeId and + ProbeSet.Name = "%s" and + ProbeSetFreeze.Name = "%s" + ''' % (self.name, self.db.name) + self.cursor.execute(query) + self.sequence = self.cursor.fetchone()[0] + + + def getName(self): + str = "" + if self.db and self.name: + str = "%s::%s" % (self.db, self.name) + if self.cellid: + str += "::" + self.cellid + else: + str = self.description + return str + + # + # when user enter a trait or GN generate a trait, user want show the name + # not the name that generated by GN randomly, the two follow function are + # used to give the real name and the database. displayName() will show the + # database also, getGivenName() just show the name. + # For other trait, displayName() as same as getName(), getGivenName() as + # same as self.name + # + # Hongqiang 11/29/07 + # + def getGivenName(self): + str = self.name + if self.db and self.name: + if self.db.type=='Temp': + self.cursor.execute('SELECT description FROM Temp WHERE Name=%s',self.name) + desc = self.cursor.fetchone()[0] + if desc.__contains__('PCA'): + desc = desc[desc.rindex(':')+1:].strip() + else: + desc = desc[:desc.index('entered')].strip() + str = desc + return str + + def displayName(self): + str = "" + if self.db and self.name: + if self.db.type=='Temp': + desc = self.description + if desc.__contains__('PCA'): + desc = desc[desc.rindex(':')+1:].strip() + else: + desc = desc[:desc.index('entered')].strip() + str = "%s::%s" % (self.db, desc) + else: + str = "%s::%s" % (self.db, self.name) + if self.cellid: + str += "::" + self.cellid + else: + str = self.description + + return str + + + #def __str__(self): + # #return "%s %s" % (self.getName(), self.riset) + # return self.getName() + __str__ = getName + __repr__ = __str__ + + def exportData(self, strainlist, type="val"): + """ + export data according to strainlist + mostly used in calculating correlation + """ + result = [] + for strain in strainlist: + if self.data.has_key(strain): + if type=='val': + result.append(self.data[strain].val) + elif type=='var': + result.append(self.data[strain].var) + elif type=='N': + result.append(self.data[strain].N) + else: + raise KeyError, `type`+' type is incorrect.' + else: + result.append(None) + return result + + def exportInformative(self, incVar=0): + """ + export informative strain + mostly used in qtl regression + """ + strains = [] + vals = [] + vars = [] + for strain, value in self.data.items(): + if value.val != None: + if not incVar or value.var != None: + strains.append(strain) + vals.append(value.val) + vars.append(value.var) + return strains, vals, vars + + + # + # In ProbeSet, there are maybe several annotations match one sequence + # so we need use sequence(BlatSeq) as the identification, when we update + # one annotation, we update the others who match the sequence also. + # + # Hongqiang Li, 3/3/2008 + # + def getSequence(self): + assert self.cursor + if self.db.type == 'ProbeSet': + query = ''' + SELECT + ProbeSet.BlatSeq + FROM + ProbeSet, ProbeSetFreeze, ProbeSetXRef + WHERE + ProbeSet.Id=ProbeSetXRef.ProbeSetId and + ProbeSetFreeze.Id = ProbeSetXRef.ProbSetFreezeId and + ProbeSet.Name = %s + ProbeSetFreeze.Name = %s + ''' , (self.name, self.db.name) + self.cursor.execute(query) + results = self.fetchone() + + return results[0] + + + + def retrieveData(self, strainlist=[]): + assert self.db and self.cursor + + if self.db.type == 'Temp': + query = ''' + SELECT + Strain.Name, TempData.value, TempData.SE, TempData.NStrain, TempData.Id + FROM + TempData, Temp, Strain + WHERE + TempData.StrainId = Strain.Id AND + TempData.Id = Temp.DataId AND + Temp.name = '%s' + Order BY + Strain.Name + ''' % self.name + #XZ, 03/02/2009: Xiaodong changed Data to PublishData, SE to PublishSE + elif self.db.type == 'Publish': + query = ''' + SELECT + Strain.Name, PublishData.value, PublishSE.error, NStrain.count, PublishData.Id + FROM + (PublishData, Strain, PublishXRef, PublishFreeze) + left join PublishSE on + (PublishSE.DataId = PublishData.Id AND PublishSE.StrainId = PublishData.StrainId) + left join NStrain on + (NStrain.DataId = PublishData.Id AND + NStrain.StrainId = PublishData.StrainId) + WHERE + PublishXRef.InbredSetId = PublishFreeze.InbredSetId AND + PublishData.Id = PublishXRef.DataId AND PublishXRef.Id = %s AND + PublishFreeze.Id = %d AND PublishData.StrainId = Strain.Id + Order BY + Strain.Name + ''' % (self.name, self.db.id) + + #XZ, 03/02/2009: Xiaodong changed Data to ProbeData, SE to ProbeSE + elif self.cellid: + #Probe Data + query = ''' + SELECT + Strain.Name, ProbeData.value, ProbeSE.error, ProbeData.Id + FROM + (ProbeData, ProbeFreeze, ProbeSetFreeze, ProbeXRef, + Strain, Probe, ProbeSet) + left join ProbeSE on + (ProbeSE.DataId = ProbeData.Id AND ProbeSE.StrainId = ProbeData.StrainId) + WHERE + Probe.Name = '%s' AND ProbeSet.Name = '%s' AND + Probe.ProbeSetId = ProbeSet.Id AND + ProbeXRef.ProbeId = Probe.Id AND + ProbeXRef.ProbeFreezeId = ProbeFreeze.Id AND + ProbeSetFreeze.ProbeFreezeId = ProbeFreeze.Id AND + ProbeSetFreeze.Name = '%s' AND + ProbeXRef.DataId = ProbeData.Id AND + ProbeData.StrainId = Strain.Id + Order BY + Strain.Name + ''' % (self.cellid, self.name, self.db.name) + #XZ, 03/02/2009: Xiaodong added this block for ProbeSetData and ProbeSetSE + elif self.db.type == 'ProbeSet': + #ProbeSet Data + query = ''' + SELECT + Strain.Name, ProbeSetData.value, ProbeSetSE.error, ProbeSetData.Id + FROM + (ProbeSetData, ProbeSetFreeze, Strain, ProbeSet, ProbeSetXRef) + left join ProbeSetSE on + (ProbeSetSE.DataId = ProbeSetData.Id AND ProbeSetSE.StrainId = ProbeSetData.StrainId) + WHERE + ProbeSet.Name = '%s' AND ProbeSetXRef.ProbeSetId = ProbeSet.Id AND + ProbeSetXRef.ProbeSetFreezeId = ProbeSetFreeze.Id AND + ProbeSetFreeze.Name = '%s' AND + ProbeSetXRef.DataId = ProbeSetData.Id AND + ProbeSetData.StrainId = Strain.Id + Order BY + Strain.Name + ''' % (self.name, self.db.name) + #XZ, 03/02/2009: Xiaodong changeded Data to GenoData, SE to GenoSE + else: + #Geno Data + #XZ: The SpeciesId is not necessary, but it's nice to keep it to speed up database search. + query = ''' + SELECT + Strain.Name, GenoData.value, GenoSE.error, GenoData.Id + FROM + (GenoData, GenoFreeze, Strain, Geno, GenoXRef) + left join GenoSE on + (GenoSE.DataId = GenoData.Id AND GenoSE.StrainId = GenoData.StrainId) + WHERE + Geno.SpeciesId = %s AND Geno.Name = '%s' AND GenoXRef.GenoId = Geno.Id AND + GenoXRef.GenoFreezeId = GenoFreeze.Id AND + GenoFreeze.Name = '%s' AND + GenoXRef.DataId = GenoData.Id AND + GenoData.StrainId = Strain.Id + Order BY + Strain.Name + ''' % (webqtlDatabaseFunction.retrieveSpeciesId(self.cursor, self.db.riset), self.name, self.db.name) + + + self.cursor.execute(query) + results = self.cursor.fetchall() + self.data.clear() + if results: + self.mysqlid = results[0][-1] + if strainlist: + for item in results: + if item[0] in strainlist: + val = item[1] + if val != None: + var = item[2] + ndata = None + if self.db.type in ('Publish', 'Temp'): + ndata = item[3] + self.data[item[0]] = webqtlCaseData(val, var, ndata) + #end for + else: + for item in results: + val = item[1] + if val != None: + var = item[2] + ndata = None + if self.db.type in ('Publish', 'Temp'): + ndata = item[3] + self.data[item[0]] = webqtlCaseData(val, var, ndata) + #end for + #end if + else: + pass + + def keys(self): + return self.__dict__.keys() + + def has_key(self, key): + return self.__dict__.has_key(key) + + def items(self): + return self.__dict__.items() + + def retrieveInfo(self, QTL = None): + assert self.db and self.cursor + if self.db.type == 'Publish': + #self.db.DisField = ['Name','PubMed_ID','Phenotype','Abbreviation','Authors','Title',\ + # 'Abstract', 'Journal','Volume','Pages','Month','Year','Sequence',\ + # 'Units', 'comments'] + query = ''' + SELECT + PublishXRef.Id, Publication.PubMed_ID, + Phenotype.Pre_publication_description, Phenotype.Post_publication_description, Phenotype.Original_description, + Phenotype.Pre_publication_abbreviation, Phenotype.Post_publication_abbreviation, + Phenotype.Lab_code, Phenotype.Submitter, Phenotype.Owner, Phenotype.Authorized_Users, + Publication.Authors, Publication.Title, Publication.Abstract, + Publication.Journal, Publication.Volume, Publication.Pages, + Publication.Month, Publication.Year, PublishXRef.Sequence, + Phenotype.Units, PublishXRef.comments + FROM + PublishXRef, Publication, Phenotype, PublishFreeze + WHERE + PublishXRef.Id = %s AND + Phenotype.Id = PublishXRef.PhenotypeId AND + Publication.Id = PublishXRef.PublicationId AND + PublishXRef.InbredSetId = PublishFreeze.InbredSetId AND + PublishFreeze.Id =%s + ''' % (self.name, self.db.id) + #XZ, 05/08/2009: Xiaodong add this block to use ProbeSet.Id to find the probeset instead of just using ProbeSet.Name + #XZ, 05/08/2009: to avoid the problem of same probeset name from different platforms. + elif self.db.type == 'ProbeSet': + disfieldString = string.join(self.db.disfield,',ProbeSet.') + disfieldString = 'ProbeSet.' + disfieldString + query = """ + SELECT %s + FROM ProbeSet, ProbeSetFreeze, ProbeSetXRef + WHERE + ProbeSetXRef.ProbeSetFreezeId = ProbeSetFreeze.Id AND + ProbeSetXRef.ProbeSetId = ProbeSet.Id AND + ProbeSetFreeze.Name = '%s' AND + ProbeSet.Name = '%s' + """ % (disfieldString, self.db.name, self.name) + #XZ, 05/08/2009: We also should use Geno.Id to find marker instead of just using Geno.Name + # to avoid the problem of same marker name from different species. + elif self.db.type == 'Geno': + disfieldString = string.join(self.db.disfield,',Geno.') + disfieldString = 'Geno.' + disfieldString + query = """ + SELECT %s + FROM Geno, GenoFreeze, GenoXRef + WHERE + GenoXRef.GenoFreezeId = GenoFreeze.Id AND + GenoXRef.GenoId = Geno.Id AND + GenoFreeze.Name = '%s' AND + Geno.Name = '%s' + """ % (disfieldString, self.db.name, self.name) + else: #Temp type + query = 'SELECT %s FROM %s WHERE Name = "%s"' % \ + (string.join(self.db.disfield,','), self.db.type, self.name) + + + self.cursor.execute(query) + traitInfo = self.cursor.fetchone() + if traitInfo: + self.haveinfo = 1 + + #XZ: assign SQL query result to trait attributes. + for i, field in enumerate(self.db.disfield): + setattr(self, field, traitInfo[i]) + + if self.db.type == 'Publish': + self.confidential = 0 + if self.pre_publication_description and not self.pubmed_id: + self.confidential = 1 + + self.homologeneid = None + if self.db.type == 'ProbeSet' and self.riset and self.geneid: + #XZ, 05/26/2010: From time to time, this query get error message because some geneid values in database are not number. + #XZ: So I have to test if geneid is number before execute the query. + #XZ: The geneid values in database should be cleaned up. + try: + junk = float(self.geneid) + geneidIsNumber = 1 + except: + geneidIsNumber = 0 + + if geneidIsNumber: + query = """ + SELECT + HomologeneId + FROM + Homologene, Species, InbredSet + WHERE + Homologene.GeneId =%s AND + InbredSet.Name = '%s' AND + InbredSet.SpeciesId = Species.Id AND + Species.TaxonomyId = Homologene.TaxonomyId + """ % (self.geneid, self.riset) + self.cursor.execute(query) + result = self.cursor.fetchone() + else: + result = None + + if result: + self.homologeneid = result[0] + + if QTL: + if self.db.type == 'ProbeSet' and not self.cellid: + query = ''' + SELECT + ProbeSetXRef.Locus, ProbeSetXRef.LRS, ProbeSetXRef.pValue, ProbeSetXRef.mean + FROM + ProbeSetXRef, ProbeSet + WHERE + ProbeSetXRef.ProbeSetId = ProbeSet.Id AND + ProbeSet.Name = "%s" AND + ProbeSetXRef.ProbeSetFreezeId =%s + ''' % (self.name, self.db.id) + self.cursor.execute(query) + traitQTL = self.cursor.fetchone() + if traitQTL: + self.locus, self.lrs, self.pvalue, self.mean = traitQTL + else: + self.locus = self.lrs = self.pvalue = self.mean = "" + if self.db.type == 'Publish': + query = ''' + SELECT + PublishXRef.Locus, PublishXRef.LRS + FROM + PublishXRef, PublishFreeze + WHERE + PublishXRef.Id = %s AND + PublishXRef.InbredSetId = PublishFreeze.InbredSetId AND + PublishFreeze.Id =%s + ''' % (self.name, self.db.id) + self.cursor.execute(query) + traitQTL = self.cursor.fetchone() + if traitQTL: + self.locus, self.lrs = traitQTL + else: + self.locus = self.lrs = "" + else: + raise KeyError, `self.name`+' information is not found in the database.' + + def genHTML(self, formName = "", dispFromDatabase=0, privilege="guest", userName="Guest", authorized_users=""): + if not self.haveinfo: + self.retrieveInfo() + + if self.db.type == 'Publish': + PubMedLink = "" + if self.pubmed_id: + PubMedLink = HT.Href(text="PubMed %d : " % self.pubmed_id, + target = "_blank", url = webqtlConfig.PUBMEDLINK_URL % self.pubmed_id) + else: + PubMedLink = HT.Span("Unpublished : ", Class="fs15") + + if formName: + setDescription2 = HT.Href(url="javascript:showDatabase3('%s','%s','%s','')" % + (formName, self.db.name, self.name), Class = "fs14") + else: + setDescription2 = HT.Href(url="javascript:showDatabase2('%s','%s','')" % + (self.db.name,self.name), Class = "fs14") + + if self.confidential and not webqtlUtil.hasAccessToConfidentialPhenotypeTrait(privilege=privilege, userName=userName, authorized_users=authorized_users): + setDescription2.append('RecordID/%s - %s' % (self.name, self.pre_publication_description)) + else: + setDescription2.append('RecordID/%s - %s' % (self.name, self.post_publication_description)) + + #XZ 03/26/2011: Xiaodong comment out the following two lins as Rob asked. Need to check with Rob why in PublishXRef table, there are few row whose Sequence > 1. + #if self.sequence > 1: + # setDescription2.append(' btach %d' % self.sequence) + if self.authors: + a1 = string.split(self.authors,',')[0] + while a1[0] == '"' or a1[0] == "'" : + a1 = a1[1:] + setDescription2.append(' by ') + setDescription2.append(HT.Italic('%s, and colleagues' % a1)) + setDescription = HT.Span(PubMedLink, setDescription2) + + elif self.db.type == 'Temp': + setDescription = HT.Href(text="%s" % (self.description),url="javascript:showDatabase2\ + ('%s','%s','')" % (self.db.name,self.name), Class = "fs14") + setDescription = HT.Span(setDescription) + + elif self.db.type == 'Geno': # Genome DB only available for single search + if formName: + setDescription = HT.Href(text="Locus %s [Chr %s @ %s Mb]" % (self.name,self.chr,\ + '%2.3f' % self.mb),url="javascript:showDatabase3('%s','%s','%s','')" % \ + (formName, self.db.name, self.name), Class = "fs14") + else: + setDescription = HT.Href(text="Locus %s [Chr %s @ %s Mb]" % (self.name,self.chr,\ + '%2.3f' % self.mb),url="javascript:showDatabase2('%s','%s','')" % \ + (self.db.name,self.name), Class = "fs14") + + setDescription = HT.Span(setDescription) + + else: + if self.cellid: + if formName: + setDescription = HT.Href(text="ProbeSet/%s/%s" % (self.name, self.cellid),url=\ + "javascript:showDatabase3('%s','%s','%s','%s')" % (formName, self.db.name,self.name,self.cellid), \ + Class = "fs14") + else: + setDescription = HT.Href(text="ProbeSet/%s/%s" % (self.name,self.cellid),url=\ + "javascript:showDatabase2('%s','%s','%s')" % (self.db.name,self.name,self.cellid), \ + Class = "fs14") + else: + if formName: + setDescription = HT.Href(text="ProbeSet/%s" % self.name, url=\ + "javascript:showDatabase3('%s','%s','%s','')" % (formName, self.db.name,self.name), \ + Class = "fs14") + else: + setDescription = HT.Href(text="ProbeSet/%s" % self.name, url=\ + "javascript:showDatabase2('%s','%s','')" % (self.db.name,self.name), \ + Class = "fs14") + if self.symbol and self.chr and self.mb: + setDescription.append(' [') + setDescription.append(HT.Italic('%s' % self.symbol,Class="cdg fwb")) + setDescription.append(' on Chr %s @ %s Mb]' % (self.chr,self.mb)) + if self.description: + setDescription.append(': %s' % self.description) + if self.probe_target_description: + setDescription.append('; %s' % self.probe_target_description) + setDescription = HT.Span(setDescription) + + if self.db.type != 'Temp' and dispFromDatabase: + setDescription.append( ' --- FROM : ') + setDescription.append(self.db.genHTML(Class='cori')) + return setDescription + + diff --git a/wqflask/dbFunction/__init__.py b/wqflask/dbFunction/__init__.py new file mode 100755 index 00000000..e69de29b --- /dev/null +++ b/wqflask/dbFunction/__init__.py diff --git a/wqflask/dbFunction/webqtlDatabaseFunction.py b/wqflask/dbFunction/webqtlDatabaseFunction.py new file mode 100755 index 00000000..772e0526 --- /dev/null +++ b/wqflask/dbFunction/webqtlDatabaseFunction.py @@ -0,0 +1,265 @@ +# Copyright (C) University of Tennessee Health Science Center, Memphis, TN. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Affero General Public License for more details. +# +# This program is available from Source Forge: at GeneNetwork Project +# (sourceforge.net/projects/genenetwork/). +# +# 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 +# +# Last updated by Xiaodong Zhou 2011/Jan/20 + +#webqtlDatabaseFunction.py +# +#This file consists of various database related functions; the names are generally self-explanatory. + +import MySQLdb +import string +from base import webqtlConfig + +########################################################################### +#output: cursor instance +#function: connect to database and return cursor instance +########################################################################### +def getCursor(): + try: + con = MySQLdb.Connect(db=webqtlConfig.DB_NAME, host=webqtlConfig.MYSQL_SERVER, user=webqtlConfig.DB_USER, passwd=webqtlConfig.DB_PASSWD) + cursor = con.cursor() + return cursor + except: + return None + + + +########################################################################### +#input: cursor, groupName (string) +#output: mappingMethodId (int) info, value will be Null or else +#function: retrieve mappingMethodId info from InbredSet table +########################################################################### + +def getMappingMethod(cursor=None, groupName=None): + cursor.execute("select MappingMethodId from InbredSet where Name= '%s'" % groupName) + mappingMethodId = cursor.fetchone()[0] + return mappingMethodId + +########################################################################### +#input: cursor, inbredSetId (int), strainId (int) +#output: isMappingId (bull) info, value will be 0,1,2 or else, 0 or Null means +# "can not do mapping", >0 means "can do mapping", >1 means "there exsists +# redundant data, user needs to choose one to do mapping function" +#function: retrieve isMappingId info from StrainXRef table +########################################################################### + +def isMapping(cursor=None, inbredSetId=None, strainId=None): + cursor.execute("select IsMapping from StrainXRef where InbredSetId='%d' and StrainId = '%d'" %(inbredSetId, strainId)) + isMappingId = cursor.fetchone()[0] + return isMappingId + +########################################################################### +#input: cursor, groupName (string) +#output: all species data info (array), value will be Null or else +#function: retrieve all species info from Species table +########################################################################### + +def getAllSpecies(cursor=None): + cursor.execute("select Id, Name, MenuName, FullName, TaxonomyId,OrderId from Species Order by OrderId") + allSpecies = cursor.fetchall() + return allSpecies + +########################################################################### +#input: cursor, RISet (string) +#output: specie's name (string), value will be None or else +#function: retrieve specie's name info based on RISet +########################################################################### + +def retrieveSpecies(cursor=None, RISet=None): + try: + cursor.execute("select Species.Name from Species, InbredSet where InbredSet.Name = '%s' and InbredSet.SpeciesId = Species.Id" % RISet) + return cursor.fetchone()[0] + except: + return None + +########################################################################### +#input: cursor, RISet (string) +#output: specie's Id (string), value will be None or else +#function: retrieve specie's Id info based on RISet +########################################################################### + +def retrieveSpeciesId(cursor=None, RISet=None): + try: + cursor.execute("select SpeciesId from InbredSet where Name = '%s'" % RISet) + return cursor.fetchone()[0] + except: + return None + +########################################################################### +# input: cursor +# output: tissProbeSetFreezeIdList (list), +# nameList (list), +# fullNameList (list) +# function: retrieve all TissueProbeSetFreezeId,Name,FullName info +# from TissueProbeSetFreeze table. +# These data will listed in the dropdown menu in the first page of Tissue Correlation +########################################################################### + +def getTissueDataSet(cursor=None): + tissProbeSetFreezeIdList=[] + nameList =[] + fullNameList = [] + + query = "select Id,Name,FullName from TissueProbeSetFreeze; " + try: + cursor.execute(query) + result = cursor.fetchall() + + for row in result: + tissProbeSetFreezeIdList.append(row[0]) + nameList.append(row[1]) + fullNameList.append(row[2]) + except: + return None + + return tissProbeSetFreezeIdList,nameList,fullNameList + +########################################################################### +# input: cursor,GeneSymbol (string), and TissueProbeSetFreezeId (string) +# output: geneId (string), dataId (string) +# function: retrieve geneId and DataId from TissueProbeSetXRef table +########################################################################### + +def getGeneIdDataIdForTissueBySymbol(cursor=None, GeneSymbol=None, TissueProbeSetFreezeId= 0): + query ="select GeneId, DataId from TissueProbeSetXRef where Symbol = '%s' and TissueProbeSetFreezeId=%s order by Mean desc" %(GeneSymbol,TissueProbeSetFreezeId) + try: + cursor.execute(query) + result = cursor.fetchone() + geneId = result[0] + dataId = result[1] + except: + geneId = 0 + dataId = 0 + + return geneId,dataId + +########################################################################### +# input: cursor, TissueProbeSetFreezeId (int) +# output: chipId (int) +# function: retrieve chipId from TissueProbeFreeze table +########################################################################### + +def getChipIdByTissueProbeSetFreezeId(cursor=None, TissueProbeSetFreezeId=None): + query = "select TissueProbeFreezeId from TissueProbeSetFreeze where Id =%s" % TissueProbeSetFreezeId + try: + cursor.execute(query) + result = cursor.fetchone() + TissueProbeFreezeId = result[0] + except: + TissueProbeFreezeId =0 + + query1 = "select ChipId from TissueProbeFreeze where Id =%s" % TissueProbeFreezeId + try: + cursor.execute(query1) + result1 = cursor.fetchone() + chipId = result1[0] + except: + chipId =0 + + return chipId + +########################################################################### +# input: cursor, TissueProbeSetFreezeId (int) +# output: TissueCount (int) +# function: retrieve how many tissue used in the specific dataset based on TissueProbeSetFreezeId +########################################################################### +def getTissueCountByTissueProbeSetFreezeId(cursor=None, TissueProbeSetFreezeId=None): + query1 ="select DataId from TissueProbeSetXRef where TissueProbeSetFreezeId =%s limit 1" % TissueProbeSetFreezeId + try: + cursor.execute(query1) + result1 = cursor.fetchone() + DataId = result1[0] + + query2 =" select count(*) from TissueProbeSetData where Id=%s" % DataId + try: + cursor.execute(query2) + result2 = cursor.fetchone() + TissueCount = result2[0] + except: + TissueCount =0 + except: + TissueCount =0 + + return TissueCount + +########################################################################### +# input: cursor, TissueProbeSetFreezeId (int) +# output: DatasetName(string),DatasetFullName(string) +# function: retrieve DatasetName, DatasetFullName based on TissueProbeSetFreezeId +########################################################################### +def getDatasetNamesByTissueProbeSetFreezeId(cursor=None, TissueProbeSetFreezeId=None): + query ="select Name, FullName from TissueProbeSetFreeze where Id=%s" % TissueProbeSetFreezeId + try: + cursor.execute(query) + result = cursor.fetchone() + DatasetName = result[0] + DatasetFullName =result[1] + except: + DatasetName =None + DatasetFullName =None + + return DatasetName, DatasetFullName + +########################################################################### +# input: cursor, geneIdLst (list) +# output: geneIdSymbolPair(dict),key is geneId, value is geneSymbol +# function: retrieve GeneId, GeneSymbol based on geneId List +########################################################################### +def getGeneIdSymbolPairByGeneId(cursor=None, geneIdLst =None): + geneIdSymbolPair={} + for geneId in geneIdLst: + geneIdSymbolPair[geneId]=None + + query ="select GeneId,GeneSymbol from GeneList where GeneId in (%s)" % string.join(geneIdLst, ", ") + try: + cursor.execute(query) + results = cursor.fetchall() + for item in results: + geneId =item[0] + geneSymbol =item[1] + geneIdSymbolPair[geneId]=geneSymbol + except: + geneIdSymbolPair=None + + return geneIdSymbolPair + + +def updateTissueProbesetXRefByProbesetId(cursor=None, probesetId=None): + query ="select Symbol,GeneId,Chr,Mb,description, Probe_Target_Description from ProbeSet where Id =%s"%probesetId + try: + cursor.execute(query) + result =cursor.fetchone() + + updateQuery =''' + Update TissueProbeSetXRef + Set Symbol='%s',GeneId='%s', Chr='%s', Mb='%s', description ='%s',Probe_Target_Description='%s' + where ProbesetId=%s + '''%(result[0],result[1],result[2],result[3],result[4],result[5],probesetId) + + cursor.execute(updateQuery) + + except: + return None +
\ No newline at end of file diff --git a/wqflask/htmlgen.py b/wqflask/htmlgen.py new file mode 100644 index 00000000..8406d925 --- /dev/null +++ b/wqflask/htmlgen.py @@ -0,0 +1,14 @@ +from __future__ import absolute_import, division, print_function + +class HTMLgen(object): + """A redefined HT until we manage to completely eliminate it""" + def __getattr__(self, name): + return "" + + def Item(self, *args, **kw): + print("This way of generating html is obsolete!") + return "foo" + + Href = Span = TD = Blockquote = Image = Item + +HTMLgen2 = HTMLgen() diff --git a/wqflask/requirements.txt b/wqflask/requirements.txt new file mode 100644 index 00000000..caa5d61e --- /dev/null +++ b/wqflask/requirements.txt @@ -0,0 +1,6 @@ +Flask==0.8 +Jinja2==2.6 +MySQL-python==1.2.3 +Werkzeug==0.8.3 +pyXLWriter==0.4a3 +wsgiref==0.1.2 diff --git a/wqflask/runserver.py b/wqflask/runserver.py new file mode 100644 index 00000000..bf73ed37 --- /dev/null +++ b/wqflask/runserver.py @@ -0,0 +1,15 @@ +from wqflask import app + +# Please note, running with host set externally below combined with debug mode +# is a big security no-no +# Unless you have a firewall setup +# +# Something like /sbin/iptables -A INPUT -p tcp -i eth0 -s ! 71.236.239.43 --dport 5000 -j DROP +# should do the trick +# +# You'll probably have to firewall the main port and the +# +# For more info see: http://www.cyberciti.biz/faq/iptables-block-port/ + + +app.run(host='0.0.0.0') diff --git a/wqflask/utility/AJAX_table.py b/wqflask/utility/AJAX_table.py new file mode 100755 index 00000000..963a530e --- /dev/null +++ b/wqflask/utility/AJAX_table.py @@ -0,0 +1,153 @@ +# Copyright (C) University of Tennessee Health Science Center, Memphis, TN. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Affero General Public License for more details. +# +# This program is available from Source Forge: at GeneNetwork Project +# (sourceforge.net/projects/genenetwork/). +# +# 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 +# +# Last updated by GeneNetwork Core Team 2010/10/20 + +import cPickle +import os +import MySQLdb +import time +import pyXLWriter as xl + +from htmlgen import HTMLgen2 as HT + +from base import webqtlConfig +from THCell import THCell +from TDCell import TDCell +import webqtlUtil + + +class AJAX_table: + def __init__(self, fd): + file = fd.formdata.getfirst("file", "") + sort = fd.formdata.getfirst("sort", "") + order = fd.formdata.getfirst("order", "up") + cmd = fd.formdata.getfirst("cmd", "") + tableID = fd.formdata.getfirst("tableID", "") + addIndex = fd.formdata.getfirst("addIndex", "1") + hiddenColumnsString = fd.formdata.getfirst("hiddenColumns", "") + hiddenColumns = hiddenColumnsString.split(',') + + try: + fp = open(os.path.join(webqtlConfig.TMPDIR, file + '.obj'), 'rb') + tblobj = cPickle.load(fp) + fp.close() + + if cmd == 'addCorr': + dbId = int(fd.formdata.getfirst("db")) + dbFullName = fd.formdata.getfirst("dbname") + trait = fd.formdata.getfirst("trait") + form = fd.formdata.getfirst("form") + ids = fd.formdata.getfirst("ids") + vals = fd.formdata.getfirst("vals") + ids = eval(ids) + nnCorr = len(ids) + vals = eval(vals) + + workbook = xl.Writer('%s.xls' % (webqtlConfig.TMPDIR+file)) + worksheet = workbook.add_worksheet() + + con = MySQLdb.Connect(db=webqtlConfig.DB_NAME,host=webqtlConfig.MYSQL_SERVER, user=webqtlConfig.DB_USER,passwd=webqtlConfig.DB_PASSWD) + cursor = con.cursor() + + cursor.execute("Select name, ShortName from ProbeSetFreeze where Id = %s", dbId) + dbName, dbShortName = cursor.fetchone() + + tblobj['header'][0].append( + THCell(HT.TD(dbShortName, Class="fs11 ffl b1 cw cbrb"), + text="%s" % dbShortName, idx=tblobj['header'][0][-1].idx + 1), + ) + + headingStyle = workbook.add_format(align = 'center', bold = 1, border = 1, size=13, fg_color = 0x1E, color="white") + for i, item in enumerate(tblobj['header'][0]): + if (i > 0): + worksheet.write([8, i-1], item.text, headingStyle) + worksheet.set_column([i-1, i-1], 2*len(item.text)) + + for i, row in enumerate(tblobj['body']): + ProbeSetId = row[1].text + #XZ, 03/02/2009: Xiaodong changed Data to ProbeSetData + cursor.execute(""" + Select ProbeSetData.StrainId, ProbeSetData.Value + From ProbeSetData, ProbeSetXRef, ProbeSet + where ProbeSetXRef.ProbeSetFreezeId = %d AND + ProbeSetXRef.DataId = ProbeSetData.Id AND + ProbeSetXRef.ProbeSetId = ProbeSet.Id AND + ProbeSet.Name = '%s' + """ % (dbId, ProbeSetId)) + results = cursor.fetchall() + vdict = {} + for item in results: + vdict[item[0]] = item[1] + newvals = [] + for id in ids: + if vdict.has_key(id): + newvals.append(vdict[id]) + else: + newvals.append(None) + corr,nOverlap= webqtlUtil.calCorrelation(newvals,vals,nnCorr) + repr = '%0.4f' % corr + row.append( + TDCell(HT.TD(HT.Href(text=repr, url="javascript:showCorrPlotThird('%s', '%s', '%s')" % (form, dbName, ProbeSetId), Class="fs11 fwn ffl"), " / ", nOverlap, Class="fs11 fwn ffl b1 c222", align="middle"),repr,abs(corr)) + ) + + last_row=0 + for j, item in enumerate(tblobj['body'][i]): + if (j > 0): + worksheet.write([9+i, j-1], item.text) + last_row = 9+i + last_row += 1 + + titleStyle = workbook.add_format(align = 'left', bold = 0, size=14, border = 1, border_color="gray") + ##Write title Info + # Modified by Hongqiang Li + worksheet.write([0, 0], "Citations: Please see %s/reference.html" % webqtlConfig.PORTADDR, titleStyle) + worksheet.write([1, 0], "Trait : %s" % trait, titleStyle) + worksheet.write([2, 0], "Database : %s" % dbFullName, titleStyle) + worksheet.write([3, 0], "Date : %s" % time.strftime("%B %d, %Y", time.gmtime()), titleStyle) + worksheet.write([4, 0], "Time : %s GMT" % time.strftime("%H:%M ", time.gmtime()), titleStyle) + worksheet.write([5, 0], "Status of data ownership: Possibly unpublished data; please see %s/statusandContact.html for details on sources, ownership, and usage of these data." % webqtlConfig.PORTADDR, titleStyle) + #Write footer info + worksheet.write([1 + last_row, 0], "Funding for The GeneNetwork: NIAAA (U01AA13499, U24AA13513), NIDA, NIMH, and NIAAA (P20-DA21131), NCI MMHCC (U01CA105417), and NCRR (U01NR 105417)", titleStyle) + worksheet.write([2 + last_row, 0], "PLEASE RETAIN DATA SOURCE INFORMATION WHENEVER POSSIBLE", titleStyle) + + cursor.close() + workbook.close() + + objfile = open(os.path.join(webqtlConfig.TMPDIR, file + '.obj'), 'wb') + cPickle.dump(tblobj, objfile) + objfile.close() + else: + pass + + self.value = str(webqtlUtil.genTableObj(tblobj=tblobj, file=file, sortby=(sort, order), tableID = tableID, addIndex = addIndex, hiddenColumns = hiddenColumns)) + + except: + self.value = "<span class='fs16 fwb cr ffl'>The table is no longer available on this server</span>" + + def __str__(self): + return self.value + + def write(self): + return str(self) diff --git a/wqflask/utility/Plot.py b/wqflask/utility/Plot.py new file mode 100755 index 00000000..2401c85c --- /dev/null +++ b/wqflask/utility/Plot.py @@ -0,0 +1,1283 @@ +# Copyright (C) University of Tennessee Health Science Center, Memphis, TN. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Affero General Public License for more details. +# +# This program is available from Source Forge: at GeneNetwork Project +# (sourceforge.net/projects/genenetwork/). +# +# 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 +# +# Last updated by GeneNetwork Core Team 2010/10/20 + +import piddle as pid +from math import * +import random +import sys, os +from numarray import linear_algebra as la +from numarray import ones, array, dot, swapaxes + +import reaper + +import svg +import webqtlUtil +from base import webqtlConfig + + +def cformat(d, rank=0): + 'custom string format' + strD = "%2.6f" % d + + if rank == 0: + while strD[-1] in ('0','.'): + if strD[-1] == '0' and strD[-2] == '.' and len(strD) <= 4: + break + elif strD[-1] == '.': + strD = strD[:-1] + break + else: + strD = strD[:-1] + + else: + strD = strD.split(".")[0] + + if strD == '-0.0': + strD = '0.0' + return strD + +def frange(start, end=None, inc=1.0): + "A faster range-like function that does accept float increments..." + if end == None: + end = start + 0.0 + start = 0.0 + else: + start += 0.0 # force it to be a float + count = int((end - start) / inc) + if start + count * inc != end: + # Need to adjust the count. AFAICT, it always comes up one short. + count += 1 + L = [start] * count + for i in xrange(1, count): + L[i] = start + i * inc + return L + + +def gammln(xx): + cof=[76.18009173,-86.50532033,24.01409822,-1.231739516,0.120858003e-2,-0.536382e-5] + x=xx-1.0 + tmp=x+5.5 + tmp -=(x+0.5)*log(tmp) + ser=1.0 + for item in cof: + x+=1.0 + ser+=item/x + + return -tmp+log(2.50662827465*ser) + + +def gser(a,x): + gln=gammln(a) + ITMAX=100 + EPS=3.0e-7 + + if x<=0.0: + gamser=0.0 + return [gamser,gln] + else: + ap=a + sum=1.0/a + dele=sum + for i in range(1,ITMAX+1): + ap+=1.0 + dele*=x/ap + sum+=dele + if abs(dele)<abs(sum)*EPS: + gamser=sum*exp(-x+a*log(x)-gln) + return [gamser,gln] + return None + +def gcf(a,x): + ITMAX=100 + EPS=3.0e-7 + gold=0.0 + fac=1 + b1=1.0 + b0=0.0 + a0=1.0 + gln=gammln(a) + + a1=x + for n in range(1,ITMAX+1): + an=n+0.0 + ana=an-a + a0=(a1+a0*ana)*fac + b0=(b1+b0*ana)*fac + anf=an*fac + a1=x*a0+anf*a1 + b1=x*b0+anf*b1 + if (a1): + fac=1.0/a1 + g=b1*fac + if abs((g-gold)/g)<EPS: + gammcf=exp(-x+a*log(x)-gln)*g + return [gammcf,gln] + gold=g + return None + +def gammp(a,x): + if x<0.0 or a<=0.0: + return None + if x<(a+1.0): + a=gser(a,x)[0] + return a + else: + a=gcf(a,x)[0] + return 1.0-a +def U(n): + x=pow(0.5,1.0/n) + m=[1-x] + for i in range(2,n): + a=(i-0.3175)/(n+0.365) + m.append(a) + m.append(x) + return m + +def erf(x): + if x<0.0: + return -gammp(0.5,x*x) + else: + return gammp(0.5,x*x) + +def erfcc(x): + z=abs(x) + t=1.0/(1.0+0.5*z) + ans=t*exp(-z*z-1.26551223+t*(1.00002368+t*(0.37409196+t*(0.09678418+t*(-0.18628806+t*(0.27886807+t*(-1.13520398+t*(1.48851587+t*(-0.82215223+t*0.17087277))))))))) + if x>=0.0: + return ans + else: + return 2.0-ans + +def calMeanVar(data): + n=len(data) + if n<2: + return None + else: + sum=reduce(lambda x,y:x+y,data,0.0) + mean=sum/n + z=data[:] + for i in range(n): + z[i]=z[i]-mean + variance=reduce(lambda x,y:x+y*y,z,0.0) + variance /= n-1 + variance =sqrt(variance) + for i in range(n): + z[i]=z[i]/variance + return z + +def inverseCumul(p): + #Coefficients in rational approximations. + a = [-3.969683028665376e+01,2.209460984245205e+02,-2.759285104469687e+02,1.383577518672690e+02,-3.066479806614716e+01,2.506628277459239e+00] + + b = [-5.447609879822406e+01,1.615858368580409e+02,-1.556989798598866e+02,6.680131188771972e+01,-1.328068155288572e+01] + + c = [-7.784894002430293e-03,-3.223964580411365e-01,-2.400758277161838e+00,-2.549732539343734e+00,4.374664141464968e+00,2.938163982698783e+00] + + d = [7.784695709041462e-03,3.224671290700398e-01,2.445134137142996e+00,3.754408661907416e+00] + + #Define break-points. + + p_low = 0.02425 + p_high = 1 - p_low + + #Rational approximation for lower region. + + if p > 0 and p < p_low: + q = sqrt(-2*log(p)) + x = (((((c[0]*q+c[1])*q+c[2])*q+c[3])*q+c[4])*q+c[5]) / ((((d[0]*q+d[1])*q+d[2])*q+d[3])*q+1) + + + #Rational approximation for central region. + + elif p>= p_low and p <= p_high: + q = p - 0.5 + r = q*q + x = (((((a[0]*r+a[1])*r+a[2])*r+a[3])*r+a[4])*r+a[5])*q /(((((b[0]*r+b[1])*r+b[2])*r+b[3])*r+b[4])*r+1) + + #Rational approximation for upper region. + + elif p>p_high and p < 1: + q = sqrt(-2*log(1-p)) + x = -(((((c[0]*q+c[1])*q+c[2])*q+c[3])*q+c[4])*q+c[5]) /((((d[0]*q+d[1])*q+d[2])*q+d[3])*q+1) + + else: + return None + + if p>0 and p < 1: + e = 0.5 * erfcc(-x/sqrt(2)) - p + u = e * sqrt(2*pi) * exp(x*x/2) + x = x - u/(1 + x*u/2) + return x + else: + return None + +def gmean(lst): + N = len(lst) + if N == 0: + return 0 + else: + return (reduce(lambda x,y: x+y, lst, 0.0))/N + +def gmedian(lst2): + lst = lst2[:] + N = len(lst) + if N == 0: + return 0 + else: + lst.sort() + if N % 2 == 0: + return (lst[N/2]+lst[(N-2)/2])/2.0 + else: + return lst[(N-1)/2] + +def gpercentile(lst2, np): + lst = lst2[:] + N = len(lst) + if N == 0 or np > 100 or np < 0: + return None + else: + lst.sort() + pNadd1 = (np/100.0)*N + k = int(pNadd1) + d = pNadd1 - k + if k == 0: + return lst[0] + elif k >= N-1: + return lst[N-1] + else: + return lst[k-1] + d*(lst[k] - lst[k-1]) + +def findOutliers(vals): + + valsOnly = [] + dataXZ = vals[:] + for i in range(len(dataXZ)): + valsOnly.append(dataXZ[i][1]) + + data = [('', valsOnly[:])] + + for item in data: + itemvalue = item[1] + nValue = len(itemvalue) + catValue = [] + + for item2 in itemvalue: + try: + tstrain, tvalue = item2 + except: + tvalue = item2 + if nValue <= 4: + continue + else: + catValue.append(tvalue) + + if catValue != []: + lowHinge = gpercentile(catValue, 25) + upHinge = gpercentile(catValue, 75) + Hstep = 1.5*(upHinge - lowHinge) + + outlier = [] + extreme = [] + + upperBound = upHinge + Hstep + lowerBound = lowHinge - Hstep + + for item in catValue: + if item >= upHinge + 2*Hstep: + extreme.append(item) + elif item >= upHinge + Hstep: + outlier.append(item) + else: + pass + + for item in catValue: + if item <= lowHinge - 2*Hstep: + extreme.append(item) + elif item <= lowHinge - Hstep: + outlier.append(item) + else: + pass + else: + upperBound = 1000 + lowerBound = -1000 + + return upperBound, lowerBound + + +def plotBoxPlot(canvas, data, offset= (40, 40, 40, 40), XLabel="Category", YLabel="Value"): + xLeftOffset, xRightOffset, yTopOffset, yBottomOffset = offset + plotWidth = canvas.size[0] - xLeftOffset - xRightOffset + plotHeight = canvas.size[1] - yTopOffset - yBottomOffset + iValues = [] + for item in data: + for item2 in item[1]: + try: + iValues.append(item2[1]) + except: + iValues.append(item2) + + #draw frame + max_Y = max(iValues) + min_Y = min(iValues) + scaleY = detScale(min_Y, max_Y) + Yll = scaleY[0] + Yur = scaleY[1] + nStep = scaleY[2] + stepY = (Yur - Yll)/nStep + stepYPixel = plotHeight/(nStep) + canvas.drawRect(plotWidth+xLeftOffset, plotHeight + yTopOffset, xLeftOffset, yTopOffset) + + ##draw Y Scale + YYY = Yll + YCoord = plotHeight + yTopOffset + scaleFont=pid.Font(ttf="cour",size=11,bold=1) + for i in range(nStep+1): + strY = cformat(d=YYY, rank=0) + YCoord = max(YCoord, yTopOffset) + canvas.drawLine(xLeftOffset,YCoord,xLeftOffset-5,YCoord) + canvas.drawString(strY, xLeftOffset -30,YCoord +5,font=scaleFont) + YYY += stepY + YCoord -= stepYPixel + + ##draw X Scale + stepX = plotWidth/len(data) + XCoord = xLeftOffset + 0.5*stepX + YCoord = plotHeight + yTopOffset + scaleFont = pid.Font(ttf="tahoma",size=12,bold=0) + labelFont = pid.Font(ttf="tahoma",size=13,bold=0) + for item in data: + itemname, itemvalue = item + canvas.drawLine(XCoord, YCoord,XCoord, YCoord+5, color=pid.black) + canvas.drawString(itemname, XCoord - canvas.stringWidth(itemname,font=labelFont)/2.0,\ + YCoord +20,font=labelFont) + + nValue = len(itemvalue) + catValue = [] + for item2 in itemvalue: + try: + tstrain, tvalue = item2 + except: + tvalue = item2 + if nValue <= 4: + canvas.drawCross(XCoord, plotHeight + yTopOffset - (tvalue-Yll)*plotHeight/(Yur - Yll), color=pid.red,size=5) + else: + catValue.append(tvalue) + if catValue != []: + catMean = gmean(catValue) + catMedian = gmedian(catValue) + lowHinge = gpercentile(catValue, 25) + upHinge = gpercentile(catValue, 75) + Hstep = 1.5*(upHinge - lowHinge) + + outlier = [] + extrem = [] + + upperAdj = None + for item in catValue: + if item >= upHinge + 2*Hstep: + extrem.append(item) + elif item >= upHinge + Hstep: + outlier.append(item) + elif item > upHinge and item < upHinge + Hstep: + if upperAdj == None or item > upperAdj: + upperAdj = item + else: + pass + lowerAdj = None + for item in catValue: + if item <= lowHinge - 2*Hstep: + extrem.append(item) + elif item <= lowHinge - Hstep: + outlier.append(item) + if item < lowHinge and item > lowHinge - Hstep: + if lowerAdj == None or item < lowerAdj: + lowerAdj = item + else: + pass + canvas.drawRect(XCoord-20, plotHeight + yTopOffset - (lowHinge-Yll)*plotHeight/(Yur - Yll), \ + XCoord+20, plotHeight + yTopOffset - (upHinge-Yll)*plotHeight/(Yur - Yll)) + canvas.drawLine(XCoord-20, plotHeight + yTopOffset - (catMedian-Yll)*plotHeight/(Yur - Yll), \ + XCoord+20, plotHeight + yTopOffset - (catMedian-Yll)*plotHeight/(Yur - Yll)) + if upperAdj != None: + canvas.drawLine(XCoord, plotHeight + yTopOffset - (upHinge-Yll)*plotHeight/(Yur - Yll), \ + XCoord, plotHeight + yTopOffset - (upperAdj-Yll)*plotHeight/(Yur - Yll)) + canvas.drawLine(XCoord-20, plotHeight + yTopOffset - (upperAdj-Yll)*plotHeight/(Yur - Yll), \ + XCoord+20, plotHeight + yTopOffset - (upperAdj-Yll)*plotHeight/(Yur - Yll)) + if lowerAdj != None: + canvas.drawLine(XCoord, plotHeight + yTopOffset - (lowHinge-Yll)*plotHeight/(Yur - Yll), \ + XCoord, plotHeight + yTopOffset - (lowerAdj-Yll)*plotHeight/(Yur - Yll)) + canvas.drawLine(XCoord-20, plotHeight + yTopOffset - (lowerAdj-Yll)*plotHeight/(Yur - Yll), \ + XCoord+20, plotHeight + yTopOffset - (lowerAdj-Yll)*plotHeight/(Yur - Yll)) + + outlierFont = pid.Font(ttf="cour",size=12,bold=0) + if outlier != []: + for item in outlier: + yc = plotHeight + yTopOffset - (item-Yll)*plotHeight/(Yur - Yll) + #canvas.drawEllipse(XCoord-3, yc-3, XCoord+3, yc+3) + canvas.drawString('o', XCoord-3, yc+5, font=outlierFont, color=pid.orange) + if extrem != []: + for item in extrem: + yc = plotHeight + yTopOffset - (item-Yll)*plotHeight/(Yur - Yll) + #canvas.drawEllipse(XCoord-3, yc-3, XCoord+3, yc+3) + canvas.drawString('*', XCoord-3, yc+6, font=outlierFont, color=pid.red) + + canvas.drawCross(XCoord, plotHeight + yTopOffset - (catMean-Yll)*plotHeight/(Yur - Yll), \ + color=pid.blue,size=3) + #print (catMean, catMedian, cat25per, cat75per) + pass + + XCoord += stepX + + labelFont=pid.Font(ttf="verdana",size=18,bold=0) + canvas.drawString(XLabel, xLeftOffset + (plotWidth -canvas.stringWidth(XLabel,font=labelFont))/2.0, \ + YCoord +40, font=labelFont) + canvas.drawString(YLabel,xLeftOffset-40, YCoord-(plotHeight -canvas.stringWidth(YLabel,font=labelFont))/2.0,\ + font=labelFont, angle =90) + +def plotSecurity(canvas, text="12345"): + if not text: + return + + plotWidth = canvas.size[0] + plotHeight = canvas.size[1] + if plotHeight<=0 or plotWidth<=0: + return + + bgColor = pid.Color(0.6+0.4*random.random(), 0.6+0.4*random.random(), 0.6+0.4*random.random()) + canvas.drawRect(0,0,plotWidth,plotHeight, edgeColor=bgColor, fillColor=bgColor) + + for i in range(30): + randomColor = pid.Color(0.6+0.4*random.random(), 0.6+0.4*random.random(), 0.6+0.4*random.random()) + scaleFont=pid.Font(ttf="cour",size=random.choice(range(20, 50))) + canvas.drawString(random.choice('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), + int(random.random()*plotWidth), int(random.random()*plotHeight), font=scaleFont, + color=randomColor, angle=random.choice(range(-45, 50))) + + step = (plotWidth-20)/len(text) + startX = 20 + for item in text: + randomColor = pid.Color(0.6*random.random(),0.6*random.random(), 0.6*random.random()) + scaleFont=pid.Font(ttf="verdana",size=random.choice(range(50, 60)),bold=1) + canvas.drawString(item, startX, plotHeight/2-10, font=scaleFont, + color=randomColor, angle=random.choice(range(-45, 50))) + startX += step + +# parameter: data is either object returned by reaper permutation function (called by MarkerRegressionPage.py) +# or the first object returned by direct (pair-scan) permu function (called by DirectPlotPage.py) +def plotBar(canvas, data, barColor=pid.blue, axesColor=pid.black, labelColor=pid.black, XLabel=None, YLabel=None, title=None, offset= (60, 20, 40, 40), zoom = 1): + + xLeftOffset, xRightOffset, yTopOffset, yBottomOffset = offset + + plotWidth = canvas.size[0] - xLeftOffset - xRightOffset + plotHeight = canvas.size[1] - yTopOffset - yBottomOffset + if plotHeight<=0 or plotWidth<=0: + return + + if len(data) < 2: + return + + max_D = max(data) + min_D = min(data) + #add by NL 06-20-2011: fix the error: when max_D is infinite, log function in detScale will go wrong + if max_D == float('inf') or max_D>webqtlConfig.MAXLRS: + max_D=webqtlConfig.MAXLRS #maximum LRS value + + xLow, xTop, stepX = detScale(min_D, max_D) + + #reduce data + step = ceil((xTop-xLow)/50.0) + j = xLow + dataXY = [] + Count = [] + while j <= xTop: + dataXY.append(j) + Count.append(0) + j += step + + for i, item in enumerate(data): + if item == float('inf') or item>webqtlConfig.MAXLRS: + item = webqtlConfig.MAXLRS #maximum LRS value + j = int((item-xLow)/step) + Count[j] += 1 + + yLow, yTop, stepY=detScale(0,max(Count)) + + #draw data + xScale = plotWidth/(xTop-xLow) + yScale = plotHeight/(yTop-yLow) + barWidth = xScale*step + + for i, count in enumerate(Count): + if count: + xc = (dataXY[i]-xLow)*xScale+xLeftOffset + yc =-(count-yLow)*yScale+yTopOffset+plotHeight + canvas.drawRect(xc+2,yc,xc+barWidth-2,yTopOffset+plotHeight,edgeColor=barColor,fillColor=barColor) + + #draw drawing region + canvas.drawRect(xLeftOffset, yTopOffset, xLeftOffset+plotWidth, yTopOffset+plotHeight) + + #draw scale + scaleFont=pid.Font(ttf="cour",size=11,bold=1) + x=xLow + for i in range(stepX+1): + xc=xLeftOffset+(x-xLow)*xScale + canvas.drawLine(xc,yTopOffset+plotHeight,xc,yTopOffset+plotHeight+5, color=axesColor) + strX = cformat(d=x, rank=0) + canvas.drawString(strX,xc-canvas.stringWidth(strX,font=scaleFont)/2,yTopOffset+plotHeight+14,font=scaleFont) + x+= (xTop - xLow)/stepX + + y=yLow + for i in range(stepY+1): + yc=yTopOffset+plotHeight-(y-yLow)*yScale + canvas.drawLine(xLeftOffset,yc,xLeftOffset-5,yc, color=axesColor) + strY = "%d" %y + canvas.drawString(strY,xLeftOffset-canvas.stringWidth(strY,font=scaleFont)-6,yc+5,font=scaleFont) + y+= (yTop - yLow)/stepY + + #draw label + labelFont=pid.Font(ttf="tahoma",size=17,bold=0) + if XLabel: + canvas.drawString(XLabel,xLeftOffset+(plotWidth-canvas.stringWidth(XLabel,font=labelFont))/2.0, + yTopOffset+plotHeight+yBottomOffset-10,font=labelFont,color=labelColor) + + if YLabel: + canvas.drawString(YLabel, 19, yTopOffset+plotHeight-(plotHeight-canvas.stringWidth(YLabel,font=labelFont))/2.0, + font=labelFont,color=labelColor,angle=90) + + labelFont=pid.Font(ttf="verdana",size=16,bold=0) + if title: + canvas.drawString(title,xLeftOffset+(plotWidth-canvas.stringWidth(title,font=labelFont))/2.0, + 20,font=labelFont,color=labelColor) + +def plotBarText(canvas, data, label, variance=None, barColor=pid.blue, axesColor=pid.black, labelColor=pid.black, XLabel=None, YLabel=None, title=None, sLabel = None, offset= (80, 20, 40, 100), barSpace = 2, zoom = 1): + xLeftOffset, xRightOffset, yTopOffset, yBottomOffset = offset + plotWidth = canvas.size[0] - xLeftOffset - xRightOffset + plotHeight = canvas.size[1] - yTopOffset - yBottomOffset + if plotHeight<=0 or plotWidth<=0: + return + + NNN = len(data) + if NNN < 2 or NNN != len(label): + return + if variance and len(variance)!=NNN: + variance = [] + + Y2 = data[:] + if variance: + for i in range(NNN): + if variance[i]: + Y2 += [data[i]-variance[i]] + + #Y axis + YLow, YTop, stepY = detScale(min(Y2), max(Y2)) + YScale = plotHeight/(YTop - YLow) + + if YLow < 0 and YTop > 0: + drawZero = 1 + else: + drawZero = 0 + + #X axis + X = range(NNN) + Xll= 0 + Xur= NNN-1 + + + if drawZero: + YZero = yTopOffset+plotHeight-YScale*(0-YLow) + canvas.drawLine(xLeftOffset, YZero, xLeftOffset+plotWidth, YZero) + else: + YZero = yTopOffset+plotHeight + #draw data + spaceWidth = barSpace + if spaceWidth < 1: + spaceWidth = 1 + barWidth = int((plotWidth - (NNN-1.0)*spaceWidth)/NNN) + + xc= xLeftOffset + scaleFont=pid.Font(ttf="verdana",size=11,bold=0) + for i in range(NNN): + yc = yTopOffset+plotHeight-(data[i]-YLow)*YScale + canvas.drawRect(xc,YZero,xc+barWidth-1, yc, edgeColor=barColor,fillColor=barColor) + if variance and variance[i]: + varlen = variance[i]*YScale + if yc-varlen < yTopOffset: + topYd = yTopOffset + else: + topYd = yc-varlen + canvas.drawLine(xc+barWidth/2-2,yc-varlen,xc+barWidth/2+2,yc-varlen,color=pid.red) + canvas.drawLine(xc+barWidth/2,yc+varlen,xc+barWidth/2,topYd,color=pid.red) + canvas.drawLine(xc+barWidth/2-2,yc+varlen,xc+barWidth/2+2,yc+varlen,color=pid.red) + strX = label[i] + canvas.drawString(strX,xc+barWidth/2.0+2,yTopOffset+plotHeight+2+canvas.stringWidth(strX,font=scaleFont),font=scaleFont,angle=90) + xc += barWidth + spaceWidth + + #draw drawing region + canvas.drawRect(xLeftOffset, yTopOffset, xLeftOffset+plotWidth, yTopOffset+plotHeight) + + #draw Y scale + scaleFont=pid.Font(ttf="cour",size=16,bold=1) + y=YLow + for i in range(stepY+1): + yc=yTopOffset+plotHeight-(y-YLow)*YScale + canvas.drawLine(xLeftOffset,yc,xLeftOffset-5,yc, color=axesColor) + strY = cformat(d=y, rank=0) + canvas.drawString(strY,xLeftOffset-canvas.stringWidth(strY,font=scaleFont)-6,yc+5,font=scaleFont) + y+= (YTop - YLow)/stepY + + #draw label + labelFont=pid.Font(ttf="verdana",size=17,bold=0) + if XLabel: + canvas.drawString(XLabel,xLeftOffset+(plotWidth-canvas.stringWidth(XLabel,font=labelFont))/2.0,yTopOffset+plotHeight+65,font=labelFont,color=labelColor) + + if YLabel: + canvas.drawString(YLabel,xLeftOffset-50, yTopOffset+plotHeight-(plotHeight-canvas.stringWidth(YLabel,font=labelFont))/2.0,font=labelFont,color=labelColor,angle=90) + + labelFont=pid.Font(ttf="verdana",size=18,bold=0) + if title: + canvas.drawString(title,xLeftOffset,yTopOffset-15,font=labelFont,color=labelColor) + + return + +def plotXY(canvas, dataX, dataY, rank=0, dataLabel=[], plotColor = pid.black, axesColor=pid.black, labelColor=pid.black, lineSize="thin", lineColor=pid.grey, idFont="arial", idColor=pid.blue, idSize="14", symbolColor=pid.black, symbolType="circle", filled="yes", symbolSize="tiny", XLabel=None, YLabel=None, title=None, fitcurve=None, connectdot=1, displayR=None, loadingPlot = 0, offset= (80, 20, 40, 60), zoom = 1, specialCases=[], showLabel = 1, bufferSpace = 15): + 'displayR : correlation scatter plot, loadings : loading plot' + + dataXRanked, dataYRanked = webqtlUtil.calRank(dataX, dataY, len(dataX)) + + #get ID font size + idFontSize = int(idSize) + + #If filled is yes, set fill color + if filled == "yes": + fillColor = symbolColor + else: + fillColor = None + + if symbolSize == "large": + sizeModifier = 7 + fontModifier = 12 + elif symbolSize == "medium": + sizeModifier = 5 + fontModifier = 8 + elif symbolSize == "small": + sizeModifier = 3 + fontModifier = 3 + else: + sizeModifier = 1 + fontModifier = -1 + + if rank == 0: # Pearson correlation + bufferSpace = 0 + dataXPrimary = dataX + dataYPrimary = dataY + dataXAlt = dataXRanked #Values used just for printing the other corr type to the graph image + dataYAlt = dataYRanked #Values used just for printing the other corr type to the graph image + else: # Spearman correlation: Switching Ranked and Unranked X and Y values + dataXPrimary = dataXRanked + dataYPrimary = dataYRanked + dataXAlt = dataX #Values used just for printing the other corr type to the graph image + dataYAlt = dataY #Values used just for printing the other corr type to the graph image + + xLeftOffset, xRightOffset, yTopOffset, yBottomOffset = offset + plotWidth = canvas.size[0] - xLeftOffset - xRightOffset + plotHeight = canvas.size[1] - yTopOffset - yBottomOffset + if plotHeight<=0 or plotWidth<=0: + return + if len(dataXPrimary) < 1 or len(dataXPrimary) != len(dataYPrimary) or (dataLabel and len(dataXPrimary) != len(dataLabel)): + return + + max_X=max(dataXPrimary) + min_X=min(dataXPrimary) + max_Y=max(dataYPrimary) + min_Y=min(dataYPrimary) + + #for some reason I forgot why I need to do this + if loadingPlot: + min_X = min(-0.1,min_X) + max_X = max(0.1,max_X) + min_Y = min(-0.1,min_Y) + max_Y = max(0.1,max_Y) + + xLow, xTop, stepX=detScale(min_X,max_X) + yLow, yTop, stepY=detScale(min_Y,max_Y) + xScale = plotWidth/(xTop-xLow) + yScale = plotHeight/(yTop-yLow) + + #draw drawing region + canvas.drawRect(xLeftOffset-bufferSpace, yTopOffset, xLeftOffset+plotWidth, yTopOffset+plotHeight+bufferSpace) + canvas.drawRect(xLeftOffset-bufferSpace+1, yTopOffset, xLeftOffset+plotWidth, yTopOffset+plotHeight+bufferSpace-1) + + #calculate data points + data = map(lambda X, Y: (X, Y), dataXPrimary, dataYPrimary) + xCoord = map(lambda X, Y: ((X-xLow)*xScale + xLeftOffset, yTopOffset+plotHeight-(Y-yLow)*yScale), dataXPrimary, dataYPrimary) + + labelFont=pid.Font(ttf=idFont,size=idFontSize,bold=0) + + if loadingPlot: + xZero = -xLow*xScale+xLeftOffset + yZero = yTopOffset+plotHeight+yLow*yScale + for point in xCoord: + canvas.drawLine(xZero,yZero,point[0],point[1],color=pid.red) + else: + if connectdot: + canvas.drawPolygon(xCoord,edgeColor=plotColor,closed=0) + else: + pass + + symbolFont = pid.Font(ttf="fnt_bs", size=12+fontModifier,bold=0) + + for i, item in enumerate(xCoord): + if dataLabel and dataLabel[i] in specialCases: + canvas.drawRect(item[0]-3, item[1]-3, item[0]+3, item[1]+3, edgeColor=pid.green) + #canvas.drawCross(item[0],item[1],color=pid.blue,size=5) + else: + if symbolType == "vertRect": + canvas.drawRect(x1=item[0]-sizeModifier+2,y1=item[1]-sizeModifier-2, x2=item[0]+sizeModifier-1,y2=item[1]+sizeModifier+2, edgeColor=symbolColor, edgeWidth=1, fillColor=fillColor) + elif (symbolType == "circle" and filled != "yes"): + canvas.drawString(":", item[0]-canvas.stringWidth(":",font=symbolFont)/2+1,item[1]+2,color=symbolColor, font=symbolFont) + elif (symbolType == "circle" and filled == "yes"): + canvas.drawString("5", item[0]-canvas.stringWidth("5",font=symbolFont)/2+1,item[1]+2,color=symbolColor, font=symbolFont) + elif symbolType == "horiRect": + canvas.drawRect(x1=item[0]-sizeModifier-1,y1=item[1]-sizeModifier+3, x2=item[0]+sizeModifier+3,y2=item[1]+sizeModifier-2, edgeColor=symbolColor, edgeWidth=1, fillColor=fillColor) + elif (symbolType == "square"): + canvas.drawRect(x1=item[0]-sizeModifier+1,y1=item[1]-sizeModifier-4, x2=item[0]+sizeModifier+2,y2=item[1]+sizeModifier-3, edgeColor=symbolColor, edgeWidth=1, fillColor=fillColor) + elif (symbolType == "diamond" and filled != "yes"): + canvas.drawString(",", item[0]-canvas.stringWidth(",",font=symbolFont)/2+2, item[1]+6, font=symbolFont, color=symbolColor) + elif (symbolType == "diamond" and filled == "yes"): + canvas.drawString("D", item[0]-canvas.stringWidth("D",font=symbolFont)/2+2, item[1]+6, font=symbolFont, color=symbolColor) + elif symbolType == "4-star": + canvas.drawString("l", item[0]-canvas.stringWidth("l",font=symbolFont)/2+1, item[1]+3, font=symbolFont, color=symbolColor) + elif symbolType == "3-star": + canvas.drawString("k", item[0]-canvas.stringWidth("k",font=symbolFont)/2+1, item[1]+3, font=symbolFont, color=symbolColor) + else: + canvas.drawCross(item[0],item[1]-2,color=symbolColor, size=sizeModifier+2) + + if showLabel and dataLabel: + if (symbolType == "vertRect" or symbolType == "diamond"): + labelGap = 15 + elif (symbolType == "4-star" or symbolType == "3-star"): + labelGap = 12 + else: + labelGap = 11 + canvas.drawString(dataLabel[i], item[0]- canvas.stringWidth(dataLabel[i], + font=labelFont)/2 + 1, item[1]+(labelGap+sizeModifier+(idFontSize-12)), font=labelFont, color=idColor) + + #draw scale + scaleFont=pid.Font(ttf="cour",size=16,bold=1) + + + x=xLow + for i in range(stepX+1): + xc=xLeftOffset+(x-xLow)*xScale + if ((x == 0) & (rank == 1)): + pass + else: + canvas.drawLine(xc,yTopOffset+plotHeight + bufferSpace,xc,yTopOffset+plotHeight+5 + bufferSpace, color=axesColor) + strX = cformat(d=x, rank=rank) + if ((strX == "0") & (rank == 1)): + pass + else: + canvas.drawString(strX,xc-canvas.stringWidth(strX,font=scaleFont)/2,yTopOffset+plotHeight+20 + bufferSpace,font=scaleFont) + x+= (xTop - xLow)/stepX + + y=yLow + for i in range(stepY+1): + yc=yTopOffset+plotHeight-(y-yLow)*yScale + if ((y == 0) & (rank == 1)): + pass + else: + canvas.drawLine(xLeftOffset - bufferSpace,yc,xLeftOffset-5 - bufferSpace,yc, color=axesColor) + strY = cformat(d=y, rank=rank) + if ((strY == "0") & (rank == 1)): + pass + else: + canvas.drawString(strY,xLeftOffset-canvas.stringWidth(strY,font=scaleFont)- 10 - bufferSpace,yc+4,font=scaleFont) + y+= (yTop - yLow)/stepY + + #draw label + + labelFont=pid.Font(ttf="verdana",size=canvas.size[0]/45,bold=0) + titleFont=pid.Font(ttf="verdana",size=canvas.size[0]/40,bold=0) + + if (rank == 1 and not title): + canvas.drawString("Spearman Rank Correlation", xLeftOffset-canvas.size[0]*.025+(plotWidth-canvas.stringWidth("Spearman Rank Correlation",font=titleFont))/2.0, + 25,font=titleFont,color=labelColor) + elif (rank == 0 and not title): + canvas.drawString("Pearson Correlation", xLeftOffset-canvas.size[0]*.025+(plotWidth-canvas.stringWidth("Pearson Correlation",font=titleFont))/2.0, + 25,font=titleFont,color=labelColor) + + if XLabel: + canvas.drawString(XLabel,xLeftOffset+(plotWidth-canvas.stringWidth(XLabel,font=labelFont))/2.0, + yTopOffset+plotHeight+yBottomOffset-25,font=labelFont,color=labelColor) + + if YLabel: + canvas.drawString(YLabel, xLeftOffset-65, yTopOffset+plotHeight- (plotHeight-canvas.stringWidth(YLabel,font=labelFont))/2.0, + font=labelFont,color=labelColor,angle=90) + + labelFont=pid.Font(ttf="verdana",size=20,bold=0) + if title: + canvas.drawString(title,xLeftOffset+(plotWidth-canvas.stringWidth(title,font=labelFont))/2.0, + 20,font=labelFont,color=labelColor) + + if fitcurve: + import sys + sys.argv = [ "mod_python" ] + #from numarray import linear_algebra as la + #from numarray import ones, array, dot, swapaxes + fitYY = array(dataYPrimary) + fitXX = array([ones(len(dataXPrimary)),dataXPrimary]) + AA = dot(fitXX,swapaxes(fitXX,0,1)) + BB = dot(fitXX,fitYY) + bb = la.linear_least_squares(AA,BB)[0] + + xc1 = xLeftOffset + yc1 = yTopOffset+plotHeight-(bb[0]+bb[1]*xLow-yLow)*yScale + if yc1 > yTopOffset+plotHeight: + yc1 = yTopOffset+plotHeight + xc1 = (yLow-bb[0])/bb[1] + xc1=(xc1-xLow)*xScale+xLeftOffset + elif yc1 < yTopOffset: + yc1 = yTopOffset + xc1 = (yTop-bb[0])/bb[1] + xc1=(xc1-xLow)*xScale+xLeftOffset + else: + pass + + xc2 = xLeftOffset + plotWidth + yc2 = yTopOffset+plotHeight-(bb[0]+bb[1]*xTop-yLow)*yScale + if yc2 > yTopOffset+plotHeight: + yc2 = yTopOffset+plotHeight + xc2 = (yLow-bb[0])/bb[1] + xc2=(xc2-xLow)*xScale+xLeftOffset + elif yc2 < yTopOffset: + yc2 = yTopOffset + xc2 = (yTop-bb[0])/bb[1] + xc2=(xc2-xLow)*xScale+xLeftOffset + else: + pass + + canvas.drawLine(xc1 - bufferSpace,yc1 + bufferSpace,xc2,yc2,color=lineColor) + if lineSize == "medium": + canvas.drawLine(xc1 - bufferSpace,yc1 + bufferSpace+1,xc2,yc2+1,color=lineColor) + if lineSize == "thick": + canvas.drawLine(xc1 - bufferSpace,yc1 + bufferSpace+1,xc2,yc2+1,color=lineColor) + canvas.drawLine(xc1 - bufferSpace,yc1 + bufferSpace-1,xc2,yc2-1,color=lineColor) + + + if displayR: + labelFont=pid.Font(ttf="trebuc",size=canvas.size[0]/60,bold=0) + NNN = len(dataX) + corr = webqtlUtil.calCorrelation(dataXPrimary,dataYPrimary,NNN)[0] + + if NNN < 3: + corrPValue = 1.0 + else: + if abs(corr) >= 1.0: + corrPValue = 0.0 + else: + ZValue = 0.5*log((1.0+corr)/(1.0-corr)) + ZValue = ZValue*sqrt(NNN-3) + corrPValue = 2.0*(1.0 - reaper.normp(abs(ZValue))) + + NStr = "N = %d" % NNN + strLenN = canvas.stringWidth(NStr,font=labelFont) + + if rank == 1: + if corrPValue < 0.0000000000000001: + corrStr = "Rho = %1.3f P < 1.00 E-16" % (corr) + else: + corrStr = "Rho = %1.3f P = %3.2E" % (corr, corrPValue) + else: + if corrPValue < 0.0000000000000001: + corrStr = "r = %1.3f P < 1.00 E-16" % (corr) + else: + corrStr = "r = %1.3f P = %3.2E" % (corr, corrPValue) + strLen = canvas.stringWidth(corrStr,font=labelFont) + + canvas.drawString(NStr,xLeftOffset,yTopOffset-10,font=labelFont,color=labelColor) + canvas.drawString(corrStr,xLeftOffset+plotWidth-strLen,yTopOffset-10,font=labelFont,color=labelColor) + + return xCoord + +def plotXYSVG(drawSpace, dataX, dataY, rank=0, dataLabel=[], plotColor = "black", axesColor="black", labelColor="black", symbolColor="red", XLabel=None, YLabel=None, title=None, fitcurve=None, connectdot=1, displayR=None, loadingPlot = 0, offset= (80, 20, 40, 60), zoom = 1, specialCases=[], showLabel = 1): + 'displayR : correlation scatter plot, loadings : loading plot' + + dataXRanked, dataYRanked = webqtlUtil.calRank(dataX, dataY, len(dataX)) + + # Switching Ranked and Unranked X and Y values if a Spearman Rank Correlation + if rank == 0: + dataXPrimary = dataX + dataYPrimary = dataY + dataXAlt = dataXRanked + dataYAlt = dataYRanked + + else: + dataXPrimary = dataXRanked + dataYPrimary = dataYRanked + dataXAlt = dataX + dataYAlt = dataY + + + + xLeftOffset, xRightOffset, yTopOffset, yBottomOffset = offset + plotWidth = drawSpace.attributes['width'] - xLeftOffset - xRightOffset + plotHeight = drawSpace.attributes['height'] - yTopOffset - yBottomOffset + if plotHeight<=0 or plotWidth<=0: + return + if len(dataXPrimary) < 1 or len(dataXPrimary) != len(dataYPrimary) or (dataLabel and len(dataXPrimary) != len(dataLabel)): + return + + max_X=max(dataXPrimary) + min_X=min(dataXPrimary) + max_Y=max(dataYPrimary) + min_Y=min(dataYPrimary) + + #for some reason I forgot why I need to do this + if loadingPlot: + min_X = min(-0.1,min_X) + max_X = max(0.1,max_X) + min_Y = min(-0.1,min_Y) + max_Y = max(0.1,max_Y) + + xLow, xTop, stepX=detScale(min_X,max_X) + yLow, yTop, stepY=detScale(min_Y,max_Y) + xScale = plotWidth/(xTop-xLow) + yScale = plotHeight/(yTop-yLow) + + #draw drawing region + r = svg.rect(xLeftOffset, yTopOffset, plotWidth, plotHeight, 'none', axesColor, 1) + drawSpace.addElement(r) + + #calculate data points + data = map(lambda X, Y: (X, Y), dataXPrimary, dataYPrimary) + xCoord = map(lambda X, Y: ((X-xLow)*xScale + xLeftOffset, yTopOffset+plotHeight-(Y-yLow)*yScale), dataXPrimary, dataYPrimary) + labelFontF = "verdana" + labelFontS = 11 + + if loadingPlot: + xZero = -xLow*xScale+xLeftOffset + yZero = yTopOffset+plotHeight+yLow*yScale + for point in xCoord: + drawSpace.addElement(svg.line(xZero,yZero,point[0],point[1], "red", 1)) + else: + if connectdot: + pass + #drawSpace.drawPolygon(xCoord,edgeColor=plotColor,closed=0) + else: + pass + + for i, item in enumerate(xCoord): + if dataLabel and dataLabel[i] in specialCases: + drawSpace.addElement(svg.rect(item[0]-3, item[1]-3, 6, 6, "none", "green", 0.5)) + #drawSpace.drawCross(item[0],item[1],color=pid.blue,size=5) + else: + drawSpace.addElement(svg.line(item[0],item[1]+5,item[0],item[1]-5,symbolColor,1)) + drawSpace.addElement(svg.line(item[0]+5,item[1],item[0]-5,item[1],symbolColor,1)) + if showLabel and dataLabel: + pass + drawSpace.addElement(svg.text(item[0], item[1]+14, dataLabel[i], labelFontS, + labelFontF, text_anchor="middle", style="stroke:blue;stroke-width:0.5;")) + #canvas.drawString(, item[0]- canvas.stringWidth(dataLabel[i], + # font=labelFont)/2, item[1]+14, font=labelFont, color=pid.blue) + + #draw scale + #scaleFont=pid.Font(ttf="cour",size=14,bold=1) + x=xLow + for i in range(stepX+1): + xc=xLeftOffset+(x-xLow)*xScale + drawSpace.addElement(svg.line(xc,yTopOffset+plotHeight,xc,yTopOffset+plotHeight+5, axesColor, 1)) + strX = cformat(d=x, rank=rank) + drawSpace.addElement(svg.text(xc,yTopOffset+plotHeight+20,strX,13, "courier", text_anchor="middle")) + x+= (xTop - xLow)/stepX + + y=yLow + for i in range(stepY+1): + yc=yTopOffset+plotHeight-(y-yLow)*yScale + drawSpace.addElement(svg.line(xLeftOffset,yc,xLeftOffset-5,yc, axesColor, 1)) + strY = cformat(d=y, rank=rank) + drawSpace.addElement(svg.text(xLeftOffset-10,yc+5,strY,13, "courier", text_anchor="end")) + y+= (yTop - yLow)/stepY + + #draw label + labelFontF = "verdana" + labelFontS = 17 + if XLabel: + drawSpace.addElement(svg.text(xLeftOffset+plotWidth/2.0, + yTopOffset+plotHeight+yBottomOffset-10,XLabel, + labelFontS, labelFontF, text_anchor="middle")) + + if YLabel: + drawSpace.addElement(svg.text(xLeftOffset-50, + yTopOffset+plotHeight/2,YLabel, + labelFontS, labelFontF, text_anchor="middle", style="writing-mode:tb-rl", transform="rotate(270 %d %d)" % (xLeftOffset-50, yTopOffset+plotHeight/2))) + #drawSpace.drawString(YLabel, xLeftOffset-50, yTopOffset+plotHeight- (plotHeight-drawSpace.stringWidth(YLabel,font=labelFont))/2.0, + # font=labelFont,color=labelColor,angle=90) + + + if fitcurve: + sys.argv = [ "mod_python" ] + #from numarray import linear_algebra as la + #from numarray import ones, array, dot, swapaxes + fitYY = array(dataYPrimary) + fitXX = array([ones(len(dataXPrimary)),dataXPrimary]) + AA = dot(fitXX,swapaxes(fitXX,0,1)) + BB = dot(fitXX,fitYY) + bb = la.linear_least_squares(AA,BB)[0] + + xc1 = xLeftOffset + yc1 = yTopOffset+plotHeight-(bb[0]+bb[1]*xLow-yLow)*yScale + if yc1 > yTopOffset+plotHeight: + yc1 = yTopOffset+plotHeight + xc1 = (yLow-bb[0])/bb[1] + xc1=(xc1-xLow)*xScale+xLeftOffset + elif yc1 < yTopOffset: + yc1 = yTopOffset + xc1 = (yTop-bb[0])/bb[1] + xc1=(xc1-xLow)*xScale+xLeftOffset + else: + pass + + xc2 = xLeftOffset + plotWidth + yc2 = yTopOffset+plotHeight-(bb[0]+bb[1]*xTop-yLow)*yScale + if yc2 > yTopOffset+plotHeight: + yc2 = yTopOffset+plotHeight + xc2 = (yLow-bb[0])/bb[1] + xc2=(xc2-xLow)*xScale+xLeftOffset + elif yc2 < yTopOffset: + yc2 = yTopOffset + xc2 = (yTop-bb[0])/bb[1] + xc2=(xc2-xLow)*xScale+xLeftOffset + else: + pass + + drawSpace.addElement(svg.line(xc1,yc1,xc2,yc2,"green", 1)) + + if displayR: + labelFontF = "trebuc" + labelFontS = 14 + NNN = len(dataX) + + corr = webqtlUtil.calCorrelation(dataXPrimary,dataYPrimary,NNN)[0] + + if NNN < 3: + corrPValue = 1.0 + else: + if abs(corr) >= 1.0: + corrPValue = 0.0 + else: + ZValue = 0.5*log((1.0+corr)/(1.0-corr)) + ZValue = ZValue*sqrt(NNN-3) + corrPValue = 2.0*(1.0 - reaper.normp(abs(ZValue))) + + NStr = "N of Cases=%d" % NNN + + if rank == 1: + corrStr = "Spearman's r=%1.3f P=%3.2E" % (corr, corrPValue) + else: + corrStr = "Pearson's r=%1.3f P=%3.2E" % (corr, corrPValue) + + drawSpace.addElement(svg.text(xLeftOffset,yTopOffset-10,NStr, + labelFontS, labelFontF, text_anchor="start")) + drawSpace.addElement(svg.text(xLeftOffset+plotWidth,yTopOffset-25,corrStr, + labelFontS, labelFontF, text_anchor="end")) + """ + """ + return + + +# This function determines the scale of the plot +def detScaleOld(min,max): + if min>=max: + return None + elif min == -1.0 and max == 1.0: + return [-1.2,1.2,12] + else: + a=max-min + b=floor(log10(a)) + c=pow(10.0,b) + if a < c*5.0: + c/=2.0 + #print a,b,c + low=c*floor(min/c) + high=c*ceil(max/c) + return [low,high,round((high-low)/c)] + +def detScale(min=0,max=0,bufferSpace=3): + + if min>=max: + return None + elif min == -1.0 and max == 1.0: + return [-1.2,1.2,12] + else: + a=max-min + if max != 0: + max += 0.1*a + if min != 0: + if min > 0 and min < 0.1*a: + min = 0.0 + else: + min -= 0.1*a + a=max-min + b=floor(log10(a)) + c=pow(10.0,b) + low=c*floor(min/c) + high=c*ceil(max/c) + n = round((high-low)/c) + div = 2.0 + while n < 5 or n > 15: + if n < 5: + c /= div + else: + c *= div + if div == 2.0: + div =5.0 + else: + div =2.0 + low=c*floor(min/c) + high=c*ceil(max/c) + n = round((high-low)/c) + + return [low,high,n] + + + +def colorSpectrumOld(n): + if n == 1: + return [pid.Color(1,0,0)] + elif n == 2: + return [pid.Color(1,0,0),pid.Color(0,0,1)] + elif n == 3: + return [pid.Color(1,0,0),pid.Color(0,1,0),pid.Color(0,0,1)] + else: + step = 2.0/(n-1) + red = 1.0 + green = 0.0 + blue = 0.0 + colors = [pid.Color(red,green,blue)] + i = 1 + greenpeak = 0 + while i < n: + if red >= step: + red -= step + green += step + if green >= 1.0: + greenpeak = 1 + blue += green -1.0 + green = 1.0 + else: + red = 0.0 + if greenpeak: + green -= step + blue += step + else: + green += step + if green >= 1.0: + greenpeak = 1 + blue += green -1.0 + green = 2.0 -green + elif green < 0.0: + green = 0.0 + else: + pass + colors.append(pid.Color(red,green,blue)) + i += 1 + return colors + + + + +def bluefunc(x): + return 1.0 / (1.0 + exp(-10*(x-0.6))) + + +def redfunc(x): + return 1.0 / (1.0 + exp(10*(x-0.5))) + +def greenfunc(x): + return 1 - pow(redfunc(x+0.2),2) - bluefunc(x-0.3) + +def colorSpectrum(n=100): + multiple = 10 + if n == 1: + return [pid.Color(1,0,0)] + elif n == 2: + return [pid.Color(1,0,0),pid.Color(0,0,1)] + elif n == 3: + return [pid.Color(1,0,0),pid.Color(0,1,0),pid.Color(0,0,1)] + N = n*multiple + out = [None]*N; + for i in range(N): + x = float(i)/N + out[i] = pid.Color(redfunc(x), greenfunc(x), bluefunc(x)); + out2 = [out[0]] + step = N/float(n-1) + j = 0 + for i in range(n-2): + j += step + out2.append(out[int(j)]) + out2.append(out[-1]) + return out2 + + +def colorSpectrumSVG(n=100): + multiple = 10 + if n == 1: + return ["rgb(255,0,0)"] + elif n == 2: + return ["rgb(255,0,0)","rgb(0,0,255)"] + elif n == 3: + return ["rgb(255,0,0)","rgb(0,255,0)","rgb(0,0,255)"] + N = n*multiple + out = [None]*N; + for i in range(N): + x = float(i)/N + out[i] = "rgb(%d, %d, %d)" % (redfunc(x)*255, greenfunc(x)*255, bluefunc(x)*255); + out2 = [out[0]] + step = N/float(n-1) + j = 0 + for i in range(n-2): + j += step + out2.append(out[int(j)]) + out2.append(out[-1]) + return out2 + + +def BWSpectrum(n=100): + multiple = 10 + if n == 1: + return [pid.Color(0,0,0)] + elif n == 2: + return [pid.Color(0,0,0),pid.Color(1,1,1)] + elif n == 3: + return [pid.Color(0,0,0),pid.Color(0.5,0.5,0.5),pid.Color(1,1,1)] + + step = 1.0/n + x = 0.0 + out = [] + for i in range(n): + out.append(pid.Color(x,x,x)); + x += step + return out diff --git a/wqflask/utility/TDCell.py b/wqflask/utility/TDCell.py new file mode 100755 index 00000000..76b9c5db --- /dev/null +++ b/wqflask/utility/TDCell.py @@ -0,0 +1,42 @@ +# Copyright (C) University of Tennessee Health Science Center, Memphis, TN. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Affero General Public License for more details. +# +# This program is available from Source Forge: at GeneNetwork Project +# (sourceforge.net/projects/genenetwork/). +# +# 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 +# +# Last updated by GeneNetwork Core Team 2010/10/20 + +########################################################## +# +# Table Cell Class +# +########################################################## + + +class TDCell: + def __init__(self, html="", text="", val=0.0): + self.html = html #html, for web page + self.text = text #text value, for output to a text file + self.val = val #sort by value + + def __str__(self): + return self.text + diff --git a/wqflask/utility/THCell.py b/wqflask/utility/THCell.py new file mode 100755 index 00000000..a96b9e49 --- /dev/null +++ b/wqflask/utility/THCell.py @@ -0,0 +1,44 @@ +# Copyright (C) University of Tennessee Health Science Center, Memphis, TN. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Affero General Public License for more details. +# +# This program is available from Source Forge: at GeneNetwork Project +# (sourceforge.net/projects/genenetwork/). +# +# 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 +# +# Last updated by GeneNetwork Core Team 2010/10/20 + +########################################################## +# +# Table Header Class +# +########################################################## + + +class THCell: + def __init__(self, html="", text="", sort=1, idx=-1): + self.html = html #html, for web page + self.text = text #Column text value + self.sort = sort #0: not sortable, 1: yes + self.idx = idx #sort by value + + def __str__(self): + return self.text + + diff --git a/wqflask/utility/__init__.py b/wqflask/utility/__init__.py new file mode 100755 index 00000000..e69de29b --- /dev/null +++ b/wqflask/utility/__init__.py diff --git a/wqflask/utility/formatting.py b/wqflask/utility/formatting.py new file mode 100644 index 00000000..52173417 --- /dev/null +++ b/wqflask/utility/formatting.py @@ -0,0 +1,109 @@ +def numify(number, singular=None, plural=None): + """Turn a number into a word if less than 13 and optionally add a singular or plural word + + >>> numify(3) + 'three' + + >>> numify(1, 'item', 'items') + 'one item' + + >>> numify(9, 'book', 'books') + 'nine books' + + >>> numify(15) + '15' + + >>> numify(0) + '0' + + >>> numify(12334, 'hippopotamus', 'hippopotami') + '12,334 hippopotami' + + """ + num_repr = {1 : "one", + 2 : "two", + 3 : "three", + 4 : "four", + 5 : "five", + 6 : "six", + 7 : "seven", + 8 : "eight", + 9 : "nine", + 10 : "ten", + 11 : "eleven", + 12 : "twelve"} + + #Below line commented out cause doesn't work in Python 2.4 + #assert all((singular, plural)) or not any((singular, plural)), "Need to pass two words or none" + if number == 1: + word = singular + else: + word = plural + + if number in num_repr: + number = num_repr[number] + elif number > 9999: + number = commify(number) + + if word: + return "%s %s" % (number, word) + else: + return str(number) + + +def commify(n): + """Add commas to an integer n. + + See http://stackoverflow.com/questions/3909457/whats-the-easiest-way-to-add-commas-to-an-integer-in-python + But I (Sam) made some small changes based on http://www.grammarbook.com/numbers/numbers.asp + + >>> commify(1) + '1' + >>> commify(123) + '123' + >>> commify(1234) + '1234' + >>> commify(12345) + '12,345' + >>> commify(1234567890) + '1,234,567,890' + >>> commify(123.0) + '123.0' + >>> commify(1234.5) + '1234.5' + >>> commify(1234.56789) + '1234.56789' + >>> commify(123456.789) + '123,456.789' + >>> commify('%.2f' % 1234.5) + '1234.50' + >>> commify(None) + >>> + + """ + if n is None: + return None + + n = str(n) + + if len(n) <= 4: # Might as well do this early + return n + + if '.' in n: + dollars, cents = n.split('.') + else: + dollars, cents = n, None + + # Don't commify numbers less than 10000 + if len(dollars) <= 4: + return n + + r = [] + for i, c in enumerate(reversed(str(dollars))): + if i and (not (i % 3)): + r.insert(0, ',') + r.insert(0, c) + out = ''.join(r) + if cents: + out += '.' + cents + return out diff --git a/wqflask/utility/svg.py b/wqflask/utility/svg.py new file mode 100755 index 00000000..e49a6c3c --- /dev/null +++ b/wqflask/utility/svg.py @@ -0,0 +1,1069 @@ +# Copyright (C) University of Tennessee Health Science Center, Memphis, TN. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Affero General Public License for more details. +# +# This program is available from Source Forge: at GeneNetwork Project +# (sourceforge.net/projects/genenetwork/). +# +# 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 +# +# Last updated by GeneNetwork Core Team 2010/10/20 + +#!/usr/bin/env python +##Copyright (c) 2002, Fedor Baart & Hans de Wit (Stichting Farmaceutische Kengetallen) +##All rights reserved. +## +##Redistribution and use in source and binary forms, with or without modification, +##are permitted provided that the following conditions are met: +## +##Redistributions of source code must retain the above copyright notice, this +##list of conditions and the following disclaimer. +## +##Redistributions in binary form must reproduce the above copyright notice, +##this list of conditions and the following disclaimer in the documentation and/or +##other materials provided with the distribution. +## +##Neither the name of the Stichting Farmaceutische Kengetallen nor the names of +##its contributors may be used to endorse or promote products derived from this +##software without specific prior written permission. +## +##THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +##AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +##IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +##DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +##FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +##DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +##SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +##CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +##OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +##OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +##Thanks to Gerald Rosennfellner for his help and useful comments. + +__doc__="""Use SVGdraw to generate your SVGdrawings. + +SVGdraw uses an object model drawing and a method toXML to create SVG graphics +by using easy to use classes and methods usualy you start by creating a drawing eg + + d=drawing() + #then you create a SVG root element + s=svg() + #then you add some elements eg a circle and add it to the svg root element + c=circle() + #you can supply attributes by using named arguments. + c=circle(fill='red',stroke='blue') + #or by updating the attributes attribute: + c.attributes['stroke-width']=1 + s.addElement(c) + #then you add the svg root element to the drawing + d.setSVG(s) + #and finaly you xmlify the drawing + d.toXml() + + +this results in the svg source of the drawing, which consists of a circle +on a white background. Its as easy as that;) +This module was created using the SVG specification of www.w3c.org and the +O'Reilly (www.oreilly.com) python books as information sources. A svg viewer +is available from www.adobe.com""" + +__version__="1.0" + +# there are two possibilities to generate svg: +# via a dom implementation and directly using <element>text</element> strings +# the latter is way faster (and shorter in coding) +# the former is only used in debugging svg programs +# maybe it will be removed alltogether after a while +# with the following variable you indicate whether to use the dom implementation +# Note that PyXML is required for using the dom implementation. +# It is also possible to use the standard minidom. But I didn't try that one. +# Anyway the text based approach is about 60 times faster than using the full dom implementation. +use_dom_implementation=0 + + +import exceptions +if use_dom_implementation<>0: + try: + from xml.dom import implementation + from xml.dom.ext import PrettyPrint + except: + raise exceptions.ImportError, "PyXML is required for using the dom implementation" +#The implementation is used for the creating the XML document. +#The prettyprint module is used for converting the xml document object to a xml file + +import sys +assert sys.version_info[0]>=2 +if sys.version_info[1]<2: + True=1 + False=0 + file=open + +sys.setrecursionlimit=50 +#The recursion limit is set conservative so mistakes like s=svg() s.addElement(s) +#won't eat up too much processor time. + +#the following code is pasted form xml.sax.saxutils +#it makes it possible to run the code without the xml sax package installed +#To make it possible to have <rubbish> in your text elements, it is necessary to escape the texts +def _escape(data, entities={}): + """Escape &, <, and > in a string of data. + + You can escape other strings of data by passing a dictionary as + the optional entities parameter. The keys and values must all be + strings; each key will be replaced with its corresponding value. + """ + #data = data.replace("&", "&") + data = data.replace("<", "<") + data = data.replace(">", ">") + for chars, entity in entities.items(): + data = data.replace(chars, entity) + return data + +def _quoteattr(data, entities={}): + """Escape and quote an attribute value. + + Escape &, <, and > in a string of data, then quote it for use as + an attribute value. The \" character will be escaped as well, if + necessary. + + You can escape other strings of data by passing a dictionary as + the optional entities parameter. The keys and values must all be + strings; each key will be replaced with its corresponding value. + """ + data = _escape(data, entities) + if '"' in data: + if "'" in data: + data = '"%s"' % data.replace('"', """) + else: + data = "'%s'" % data + else: + data = '"%s"' % data + return data + + + +def _xypointlist(a): + """formats a list of xy pairs""" + s='' + for e in a: #this could be done more elegant + s+=str(e)[1:-1] +' ' + return s + +def _viewboxlist(a): + """formats a tuple""" + s='' + for e in a: + s+=str(e)+' ' + return s + +def _pointlist(a): + """formats a list of numbers""" + return str(a)[1:-1] + +class pathdata: + """class used to create a pathdata object which can be used for a path. + although most methods are pretty straightforward it might be useful to look at the SVG specification.""" + #I didn't test the methods below. + def __init__(self,x=None,y=None): + self.path=[] + if x is not None and y is not None: + self.path.append('M '+str(x)+' '+str(y)) + def closepath(self): + """ends the path""" + self.path.append('z') + def move(self,x,y): + """move to absolute""" + self.path.append('M '+str(x)+' '+str(y)) + def relmove(self,x,y): + """move to relative""" + self.path.append('m '+str(x)+' '+str(y)) + def line(self,x,y): + """line to absolute""" + self.path.append('L '+str(x)+' '+str(y)) + def relline(self,x,y): + """line to relative""" + self.path.append('l '+str(x)+' '+str(y)) + def hline(self,x): + """horizontal line to absolute""" + self.path.append('H'+str(x)) + def relhline(self,x): + """horizontal line to relative""" + self.path.append('h'+str(x)) + def vline(self,y): + """verical line to absolute""" + self.path.append('V'+str(y)) + def relvline(self,y): + """vertical line to relative""" + self.path.append('v'+str(y)) + def bezier(self,x1,y1,x2,y2,x,y): + """bezier with xy1 and xy2 to xy absolut""" + self.path.append('C'+str(x1)+','+str(y1)+' '+str(x2)+','+str(y2)+' '+str(x)+','+str(y)) + def relbezier(self,x1,y1,x2,y2,x,y): + """bezier with xy1 and xy2 to xy relative""" + self.path.append('c'+str(x1)+','+str(y1)+' '+str(x2)+','+str(y2)+' '+str(x)+','+str(y)) + def smbezier(self,x2,y2,x,y): + """smooth bezier with xy2 to xy absolut""" + self.path.append('S'+str(x2)+','+str(y2)+' '+str(x)+','+str(y)) + def relsmbezier(self,x2,y2,x,y): + """smooth bezier with xy2 to xy relative""" + self.path.append('s'+str(x2)+','+str(y2)+' '+str(x)+','+str(y)) + def qbezier(self,x1,y1,x,y): + """quadratic bezier with xy1 to xy absolut""" + self.path.append('Q'+str(x1)+','+str(y1)+' '+str(x)+','+str(y)) + def relqbezier(self,x1,y1,x,y): + """quadratic bezier with xy1 to xy relative""" + self.path.append('q'+str(x1)+','+str(y1)+' '+str(x)+','+str(y)) + def smqbezier(self,x,y): + """smooth quadratic bezier to xy absolut""" + self.path.append('T'+str(x)+','+str(y)) + def relsmqbezier(self,x,y): + """smooth quadratic bezier to xy relative""" + self.path.append('t'+str(x)+','+str(y)) + def ellarc(self,rx,ry,xrot,laf,sf,x,y): + """elliptival arc with rx and ry rotating with xrot using large-arc-flag and sweep-flag to xy absolut""" + self.path.append('A'+str(rx)+','+str(ry)+' '+str(xrot)+' '+str(laf)+' '+str(sf)+' '+str(x)+' '+str(y)) + def relellarc(self,rx,ry,xrot,laf,sf,x,y): + """elliptival arc with rx and ry rotating with xrot using large-arc-flag and sweep-flag to xy relative""" + self.path.append('a'+str(rx)+','+str(ry)+' '+str(xrot)+' '+str(laf)+' '+str(sf)+' '+str(x)+' '+str(y)) + def __repr__(self): + return ' '.join(self.path) + + + + +class SVGelement: + """SVGelement(type,attributes,elements,text,namespace,**args) + Creates a arbitrary svg element and is intended to be subclassed not used on its own. + This element is the base of every svg element it defines a class which resembles + a xml-element. The main advantage of this kind of implementation is that you don't + have to create a toXML method for every different graph object. Every element + consists of a type, attribute, optional subelements, optional text and an optional + namespace. Note the elements==None, if elements = None:self.elements=[] construction. + This is done because if you default to elements=[] every object has a reference + to the same empty list.""" + def __init__(self,type='',attributes=None,elements=None,text='',namespace='',cdata=None, **args): + self.type=type + if attributes==None: + self.attributes={} + else: + self.attributes=attributes + if elements==None: + self.elements=[] + else: + self.elements=elements + self.text=text + self.namespace=namespace + self.cdata=cdata + for arg in args.keys(): + arg2 = arg.replace("__", ":") + arg2 = arg2.replace("_", "-") + self.attributes[arg2]=args[arg] + def addElement(self,SVGelement): + """adds an element to a SVGelement + + SVGelement.addElement(SVGelement) + """ + self.elements.append(SVGelement) + + def toXml(self,level,f): + f.write('\t'*level) + f.write('<'+self.type) + for attkey in self.attributes.keys(): + f.write(' '+_escape(str(attkey))+'='+_quoteattr(str(self.attributes[attkey]))) + if self.namespace: + f.write(' xmlns="'+ _escape(str(self.namespace))+'" xmlns:xlink="http://www.w3.org/1999/xlink"') + if self.elements or self.text or self.cdata: + f.write('>') + if self.elements: + f.write('\n') + for element in self.elements: + element.toXml(level+1,f) + if self.cdata: + f.write('\n'+'\t'*(level+1)+'<![CDATA[') + for line in self.cdata.splitlines(): + f.write('\n'+'\t'*(level+2)+line) + f.write('\n'+'\t'*(level+1)+']]>\n') + if self.text: + if type(self.text)==type(''): #If the text is only text + f.write(_escape(str(self.text))) + else: #If the text is a spannedtext class + f.write(str(self.text)) + if self.elements: + f.write('\t'*level+'</'+self.type+'>\n') + elif self.text: + f.write('</'+self.type+'>\n') + elif self.cdata: + f.write('\t'*level+'</'+self.type+'>\n') + else: + f.write('/>\n') + +class tspan(SVGelement): + """ts=tspan(text='',**args) + + a tspan element can be used for applying formatting to a textsection + usage: + ts=tspan('this text is bold') + ts.attributes['font-weight']='bold' + st=spannedtext() + st.addtspan(ts) + t=text(3,5,st) + """ + def __init__(self,text=None,**args): + SVGelement.__init__(self,'tspan',**args) + if self.text<>None: + self.text=text + def __repr__(self): + s="<tspan" + for key,value in self.attributes.items(): + s+= ' %s="%s"' % (key,value) + s+='>' + s+=self.text + s+='</tspan>' + return s + +class tref(SVGelement): + """tr=tref(link='',**args) + + a tref element can be used for referencing text by a link to its id. + usage: + tr=tref('#linktotext') + st=spannedtext() + st.addtref(tr) + t=text(3,5,st) + """ + def __init__(self,link,**args): + SVGelement.__init__(self,'tref',{'xlink:href':link},**args) + def __repr__(self): + s="<tref" + + for key,value in self.attributes.items(): + s+= ' %s="%s"' % (key,value) + s+='/>' + return s + +class spannedtext: + """st=spannedtext(textlist=[]) + + a spannedtext can be used for text which consists of text, tspan's and tref's + You can use it to add to a text element or path element. Don't add it directly + to a svg or a group element. + usage: + + ts=tspan('this text is bold') + ts.attributes['font-weight']='bold' + tr=tref('#linktotext') + tr.attributes['fill']='red' + st=spannedtext() + st.addtspan(ts) + st.addtref(tr) + st.addtext('This text is not bold') + t=text(3,5,st) + """ + def __init__(self,textlist=None): + if textlist==None: + self.textlist=[] + else: + self.textlist=textlist + def addtext(self,text=''): + self.textlist.append(text) + def addtspan(self,tspan): + self.textlist.append(tspan) + def addtref(self,tref): + self.textlist.append(tref) + def __repr__(self): + s="" + for element in self.textlist: + s+=str(element) + return s + +class rect(SVGelement): + """r=rect(width,height,x,y,fill,stroke,stroke_width,**args) + + a rectangle is defined by a width and height and a xy pair + """ + def __init__(self,x=None,y=None,width=None,height=None,fill=None,stroke=None,stroke_width=None,**args): + if width==None or height==None: + if width<>None: + raise ValueError, 'height is required' + if height<>None: + raise ValueError, 'width is required' + else: + raise ValueError, 'both height and width are required' + SVGelement.__init__(self,'rect',{'width':width,'height':height},**args) + if x<>None: + self.attributes['x']=x + if y<>None: + self.attributes['y']=y + if fill<>None: + self.attributes['fill']=fill + if stroke<>None: + self.attributes['stroke']=stroke + if stroke_width<>None: + self.attributes['stroke-width']=stroke_width + +class ellipse(SVGelement): + """e=ellipse(rx,ry,x,y,fill,stroke,stroke_width,**args) + + an ellipse is defined as a center and a x and y radius. + """ + def __init__(self,cx=None,cy=None,rx=None,ry=None,fill=None,stroke=None,stroke_width=None,**args): + if rx==None or ry== None: + if rx<>None: + raise ValueError, 'rx is required' + if ry<>None: + raise ValueError, 'ry is required' + else: + raise ValueError, 'both rx and ry are required' + SVGelement.__init__(self,'ellipse',{'rx':rx,'ry':ry},**args) + if cx<>None: + self.attributes['cx']=cx + if cy<>None: + self.attributes['cy']=cy + if fill<>None: + self.attributes['fill']=fill + if stroke<>None: + self.attributes['stroke']=stroke + if stroke_width<>None: + self.attributes['stroke-width']=stroke_width + + +class circle(SVGelement): + """c=circle(x,y,radius,fill,stroke,stroke_width,**args) + + The circle creates an element using a x, y and radius values eg + """ + def __init__(self,cx=None,cy=None,r=None,fill=None,stroke=None,stroke_width=None,**args): + if r==None: + raise ValueError, 'r is required' + SVGelement.__init__(self,'circle',{'r':r},**args) + if cx<>None: + self.attributes['cx']=cx + if cy<>None: + self.attributes['cy']=cy + if fill<>None: + self.attributes['fill']=fill + if stroke<>None: + self.attributes['stroke']=stroke + if stroke_width<>None: + self.attributes['stroke-width']=stroke_width + +class point(circle): + """p=point(x,y,color) + + A point is defined as a circle with a size 1 radius. It may be more efficient to use a + very small rectangle if you use many points because a circle is difficult to render. + """ + def __init__(self,x,y,fill='black',**args): + circle.__init__(self,x,y,1,fill,**args) + +class line(SVGelement): + """l=line(x1,y1,x2,y2,stroke,stroke_width,**args) + + A line is defined by a begin x,y pair and an end x,y pair + """ + def __init__(self,x1=None,y1=None,x2=None,y2=None,stroke=None,stroke_width=None,**args): + SVGelement.__init__(self,'line',**args) + if x1<>None: + self.attributes['x1']=x1 + if y1<>None: + self.attributes['y1']=y1 + if x2<>None: + self.attributes['x2']=x2 + if y2<>None: + self.attributes['y2']=y2 + if stroke_width<>None: + self.attributes['stroke-width']=stroke_width + if stroke<>None: + self.attributes['stroke']=stroke + +class polyline(SVGelement): + """pl=polyline([[x1,y1],[x2,y2],...],fill,stroke,stroke_width,**args) + + a polyline is defined by a list of xy pairs + """ + def __init__(self,points,fill=None,stroke=None,stroke_width=None,**args): + SVGelement.__init__(self,'polyline',{'points':_xypointlist(points)},**args) + if fill<>None: + self.attributes['fill']=fill + if stroke_width<>None: + self.attributes['stroke-width']=stroke_width + if stroke<>None: + self.attributes['stroke']=stroke + +class polygon(SVGelement): + """pl=polyline([[x1,y1],[x2,y2],...],fill,stroke,stroke_width,**args) + + a polygon is defined by a list of xy pairs + """ + def __init__(self,points,fill=None,stroke=None,stroke_width=None,**args): + SVGelement.__init__(self,'polygon',{'points':_xypointlist(points)},**args) + if fill<>None: + self.attributes['fill']=fill + if stroke_width<>None: + self.attributes['stroke-width']=stroke_width + if stroke<>None: + self.attributes['stroke']=stroke + +class path(SVGelement): + """p=path(path,fill,stroke,stroke_width,**args) + + a path is defined by a path object and optional width, stroke and fillcolor + """ + def __init__(self,pathdata,fill=None,stroke=None,stroke_width=None,id=None,**args): + SVGelement.__init__(self,'path',{'d':str(pathdata)},**args) + if stroke<>None: + self.attributes['stroke']=stroke + if fill<>None: + self.attributes['fill']=fill + if stroke_width<>None: + self.attributes['stroke-width']=stroke_width + if id<>None: + self.attributes['id']=id + + +class text(SVGelement): + """t=text(x,y,text,font_size,font_family,**args) + + a text element can bge used for displaying text on the screen + """ + def __init__(self,x=None,y=None,text=None,font_size=None,font_family=None,text_anchor=None,**args): + SVGelement.__init__(self,'text',**args) + if x<>None: + self.attributes['x']=x + if y<>None: + self.attributes['y']=y + if font_size<>None: + self.attributes['font-size']=font_size + if font_family<>None: + self.attributes['font-family']=font_family + if text<>None: + self.text=text + if text_anchor<>None: + self.attributes['text-anchor']=text_anchor + + +class textpath(SVGelement): + """tp=textpath(text,link,**args) + + a textpath places a text on a path which is referenced by a link. + """ + def __init__(self,link,text=None,**args): + SVGelement.__init__(self,'textPath',{'xlink:href':link},**args) + if text<>None: + self.text=text + +class pattern(SVGelement): + """p=pattern(x,y,width,height,patternUnits,**args) + + A pattern is used to fill or stroke an object using a pre-defined + graphic object which can be replicated ("tiled") at fixed intervals + in x and y to cover the areas to be painted. + """ + def __init__(self,x=None,y=None,width=None,height=None,patternUnits=None,**args): + SVGelement.__init__(self,'pattern',**args) + if x<>None: + self.attributes['x']=x + if y<>None: + self.attributes['y']=y + if width<>None: + self.attributes['width']=width + if height<>None: + self.attributes['height']=height + if patternUnits<>None: + self.attributes['patternUnits']=patternUnits + +class title(SVGelement): + """t=title(text,**args) + + a title is a text element. The text is displayed in the title bar + add at least one to the root svg element + """ + def __init__(self,text=None,**args): + SVGelement.__init__(self,'title',**args) + if text<>None: + self.text=text + +class description(SVGelement): + """d=description(text,**args) + + a description can be added to any element and is used for a tooltip + Add this element before adding other elements. + """ + def __init__(self,text=None,**args): + SVGelement.__init__(self,'desc',**args) + if text<>None: + self.text=text + +class lineargradient(SVGelement): + """lg=lineargradient(x1,y1,x2,y2,id,**args) + + defines a lineargradient using two xy pairs. + stop elements van be added to define the gradient colors. + """ + def __init__(self,x1=None,y1=None,x2=None,y2=None,id=None,**args): + SVGelement.__init__(self,'linearGradient',**args) + if x1<>None: + self.attributes['x1']=x1 + if y1<>None: + self.attributes['y1']=y1 + if x2<>None: + self.attributes['x2']=x2 + if y2<>None: + self.attributes['y2']=y2 + if id<>None: + self.attributes['id']=id + +class radialgradient(SVGelement): + """rg=radialgradient(cx,cy,r,fx,fy,id,**args) + + defines a radial gradient using a outer circle which are defined by a cx,cy and r and by using a focalpoint. + stop elements van be added to define the gradient colors. + """ + def __init__(self,cx=None,cy=None,r=None,fx=None,fy=None,id=None,**args): + SVGelement.__init__(self,'radialGradient',**args) + if cx<>None: + self.attributes['cx']=cx + if cy<>None: + self.attributes['cy']=cy + if r<>None: + self.attributes['r']=r + if fx<>None: + self.attributes['fx']=fx + if fy<>None: + self.attributes['fy']=fy + if id<>None: + self.attributes['id']=id + +class stop(SVGelement): + """st=stop(offset,stop_color,**args) + + Puts a stop color at the specified radius + """ + def __init__(self,offset,stop_color=None,**args): + SVGelement.__init__(self,'stop',{'offset':offset},**args) + if stop_color<>None: + self.attributes['stop-color']=stop_color + +class style(SVGelement): + """st=style(type,cdata=None,**args) + + Add a CDATA element to this element for defing in line stylesheets etc.. + """ + def __init__(self,type,cdata=None,**args): + SVGelement.__init__(self,'style',{'type':type},cdata=cdata, **args) + + +class image(SVGelement): + """im=image(url,width,height,x,y,**args) + + adds an image to the drawing. Supported formats are .png, .jpg and .svg. + """ + def __init__(self,url,x=None,y=None,width=None,height=None,**args): + if width==None or height==None: + if width<>None: + raise ValueError, 'height is required' + if height<>None: + raise ValueError, 'width is required' + else: + raise ValueError, 'both height and width are required' + SVGelement.__init__(self,'image',{'xlink:href':url,'width':width,'height':height},**args) + if x<>None: + self.attributes['x']=x + if y<>None: + self.attributes['y']=y + +class cursor(SVGelement): + """c=cursor(url,**args) + + defines a custom cursor for a element or a drawing + """ + def __init__(self,url,**args): + SVGelement.__init__(self,'cursor',{'xlink:href':url},**args) + + +class marker(SVGelement): + """m=marker(id,viewbox,refX,refY,markerWidth,markerHeight,**args) + + defines a marker which can be used as an endpoint for a line or other pathtypes + add an element to it which should be used as a marker. + """ + def __init__(self,id=None,viewBox=None,refx=None,refy=None,markerWidth=None,markerHeight=None,**args): + SVGelement.__init__(self,'marker',**args) + if id<>None: + self.attributes['id']=id + if viewBox<>None: + self.attributes['viewBox']=_viewboxlist(viewBox) + if refx<>None: + self.attributes['refX']=refx + if refy<>None: + self.attributes['refY']=refy + if markerWidth<>None: + self.attributes['markerWidth']=markerWidth + if markerHeight<>None: + self.attributes['markerHeight']=markerHeight + +class group(SVGelement): + """g=group(id,**args) + + a group is defined by an id and is used to contain elements + g.addElement(SVGelement) + """ + def __init__(self,id=None,**args): + SVGelement.__init__(self,'g',**args) + if id<>None: + self.attributes['id']=id + +class symbol(SVGelement): + """sy=symbol(id,viewbox,**args) + + defines a symbol which can be used on different places in your graph using + the use element. A symbol is not rendered but you can use 'use' elements to + display it by referencing its id. + sy.addElement(SVGelement) + """ + + def __init__(self,id=None,viewBox=None,**args): + SVGelement.__init__(self,'symbol',**args) + if id<>None: + self.attributes['id']=id + if viewBox<>None: + self.attributes['viewBox']=_viewboxlist(viewBox) + +class defs(SVGelement): + """d=defs(**args) + + container for defining elements + """ + def __init__(self,**args): + SVGelement.__init__(self,'defs',**args) + +class switch(SVGelement): + """sw=switch(**args) + + Elements added to a switch element which are "switched" by the attributes + requiredFeatures, requiredExtensions and systemLanguage. + Refer to the SVG specification for details. + """ + def __init__(self,**args): + SVGelement.__init__(self,'switch',**args) + + +class use(SVGelement): + """u=use(link,x,y,width,height,**args) + + references a symbol by linking to its id and its position, height and width + """ + def __init__(self,link,x=None,y=None,width=None,height=None,**args): + SVGelement.__init__(self,'use',{'xlink:href':link},**args) + if x<>None: + self.attributes['x']=x + if y<>None: + self.attributes['y']=y + + if width<>None: + self.attributes['width']=width + if height<>None: + self.attributes['height']=height + + +class link(SVGelement): + """a=link(url,**args) + + a link is defined by a hyperlink. add elements which have to be linked + a.addElement(SVGelement) + """ + def __init__(self,link='',**args): + SVGelement.__init__(self,'a',{'xlink:href':link},**args) + +class view(SVGelement): + """v=view(id,**args) + + a view can be used to create a view with different attributes""" + def __init__(self,id=None,**args): + SVGelement.__init__(self,'view',**args) + if id<>None: + self.attributes['id']=id + +class script(SVGelement): + """sc=script(type,type,cdata,**args) + + adds a script element which contains CDATA to the SVG drawing + + """ + def __init__(self,type,cdata=None,**args): + SVGelement.__init__(self,'script',{'type':type},cdata=cdata,**args) + +class animate(SVGelement): + """an=animate(attribute,from,to,during,**args) + + animates an attribute. + """ + def __init__(self,attribute,fr=None,to=None,dur=None,**args): + SVGelement.__init__(self,'animate',{'attributeName':attribute},**args) + if fr<>None: + self.attributes['from']=fr + if to<>None: + self.attributes['to']=to + if dur<>None: + self.attributes['dur']=dur + +class animateMotion(SVGelement): + """an=animateMotion(pathdata,dur,**args) + + animates a SVGelement over the given path in dur seconds + """ + def __init__(self,pathdata,dur,**args): + SVGelement.__init__(self,'animateMotion',**args) + if pathdata<>None: + self.attributes['path']=str(pathdata) + if dur<>None: + self.attributes['dur']=dur + +class animateTransform(SVGelement): + """antr=animateTransform(type,from,to,dur,**args) + + transform an element from and to a value. + """ + def __init__(self,type=None,fr=None,to=None,dur=None,**args): + SVGelement.__init__(self,'animateTransform',{'attributeName':'transform'},**args) + #As far as I know the attributeName is always transform + if type<>None: + self.attributes['type']=type + if fr<>None: + self.attributes['from']=fr + if to<>None: + self.attributes['to']=to + if dur<>None: + self.attributes['dur']=dur +class animateColor(SVGelement): + """ac=animateColor(attribute,type,from,to,dur,**args) + + Animates the color of a element + """ + def __init__(self,attribute,type=None,fr=None,to=None,dur=None,**args): + SVGelement.__init__(self,'animateColor',{'attributeName':attribute},**args) + if type<>None: + self.attributes['type']=type + if fr<>None: + self.attributes['from']=fr + if to<>None: + self.attributes['to']=to + if dur<>None: + self.attributes['dur']=dur +class set(SVGelement): + """st=set(attribute,to,during,**args) + + sets an attribute to a value for a + """ + def __init__(self,attribute,to=None,dur=None,**args): + SVGelement.__init__(self,'set',{'attributeName':attribute},**args) + if to<>None: + self.attributes['to']=to + if dur<>None: + self.attributes['dur']=dur + + + +class svg(SVGelement): + """s=svg(viewbox,width,height,**args) + + a svg or element is the root of a drawing add all elements to a svg element. + You can have different svg elements in one svg file + s.addElement(SVGelement) + + eg + d=drawing() + s=svg((0,0,100,100),'100%','100%') + c=circle(50,50,20) + s.addElement(c) + d.setSVG(s) + d.toXml() + """ + def __init__(self,viewBox=None, width=None, height=None,**args): + SVGelement.__init__(self,'svg',**args) + if viewBox<>None: + self.attributes['viewBox']=_viewboxlist(viewBox) + if width<>None: + self.attributes['width']=width + if height<>None: + self.attributes['height']=height + self.namespace="http://www.w3.org/2000/svg" + +class drawing: + """d=drawing() + + this is the actual SVG document. It needs a svg element as a root. + Use the addSVG method to set the svg to the root. Use the toXml method to write the SVG + source to the screen or to a file + d=drawing() + d.addSVG(svg) + d.toXml(optionalfilename) + """ + + def __init__(self, entity={}): + self.svg=None + self.entity = entity + def setSVG(self,svg): + self.svg=svg + #Voeg een element toe aan de grafiek toe. + if use_dom_implementation==0: + def toXml(self, filename='',compress=False): + import cStringIO + xml=cStringIO.StringIO() + xml.write("<?xml version='1.0' encoding='UTF-8'?>\n") + xml.write("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\"") + if self.entity: + xml.write(" [\n") + for item in self.entity.keys(): + xml.write("<!ENTITY %s \"%s\">\n" % (item, self.entity[item])) + xml.write("]") + xml.write(">\n") + self.svg.toXml(0,xml) + if not filename: + if compress: + import gzip + f=cStringIO.StringIO() + zf=gzip.GzipFile(fileobj=f,mode='wb') + zf.write(xml.getvalue()) + zf.close() + f.seek(0) + return f.read() + else: + return xml.getvalue() + else: + if filename[-4:]=='svgz': + import gzip + f=gzip.GzipFile(filename=filename,mode="wb", compresslevel=9) + f.write(xml.getvalue()) + f.close() + else: + f=file(filename,'w') + f.write(xml.getvalue()) + f.close() + + else: + def toXml(self,filename='',compress=False): + """drawing.toXml() ---->to the screen + drawing.toXml(filename)---->to the file + writes a svg drawing to the screen or to a file + compresses if filename ends with svgz or if compress is true + """ + doctype = implementation.createDocumentType('svg',"-//W3C//DTD SVG 1.0//EN""",'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd ') + + global root + #root is defined global so it can be used by the appender. Its also possible to use it as an arugument but + #that is a bit messy. + root=implementation.createDocument(None,None,doctype) + #Create the xml document. + global appender + def appender(element,elementroot): + """This recursive function appends elements to an element and sets the attributes + and type. It stops when alle elements have been appended""" + if element.namespace: + e=root.createElementNS(element.namespace,element.type) + else: + e=root.createElement(element.type) + if element.text: + textnode=root.createTextNode(element.text) + e.appendChild(textnode) + for attribute in element.attributes.keys(): #in element.attributes is supported from python 2.2 + e.setAttribute(attribute,str(element.attributes[attribute])) + if element.elements: + for el in element.elements: + e=appender(el,e) + elementroot.appendChild(e) + return elementroot + root=appender(self.svg,root) + if not filename: + import cStringIO + xml=cStringIO.StringIO() + PrettyPrint(root,xml) + if compress: + import gzip + f=cStringIO.StringIO() + zf=gzip.GzipFile(fileobj=f,mode='wb') + zf.write(xml.getvalue()) + zf.close() + f.seek(0) + return f.read() + else: + return xml.getvalue() + else: + try: + if filename[-4:]=='svgz': + import gzip + import cStringIO + xml=cStringIO.StringIO() + PrettyPrint(root,xml) + f=gzip.GzipFile(filename=filename,mode='wb',compresslevel=9) + f.write(xml.getvalue()) + f.close() + else: + f=open(filename,'w') + PrettyPrint(root,f) + f.close() + except: + print "Cannot write SVG file: " + filename + def validate(self): + try: + import xml.parsers.xmlproc.xmlval + except: + raise exceptions.ImportError,'PyXml is required for validating SVG' + svg=self.toXml() + xv=xml.parsers.xmlproc.xmlval.XMLValidator() + try: + xv.feed(svg) + except: + raise "SVG is not well formed, see messages above" + else: + print "SVG well formed" +if __name__=='__main__': + + + d=drawing() + s=svg((0,0,100,100)) + r=rect(-100,-100,300,300,'cyan') + s.addElement(r) + + t=title('SVGdraw Demo') + s.addElement(t) + g=group('animations') + e=ellipse(0,0,5,2) + g.addElement(e) + c=circle(0,0,1,'red') + g.addElement(c) + pd=pathdata(0,-10) + for i in range(6): + pd.relsmbezier(10,5,0,10) + pd.relsmbezier(-10,5,0,10) + an=animateMotion(pd,10) + an.attributes['rotate']='auto-reverse' + an.attributes['repeatCount']="indefinite" + g.addElement(an) + s.addElement(g) + for i in range(20,120,20): + u=use('#animations',i,0) + s.addElement(u) + for i in range(0,120,20): + for j in range(5,105,10): + c=circle(i,j,1,'red','black',.5) + s.addElement(c) + d.setSVG(s) + + print d.toXml() + diff --git a/wqflask/utility/webqtlUtil.py b/wqflask/utility/webqtlUtil.py new file mode 100755 index 00000000..6af7f846 --- /dev/null +++ b/wqflask/utility/webqtlUtil.py @@ -0,0 +1,977 @@ +# Copyright (C) University of Tennessee Health Science Center, Memphis, TN. +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License +# as published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Affero General Public License for more details. +# +# This program is available from Source Forge: at GeneNetwork Project +# (sourceforge.net/projects/genenetwork/). +# +# 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 +# +# Last updated by GeneNetwork Core Team 2010/10/20 + +import string +import time +import re +import math +from math import * + +from htmlgen import HTMLgen2 as HT + +from base import webqtlConfig + + + + +# NL, 07/27/2010. moved from webqtlForm.py +#Dict of Parents and F1 information, In the order of [F1, Mat, Pat] +ParInfo ={ +'BXH':['BHF1', 'HBF1', 'C57BL/6J', 'C3H/HeJ'], +'AKXD':['AKF1', 'KAF1', 'AKR/J', 'DBA/2J'], +'BXD':['B6D2F1', 'D2B6F1', 'C57BL/6J', 'DBA/2J'], +'BXD300':['B6D2F1', 'D2B6F1', 'C57BL/6J', 'DBA/2J'], +'B6BTBRF2':['B6BTBRF1', 'BTBRB6F1', 'C57BL/6J', 'BTBRT<+>tf/J'], +'BHHBF2':['B6HF2','HB6F2','C57BL/6J','C3H/HeJ'], +'BHF2':['B6HF2','HB6F2','C57BL/6J','C3H/HeJ'], +'B6D2F2':['B6D2F1', 'D2B6F1', 'C57BL/6J', 'DBA/2J'], +'BDF2-1999':['B6D2F2', 'D2B6F2', 'C57BL/6J', 'DBA/2J'], +'BDF2-2005':['B6D2F1', 'D2B6F1', 'C57BL/6J', 'DBA/2J'], +'CTB6F2':['CTB6F2','B6CTF2','C57BL/6J','Castaneous'], +'CXB':['CBF1', 'BCF1', 'C57BL/6ByJ', 'BALB/cByJ'], +'AXBXA':['ABF1', 'BAF1', 'C57BL/6J', 'A/J'], +'AXB':['ABF1', 'BAF1', 'C57BL/6J', 'A/J'], +'BXA':['BAF1', 'ABF1', 'C57BL/6J', 'A/J'], +'LXS':['LSF1', 'SLF1', 'ISS', 'ILS'], +'HXBBXH':['HSRBNF1', 'BNHSRF1', 'BN', 'HSR'], +'BayXSha':['BayXShaF1', 'ShaXBayF1', 'Bay-0','Shahdara'], +'ColXBur':['ColXBurF1', 'BurXColF1', 'Col-0','Bur-0'], +'ColXCvi':['ColXCviF1', 'CviXColF1', 'Col-0','Cvi'], +'SXM':['SMF1', 'MSF1', 'Steptoe','Morex'] +} + + +# NL, 07/27/2010. moved from template.py +IMGSTEP1 = HT.Image('/images/step1.gif', alt='STEP 1',border=0) #XZ, Only be used in inputPage.py +IMGSTEP2 = HT.Image('/images/step2.gif', alt='STEP 2',border=0) #XZ, Only be used in inputPage.py +IMGSTEP3 = HT.Image('/images/step3.gif', alt='STEP 3',border=0) #XZ, Only be used in inputPage.py +IMGNEXT = HT.Image('/images/arrowdown.gif', alt='NEXT',border=0) #XZ, Only be used in inputPage.py + +IMGASC = HT.Image("/images/sortup.gif", border=0) +IMGASCON = HT.Image("/images/sortupon.gif", border=0) +IMGDESC = HT.Image("/images/sortdown.gif", border=0) +IMGDESCON = HT.Image("/images/sortdownon.gif", border=0) + +""" +IMGASC = HT.Image("/images/sortup_icon.gif", border=0) +IMGASCON = HT.Image("/images/sortupon.gif", border=0) +IMGDESC = HT.Image("/images/sortdown_icon.gif", border=0) +IMGDESCON = HT.Image("/images/sortdownon.gif", border=0) +IMG_UNSORTED = HT.Image("/images/unsorted_icon.gif", border=0) +""" + +PROGRESSBAR = HT.Image('/images/waitAnima2.gif', alt='checkblue',align="middle",border=0) + +######################################### +# Accessory Functions +######################################### + +def decodeEscape(str): + a = str + pattern = re.compile('(%[0-9A-Fa-f][0-9A-Fa-f])') + match = pattern.findall(a) + matched = [] + for item in match: + if item not in matched: + a = a.replace(item, '%c' % eval("0x"+item[-2:])) + matched.append(item) + return a + +def exportData(hddn, tdata, NP = None): + for key in tdata.keys(): + _val, _var, _N = tdata[key].val, tdata[key].var, tdata[key].N + if _val != None: + hddn[key] = _val + if _var != None: + hddn['V'+key] = _var + if NP and _N != None: + hddn['N'+key] = _N + +def genShortStrainName(RISet='', input_strainName=''): + #aliasStrainDict = {'C57BL/6J':'B6','DBA/2J':'D2'} + strainName = input_strainName + if RISet != 'AXBXA': + if RISet == 'BXD300': + this_RISet = 'BXD' + elif RISet == 'BDF2-2005': + this_RISet = 'CASE05_' + else: + this_RISet = RISet + strainName = string.replace(strainName,this_RISet,'') + strainName = string.replace(strainName,'CASE','') + try: + strainName = "%02d" % int(strainName) + except: + pass + else: + strainName = string.replace(strainName,'AXB','A') + strainName = string.replace(strainName,'BXA','B') + try: + strainName = strainName[0] + "%02d" % int(strainName[1:]) + except: + pass + return strainName + +def toInt(in_str): + "Converts an arbitrary string to an unsigned integer" + start = -1 + end = -1 + for i, char in enumerate(in_str): + if char >= '0' and char <= '9': + if start < 0: + start = i + end = i+1 + else: + if start >= 0: + break + if start < end: + return int(in_str[start:end]) + else: + return -1 + +def transpose(m): + 'transpose a matrix' + n = len(m) + return [[m[j][i] for i in range(len(m[0])) for j in range(n)][k*n:k*n+n] for k in range(len(m[0]))] + +def asymTranspose(m): + 'transpose a matrix' + t = max(map(len, m)) + n = len(m) + m2 = [["-"]]*n + for i in range(n): + m2[i] = m[i] + [""]*(t- len(m[i])) + return [[m2[j][i] for i in range(len(m2[0])) for j in range(n)][k*n:k*n+n] for k in range(len(m2[0]))] + +def genRandStr(prefix = "", length=8, chars=string.letters+string.digits): + from random import choice + _str = prefix[:] + for i in range(length): + _str += choice(chars) + return _str + +def generate_session(): + import sha + return sha.new(str(time.time())).hexdigest() + +def cvt2Dict(x): + tmp = {} + for key in x.keys(): + tmp[key] = x[key] + return tmp + +def dump_session(session_obj, filename): + "It seems mod python can only cPickle most basic data type" + import cPickle + session_file = open(filename, 'wb') + #try: + # pass + #except: + # pass + cPickle.dump(session_obj, session_file) + session_file.close() + +def StringAsFloat(str): + 'Converts string to float but catches any exception and returns None' + try: + return float(str) + except: + return None + +def IntAsFloat(str): + 'Converts string to Int but catches any exception and returns None' + try: + return int(str) + except: + return None + +def FloatAsFloat(flt): + 'Converts float to string but catches any exception and returns None' + try: + return float("%2.3f" % flt) + except: + return None + +def RemoveZero(flt): + 'Converts string to float but catches any exception and returns None' + try: + if abs(flt) < 1e-6: + return None + else: + return flt + except: + return None + + +def SciFloat(d): + 'Converts string to float but catches any exception and returns None' + + try: + if abs(d) <= 1.0e-4: + return "%1.2e" % d + else: + return "%1.5f" % d + except: + return None + +###To be removed +def FloatList2String(lst): + 'Converts float list to string but catches any exception and returns None' + tt='' + try: + for item in lst: + if item == None: + tt += 'X ' + else: + tt += '%f ' % item + return tt + except: + return "" + +def ListNotNull(lst): + 'Determine if the elements in a list are all null' + for item in lst: + if item is not None: + return 1 + return None + +###To be removed +def FileDataProcess(str): + 'Remove the description text from the input file if theres any' + i=0 + while i<len(str): + if str[i]<'\x7f' and str[i]>'\x20': + break + else: + i+=1 + str=str[i:] + str=string.join(string.split(str,'\000'),'') + i=string.find(str,"*****") + if i>-1: + return str[i+5:] + else: + return str + +def rank(a,lst,offset=0): + """Calculate the integer rank of a number in an array, can be used to calculate p-value""" + n = len(lst) + if n == 2: + if a <lst[0]: + return offset + elif a > lst[1]: + return offset + 2 + else: + return offset +1 + elif n == 1: + if a <lst[0]: + return offset + else: + return offset +1 + elif n== 0: + return offset + else: + mid = n/2 + if a < lst[mid]: + return rank(a,lst[:mid-1],offset) + else: + return rank(a,lst[mid:],offset+mid) + +def cmpScanResult(A,B): + try: + if A.LRS > B.LRS: + return 1 + elif A.LRS == B.LRS: + return 0 + else: + return -1 + except: + return 0 + + +def cmpScanResult2(A,B): + try: + if A.LRS < B.LRS: + return 1 + elif A.LRS == B.LRS: + return 0 + else: + return -1 + except: + return 0 + +def cmpOrder(A,B): + try: + if A[1] < B[1]: + return -1 + elif A[1] == B[1]: + return 0 + else: + return 1 + except: + return 0 + +def cmpOrder2(A,B): + try: + if A[-1] < B[-1]: + return -1 + elif A[-1] == B[-1]: + return 0 + else: + return 1 + except: + return 0 + + + + +def calRank(xVals, yVals, N): ### Zach Sloan, February 4 2010 + """ + Returns a ranked set of X and Y values. These are used when generating + a Spearman scatterplot. Bear in mind that this sets values equal to each + other as the same rank. + """ + XX = [] + YY = [] + X = [0]*len(xVals) + Y = [0]*len(yVals) + j = 0 + + for i in range(len(xVals)): + + if xVals[i] != None and yVals[i] != None: + XX.append((j, xVals[i])) + YY.append((j, yVals[i])) + j = j + 1 + + NN = len(XX) + + XX.sort(cmpOrder2) + YY.sort(cmpOrder2) + + j = 1 + rank = 0.0 + + while j < NN: + + if XX[j][1] != XX[j-1][1]: + X[XX[j-1][0]] = j + j = j+1 + + else: + jt = j+1 + ji = j + for jt in range(j+1, NN): + if (XX[jt][1] != XX[j-1][1]): + break + rank = 0.5*(j+jt) + for ji in range(j-1, jt): + X[XX[ji][0]] = rank + if (jt == NN-1): + if (XX[jt][1] == XX[j-1][1]): + X[XX[NN-1][0]] = rank + j = jt+1 + + if j == NN: + if X[XX[NN-1][0]] == 0: + X[XX[NN-1][0]] = NN + + j = 1 + rank = 0.0 + + while j < NN: + + if YY[j][1] != YY[j-1][1]: + Y[YY[j-1][0]] = j + j = j+1 + else: + jt = j+1 + ji = j + for jt in range(j+1, NN): + if (YY[jt][1] != YY[j-1][1]): + break + rank = 0.5*(j+jt) + for ji in range(j-1, jt): + Y[YY[ji][0]] = rank + if (jt == NN-1): + if (YY[jt][1] == YY[j-1][1]): + Y[YY[NN-1][0]] = rank + j = jt+1 + + if j == NN: + if Y[YY[NN-1][0]] == 0: + Y[YY[NN-1][0]] = NN + + return (X,Y) + +def calCorrelationRank(xVals,yVals,N): + """ + Calculated Spearman Ranked Correlation. The algorithm works + by setting all tied ranks to the average of those ranks (for + example, if ranks 5-10 all have the same value, each will be set + to rank 7.5). + """ + + XX = [] + YY = [] + j = 0 + + for i in range(len(xVals)): + if xVals[i]!= None and yVals[i]!= None: + XX.append((j,xVals[i])) + YY.append((j,yVals[i])) + j = j+1 + + NN = len(XX) + if NN <6: + return (0.0,NN) + XX.sort(cmpOrder2) + YY.sort(cmpOrder2) + X = [0]*NN + Y = [0]*NN + + j = 1 + rank = 0.0 + t = 0.0 + sx = 0.0 + + while j < NN: + + if XX[j][1] != XX[j-1][1]: + X[XX[j-1][0]] = j + j = j+1 + + else: + jt = j+1 + ji = j + for jt in range(j+1, NN): + if (XX[jt][1] != XX[j-1][1]): + break + rank = 0.5*(j+jt) + for ji in range(j-1, jt): + X[XX[ji][0]] = rank + t = jt-j + sx = sx + (t*t*t-t) + if (jt == NN-1): + if (XX[jt][1] == XX[j-1][1]): + X[XX[NN-1][0]] = rank + j = jt+1 + + if j == NN: + if X[XX[NN-1][0]] == 0: + X[XX[NN-1][0]] = NN + + j = 1 + rank = 0.0 + t = 0.0 + sy = 0.0 + + while j < NN: + + if YY[j][1] != YY[j-1][1]: + Y[YY[j-1][0]] = j + j = j+1 + else: + jt = j+1 + ji = j + for jt in range(j+1, NN): + if (YY[jt][1] != YY[j-1][1]): + break + rank = 0.5*(j+jt) + for ji in range(j-1, jt): + Y[YY[ji][0]] = rank + t = jt - j + sy = sy + (t*t*t-t) + if (jt == NN-1): + if (YY[jt][1] == YY[j-1][1]): + Y[YY[NN-1][0]] = rank + j = jt+1 + + if j == NN: + if Y[YY[NN-1][0]] == 0: + Y[YY[NN-1][0]] = NN + + D = 0.0 + + for i in range(NN): + D += (X[i]-Y[i])*(X[i]-Y[i]) + + fac = (1.0 -sx/(NN*NN*NN-NN))*(1.0-sy/(NN*NN*NN-NN)) + + return ((1-(6.0/(NN*NN*NN-NN))*(D+(sx+sy)/12.0))/math.sqrt(fac),NN) + + +def calCorrelationRankText(dbdata,userdata,N): ### dcrowell = David Crowell, July 2008 + """Calculates correlation ranks with data formatted from the text file. + dbdata, userdata are lists of strings. N is an int. Returns a float. + Used by correlationPage""" + XX = [] + YY = [] + j = 0 + for i in range(N): + if (dbdata[i]!= None and userdata[i]!=None) and (dbdata[i]!= 'None' and userdata[i]!='None'): + XX.append((j,float(dbdata[i]))) + YY.append((j,float(userdata[i]))) + j += 1 + NN = len(XX) + if NN <6: + return (0.0,NN) + XX.sort(cmpOrder2) + YY.sort(cmpOrder2) + X = [0]*NN + Y = [0]*NN + + j = 1 + rank = 0.0 + t = 0.0 + sx = 0.0 + + while j < NN: + + if XX[j][1] != XX[j-1][1]: + X[XX[j-1][0]] = j + j = j+1 + + else: + jt = j+1 + ji = j + for jt in range(j+1, NN): + if (XX[jt][1] != XX[j-1][1]): + break + rank = 0.5*(j+jt) + for ji in range(j-1, jt): + X[XX[ji][0]] = rank + t = jt-j + sx = sx + (t*t*t-t) + if (jt == NN-1): + if (XX[jt][1] == XX[j-1][1]): + X[XX[NN-1][0]] = rank + j = jt+1 + + if j == NN: + if X[XX[NN-1][0]] == 0: + X[XX[NN-1][0]] = NN + + j = 1 + rank = 0.0 + t = 0.0 + sy = 0.0 + + while j < NN: + + if YY[j][1] != YY[j-1][1]: + Y[YY[j-1][0]] = j + j = j+1 + else: + jt = j+1 + ji = j + for jt in range(j+1, NN): + if (YY[jt][1] != YY[j-1][1]): + break + rank = 0.5*(j+jt) + for ji in range(j-1, jt): + Y[YY[ji][0]] = rank + t = jt - j + sy = sy + (t*t*t-t) + if (jt == NN-1): + if (YY[jt][1] == YY[j-1][1]): + Y[YY[NN-1][0]] = rank + j = jt+1 + + if j == NN: + if Y[YY[NN-1][0]] == 0: + Y[YY[NN-1][0]] = NN + + D = 0.0 + + for i in range(NN): + D += (X[i]-Y[i])*(X[i]-Y[i]) + + fac = (1.0 -sx/(NN*NN*NN-NN))*(1.0-sy/(NN*NN*NN-NN)) + + return ((1-(6.0/(NN*NN*NN-NN))*(D+(sx+sy)/12.0))/math.sqrt(fac),NN) + + + +def calCorrelation(dbdata,userdata,N): + X = [] + Y = [] + for i in range(N): + if dbdata[i]!= None and userdata[i]!= None: + X.append(dbdata[i]) + Y.append(userdata[i]) + NN = len(X) + if NN <6: + return (0.0,NN) + sx = reduce(lambda x,y:x+y,X,0.0) + sy = reduce(lambda x,y:x+y,Y,0.0) + meanx = sx/NN + meany = sy/NN + xyd = 0.0 + sxd = 0.0 + syd = 0.0 + for i in range(NN): + xyd += (X[i] - meanx)*(Y[i]-meany) + sxd += (X[i] - meanx)*(X[i] - meanx) + syd += (Y[i] - meany)*(Y[i] - meany) + try: + corr = xyd/(sqrt(sxd)*sqrt(syd)) + except: + corr = 0 + return (corr,NN) + +def calCorrelationText(dbdata,userdata,N): ### dcrowell July 2008 + """Calculates correlation coefficients with values formatted from text files. dbdata, userdata are lists of strings. N is an int. Returns a float + Used by correlationPage""" + X = [] + Y = [] + for i in range(N): + #if (dbdata[i]!= None and userdata[i]!= None) and (dbdata[i]!= 'None' and userdata[i]!= 'None'): + # X.append(float(dbdata[i])) + # Y.append(float(userdata[i])) + if dbdata[i] == None or dbdata[i] == 'None' or userdata[i] == None or userdata[i] == 'None': + continue + else: + X.append(float(dbdata[i])) + Y.append(float(userdata[i])) + NN = len(X) + if NN <6: + return (0.0,NN) + sx = sum(X) + sy = sum(Y) + meanx = sx/float(NN) + meany = sy/float(NN) + xyd = 0.0 + sxd = 0.0 + syd = 0.0 + for i in range(NN): + x1 = X[i]-meanx + y1 = Y[i]-meany + xyd += x1*y1 + sxd += x1**2 + syd += y1**2 + try: + corr = xyd/(sqrt(sxd)*sqrt(syd)) + except: + corr = 0 + return (corr,NN) + + +def readLineCSV(line): ### dcrowell July 2008 + """Parses a CSV string of text and returns a list containing each element as a string. + Used by correlationPage""" + returnList = line.split('","') + returnList[-1]=returnList[-1][:-2] + returnList[0]=returnList[0][1:] + return returnList + + +def cmpCorr(A,B): + try: + if abs(A[1]) < abs(B[1]): + return 1 + elif abs(A[1]) == abs(B[1]): + return 0 + else: + return -1 + except: + return 0 + +def cmpLitCorr(A,B): + try: + if abs(A[3]) < abs(B[3]): return 1 + elif abs(A[3]) == abs(B[3]): + if abs(A[1]) < abs(B[1]): return 1 + elif abs(A[1]) == abs(B[1]): return 0 + else: return -1 + else: return -1 + except: + return 0 + +def cmpPValue(A,B): + try: + if A.corrPValue < B.corrPValue: + return -1 + elif A.corrPValue == B.corrPValue: + if abs(A.corr) > abs(B.corr): + return -1 + elif abs(A.corr) < abs(B.corr): + return 1 + else: + return 0 + else: + return 1 + except: + return 0 + +def cmpEigenValue(A,B): + try: + if A[0] > B[0]: + return -1 + elif A[0] == B[0]: + return 0 + else: + return 1 + except: + return 0 + + +def cmpLRSFull(A,B): + try: + if A[0] < B[0]: + return -1 + elif A[0] == B[0]: + return 0 + else: + return 1 + except: + return 0 + +def cmpLRSInteract(A,B): + try: + if A[1] < B[1]: + return -1 + elif A[1] == B[1]: + return 0 + else: + return 1 + except: + return 0 + + +def cmpPos(A,B): + try: + try: + AChr = int(A.chr) + except: + AChr = 20 + try: + BChr = int(B.chr) + except: + BChr = 20 + if AChr > BChr: + return 1 + elif AChr == BChr: + if A.mb > B.mb: + return 1 + if A.mb == B.mb: + return 0 + else: + return -1 + else: + return -1 + except: + return 0 + +def cmpGenoPos(A,B): + try: + A1 = A.chr + B1 = B.chr + try: + A1 = int(A1) + except: + A1 = 25 + try: + B1 = int(B1) + except: + B1 = 25 + if A1 > B1: + return 1 + elif A1 == B1: + if A.mb > B.mb: + return 1 + if A.mb == B.mb: + return 0 + else: + return -1 + else: + return -1 + except: + return 0 + +#XZhou: Must use "BINARY" to enable case sensitive comparison. +def authUser(name,password,db, encrypt=None): + try: + if encrypt: + query = 'SELECT privilege, id,name,password, grpName FROM User WHERE name= BINARY \'%s\' and password= BINARY \'%s\'' % (name,password) + else: + query = 'SELECT privilege, id,name,password, grpName FROM User WHERE name= BINARY \'%s\' and password= BINARY SHA(\'%s\')' % (name,password) + db.execute(query) + records = db.fetchone() + if not records: + raise ValueError + return records#(privilege,id,name,password,grpName) + except: + return (None, None, None, None, None) + + +def hasAccessToConfidentialPhenotypeTrait(privilege, userName, authorized_users): + access_to_confidential_phenotype_trait = 0 + if webqtlConfig.USERDICT[privilege] > webqtlConfig.USERDICT['user']: + access_to_confidential_phenotype_trait = 1 + else: + AuthorizedUsersList=map(string.strip, string.split(authorized_users, ',')) + if AuthorizedUsersList.__contains__(userName): + access_to_confidential_phenotype_trait = 1 + return access_to_confidential_phenotype_trait + + +class VisualizeException(Exception): + def __init__(self, message): + self.message = message + def __str__(self): + return self.message + +# safeConvert : (string -> A) -> A -> A +# to convert a string to type A, using the supplied default value +# if the given conversion function doesn't work +def safeConvert(f, value, default): + try: + return f(value) + except: + return default + +# safeFloat : string -> float -> float +# to convert a string to a float safely +def safeFloat(value, default): + return safeConvert(float, value, default) + +# safeInt: string -> int -> int +# to convert a string to an int safely +def safeInt(value, default): + return safeConvert(int, value, default) + +# safeString : string -> (arrayof string) -> string -> string +# if a string is not in a list of strings to pick a default value +# for that string +def safeString(value, validChoices, default): + if value in validChoices: + return value + else: + return default + +# yesNoToInt: string -> int +# map "yes" -> 1 and "no" -> 0 +def yesNoToInt(value): + if value == "yes": + return 1 + elif value == "no": + return 0 + else: + return None + +# IntToYesNo: int -> string +# map 1 -> "yes" and 0 -> "no" +def intToYesNo(value): + if value == 1: + return "yes" + elif value == 0: + return "no" + else: + return None + +def formatField(name): + name = name.replace("_", " ") + name = name.title() + #name = name.replace("Mb Mm6", "Mb"); + return name.replace("Id", "ID") + +#XZ, 03/27/2009: This function is very specific. +#It is used by AJAX_table.py, correlationPage.py and dataPage.py + + +def genTableObj(tblobj=None, file="", sortby = ("", ""), tableID = "sortable", addIndex = "1", hiddenColumns=[]): + header = tblobj['header'] + body = tblobj['body'] + field, order = sortby + + #ZAS 9/12/2011 - The hiddenColumns array needs to be converted into a string so they can be placed into the javascript of each up/down button + hiddenColumnsString = ",".join(hiddenColumns) + + tbl = HT.TableLite(Class="collap b2", cellspacing=1, cellpadding=5) + + hiddenColumnIdx = [] #indices of columns to hide + idx = -1 + last_idx = 0 #ZS: This is the index of the last item in the regular table header (without any extra parameters). It is used to determine the index of each extra parameter. + for row in header: + hr = HT.TR() + for i, item in enumerate(row): + if (item.text == '') or (item.text not in hiddenColumns): + if item.sort and item.text: + down = HT.Href("javascript:xmlhttpPost('%smain.py?FormID=AJAX_table', '%s', 'sort=%s&order=down&file=%s&tableID=%s&addIndex=%s&hiddenColumns=%s')" % (webqtlConfig.CGIDIR, tableID, item.text, file, tableID, addIndex, hiddenColumnsString),IMGDESC) + up = HT.Href("javascript:xmlhttpPost('%smain.py?FormID=AJAX_table', '%s', 'sort=%s&order=up&file=%s&tableID=%s&addIndex=%s&hiddenColumns=%s')" % (webqtlConfig.CGIDIR, tableID, item.text, file, tableID, addIndex, hiddenColumnsString),IMGASC) + if item.text == field: + idx = item.idx + last_idx = idx + if order == 'up': + up = IMGASCON + elif order == 'down': + down = IMGDESCON + item.html.append(HT.Div(up, down, style="float: bottom;")) + hr.append(item.html) + else: + hiddenColumnIdx.append(i) + tbl.append(hr) + + for i, row in enumerate(body): + for j, item in enumerate(row): + if order == 'down': + if (item.val == '' or item.val == 'x' or item.val == 'None'): + item.val = 0 + if order == 'up': + if (item.val == '' or item.val == 'x' or item.val == 'None'): + item.val = 'zzzzz' + + if idx >= 0: + if order == 'down': + body.sort(lambda A, B: cmp(B[idx].val, A[idx].val), key=natsort_key) + elif order == 'up': + body.sort(lambda A, B: cmp(A[idx].val, B[idx].val), key=natsort_key) + else: + pass + + for i, row in enumerate(body): + hr = HT.TR(Id = row[0].text) + for j, item in enumerate(row): + if (j not in hiddenColumnIdx): + if j == 0: + if addIndex == "1": + item.html.contents = [i+1] + item.html.contents + hr.append(item.html) + tbl.append(hr) + + return tbl + +def natsort_key(string): + r = [] + for c in string: + try: + c = int(c) + try: r[-1] = r[-1] * 10 + c + except: r.append(c) + except: + r.append(c) + return r + diff --git a/wqflask/wqflask/__init__.py b/wqflask/wqflask/__init__.py new file mode 100644 index 00000000..d0484c83 --- /dev/null +++ b/wqflask/wqflask/__init__.py @@ -0,0 +1,13 @@ +from __future__ import absolute_import, division, print_function + +from flask import Flask + +from utility import formatting + +app = Flask(__name__) + +app.jinja_env.globals.update( + numify = formatting.numify +) + +import wqflask.views diff --git a/wqflask/wqflask/search_results.py b/wqflask/wqflask/search_results.py new file mode 100644 index 00000000..c100645e --- /dev/null +++ b/wqflask/wqflask/search_results.py @@ -0,0 +1,1288 @@ +from __future__ import absolute_import, division, print_function + +from wqflask import app + +from flask import render_template + +################################################### +# +# This file uses only spaces for indentation # +# +################################################### + +import string +import os +import cPickle +import re +from math import * +import time +import pyXLWriter as xl +#import pp - Note from Sam: is this used? +import math +import datetime + +from pprint import pformat as pf + +# Instead of importing HT we're going to build a class below until we can eliminate it +from htmlgen import HTMLgen2 as HT + +from base import webqtlConfig +from utility.THCell import THCell +from utility.TDCell import TDCell +from base.webqtlDataset import webqtlDataset +from base.webqtlTrait import webqtlTrait +from base.templatePage import templatePage +from utility import webqtlUtil +from dbFunction import webqtlDatabaseFunction + +import logging +logging.basicConfig(filename="/tmp/gn_log", level=logging.INFO) + +_log = logging.getLogger("search") +_ch = logging.StreamHandler() +_log.addHandler(_ch) + +from utility import formatting + +import sys +_log.info("sys.path is: %s" % (sys.path)) + + +#from base.JinjaPage import JinjaEnv, JinjaPage + + + +class SearchResultPage(templatePage): + + maxReturn = 3000 + #NPerPage = 100 + nkeywords = 0 + + def __init__(self, fd): + _log.info("Got here - xerxes2") + _log.info("sys.path: %s" % (sys.path)) + #_log.info(causeanerror) + _log.info("xerxesc") + #self.jtemplate = JinjaEnv.get_template('SearchResultPage.html') + #templatePage.__init__(self, fd) + + if not self.openMysql(): + return + + _log.info("xerxesd") + + #self.dict['title'] = 'Search Results' + #TD_LR = HT.TD(height=200,width="100%",bgColor='#eeeeee',valign="top") + print("e2.8") + self.database = [fd['database']] + print("e2.9") + if not self.database or self.database == 'spacer': + print("e3") + #Error, No database selected + heading = "Search Result" + detail = ['''No database was selected for this search, please + go back and SELECT at least one database.'''] + self.error(heading=heading,detail=detail,error="No Database Selected") + return + elif type(self.database) == type(""): + print("e3.2") + #convert database into a database list + #was used for multiple databases search, this + #feature has been abandoned, + self.database = string.split(self.database,',') + else: + print("e3.4") + pass + + print("e4") + ########################################### + # Names and IDs of RISet / F2 set + ########################################### + if self.database == ['_allPublish']: + self.cursor.execute("""select PublishFreeze.Name, InbredSet.Name, InbredSet.Id from PublishFreeze, + InbredSet where PublishFreeze.Name not like 'BXD300%' and InbredSet.Id = + PublishFreeze.InbredSetId""") + results = self.cursor.fetchall() + self.database = map(lambda x: webqtlDataset(x[0], self.cursor), results) + self.databaseCrosses = map(lambda x: x[1], results) + self.databaseCrossIds = map(lambda x: x[2], results) + self.singleCross = False + else: + self.database = map(lambda x: webqtlDataset(x, self.cursor), self.database) + #currently, webqtl wouldn't allow multiple crosses + #for other than multiple publish db search + #so we can use the first database as example + if self.database[0].type=="Publish": + pass + elif self.database[0].type in ("Geno", "ProbeSet"): + + #userExist = None + + for individualDB in self.database: + self.cursor.execute('SELECT Id, Name, FullName, confidentiality, AuthorisedUsers FROM %sFreeze WHERE Name = "%s"' % (self.database[0].type, individualDB)) + indId, indName, indFullName, confidential, AuthorisedUsers = self.cursor.fetchall()[0] + + if confidential == 1: + access_to_confidential_dataset = 0 + + #for the dataset that confidentiality is 1 + #1. 'admin' and 'root' can see all of the dataset + #2. 'user' can see the dataset that AuthorisedUsers contains his id(stored in the Id field of User table) + if webqtlConfig.USERDICT[self.privilege] > webqtlConfig.USERDICT['user']: + access_to_confidential_dataset = 1 + else: + AuthorisedUsersList=AuthorisedUsers.split(',') + if AuthorisedUsersList.__contains__(self.userName): + access_to_confidential_dataset = 1 + + if not access_to_confidential_dataset: + #Error, No database selected + heading = "Search Result" + detail = ["The %s database you selected is not open to the public at this time, please go back and SELECT other database." % indFullName] + self.error(heading=heading,detail=detail,error="Confidential Database") + return + else: + heading = "Search Result" + detail = ['''The database has not been established yet, please + go back and SELECT at least one database.'''] + self.error(heading=heading,detail=detail,error="No Database Selected") + return + + self.database[0].getRISet() + self.databaseCrosses = [self.database[0].riset] + self.databaseCrossIds = [self.database[0].risetid] + self.singleCross = True + #XZ, August 24,2010: Since self.singleCross = True, it's safe to assign one species Id. + self.speciesId = webqtlDatabaseFunction.retrieveSpeciesId(self.cursor, self.database[0].riset) + + print("e4.5") + ########################################### + # make sure search from same type of databases + ########################################### + dbTypes = map(lambda X: X.type, self.database) + self.dbType = dbTypes[0] + for item in dbTypes: + if item != self.dbType: + heading = "Search Result" + detail = ["Search can only be performed among the same type of databases"] + self.error(heading=heading,detail=detail,error="Error") + return + if self.dbType == "Publish": + self.searchField = ['Phenotype.Post_publication_description', 'Phenotype.Pre_publication_description', 'Phenotype.Pre_publication_abbreviation', 'Phenotype.Post_publication_abbreviation', 'Phenotype.Lab_code', 'Publication.PubMed_ID', 'Publication.Abstract', 'Publication.Title', 'Publication.Authors', 'PublishXRef.Id'] + + elif self.dbType == "ProbeSet": + self.searchField = ['Name','Description','Probe_Target_Description','Symbol','Alias','GenbankId', 'UniGeneId','RefSeq_TranscriptId'] + elif self.dbType == "Geno": + self.searchField = ['Name','Chr'] + + print("e4.6") + ########################################### + # Search Options + ########################################### + self.matchwhole = fd['matchwhole'] + print("e4.65") + #split result into pages + self.pageNumber = fd.get('pageno', 0) + print("e4.7") + try: + self.pageNumber = int(self.pageNumber) + except Exception as why: + print(why) + self.pageNumber = 0 + + print("e5") + ########################################### + # Generate Mysql Query + ########################################### + geneIdListQuery = fd.get('geneId', '') + if geneIdListQuery: + geneIdListQuery = string.replace(geneIdListQuery, ",", " ") + geneIdListQuery = " geneId=%s" % string.join(string.split(geneIdListQuery), "-") + + self.ANDkeyword = fd.get('ANDkeyword', "") + self.ORkeyword = fd.get('ORkeyword', "") + + self.ORkeyword += geneIdListQuery + + self.ANDkeyword = self.ANDkeyword.replace("\\", "").strip() + self.ORkeyword = self.ORkeyword.replace("\\", "").strip() + #user defined sort option + self.orderByUserInput = fd.get('orderByUserInput', "").strip() + #default sort option if user have not defined + self.orderByDefalut = "" + + #XZ, Dec/16/2010: I add examples to help understand this block of code. See details in function pattersearch. + + #XZ: self._1mPattern examples: WIKI=xxx, RIF=xxx, GO:0045202 + self._1mPattern = re.compile('\s*(\S+)\s*[:=]\s*([a-zA-Z-\+\d\.]+)\s*') + + #XZ: self._2mPattern examples: Mean=(15.0 16.0), Range=(10 100), LRS=(Low_LRS_limit, High_LRS_limit), pvalue=(Low_limit, High_limit), Range=(10 100) + self._2mPattern = re.compile('\s*(\S+)\s*[=in]{1,2}\s*\(\s*([-\d\.]+)[, \t]+([-\d\.]+)[, \t]*([-\d\.]*)\s*\)') + + #XZ: self._3mPattern examples: Position=(Chr1 98 104), Pos=(Chr1 98 104), Mb=(Chr1 98 104), CisLRS=(Low_LRS_limit, High_LRS_limit, Mb_buffer), TransLRS=(Low_LRS_limit, High_LRS_limit, Mb_buffer) + self._3mPattern = re.compile('\s*(\S+)\s*[=in]{1,2}\s*\(\s*[Cc][Hh][Rr]([^, \t]+)[, \t]+([-\d\.]+)[, \t]+([-\d\.]+)\s*\)') + + #XZ: self._5mPattern examples: LRS=(Low_LRS_limit, High_LRS_limit, ChrNN, Mb_Low_Limit, Mb_High_Limit) + self._5mPattern = re.compile('\s*(\S+)\s*[=in]{1,2}\s*\(\s*([-\d\.]+)[, \t]+([-\d\.]+)[, \t]+[Cc][Hh][Rr]([^, \t]+)[, \t]+([-\d\.]+)[, \t]+([-\d\.]+)\s*\)') + + #Error, No keyword input + if not (self.ORkeyword or self.ANDkeyword): + heading = "Search Result" + detail = ["Please make sure to enter either your search terms (genes, traits, markers), or advanced search commands."] + self.error(heading=heading,detail=detail,error="No search terms were entered") + return + + #query clauses + self.ANDQuery = [] + self.ORQuery = [] + #descriptions, one for OR search, one for AND search + self.ANDDescriptionText = [] + self.ORDescriptionText = [] + + if not self.normalSearch(): + return + if not self.patternSearch(): + return + if not self.assembleQuery(): + return + self.nresults = self.executeQuery() + + if len(self.database) > 1: + dbUrl = "Multiple phenotype databases" + dbUrlLink = " were" + else: + dbUrl = self.database[0].genHTML() + print("glasses:", dbUrl) + dbUrlLink = " was" + + #SearchText = HT.Blockquote('GeneNetwork searched the ', dbUrl, ' for all records ') + #if self.ORkeyword2: + # NNN = len(self.ORkeyword2) + # if NNN > 1: + # SearchText.append(' that match the terms ') + # else: + # SearchText.append(' that match the term ') + # for j, term in enumerate(self.ORkeyword2): + # SearchText.append(HT.U(term)) + # if NNN > 1 and j < NNN-2: + # SearchText.append(", ") + # elif j == NNN-2: + # SearchText.append(", or ") + # else: + # pass + #if self.ORDescriptionText: + # if self.ORkeyword2: + # SearchText.append("; ") + # else: + # SearchText.append(" ") + # for j, item in enumerate(self.ORDescriptionText): + # SearchText.append(item) + # if j < len(self.ORDescriptionText) -1: + # SearchText.append(";") + # + #if (self.ORkeyword2 or self.ORDescriptionText) and (self.ANDkeyword2 or self.ANDDescriptionText): + # SearchText.append("; ") + #if self.ANDkeyword2: + # if (self.ORkeyword2 or self.ORDescriptionText): + # SearchText.append(' records') + # NNN = len(self.ANDkeyword2) + # if NNN > 1: + # SearchText.append(' that match the terms ') + # else: + # SearchText.append(' that match the term ') + # for j, term in enumerate(self.ANDkeyword2): + # SearchText.append(HT.U(term)) + # if NNN > 1 and j < NNN-2: + # SearchText.append(", ") + # elif j == NNN-2: + # SearchText.append(", and ") + # else: + # pass + #if self.ANDDescriptionText: + # if self.ANDkeyword2: + # SearchText.append(" and ") + # else: + # SearchText.append(" ") + # for j, item in enumerate(self.ANDDescriptionText): + # SearchText.append(item) + # if j < len(self.ANDDescriptionText) -1: + # SearchText.append(" and ") + # + #SearchText.append(". ") + _log.info("fweep") + #if self.nresults == 0: + # heading = "Search Result" + # detail = ["Sorry, GeneNetwork did not find any records matching your request. Please check the syntax or try the ANY rather than the ALL field."] + # self.error(heading=heading,intro = SearchText.contents,detail=detail,error="Not Found") + # return + #elif self.nresults == 1: + # SearchText.append(HT.P(), 'GeneNetwork found one record that matches your request. To study this record, click on its text below. To add this record to your Selection window, use the checkbox and then click the ', HT.Strong('Add to Collection'),' button. ') + #elif self.nresults >= 1 and self.nresults <= self.maxReturn: + # SearchText.append(HT.P(), 'GeneNetwork found a total of ', HT.Span(self.nresults, Class='fwb cr'), ' records. To study any one of these records, click on its ID below. To add one or more records to your Selection window, use the checkbox and then click the ' , HT.Strong('Add to Collection'),' button. ') + #else: + # SearchText.append(' A total of ',HT.Span(self.nresults, Class='fwb cr'), ' records were found.') + # heading = "Search Result" + # # Modified by Hongqiang Li + # # detail = ["The terms you entered match %d records. Please modify your search to generate %d or fewer matches, or review " % (self.nresults, self.maxReturn), HT.Href(text='Search Help', target='_blank', url='http://web2qtl.utmem.edu/searchHelp.html', Class='fs14'), " to learn more about syntax and the use of wildcard characters."] + # detail = ["The terms you entered match %d records. Please modify your search to generate %d or fewer matches, or review " % (self.nresults, self.maxReturn), HT.Href(text='Search Help', target='_blank', url='%s/searchHelp.html' % webqtlConfig.PORTADDR, Class='fs14'), " to learn more about syntax and the use of wildcard characters."] + # # + # self.error(heading=heading,intro = SearchText.contents,detail=detail,error="Over %d" % self.maxReturn) + # return + + + #TD_LR.append(HT.Paragraph('Search Results', Class="title"), SearchText) + _log.info("flop") + self.genSearchResultTable() + #self.dict['body'] = str(TD_LR) + #self.dict['js1'] = '' + #self.dict['js2'] = 'onLoad="pageOffset()"' + #self.dict['layer'] = self.generateWarningLayer() + + def genSearchResultTable(self): + + #pageTable = HT.TableLite(cellSpacing=2,cellPadding=0,width="100%",border=0) + + lastone = False + for i, item in enumerate(self.results): + if not item: + continue + lastone = False + + self.traitList = [] + for k, item2 in enumerate(item): + j, ProbeSetID = item2[:2] + thisTrait = webqtlTrait(db=self.database[j], name=ProbeSetID, cursor=self.cursor) + self.traitList.append(thisTrait) + + ############## + # Excel file # + ############## + + # Todo: Replace this with official Python temp file naming functions? + filename= webqtlUtil.genRandStr("Search_") + #xlsUrl = HT.Input(type='button', value = 'Download Table', onClick= "location.href='/tmp/%s.xls'" % filename, Class='button') + # Create a new Excel workbook + #workbook = xl.Writer('%s.xls' % (webqtlConfig.TMPDIR+filename)) + #headingStyle = workbook.add_format(align = 'center', bold = 1, border = 1, size=13, fg_color = 0x1E, color="white") + + #XZ, 3/18/2010: pay attention to the line number of header in this file. As of today, there are 7 lines. + #worksheet = self.createExcelFileWithTitleAndFooter(workbook=workbook, db=thisTrait.db, returnNumber=len(self.traitList)) + newrow = 7 + + #tbl = HT.TableLite(cellSpacing=2,cellPadding=0,width="90%",border=0) + #seq = self.pageNumber*self.NPerPage+1 //Edited out because we show all results in one page now - Zach 2/22/11 + seq = 1 + RISet = self.databaseCrosses[i] + self.thisFormName = thisFormName = 'showDatabase'+RISet + #selectall = HT.Href(url="#", onClick="checkAll(document.getElementsByName('%s')[0]);" % thisFormName) + #selectall_img = HT.Image("/images/select_all2_final.jpg", name="selectall", alt="Select All", title="Select All", style="border:none;") + #selectall.append(selectall_img) + #reset = HT.Href(url="#", onClick="checkNone(document.getElementsByName('%s')[0]);" % thisFormName) + #reset_img = HT.Image("/images/select_none2_final.jpg", alt="Select None", title="Select None", style="border:none;") + #reset.append(reset_img) + #selectinvert = HT.Href(url="#", onClick="checkInvert(document.getElementsByName('%s')[0]);" % thisFormName) + #selectinvert_img = HT.Image("/images/invert_selection2_final.jpg", name="selectinvert", alt="Invert Selection", title="Invert Selection", style="border:none;") + #selectinvert.append(selectinvert_img) + #addselect = HT.Href(url="#") + #addselect_img = HT.Image("/images/add_collection1_final.jpg", name="addselect", alt="Add To Collection", title="Add To Collection", style="border:none;") + #addselect.append(addselect_img) + + #optionsTable = HT.TableLite(cellSpacing=2,cellPadding=0,width="20%",border=0) + #optionsRow = HT.TR(HT.TD(selectall, width="25%"), HT.TD(reset, width="25%"), HT.TD(selectinvert, width="25%"), HT.TD(addselect, width="25%")) + #labelsRow = HT.TR(HT.TD(" "*2,"Select", width="25%"), HT.TD(" ","Deselect", width="255"), HT.TD(" "*3,"Invert", width="25%"), HT.TD(" "*4,"Add", width="25%")) + #optionsTable.append(optionsRow, labelsRow) + + #pageTable.append(HT.TR(HT.TD(optionsTable)), HT.TR(HT.TD(xlsUrl, height=40))) + + tblobj = {} + mainfmName = thisFormName + species = webqtlDatabaseFunction.retrieveSpecies(cursor=self.cursor, RISet=RISet) + _log.info("flap trait is: %s" % (thisTrait.db.type)) + if thisTrait.db.type=="Geno": + tblobj['header'] = self.getTableHeaderForGeno(worksheet=worksheet, newrow=newrow, headingStyle=headingStyle) + + newrow += 1 + sortby = self.getSortByValue(datasetType="Geno") + + tblobj['body'] = self.getTableBodyForGeno(traitList=self.traitList, formName=mainfmName, worksheet=worksheet, newrow=newrow) + + #workbook.close() + objfile = open('%s.obj' % (webqtlConfig.TMPDIR+filename), 'wb') + cPickle.dump(tblobj, objfile) + objfile.close() + + div = HT.Div(webqtlUtil.genTableObj(tblobj, filename, sortby), Id="sortable") + + pageTable.append(HT.TR(HT.TD(div))) + + elif thisTrait.db.type=="Publish": + #tblobj['header'] = self.getTableHeaderForPublish(worksheet=worksheet, newrow=newrow, headingStyle=headingStyle) + + newrow += 1 + + sortby = self.getSortByValue(datasetType="Publish") + + #tblobj['body'] = self.getTableBodyForPublish(traitList=self.traitList, formName=mainfmName, worksheet=worksheet, newrow=newrow, species=species) + + #workbook.close() + #objfile = open('%s.obj' % (webqtlConfig.TMPDIR+filename), 'wb') + #cPickle.dump(tblobj, objfile) + #objfile.close() + + #div = HT.Div(webqtlUtil.genTableObj(tblobj, filename, sortby), Id="sortable") + + #pageTable.append(HT.TR(HT.TD(div))) + + elif thisTrait.db.type=="ProbeSet": + #tblobj['header'] = self.getTableHeaderForProbeSet(worksheet=worksheet, newrow=newrow, headingStyle=headingStyle) + + newrow += 1 + + sortby = self.getSortByValue(datasetType="ProbeSet") + + tblobj['body'] = self.getTableBodyForProbeSet(traitList=self.traitList, formName=mainfmName, newrow=newrow, species=species) + + #workbook.close() + objfile = open('%s.obj' % (webqtlConfig.TMPDIR+filename), 'wb') + cPickle.dump(tblobj, objfile) + objfile.close() + + #div = HT.Div(webqtlUtil.genTableObj(tblobj, filename, sortby), Id="sortable") + + #pageTable.append(HT.TR(HT.TD(div))) + + + #traitForm = HT.Form(cgi= os.path.join(webqtlConfig.CGIDIR, webqtlConfig.SCRIPTFILE), enctype='multipart/form-data', name=thisFormName, submit=HT.Input(type='hidden')) + hddn = {'FormID':'showDatabase','ProbeSetID':'_','database':'_','CellID':'_','RISet':RISet} + hddn['incparentsf1']='ON' + # for key in hddn.keys(): + # traitForm.append(HT.Input(name=key, value=hddn[key], type='hidden')) + # + # traitForm.append(HT.P(),pageTable) + # + # TD_LR.append(traitForm) + # if len(self.results) > 1 and i < len(self.results) - 1: + # lastone = True + #if lastone: + # TD_LR.contents.pop() + + def executeQuery(self): + + ##construct sorting + if self.dbType == "Publish": + sortQuery = " order by Publication_PubMed_ID desc, Phenotype_Name, thistable" + elif self.dbType == "Geno": + if not self.orderByUserInput: + if self.orderByDefalut: + self.orderByUserInput = self.orderByDefalut + else: + self.orderByUserInput = "POSITION" + if self.orderByUserInput.upper() in ["POS", "POSITION", "MB"]: + self.orderByUserInput = "POSITION" + else: + pass + self.orderByUserInput = self.orderByUserInput.upper() + self.orderByUserInputOrig = self.orderByUserInput[:] + if self.orderByUserInput == "NAME": + sortQuery = " order by Geno_Name, Geno_chr_num, Geno_Mb" + elif self.orderByUserInput == "SOURCE": + sortQuery = " order by Geno_Source2, Geno_chr_num, Geno_Mb" + else: + sortQuery = " order by Geno_chr_num, Geno_Mb" + #ProbeSet + else: + if not self.orderByUserInput: + if self.orderByDefalut: + self.orderByUserInput = self.orderByDefalut + else: + self.orderByUserInput = "POSITION" + + self.orderByUserInput = self.orderByUserInput.upper() + self.orderByUserInputOrig = self.orderByUserInput[:] + #XZ: 8/18/2009: "POSITION-" + if self.orderByUserInput[-1] == '-': + self.orderByUserInput = self.orderByUserInput[:-1] + sortDesc = 'desc' + else: + sortDesc = '' + + if self.orderByUserInput in ["MEAN", "LRS", "PVALUE"]: + #sortQuery = " order by T%s %s, TNAME, thistable desc" % (self.orderByUserInput, sortDesc) + sortQuery = " order by T%s desc, TNAME, thistable desc" % self.orderByUserInput + elif self.orderByUserInput in ["POS", "POSITION", "MB"]: + sortQuery = " order by TCHR_NUM %s, TMB %s, TNAME, thistable desc" % (sortDesc, sortDesc) + elif self.orderByUserInput == 'SYMBOL': + sortQuery = " order by TSYMBOL, thistable desc" + else: + sortQuery = " order by TNAME_NUM, thistable desc" + + if self.singleCross: + if len(self.query) > 1: + searchQuery = map(lambda X:'(%s)' % X, self.query) + searchQuery = string.join(searchQuery, ' UNION ALL ') + else: + searchQuery = self.query[0] + searchQuery += sortQuery + #searchCountQuery retrieve all the results + searchCountQuery = [searchQuery] + #searchQuery = searchQuery + " limit %d,%d" % (self.pageNumber*self.NPerPage, self.NPerPage) // We removed the page limit - Zach 2/22/11 + searchQuery = [searchQuery] + else: + searchCountQuery = searchQuery = map(lambda X: X+sortQuery, self.query) + + allResults = [] + self.results = [] + for item in searchCountQuery: + start_time = datetime.datetime.now() + _log.info("foo - Executing query: %s"%(item)) + self.cursor.execute(item) + allResults.append(self.cursor.fetchall()) + end_time = datetime.datetime.now() + _log.info("Total time: %s"%(end_time-start_time)) + + _log.info("Done executing queries") + + + #searchCountQuery retrieve all the results, for counting use only + if searchCountQuery != searchQuery: + for item in searchQuery: + self.cursor.execute(item) + self.results.append(self.cursor.fetchall()) + else: + self.results = allResults + + nresults = reduce(lambda Y,X:len(X)+Y, allResults, 0) + return nresults + + + + def assembleQuery(self): + self.query = [] + if self.ANDQuery or self.ORQuery: + clause = self.ORQuery[:] + + for j, database in enumerate(self.database): + if self.ANDQuery: + clause.append(" (%s) " % string.join(self.ANDQuery, " AND ")) + + newclause = [] + + for item in clause: + ##need to retrieve additional field which won't be used + ##in the future, for sorting purpose only + if self.dbType == "Publish": + if item.find("Geno.name") < 0: + incGenoTbl = "" + else: + incGenoTbl = " Geno, " + newclause.append("SELECT %d, PublishXRef.Id, PublishFreeze.createtime as thistable, Publication.PubMed_ID as Publication_PubMed_ID, Phenotype.Post_publication_description as Phenotype_Name FROM %s PublishFreeze, Publication, PublishXRef, Phenotype WHERE PublishXRef.InbredSetId = %d and %s and PublishXRef.PhenotypeId = Phenotype.Id and PublishXRef.PublicationId = Publication.Id and PublishFreeze.Id = %d" % (j, incGenoTbl, self.databaseCrossIds[j], item, database.id)) + elif self.dbType == "ProbeSet": + if item.find("GOgene") < 0: + incGoTbl = "" + else: + incGoTbl = " ,db_GeneOntology.term as GOterm, db_GeneOntology.association as GOassociation, db_GeneOntology.gene_product as GOgene_product " + if item.find("Geno.name") < 0: + incGenoTbl = "" + else: + incGenoTbl = " Geno, " + if item.find("GeneRIF_BASIC.") < 0: + incGeneRIFTbl = "" + else: + incGeneRIFTbl = " GeneRIF_BASIC, " + if item.find("GeneRIF.") < 0: + incGeneRIFTbl += "" + else: + incGeneRIFTbl += " GeneRIF, " + newclause.append("""SELECT distinct %d, ProbeSet.Name as TNAME, 0 as thistable, + ProbeSetXRef.Mean as TMEAN, ProbeSetXRef.LRS as TLRS, ProbeSetXRef.PVALUE as TPVALUE, + ProbeSet.Chr_num as TCHR_NUM, ProbeSet.Mb as TMB, ProbeSet.Symbol as TSYMBOL, + ProbeSet.name_num as TNAME_NUM FROM %s%s ProbeSetXRef, ProbeSet %s + WHERE %s and ProbeSet.Id = ProbeSetXRef.ProbeSetId and ProbeSetXRef.ProbeSetFreezeId = %d + """ % (j, incGeneRIFTbl, incGenoTbl, incGoTbl, item, database.id)) + elif self.dbType == "Geno": + newclause.append("SELECT %d, Geno.Name, GenoFreeze.createtime as thistable, Geno.Name as Geno_Name, Geno.Source2 as Geno_Source2, Geno.chr_num as Geno_chr_num, Geno.Mb as Geno_Mb FROM GenoXRef, GenoFreeze, Geno WHERE %s and Geno.Id = GenoXRef.GenoId and GenoXRef.GenoFreezeId = GenoFreeze.Id and GenoFreeze.Id = %d"% (j, item, database.id)) + else: + pass + + searchQuery = map(lambda X:'(%s)' % X, newclause) + searchQuery = string.join(searchQuery, ' UNION ') + self.query.append(searchQuery) + return 1 + else: + heading = "Search Result" + detail = ["No keyword was entered for this search, please go back and enter your keyword."] + self.error(heading=heading,detail=detail,error="No Keyword") + return 0 + + + + def normalSearch(self): + self.ANDkeyword2 = re.sub(self._1mPattern, '', self.ANDkeyword) + self.ANDkeyword2 = re.sub(self._2mPattern, '', self.ANDkeyword2) + self.ANDkeyword2 = re.sub(self._3mPattern, '', self.ANDkeyword2) + self.ANDkeyword2 = re.sub(self._5mPattern, '', self.ANDkeyword2) + ##remove remain parethesis, could be input with syntax error + self.ANDkeyword2 = re.sub(re.compile('\s*\([\s\S]*\)'), '', self.ANDkeyword2) + self.ANDkeyword2 = self.encregexp(self.ANDkeyword2) + + self.ORkeyword2 = re.sub(self._1mPattern, '', self.ORkeyword) + self.ORkeyword2 = re.sub(self._2mPattern, '', self.ORkeyword2) + self.ORkeyword2 = re.sub(self._3mPattern, '', self.ORkeyword2) + self.ORkeyword2 = re.sub(self._5mPattern, '', self.ORkeyword2) + ##remove remain parethesis, could be input with syntax error + self.ORkeyword2 = re.sub(re.compile('\s*\([\s\S]*\)'), '', self.ORkeyword2) + self.ORkeyword2 = self.encregexp(self.ORkeyword2) + + if self.ORkeyword2 or self.ANDkeyword2: + ANDFulltext = [] + ORFulltext = [] + for k, item in enumerate(self.ORkeyword2 + self.ANDkeyword2): + self.nkeywords += 1 + if k >=len(self.ORkeyword2): + query = self.ANDQuery + DescriptionText = self.ANDDescriptionText + clausejoin = ' OR ' + fulltext = ANDFulltext + else: + query = self.ORQuery + DescriptionText = self.ORDescriptionText + clausejoin = ' OR ' + fulltext = ORFulltext + + if self.dbType == "ProbeSet" and item.find('.') < 0 and item.find('\'') < 0: + fulltext.append(item) + else: + if self.matchwhole and item.find("'") < 0: + item = "[[:<:]]"+ item+"[[:>:]]" + clause2 = [] + for field in self.searchField: + if self.dbType == "Publish": + clause2.append("%s REGEXP \"%s\"" % (field,item)) + else: + clause2.append("%s REGEXP \"%s\"" % ("%s.%s" % (self.dbType,field),item)) + clauseItem = "(%s)" % string.join(clause2, clausejoin) + query.append(" (%s) " % clauseItem) + if ANDFulltext: + clauseItem = " MATCH (ProbeSet.Name,ProbeSet.description,ProbeSet.symbol,alias,GenbankId, UniGeneId, Probe_Target_Description) AGAINST ('+%s' IN BOOLEAN MODE) " % string.join(ANDFulltext, " +") + self.ANDQuery.append(" (%s) " % clauseItem) + if ORFulltext: + clauseItem = " MATCH (ProbeSet.Name,ProbeSet.description,ProbeSet.symbol,alias,GenbankId, UniGeneId, Probe_Target_Description) AGAINST ('%s' IN BOOLEAN MODE) " % string.join(ORFulltext, " ") + self.ORQuery.append(" (%s) " % clauseItem) + else: + pass + return 1 + + + + def encregexp(self,str): + if not str: + return [] + else: + wildcardkeyword = str.strip() + wildcardkeyword = string.replace(wildcardkeyword,',',' ') + wildcardkeyword = string.replace(wildcardkeyword,';',' ') + wildcardkeyword = wildcardkeyword.split() + NNN = len(wildcardkeyword) + for i in range(NNN): + keyword = wildcardkeyword[i] + keyword = string.replace(keyword,"*",".*") + keyword = string.replace(keyword,"?",".") + wildcardkeyword[i] = keyword#'[[:<:]]'+ keyword+'[[:>:]]' + return wildcardkeyword + + + + def patternSearch(self): + # Lei Yan + ##Process Inputs + m1_AND = self._1mPattern.findall(self.ANDkeyword) + m2_AND = self._2mPattern.findall(self.ANDkeyword) + m3_AND = self._3mPattern.findall(self.ANDkeyword) + m5_AND = self._5mPattern.findall(self.ANDkeyword) + m1_OR = self._1mPattern.findall(self.ORkeyword) + m2_OR = self._2mPattern.findall(self.ORkeyword) + m3_OR = self._3mPattern.findall(self.ORkeyword) + m5_OR = self._5mPattern.findall(self.ORkeyword) + + #pattern search + if m1_AND or m1_OR or m2_AND or m2_OR or m3_AND or m3_OR or m5_AND or m5_OR: + + self.orderByDefalut = 'PROBESETID' + + _1Cmds = map(string.upper, map(lambda x:x[0], m1_AND + m1_OR)) + _2Cmds = map(string.upper, map(lambda x:x[0], m2_AND + m2_OR)) + _3Cmds = map(string.upper, map(lambda x:x[0], m3_AND + m3_OR)) + _5Cmds = map(string.upper, map(lambda x:x[0], m5_AND + m5_OR)) + + self.nkeywords += len(_1Cmds) + len(_2Cmds) + len(_3Cmds) + + if self.dbType == "Publish" and \ + ( (_2Cmds and reduce(lambda x, y: (y not in ["LRS"]) or x, _2Cmds, False))\ + or (_5Cmds and reduce(lambda x, y: (y not in ["LRS"]) or x, _5Cmds, False)) ): + heading = "Search Result" + detail = ["Pattern search is not available for phenotype databases at this time."] + self.error(heading=heading,detail=detail,error="Error") + return 0 + elif self.dbType == "ProbeSet" and \ + ((_2Cmds and reduce(lambda x, y: (y not in ["MEAN", "LRS", "PVALUE", "TRANSLRS", "CISLRS", "RANGE", "H2"]) or x, _2Cmds, False))\ + or (_3Cmds and reduce(lambda x, y: (y not in ["POS", "POSITION", "MB"]) or x, _3Cmds, False))\ + or (_5Cmds and reduce(lambda x, y: (y not in ["LRS"]) or x, _5Cmds, False))\ + or (_1Cmds and reduce(lambda x, y: (y not in ["FLAG", "STRAND_PROBE", "STRAND_GENE", "GO", "WIKI", "RIF", "GENEID"]) or x, _1Cmds, False))): + heading = "Search Result" + detail = ["You entered at least one incorrect search command."] + self.error(heading=heading,detail=detail,error="Error") + return 0 + elif self.dbType == "Geno" and (_1Cmds or _2Cmds or _5Cmds or (_3Cmds and reduce(lambda x, y: (y not in ["POS", "POSITION", "MB"]) or x, _3Cmds, False)) ): + heading = "Search Result" + detail = ["You entered at least one incorrect search command."] + self.error(heading=heading,detail=detail,error="Error") + return 0 + else: + for k, item in enumerate(m1_OR+m1_AND): + if k >=len(m1_OR): + query = self.ANDQuery + DescriptionText = self.ANDDescriptionText + else: + query = self.ORQuery + DescriptionText = self.ORDescriptionText + + if item[1] == '-': + strandName = 'minus' + elif item[1] == '+': + strandName = 'plus' + else: + strandName = item[1] + + if item[0].upper() in ("FLAG"): + clauseItem = " %s.%s = %s " % (self.dbType, item[0], item[1]) + DescriptionText.append(HT.Span(' with ', HT.U('FLAG'), ' equal to ', item[1])) + elif item[0].upper() in ("WIKI"): + clauseItem = " %s.symbol = GeneRIF.symbol and GeneRIF.versionId=0 and GeneRIF.display>0 and (GeneRIF.comment REGEXP \"%s\" or GeneRIF.initial = \"%s\") " % (self.dbType, "[[:<:]]"+ item[1]+"[[:>:]]", item[1]) + DescriptionText.append(HT.Span(' with GeneWiki contains ', HT.U(item[1]))) + elif item[0].upper() in ("RIF"): + clauseItem = " %s.symbol = GeneRIF_BASIC.symbol and MATCH (GeneRIF_BASIC.comment) AGAINST ('+%s' IN BOOLEAN MODE) " % (self.dbType, item[1]) + DescriptionText.append(HT.Span(' with GeneRIF contains ', HT.U(item[1]))) + elif item[0].upper() in ("GENEID"): + clauseItem = " %s.GeneId in ( %s ) " % (self.dbType, string.replace(item[1], '-', ', ')) + DescriptionText.append(HT.Span(' with Entrez Gene ID in ', HT.U(string.replace(item[1], '-', ', ')))) + elif item[0].upper() in ("GO"): + Field = 'GOterm.acc' + Id = 'GO:'+('0000000'+item[1])[-7:] + Statements = '%s.symbol=GOgene_product.symbol and GOassociation.gene_product_id=GOgene_product.id and GOterm.id=GOassociation.term_id' % (self.dbType); + clauseItem = " %s = '%s' and %s " % (Field, Id, Statements) + #self.incGoTbl = " ,db_GeneOntology.term as GOterm, db_GeneOntology.association as GOassociation, db_GeneOntology.gene_product as GOgene_product " + DescriptionText.append(HT.Span(' with ', HT.U('GO'), ' ID equal to ', Id)) + else: + clauseItem = " %s.%s = '%s' " % (self.dbType, item[0], item[1]) + if item[0].upper() in ["STRAND_PROBE"]: + DescriptionText.append(' with probe on the %s strand' % strandName) + elif item[0].upper() in ["STRAND_GENE"]: + DescriptionText.append(' with gene on the %s strand' % strandName) + else: + pass + query.append(" (%s) " % clauseItem) + + for k, item in enumerate(m2_OR+m2_AND): + if k >=len(m2_OR): + query = self.ANDQuery + DescriptionText = self.ANDDescriptionText + else: + query = self.ORQuery + DescriptionText = self.ORDescriptionText + + itemCmd = item[0] + lowerLimit = float(item[1]) + upperLimit = float(item[2]) + + if itemCmd.upper() in ("TRANSLRS", "CISLRS"): + if item[3]: + mthresh = float(item[3]) + clauseItem = " %sXRef.LRS > %2.7f and %sXRef.LRS < %2.7f " % \ + (self.dbType, min(lowerLimit, upperLimit), self.dbType, max(lowerLimit, upperLimit)) + if itemCmd.upper() == "CISLRS": + clauseItem += """ and %sXRef.Locus = Geno.name and Geno.SpeciesId = %s and %s.Chr = Geno.Chr and ABS(%s.Mb-Geno.Mb) < %2.7f """ % (self.dbType, self.speciesId, self.dbType, self.dbType, mthresh) + DescriptionText.append(HT.Span(' with a ', HT.U('cis-QTL'), ' having an LRS between %g and %g using a %g Mb exclusion buffer' % (min(lowerLimit, upperLimit), max(lowerLimit, upperLimit), mthresh))) + else: + clauseItem += """ and %sXRef.Locus = Geno.name and Geno.SpeciesId = %s and (%s.Chr != Geno.Chr or (%s.Chr != Geno.Chr and ABS(%s.Mb-Geno.Mb) > %2.7f)) """ % (self.dbType, self.speciesId, self.dbType, self.dbType, self.dbType, mthresh) + DescriptionText.append(HT.Span(' with a ', HT.U('trans-QTL'), ' having an LRS between %g and %g using a %g Mb exclusion buffer' % (min(lowerLimit, upperLimit), max(lowerLimit, upperLimit), mthresh))) + query.append(" (%s) " % clauseItem) + self.orderByDefalut = "LRS" + else: + pass + elif itemCmd.upper() in ("RANGE"): + #XZ, 03/05/2009: Xiaodong changed Data to ProbeSetData + clauseItem = " (select Pow(2, max(value) -min(value)) from ProbeSetData where Id = ProbeSetXRef.dataId) > %2.7f and (select Pow(2, max(value) -min(value)) from ProbeSetData where Id = ProbeSetXRef.dataId) < %2.7f " % (min(lowerLimit, upperLimit), max(lowerLimit, upperLimit)) + query.append(" (%s) " % clauseItem) + DescriptionText.append(HT.Span(' with a range of expression that varied between %g and %g' % (min(lowerLimit, upperLimit), max(lowerLimit, upperLimit)), " (fold difference)")) + else: + clauseItem = " %sXRef.%s > %2.7f and %sXRef.%s < %2.7f " % \ + (self.dbType, itemCmd, min(lowerLimit, upperLimit), self.dbType, itemCmd, max(lowerLimit, upperLimit)) + query.append(" (%s) " % clauseItem) + self.orderByDefalut = itemCmd + DescriptionText.append(HT.Span(' with ', HT.U(itemCmd), ' between %g and %g' % (min(lowerLimit, upperLimit), max(lowerLimit, upperLimit)))) + + for k, item in enumerate(m3_OR+m3_AND): + if k >=len(m3_OR): + query = self.ANDQuery + DescriptionText = self.ANDDescriptionText + else: + query = self.ORQuery + DescriptionText = self.ORDescriptionText + itemCmd = item[0] + chrsch = item[1] + lowerLimit = float(item[2]) + upperLimit = float(item[3]) + fname = 'target genes' + if self.dbType == "ProbeSet": + clauseItem = " %s.Chr = '%s' and %s.Mb > %2.7f and %s.Mb < %2.7f " % \ + (self.dbType, chrsch, self.dbType, min(lowerLimit, upperLimit), self.dbType, max(lowerLimit, upperLimit)) + elif self.dbType == "Geno": + fname = 'loci' + clauseItem = " %s.Chr = '%s' and %s.Mb > %2.7f and %s.Mb < %2.7f " % \ + (self.dbType, chrsch, self.dbType, min(lowerLimit, upperLimit), self.dbType, max(lowerLimit, upperLimit)) + else: + continue + query.append(" (%s) " % clauseItem) + self.orderByDefalut = itemCmd + DescriptionText.append(HT.Span(' with ', HT.U('target genes'), ' on chromosome %s between %g and %g Mb' % \ + (chrsch, min(lowerLimit, upperLimit), max(lowerLimit, upperLimit)))) + + for k, item in enumerate(m5_OR+m5_AND): + if k >=len(m5_OR): + query = self.ANDQuery + DescriptionText = self.ANDDescriptionText + else: + query = self.ORQuery + DescriptionText = self.ORDescriptionText + itemCmd = item[0] + lowerLimit = float(item[1]) + upperLimit = float(item[2]) + chrsch = item[3] + MblowerLimit = float(item[4]) + MbupperLimit = float(item[5]) + if self.dbType == "ProbeSet" or self.dbType == "Publish": + clauseItem = " %sXRef.LRS > %2.7f and %sXRef.LRS < %2.7f " % \ + (self.dbType, min(lowerLimit, upperLimit), self.dbType, max(lowerLimit, upperLimit)) + clauseItem += " and %sXRef.Locus = Geno.name and Geno.SpeciesId = %s and Geno.Chr = '%s' and Geno.Mb > %2.7f and Geno.Mb < %2.7f" \ + % (self.dbType, self.speciesId, chrsch, min(MblowerLimit, MbupperLimit), max(MblowerLimit, MbupperLimit)) + query.append(" (%s) " % clauseItem) + self.orderByDefalut = "MB" + DescriptionText.append(HT.Span(' with ', HT.U('LRS'), ' between %g and %g' % \ + (min(lowerLimit, upperLimit), max(lowerLimit, upperLimit)), \ + ' on chromosome %s between %g and %g Mb' % \ + (chrsch, min(MblowerLimit, MbupperLimit), max(MblowerLimit, MbupperLimit)))) + pass + + return 1 + + def generateWarningLayer(self): + + layerString = """ + <!-- BEGIN FLOATING LAYER CODE //--> + <div id="warningLayer" style="padding:3px; border: 1px solid #222; + background-color: #fff; position:absolute;width:250px;left:100;top:100;visibility:hidden"> + <table border="0" width="250" class="cbrb" cellspacing="0" cellpadding="5"> + <tr> + <td width="100%"> + <table border="0" width="100%" cellspacing="0" cellpadding="0" height="36"> + <tr> + <td class="cbrb cw ff15 fwb" align="Center" width="100%" style="padding:4px"> + Sort Table + </td> + </tr> + <tr> + <td width="100%" bgcolor="#eeeeee" align="Center" style="padding:4px"> + <!-- PLACE YOUR CONTENT HERE //--> + Resorting this table <br> + <!-- END OF CONTENT AREA //--> + </td> + </tr> + </table> + </td> + </tr> + </table> + </div> + <!-- END FLOATING LAYER CODE //--> + + """ + + return layerString + + def getTableHeaderForGeno(self, worksheet=None, newrow=None, headingStyle=None): + + tblobj_header = [] + + className = "fs13 fwb ffl b1 cw cbrb" + + tblobj_header = [[THCell(HT.TD(' ', Class=className), sort=0), + THCell(HT.TD('Record', HT.BR(), 'ID', HT.BR(), Class=className), text='record_id', idx=1), + THCell(HT.TD('Location', HT.BR(), 'Chr and Mb', HT.BR(), Class=className), text='location', idx=2)]] + + for ncol, item in enumerate(['Record ID', 'Location (Chr, Mb)']): + worksheet.write([newrow, ncol], item, headingStyle) + worksheet.set_column([ncol, ncol], 2*len(item)) + + return tblobj_header + + + def getTableBodyForGeno(self, traitList, formName=None, worksheet=None, newrow=None): + + tblobj_body = [] + + className = "fs12 fwn ffl b1 c222" + + for thisTrait in traitList: + tr = [] + + if not thisTrait.haveinfo: + thisTrait.retrieveInfo() + + trId = str(thisTrait) + + tr.append(TDCell(HT.TD(HT.Input(type="checkbox", Class="checkbox", name="searchResult",value=trId, onClick="highlight(this)"), nowrap="on", Class=className), text=trId)) + + tr.append(TDCell(HT.TD(HT.Href(text=thisTrait.name,url="javascript:showDatabase3('%s','%s','%s','')" % (formName, thisTrait.db.name, thisTrait.name), Class="fs12 fwn ffl"),align="left", Class=className), text=thisTrait.name, val=thisTrait.name.upper())) + + #XZ: trait_location_value is used for sorting + trait_location_repr = 'N/A' + trait_location_value = 1000000 + + if thisTrait.chr and thisTrait.mb: + try: + trait_location_value = int(thisTrait.chr)*1000 + thisTrait.mb + except: + if thisTrait.chr.upper() == 'X': + trait_location_value = 20*1000 + thisTrait.mb + else: + trait_location_value = ord(str(thisTrait.chr).upper()[0])*1000 + thisTrait.mb + + trait_location_repr = 'Chr%s: %.6f' % (thisTrait.chr, float(thisTrait.mb) ) + + tr.append(TDCell(HT.TD(trait_location_repr, Class="fs12 fwn b1 c222", nowrap="on"), trait_location_repr, trait_location_value)) + + tblobj_body.append(tr) + + for ncol, item in enumerate([thisTrait.name, trait_location_repr]): + worksheet.write([newrow, ncol], item) + + newrow += 1 + + return tblobj_body + + def getTableHeaderForPublish(self, worksheet=None, newrow=None, headingStyle=None): + + tblobj_header = [] + + className = "fs13 fwb ffl b1 cw cbrb" + + tblobj_header = [[THCell(HT.TD(' ', Class=className, nowrap="on"), sort=0), + THCell(HT.TD('Record',HT.BR(), 'ID',HT.BR(), Class=className, nowrap="on"), text="recond_id", idx=1), + THCell(HT.TD('Phenotype',HT.BR(),HT.BR(), Class=className, nowrap="on"), text="pheno", idx=2), + THCell(HT.TD('Authors',HT.BR(),HT.BR(), Class=className, nowrap="on"), text="auth", idx=3), + THCell(HT.TD('Year',HT.BR(),HT.BR(), Class=className, nowrap="on"), text="year", idx=4), + THCell(HT.TD('Max',HT.BR(), 'LRS', HT.BR(), Class="fs13 fwb ffl b1 cw cbrb", nowrap="on"), text="lrs", idx=5), + THCell(HT.TD('Max LRS Location',HT.BR(),'Chr and Mb',HT.BR(), Class="fs13 fwb ffl b1 cw cbrb", nowrap="on"), text="lrs_location", idx=6)]] + + for ncol, item in enumerate(["Record", "Phenotype", "Authors", "Year", "Pubmed Id", "Max LRS", "Max LRS Location (Chr: Mb)"]): + worksheet.write([newrow, ncol], item, headingStyle) + worksheet.set_column([ncol, ncol], 2*len(item)) + + return tblobj_header + + def getTableBodyForPublish(self, traitList, formName=None, worksheet=None, newrow=None, species=''): + + tblobj_body = [] + + className = "fs12 fwn b1 c222" + + for thisTrait in traitList: + tr = [] + + if not thisTrait.haveinfo: + thisTrait.retrieveInfo(QTL=1) + + trId = str(thisTrait) + + tr.append(TDCell(HT.TD(HT.Input(type="checkbox", Class="checkbox", name="searchResult",value=trId, onClick="highlight(this)"), nowrap="on", Class=className), text=trId)) + + tr.append(TDCell(HT.TD(HT.Href(text=thisTrait.name,url="javascript:showDatabase3('%s','%s','%s','')" % (formName, thisTrait.db.name, thisTrait.name), Class="fs12 fwn"), nowrap="yes",align="center", Class=className),str(thisTrait.name), thisTrait.name)) + + PhenotypeString = thisTrait.post_publication_description + if thisTrait.confidential: + if not webqtlUtil.hasAccessToConfidentialPhenotypeTrait(privilege=self.privilege, userName=self.userName, authorized_users=thisTrait.authorized_users): + PhenotypeString = thisTrait.pre_publication_description + tr.append(TDCell(HT.TD(PhenotypeString, Class=className), PhenotypeString, PhenotypeString.upper())) + + tr.append(TDCell(HT.TD(thisTrait.authors, Class="fs12 fwn b1 c222 fsI"),thisTrait.authors, thisTrait.authors.strip().upper())) + + try: + PubMedLinkText = myear = repr = int(thisTrait.year) + except: + PubMedLinkText = repr = "N/A" + myear = 0 + + if thisTrait.pubmed_id: + PubMedLink = HT.Href(text= repr,url= webqtlConfig.PUBMEDLINK_URL % thisTrait.pubmed_id,target='_blank', Class="fs12 fwn") + else: + PubMedLink = repr + + tr.append(TDCell(HT.TD(PubMedLink, Class=className, align='center'), repr, myear)) + + #LRS and its location + LRS_score_repr = 'N/A' + LRS_score_value = 0 + LRS_location_repr = 'N/A' + LRS_location_value = 1000000 + LRS_flag = 1 + + + if thisTrait.lrs: + LRS_score_repr = '%3.1f' % thisTrait.lrs + LRS_score_value = thisTrait.lrs + tr.append(TDCell(HT.TD(LRS_score_repr, Class=className), LRS_score_repr, LRS_score_value)) + + self.cursor.execute(""" + select Geno.Chr, Geno.Mb from Geno, Species + where Species.Name = '%s' and + Geno.Name = '%s' and + Geno.SpeciesId = Species.Id + """ % (species, thisTrait.locus)) + result = self.cursor.fetchone() + + if result: + if result[0] and result[1]: + LRS_Chr = result[0] + LRS_Mb = result[1] + + #XZ: LRS_location_value is used for sorting + try: + LRS_location_value = int(LRS_Chr)*1000 + float(LRS_Mb) + except: + if LRS_Chr.upper() == 'X': + LRS_location_value = 20*1000 + float(LRS_Mb) + else: + LRS_location_value = ord(str(LRS_chr).upper()[0])*1000 + float(LRS_Mb) + + LRS_location_repr = 'Chr%s: %.6f' % (LRS_Chr, float(LRS_Mb) ) + LRS_flag = 0 + + tr.append(TDCell(HT.TD(LRS_location_repr, Class=className, nowrap="on"), LRS_location_repr, LRS_location_value)) + + else: + tr.append(TDCell(HT.TD("N/A", Class=className), "N/A", "N/A")) + tr.append(TDCell(HT.TD("N/A", Class=className), "N/A", "N/A")) + + tblobj_body.append(tr) + + for ncol, item in enumerate([thisTrait.name, PhenotypeString, thisTrait.authors, thisTrait.year, thisTrait.pubmed_id, LRS_score_repr, LRS_location_repr]): + worksheet.write([newrow, ncol], item) + + newrow += 1 + + return tblobj_body + + def getTableHeaderForProbeSet(self, worksheet=None, newrow=None, headingStyle=None): + + tblobj_header = [] + + className = "fs13 fwb ffl b1 cw cbrb" + + #tblobj_header = [[THCell(HT.TD(' ', Class="fs13 fwb ffl b1 cw cbrb",nowrap='ON'), sort=0), + # THCell(HT.TD('Record',HT.BR(), 'ID',HT.BR(), Class="fs13 fwb ffl b1 cw cbrb"), text="record_id", idx=1), + # THCell(HT.TD('Symbol',HT.BR(),HT.BR(), Class="fs13 fwb ffl b1 cw cbrb"), text="symbol", idx=2), + # THCell(HT.TD('Description',HT.BR(),HT.BR(), Class="fs13 fwb ffl b1 cw cbrb"), text="desc", idx=3), + # THCell(HT.TD('Location',HT.BR(), 'Chr and Mb', HT.BR(), Class="fs13 fwb ffl b1 cw cbrb"), text="location", idx=4), + # THCell(HT.TD('Mean',HT.BR(),'Expr',HT.BR(), Class="fs13 fwb ffl b1 cw cbrb"), text="mean", idx=5), + # THCell(HT.TD('Max',HT.BR(),'LRS',HT.BR(), Class="fs13 fwb ffl b1 cw cbrb", nowrap='ON'), text="lrs", idx=6), + # THCell(HT.TD('Max LRS Location',HT.BR(),'Chr and Mb',HT.BR(), Class="fs13 fwb ffl b1 cw cbrb", nowrap='ON'), text="lrs_location", idx=7)]] + # + #for ncol, item in enumerate(['Record', 'Gene ID', 'Homologene ID', 'Symbol', 'Description', 'Location (Chr, Mb)', 'Mean Expr', 'Max LRS', 'Max LRS Location (Chr: Mb)']): + # worksheet.write([newrow, ncol], item, headingStyle) + # worksheet.set_column([ncol, ncol], 2*len(item)) + + return tblobj_header + + def getTableBodyForProbeSet(self, traitList=[], primaryTrait=None, formName=None, worksheet=None, newrow=None, species=''): + # Note: setting traitList to [] is probably not a great idea. + tblobj_body = [] + + className = "fs12 fwn b1 c222" + + for thisTrait in traitList: + + if not thisTrait.haveinfo: + thisTrait.retrieveInfo(QTL=1) + + if thisTrait.symbol: + pass + else: + thisTrait.symbol = "N/A" + + tr = [] + + trId = str(thisTrait) + + #XZ, 12/08/2008: checkbox + #tr.append(TDCell(HT.TD(HT.Input(type="checkbox", Class="checkbox", name="searchResult",value=trId, onClick="highlight(this)"), nowrap="on", Class="fs12 fwn ffl b1 c222"), text=trId)) + + #XZ, 12/08/2008: probeset name + #if thisTrait.cellid: + # tr.append(TDCell(HT.TD(HT.Href(text=thisTrait.name, url="javascript:showDatabase3('%s','%s','%s','%s')" % (formName, thisTrait.db.name,thisTrait.name,thisTrait.cellid), Class="fs12 fwn"), Class=className), thisTrait.name, thisTrait.name.upper())) + #else: + # tr.append(TDCell(HT.TD(HT.Href(text=thisTrait.name, url="javascript:showDatabase3('%s','%s','%s','')" % (formName, thisTrait.db.name,thisTrait.name), Class="fs12 fwn"), Class=className), thisTrait.name, thisTrait.name.upper())) + # + #if thisTrait.geneid: + # symbolurl = HT.Href(text=thisTrait.symbol,target='_blank',url="http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?db=gene&cmd=Retrieve&dopt=Graphics&list_uids=%s" % thisTrait.geneid, Class="font_black fs12 fwn") + #else: + # symbolurl = HT.Href(text=thisTrait.symbol,target='_blank',url="http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?CMD=search&DB=gene&term=%s" % thisTrait.symbol, Class="font_black fs12 fwn") + # + ##XZ, 12/08/2008: gene symbol + #tr.append(TDCell(HT.TD(symbolurl, Class="fs12 fwn b1 c222 fsI"),thisTrait.symbol, thisTrait.symbol.upper())) + + #XZ, 12/08/2008: description + #XZ, 06/05/2009: Rob asked to add probe target description + description_string = str(thisTrait.description).strip() + target_string = str(thisTrait.probe_target_description).strip() + + description_display = '' + + if len(description_string) > 1 and description_string != 'None': + description_display = description_string + else: + description_display = thisTrait.symbol + + if len(description_display) > 1 and description_display != 'N/A' and len(target_string) > 1 and target_string != 'None': + description_display = description_display + '; ' + target_string.strip() + + #tr.append(TDCell(HT.TD(description_display, Class=className), description_display, description_display)) + + # Save it for the jinja2 tablet + thisTrait.description_display = description_display + + #XZ: trait_location_value is used for sorting + trait_location_repr = 'N/A' + trait_location_value = 1000000 + + if thisTrait.chr and thisTrait.mb: + try: + trait_location_value = int(thisTrait.chr)*1000 + thisTrait.mb + except: + if thisTrait.chr.upper() == 'X': + trait_location_value = 20*1000 + thisTrait.mb + else: + trait_location_value = ord(str(thisTrait.chr).upper()[0])*1000 + thisTrait.mb + + trait_location_repr = 'Chr%s: %.6f' % (thisTrait.chr, float(thisTrait.mb) ) + thisTrait.trait_location_repr = trait_location_repr + #thisTrait.trait_location_value = trait_location_value + tr.append(TDCell(HT.TD(trait_location_repr, Class=className, nowrap="on"), trait_location_repr, trait_location_value)) + + #XZ, 01/12/08: This SQL query is much faster. + self.cursor.execute(""" + select ProbeSetXRef.mean from ProbeSetXRef, ProbeSet + where ProbeSetXRef.ProbeSetFreezeId = %d and + ProbeSet.Id = ProbeSetXRef.ProbeSetId and + ProbeSet.Name = '%s' + """ % (thisTrait.db.id, thisTrait.name)) + result = self.cursor.fetchone() + if result: + if result[0]: + mean = result[0] + else: + mean=0 + else: + mean = 0 + + #XZ, 06/05/2009: It is neccessary to turn on nowrap + thisTrait.mean = repr = "%2.3f" % mean + tr.append(TDCell(HT.TD(repr, Class=className, align='right', nowrap='ON'),repr, mean)) + + #LRS and its location + LRS_score_repr = 'N/A' + LRS_score_value = 0 + LRS_location_repr = 'N/A' + LRS_location_value = 1000000 + LRS_flag = 1 + + #Max LRS and its Locus location + if thisTrait.lrs and thisTrait.locus: + self.cursor.execute(""" + select Geno.Chr, Geno.Mb from Geno, Species + where Species.Name = '%s' and + Geno.Name = '%s' and + Geno.SpeciesId = Species.Id + """ % (species, thisTrait.locus)) + result = self.cursor.fetchone() + + if result: + if result[0] and result[1]: + LRS_Chr = result[0] + LRS_Mb = result[1] + + #XZ: LRS_location_value is used for sorting + try: + LRS_location_value = int(LRS_Chr)*1000 + float(LRS_Mb) + except: + if LRS_Chr.upper() == 'X': + LRS_location_value = 20*1000 + float(LRS_Mb) + else: + LRS_location_value = ord(str(LRS_chr).upper()[0])*1000 + float(LRS_Mb) + + thisTrait.LRS_score_repr = LRS_score_repr = '%3.1f' % thisTrait.lrs + thisTrait.LRS_score_value = LRS_score_value = thisTrait.lrs + thisTrait.LRS_location_repr = LRS_location_repr = 'Chr%s: %.6f' % (LRS_Chr, float(LRS_Mb) ) + LRS_flag = 0 + + #tr.append(TDCell(HT.TD(HT.Href(text=LRS_score_repr,url="javascript:showIntervalMapping('%s', '%s : %s')" % (formName, thisTrait.db.shortname, thisTrait.name), Class="fs12 fwn"), Class=className, align='right', nowrap="on"),LRS_score_repr, LRS_score_value)) + tr.append(TDCell(HT.TD(LRS_score_repr, Class=className, align='right', nowrap="on"), LRS_score_repr, LRS_score_value)) + tr.append(TDCell(HT.TD(LRS_location_repr, Class=className, nowrap="on"), LRS_location_repr, LRS_location_value)) + + if LRS_flag: + tr.append(TDCell(HT.TD(LRS_score_repr, Class=className), LRS_score_repr, LRS_score_value)) + tr.append(TDCell(HT.TD(LRS_location_repr, Class=className), LRS_location_repr, LRS_location_value)) + + else: + tr.append(TDCell(HT.TD("N/A", Class=className), "N/A", "N/A")) + tr.append(TDCell(HT.TD("N/A", Class=className), "N/A", "N/A")) + + tblobj_body.append(tr) + + #for ncol, item in enumerate([thisTrait.name, thisTrait.geneid, thisTrait.homologeneid, thisTrait.symbol, description_display, trait_location_repr, mean, LRS_score_repr, LRS_location_repr]): + # worksheet.write([newrow, ncol], item) + + + newrow += 1 + + return tblobj_body + + def createExcelFileWithTitleAndFooter(self, workbook=None, identification=None, db=None, returnNumber=None): + + worksheet = workbook.add_worksheet() + + titleStyle = workbook.add_format(align = 'left', bold = 0, size=14, border = 1, border_color="gray") + + ##Write title Info + # Modified by Hongqiang Li + worksheet.write([1, 0], "Citations: Please see %s/reference.html" % webqtlConfig.PORTADDR, titleStyle) + worksheet.write([1, 0], "Citations: Please see %s/reference.html" % webqtlConfig.PORTADDR, titleStyle) + worksheet.write([2, 0], "Trait : %s" % identification, titleStyle) + worksheet.write([3, 0], "Database : %s" % db.fullname, titleStyle) + worksheet.write([4, 0], "Date : %s" % time.strftime("%B %d, %Y", time.gmtime()), titleStyle) + worksheet.write([5, 0], "Time : %s GMT" % time.strftime("%H:%M ", time.gmtime()), titleStyle) + worksheet.write([6, 0], "Status of data ownership: Possibly unpublished data; please see %s/statusandContact.html for details on sources, ownership, and usage of these data." % webqtlConfig.PORTADDR, titleStyle) + #Write footer info + worksheet.write([9 + returnNumber, 0], "Funding for The GeneNetwork: NIAAA (U01AA13499, U24AA13513), NIDA, NIMH, and NIAAA (P20-DA21131), NCI MMHCC (U01CA105417), and NCRR (U01NR 105417)", titleStyle) + worksheet.write([10 + returnNumber, 0], "PLEASE RETAIN DATA SOURCE INFORMATION WHENEVER POSSIBLE", titleStyle) + + return worksheet + + def getSortByValue(self, datasetType=''): + + if datasetType == 'Geno': + sortby = ("location", "up") + elif datasetType == 'ProbeSet': + sortby = ("symbol", "up") + else: #Phenotype + sortby = ("record_id", "down") + + return sortby diff --git a/wqflask/wqflask/static/css b/wqflask/wqflask/static/css new file mode 120000 index 00000000..9d8c2f68 --- /dev/null +++ b/wqflask/wqflask/static/css @@ -0,0 +1 @@ +../../../web/css
\ No newline at end of file diff --git a/wqflask/wqflask/static/images b/wqflask/wqflask/static/images new file mode 120000 index 00000000..12f0f8b5 --- /dev/null +++ b/wqflask/wqflask/static/images @@ -0,0 +1 @@ +../../../web/images
\ No newline at end of file diff --git a/wqflask/wqflask/static/javascript b/wqflask/wqflask/static/javascript new file mode 120000 index 00000000..5f58faf4 --- /dev/null +++ b/wqflask/wqflask/static/javascript @@ -0,0 +1 @@ +../../../web/javascript
\ No newline at end of file diff --git a/wqflask/wqflask/templates/base.html b/wqflask/wqflask/templates/base.html new file mode 100644 index 00000000..117d26fb --- /dev/null +++ b/wqflask/wqflask/templates/base.html @@ -0,0 +1,215 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> +<html lang="en"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> + {% block head %} + <title>{% block title %}{% endblock %} - GeneNetwork</title> + <META http-equiv=Content-Type content="text/html; charset=iso-8859-1"> + <META NAME="keywords" CONTENT="genetics, bioinformatics, genome, phenome, gene expression, complex trait analysis, gene mapping, SNP, quantitative trait locus QTL, expression eQTL, WebQTL, Traitnet, Traitnetwork, personalized medicine"> + <META NAME="description" CONTENT ="GeneNetwork is a free scientific web resource used to study relationships between differences in genes, environmental factors, phenotypes, and disease risk." > + <META NAME="author" CONTENT ="GeneNetwork developers" > + <META NAME="geo.placename" CONTENT ="Memphis, TN" > + <META NAME="geo.region" CONTENT="US-TN"> + + <LINK REL="stylesheet" TYPE="text/css" HREF='/css/general.css'> + <LINK REL="stylesheet" TYPE="text/css" HREF='/css/menu.css'> + <link rel="stylesheet" media="all" type="text/css" href="/css/tabbed_pages.css" /> + <LINK REL="apple-touch-icon" href="/images/ipad_icon3.png" /> + <link type="text/css" href='/css/custom-theme/jquery-ui-1.8.12.custom.css' rel='Stylesheet' /> + <link type="text/css" href='/css/tab_style.css' rel='Stylesheet' /> + + <script type="text/javascript" src="/javascript/jquery-1.5.2.min.js"></script> + <SCRIPT SRC="/javascript/webqtl.js"></SCRIPT> + <SCRIPT SRC="/javascript/dhtml.js"></SCRIPT> + <SCRIPT SRC="/javascript/tablesorter.js"></SCRIPT> + <SCRIPT SRC="/javascript/jqueryFunction.js"></SCRIPT> + <script src="/javascript/tabbed_pages.js" type="text/javascript"></script> + <script src="/javascript/jquery-ui-1.8.12.custom.min.js" type="text/javascript"></script> + + + <script type="text/javascript"> + var _gaq = _gaq || []; + _gaq.push(['_setAccount', 'UA-3782271-1']); + _gaq.push(['_trackPageview']); + (function() { + var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; + ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; + var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); + })(); + </script> + {% endblock %} +</head> +<body bottommargin="2" leftmargin="2" rightmargin="2" topmargin="2" text=#000000 bgColor=#ffffff onLoad="pageOffset()"> + + <!-- BEGIN FLOATING LAYER CODE //--> + <div id="warningLayer" style="padding:3px; border: 1px solid #222; + background-color: #fff; position:absolute;width:250px;left:100;top:100;visibility:hidden"> + <table border="0" width="250" class="cbrb" cellspacing="0" cellpadding="5"> + <tr> + <td width="100%"> + <table border="0" width="100%" cellspacing="0" cellpadding="0" height="36"> + <tr> + <td class="cbrb cw ff15 fwb" align="Center" width="100%" style="padding:4px"> + Sort Table + </td> + </tr> + <tr> + <td width="100%" bgcolor="#eeeeee" align="Center" style="padding:4px"> + <!-- PLACE YOUR CONTENT HERE //--> + Resorting this table <br> + <!-- END OF CONTENT AREA //--> + </td> + </tr> + </table> + </td> + </tr> + </table> + </div> + <!-- END FLOATING LAYER CODE //--> + + + <TABLE cellSpacing=5 cellPadding=4 width="100%" border=0> + <TBODY> + <!-- Start of header --> + <TR> + <TD width=30 rowSpan=5> </TD> + <TD bgColor=#ffffff NOWRAP="yes" width="100%" class="solidBorder"> + <Table width= "100%" cellSpacing=0 cellPadding=0> + <TR> + <TD width= "100%" id="smallsize"> + <a href="/"> + <IMG src="/images/upload/GeneNet_Banner2009c.png" border="0"> + </a> + </TD> + <TD valign="bottom"> + <A HREF="http://www.touchgraph.com/TGGoogleBrowser.php?start=genenetwork.org&signed=false" target="_blank"> + <IMG SRC="/images/upload/NetworkLogo.png" width="101" height="73" border="0"> + </a> + </td> + <TD valign="bottom"> + <IMG src="/images/webqtllogo2.gif" alt="WebQTL" border="0"> + </TD> + </TR> + </Table> + </TD> + <TD width="30" rowSpan=5> </TD> + </TR> + <TR> + <!--Home Help Search News Papers Policies Accounts Links--> + <TD bgColor=#ddddff NOWRAP="yes" class="solidBorder"> + <table width="100%" cellSpacing=0 cellPadding=0 border=0> + <tr> + <td aligh=left NOWRAP="yes"> + | + <Span Id= "menu_grp1" onmouseover="A_MENUS[0].onmouseover(grpObj['menu_grp1'])" onmouseout="A_MENUS[0].onmouseout(grpObj['menu_grp1'])" style="font-size:12px;font-family:verdana;color:#0000ae"> + <Strong>Home</Strong></Span> + | + <Span Id= "menu_grp2" onmouseover="A_MENUS[0].onmouseover(grpObj['menu_grp2'])" onmouseout="A_MENUS[0].onmouseout(grpObj['menu_grp2'])" style="font-size:12px;font-family:verdana;color:#0000ae"> + <Strong>Search</Strong></Span> + | + <Span Id= "menu_grp3" onmouseover="A_MENUS[0].onmouseover(grpObj['menu_grp3'])" onmouseout="A_MENUS[0].onmouseout(grpObj['menu_grp3'])" style="font-size:12px;font-family:verdana;color:#0000ae"> + <Strong>Help</Strong></Span> + | + <Span Id= "menu_grp4" onmouseover="A_MENUS[0].onmouseover(grpObj['menu_grp4'])" onmouseout="A_MENUS[0].onmouseout(grpObj['menu_grp4'])" style="font-size:12px;font-family:verdana;color:#0000ae"> + <A Href="/whats_new.html" style="font-size:12px;font-family:verdana;color:#0000ae"> + <Strong>News</Strong></A></Span> + | + <Span Id= "menu_grp5" onmouseover="A_MENUS[0].onmouseover(grpObj['menu_grp5'])" onmouseout="A_MENUS[0].onmouseout(grpObj['menu_grp5'])" style="font-size:12px;font-family:verdana;color:#0000ae"> + <A Href="/reference.html" style="font-size:12px;font-family:verdana;color:#0000ae"> + <Strong>References</Strong></A></Span> + | + <Span Id= "menu_grp6" onmouseover="A_MENUS[0].onmouseover(grpObj['menu_grp6'])" onmouseout="A_MENUS[0].onmouseout(grpObj['menu_grp6'])" style="font-size:12px;font-family:verdana;color:#0000ae"> + <Strong>Policies</Strong></Span> + | + <Span Id= "menu_grp8" onmouseover="A_MENUS[0].onmouseover(grpObj['menu_grp8'])" onmouseout="A_MENUS[0].onmouseout(grpObj['menu_grp8'])" style="font-size:12px;font-family:verdana;color:#0000ae"> + <A Href="/links.html" style="font-size:12px;font-family:verdana;color:#0000ae"> + <Strong>Links</Strong></A></Span> + | + </td> + <td align="right" NOWRAP="yes"> + Welcome! <a href=/account.html><U>Login</U></a> + </td> + </tr> + </table> + </TD> + + </TR> + <!-- End of header --> + + <div id="content">{% block content %}{% endblock %}</div> + + <!-- Start of footer --> + <TR> + <TD align=center bgColor=#ddddff class="solidBorder"> + <TABLE width="90%"><TR> + <TD align="left"> + <A HREF="http://citg.uthsc.edu/" target="_blank"> + <IMG SRC="/images/upload/CITGLogo.png" alt="CITG" border="0"></A> + </TD> + <TD align="left" id="smallsize" style="font-size:11px;font-family:verdana;color:black"> +WWW service initiated January, 1994 as <A HREF="http://www.ncbi.nlm.nih.gov/pubmed?term=8043953">The Portable Dictionary of the Mouse Genome</A> and June 15, 2001 as WebQTL. + +This site is currently operated by + <A class="smallsize" HREF="mailto:rwilliams@uthsc.edu">Rob Williams</A>, + <A class="smallsize" HREF="mailto:lyan6@uthsc.edu">Lei Yan</A>, + <A class="smallsize" HREF="mailto:zachary.a.sloan@gmail.com">Zachary Sloan</A>, + <A class="smallsize" HREF="mailto:acenteno@uthsc.edu" target="_blank">Arthur Centeno</A>. Design and code by Xiaodong Zhou, Christian Fernandez, Ning Liu, Rudi Alberts, Elissa Chesler, Jintao Wang, Kenneth Manly, Robert W. Williams, and <A class="smallsize" HREF="/credit.html">colleagues</A>. + + + </TD> + <TD align="right"> + <A HREF="http://www.python.org/" target="_blank"> + <IMG src="/images/upload/PythonLogo.png" alt="Python Powered" border="0"></A> + </TD> + <TD align="right"> + <A HREF="http://www.neuinfo.org" target="_blank"> + <img src="/images/upload/Nif.png" alt="Registered with Nif" border="0"></A> + </TD> +</TR> +<TR> + +<!-- GENENETWORK SUPPORTED BY --> + + <TD colspan=4 style="font-size:12px;font-family:verdana;color:black"> + GeneNetwork support from: + <UL> + <LI><a class="smallsize" target="_blank" href="http://citg.uthsc.edu">The UT Center for Integrative and Translational Genomics</A> + <LI><a class="smallsize" target="_blank" href="http://www.iniastress.org">NIAAA</A> Integrative Neuroscience Initiative on Alcoholism (U01AA13499, U24AA13513, U01AA014425) + <LI><a class="smallsize" target="_blank" href="http://www.drugabuse.gov/about/organization/Genetics/geneexpression/index.html">NIDA</A>, <a class="smallsize" target="_blank" href="http://www.nimh.nih.gov/">NIMH</A>, and <a class="smallsize" target="_blank" href="http://www.niaaa.nih.gov/">NIAAA</A> (P20-DA 21131) + <LI>NCI <a class="smallsize" target="_blank" href="http://emice.nci.nih.gov/">MMHCC</A> (U01CA105417), <a class="smallsize" target="_blank" href="http://www.ncrr.nih.gov/">NCRR</A> <a class="smallsize" target="_blank" href="http://www.nbirn.net/TestBeds/Mouse/index.htm">BIRN</A>, (U24 RR021760) + </UL> + </TD> +</TR> +<TR> + <TD colspan=4 id="smallsize" align="left"> + It took 0.041 second(s) for spring211.uthsc.edu to generate this page + </TD> +</TR></table> + </td> + </TR> + <!-- End of footer --> +</TABLE> + +<!-- menu script itself. you should not modify this file --> +<script language="JavaScript" src="/javascript/menu_new.js"></script> +<!-- items structure. menu hierarchy and links are stored there --> +<script language="JavaScript" src="/javascript/menu_items.js"></script> +<!-- files with geometry and styles structures --> +<script language="JavaScript" src="/javascript/menu_tpl.js"></script> +<script language="JavaScript"> + <!--// + // Note where menu initialization block is located in HTML document. + // Don't try to position menu locating menu initialization block in + // some table cell or other HTML element. Always put it before </body> + // each menu gets two parameters (see demo files) + // 1. items structure + // 2. geometry structure + new menu (MENU_ITEMS, MENU_POS); + // make sure files containing definitions for these variables are linked to the document + // if you got some javascript error like "MENU_POS is not defined", then you've made syntax + // error in menu_tpl.js file or that file isn't linked properly. + + // also take a look at stylesheets loaded in header in order to set styles + //--> +</script> +</body> diff --git a/wqflask/wqflask/templates/index_page.html b/wqflask/wqflask/templates/index_page.html new file mode 100644 index 00000000..89581075 --- /dev/null +++ b/wqflask/wqflask/templates/index_page.html @@ -0,0 +1,313 @@ +{% extends "base.html" %} +{% block title %}GeneNetwork{% endblock %} +{% block content %} +<!-- Start of body --> +<TR> + <TD bgColor=#eeeeee class="solidBorder"> + <Table width= "100%" cellSpacing=0 cellPadding=5> + <TR> + +<TD vAlign=top width="40%" align="left" height=10 bgColor=#eeeeee> + <p style="font-size:18px;font-family:verdana;color:black"><B> Select and Search</B> + <Form METHOD="GET" ACTION="/search" ENCTYPE="multipart/form-data" NAME="SEARCHFORM"> + + <TABLE width="100%"> + + <!-- SPECIES SELECTION --> + <TR> + <TD align=right height="35" style="font-size:14px;font-family:verdana;color:black" width="16%"> + <B>Species:</B> + </TD> + + <TD width="3%"> + </TD> + + <TD NOWRAP width="85%" align="left"> + <DIV Id="menu0"> + <Select NAME="species" size=1 id="species" onchange="fillOptions('species');"> + </Select> + </DIV> + </TD> + </TR> + + <!-- GROUP SELECTION --> + + <TR> + + <TD align="right" height="35" style="font-size:14px;font-family:verdana;color:black"> + <B>Group:</B> + </TD> + + <TD width="3%"> + </TD> + + <TD NOWRAP width="85%" align="left"> + <DIV Id="menu1"> + + <Select NAME="cross" size=1 id="cross" onchange="fillOptions('cross');"> + </Select> + <input type="button" class="button" value=" Info " onCLick="javascript:crossinfo();"> + </DIV> + </TD> + </TR> + + + <!-- TYPE SELECTION --> + + <TR> + + <TD align=right height=35 style="font-size:14px;font-family:verdana;color:black"> + <B>Type:</B> + </TD> + + <TD width="3%"> + </TD> + <TD NOWRAP width="85%" align="left"> + <DIV Id="menu2"> + <Select NAME="tissue" size=1 id="tissue" onchange="fillOptions('tissue');"> + + </Select> + </DIV> + </TD> + </TR> + + + <!-- DATABASE SELECTION --> + <TR> + <TD align=right height=35 style="font-size:14px;font-family:verdana;color:black"> + <B>Database:</B> + </TD> + + <TD width="3%"> + </TD> + + <TD NOWRAP width="85%" align="left"> + <DIV Id="menu3"> + <Select NAME="database" size=1 id="database"> + </Select> + <input type="button" class="button" value=" Info " onCLick="javascript:databaseinfo();"> + </DIV> + + </TD> + </TR> + + <!-- USER HELP --> + <TR> + <TD align=right height=20 width="10%"> + </TD> + <TD width="3%"> + </TD> + + <TD align="left" width="85%"> + <P class="fs12"> Databases marked with <B>**</B> suffix are not public yet. + <BR> Access requires <A HREF="/account.html" target="_blank" class="fs14"><small>user login</small></A>.</P> + </TD> + </TR> + + +<!-- GET ANY SEARCH --> + <TR> + <TD align=right height=35 NOWRAP="on" style="font-size:14px;font-family:verdana;color:black" width="10%"> + <B>Get Any:</B> + </TD> + + <TD width="3%"> + </TD> + + <TD NOWRAP width="85%" align="left"> + + <input id="tfor" name="ORkeyword" style="width:420px; background-color:white; font-family:verdana; font-size:14px" type="text" maxlength="500"> + </TD> + </TR> + + + +<!-- GET ANY HELP --> + <TR> + <TD align=right height=20 width="10%"> + </TD> + <TD width="3%"> + + </TD> + <TD width="85%" align="left"> + <P class="fs12"> Enter terms, genes, ID numbers in the <B>Get Any</B> field. + <BR> Use <B>*</B> or <B>?</B> wildcards (Cyp*a?, synap*). + <BR> Use <B>Combined</B> for terms such as <I>tyrosine kinase</I>.</P> + + </TD> + </TR> + + + +<!-- COMBINED SEARCH --> + + <TR> + <TD align=right height=35 NOWRAP="on" STYLE="font-size:14px;font-family:verdana;color:black" width="10%"> + <B>Combined:</B> + </TD> + + <TD width="3%"> + </TD> + + <TD NOWRAP width="85%" align="left"> + <input id="tfand" NAME="ANDkeyword" STYLE="width:420px; background-color:white; font-family:verdana; font-size:14px" type="text" maxlength="500"> + <input name="matchwhole" type="hidden" value="ON"> + </TD> + </TR> + + + +<!-- SEARCH, MAKE DEFAULT, ADVANCED SEARCH --> + + <TR ALIGN="center"> + <TD width="3%"> + </TD> + <TD width="3%"> + </TD> + <TD ALIGN="left" HEIGHT="40" COLSPAN=3> + <INPUT id="btsearch" TYPE="Submit" CLASS="button" STYLE="font-size:12px" VALUE=" Search "> + <INPUT TYPE="button" CLASS="button" STYLE="font-size:12px" VALUE=" Make Default " onClick = "setDefault(this.form);"> + <INPUT TYPE="button" CLASS="button" STYLE="font-size:12px" VALUE=" Advanced Search " onClick="javascript:window.open('/index3.html', '_self');"> + + </TD> + </TR> + </TABLE> + <INPUT TYPE="hidden" NAME="FormID" VALUE="searchResult"> + <INPUT TYPE="hidden" NAME="RISet" VALUE="BXD"> + <SCRIPT SRC="/javascript/selectDatasetMenu.js"></SCRIPT> + </FORM> + </CENTER> + + + + + +<!-- QUICK HELP --> + +<P><LEFT> ______________________________________________________ + +<P STYLE="font-size:13px;font-family:verdana;color:black"><B> + +Quick HELP Examples and </B> +<A HREF="http://www.genenetwork.org/index4.html" target="_blank" class="fs14"><B> + User's Guide</B></A></P> + +</CENTER style="font-size:12px;font-family:verdana;color:black"> + You can also use advanced commands. Copy these simple examples +<BR> into the <B>Get Any</B> or <B>Combined</B> search fields: +<UL style="font-size:12px;font-family:verdana;color:black"> + +<LI><B><I>POSITION=(chr1 25 30)</I></B> finds genes, markers, or transcripts on chromosome 1 between 25 and 30 Mb. + +<LI><B><I>MEAN=(15 16) LRS=(23 46)</I></B> in the <B>Combined</B> field finds highly expressed genes (15 to 16 log2 units) AND with peak <A HREF="http://www.genenetwork.org/glossary.html#L" target="_blank" class="fs14"><small>LRS</small></A> linkage between 23 and 46. + + +<LI><B><I>RIF=mitochondrial</I></B> searches RNA databases for <A HREF="http://www.ncbi.nlm.nih.gov/projects/GeneRIF/GeneRIFhelp.html" target="_blank" class="fs14"><small>GeneRIF</small></A> links. + +<LI><B><I>WIKI=nicotine</I></B> searches <A HREF="http://www.genenetwork.org/webqtl/main.py?FormID=geneWiki" target="_blank" class="fs14"><small>GeneWiki</small></A> for genes that you or other users have annotated with the word <I>nicotine</I>. + +<LI><B><I>GO:0045202</I></B> searches for synapse-associated genes listed in the <A HREF="http://www.godatabase.org/cgi-bin/amigo/go.cgi" target="_blank" class="fs14"><small>Gene Ontology</small></A>. + + +<LI><B><I>GO:0045202 LRS=(9 99 Chr4 122 155) cisLRS=(9 999 10)</I> </B><BR> in <B>Combined</B> finds synapse-associated genes with <A HREF="http://www.genenetwork.org/glossary.html#E" target="_blank" class="fs14"><small>cis eQTL</small></A> on Chr 4 from 122 and 155 Mb with LRS scores between 9 and 999. + +<LI><B><I>RIF=diabetes LRS=(9 999 Chr2 100 105) transLRS=(9 999 10)</I> </B><BR> in <B>Combined</B> finds diabetes-associated transcripts with peak <A HREF="http://www.genenetwork.org/glossary.html#E" target="_blank" class="fs14"><small>trans eQTLs</small></A> on Chr 2 between 100 and 105 Mb with LRS scores between 9 and 999. + + +</UL> +</DIR> + </TD> +<!-- END OF FIND SELECTOR PULL-DOWN PANEL (LEFT SIDE) --> + +<!-- START OF TOP RIGHT PANEL --> + +<TD vAlign=top width="40%" bgColor=#FFFFFF> + <p style="font-size:15px;font-family:verdana;color:black"><B>Websites Affiliated with GeneNetwork</B></p> + <p style="font-size:12px;font-family:verdana;color:black"> + <ul> + <li><a href="http://ucscbrowser.genenetwork.org/" target="_blank">Genome Browser</a> at UTHSC</li> + <li><a href="http://galaxy.genenetwork.org/" target="_blank">Galaxy</a> at UTHSC</li> + <li>GeneNetwork at <a href="http://ec2.genenetwork.org/" target="_blank">Amazon Cloud (EC2)</a></li> + <li>GeneNetwork Source Codes at <a href="http://sourceforge.net/projects/genenetwork/" target="_blank">SourceForge</a></li> + <li>GeneNetwork Source Codes at <a href="https://github.com/genenetwork/genenetwork" target="_blank">GitHub</a></li> + </ul> + </p> + <P>____________________________ + + <p style="font-size:15px;font-family:verdana;color:black"><B>Getting Started</B> </p> + <OL style="font-size:12px;font-family:verdana;color:black"> + <LI>Select <B>Species</B> (or select All) + <LI>Select <B>Group</B> (a specific sample) + <LI>Select <B>Type</B> of data: + <UL> + <LI>Phenotype (traits) + <LI>Genotype (markers) + <LI>Expression (mRNAs) + </UL> + <LI>Select a <B>Database</B> + <LI>Enter search terms in the <B>Get Any</B> or <B>Combined</B> field: words, genes, ID numbers, probes, advanced search commands + <LI>Click on the <B>Search</B> button + <LI>Optional: Use the <B>Make Default</B> button to save your preferences + </OL> + + <P>____________________________ + +<p style="font-size:14px;font-family:verdana;color:black"><B>How to Use GeneNetwork</B> + + <BLOCKQUOTE> + <p style="font-size:12px;font-family:verdana;color:black">Take a 20-40 minute GeneNetwork <A HREF="http://www.genenetwork.org/tutorial/WebQTLTour/" target="_blank" class="fs14"><small>Tour</small></A> that includes screen shots and typical steps in the analysis.</P> + </BLOCKQUOTE> + <BLOCKQUOTE> + <p style="font-size:12px;font-family:verdana;color:black">For information about resources and methods, select the <img src="http://www.genenetwork.org/images/upload/Info.png" alt="INFO" border= 0 valign="middle"> buttons.</P> + + + +<p style="font-size:12px;font-family:verdana;color:black">Try the <A HREF="http://alexandria.uthsc.edu/" target="_blank" class="fs14"><small>Workstation</small></A> site to explore data and features that are being implemented.</P> + + +<p style="font-size:12px;font-family:verdana;color:black">Review the <A HREF="/conditionsofUse.html" target="_blank" class="fs14"><small>Conditions</small></A> and <A HREF="/statusandContact.html" target="_blank" class="fs14"><small>Contacts</small></A> pages for information on the status of data sets and advice on their use and citation.</P> + + + </BLOCKQUOTE> + + + + <p style="font-size:14px;font-family:verdana;color:black"><B>Mirror and Development Sites</B></P> + + <UL> + <LI><A HREF="http://www.genenetwork.org/" target="_blank" style="font-size:12px;font-family:verdana;color:blue">Main GN site at UTHSC</A> (main site) + <LI><A HREF="http://www.genenetwork.waimr.uwa.edu.au/" target="_blank" style="font-size:12px;font-family:verdana;color:blue">Australia at the UWA</A> + <LI><A HREF="http://gn.genetics.ucla.edu/" target="_blank" style="font-size:12px;font-family:verdana;color:blue">California at UCLA</A> + <LI><A HREF="http://genenetwork.helmholtz-hzi.de/" target="_blank" style="font-size:12px;font-family:verdana;color:blue">Germany at the HZI</A> + <LI><A HREF="https://genenetwork.hubrecht.eu/" target="_blank" style="font-size:12px;font-family:verdana;color:blue">Netherlands at the Hubrecht</A> (Development) + <LI><A HREF="http://genenetwork.memphis.edu/" target="_blank" style="font-size:12px;font-family:verdana;color:blue">Memphis at the U of M</A> + <LI><A HREF="http://webqtl.bic.nus.edu.sg/" target="_blank" style="font-size:12px;font-family:verdana;color:blue">Singapore at the NUS</A> + <LI><A HREF="http://genenetwork.epfl.ch/" target="_blank" style="font-size:12px;font-family:verdana;color:blue">Switzerland at the EPFL</A> + </UL> + + + <p style="font-size:14px;font-family:verdana;color:black"><B>History and Archive</B> + + <BLOCKQUOTE> + <p style="font-size:12px;font-family:verdana;color:black">GeneNetwork's <A HREF="http://artemis.uthsc.edu" target="_blank" class="fs14"><small>Time Machine</small></A> links to earlier versions that correspond to specific publication dates.</P> + + </BLOCKQUOTE> + + +</P> + </TD> + + </TR> + </TABLE> + </TD> + </TR> + +<SCRIPT SRC="/javascript/searchtip.js"></SCRIPT> +<script> + $(document).ready(function () { + initialDatasetSelection(); + }); +</script> +<!-- End of body --> + +{% endblock %} diff --git a/wqflask/wqflask/templates/search_result_page.html b/wqflask/wqflask/templates/search_result_page.html new file mode 100644 index 00000000..f79a19a7 --- /dev/null +++ b/wqflask/wqflask/templates/search_result_page.html @@ -0,0 +1,203 @@ +{% extends "base.html" %} +{% block title %}Search Results{% endblock %} +{% block content %} +<!-- Start of body --> + <TR> + <TD bgColor=#eeeeee class="solidBorder"> + <Table width= "100%" cellSpacing=0 cellPadding=5> + <TR> + <TD valign="top" height="200" width="100%" bgcolor="#eeeeee"> + <P class="title">Search Results</P> + <BLOCKQUOTE>GeneNetwork searched the following databases: + <ul> + {% for db in database %} + <li><a href="/dbdoc/{{db.fullname}}">{{ db.fullname }}</a></li> + {% endfor %} + </ul> + + For all records that match: + <ul> + {% if ORkeyword2 %} + <li> + {% for word in ORkeyword2 %} + <strong>{{word}}</strong> {% if not loop.last %} or {% endif %} + {% endfor %} + </li> + {% endif %} + {% if ANDkeyword2 %} + <li> + {% for word in ANDkeyword2 %} + <strong>{{word}}</strong> {% if not loop.last %} and {% endif %} + {% endfor %} + </li> + {% endif %} + </ul> + + <P>GeneNetwork found <strong>{{ numify(nresults, "record", "records") }}</strong>.</P> + + <P>To study a record, click on its ID below.</P> + + <P>To add one or more records to your Selection window, use the checkbox and then click the <STRONG>Add to Collection</STRONG> button.</P> + </BLOCKQUOTE> + <FORM METHOD="GET" ACTION="/search" ENCTYPE="multipart/form-data" NAME="showDatabaseBXD"> + + <INPUT TYPE="hidden" NAME="database" VALUE="_"> + <INPUT TYPE="hidden" NAME="incparentsf1" VALUE="ON"> + <INPUT TYPE="hidden" NAME="FormID" VALUE="showDatabase"> + <INPUT TYPE="hidden" NAME="ProbeSetID" VALUE="_"> + <INPUT TYPE="hidden" NAME="RISet" VALUE="BXD"> + <INPUT TYPE="hidden" NAME="CellID" VALUE="_"> + <P> + <TABLE border="0" cellpadding="0" cellspacing="2" width="100%"> + <TR> + <TD> + <TABLE border="0" cellpadding="0" cellspacing="2" width="20%"> + <TR> + <TD width="25%"> + <A HREF="#" onClick="checkAll(document.getElementsByName('showDatabaseBXD')[0]);"> + <IMG src="/images/select_all2_final.jpg" alt="Select All" name="selectall" style="border:none;" title="Select All"></A> + </TD> + <TD width="25%"> + <A HREF="#" onClick="checkNone(document.getElementsByName('showDatabaseBXD')[0]);"> + <IMG src="/images/select_none2_final.jpg" alt="Select None" style="border:none;" title="Select None"> + </A> + </TD> + <TD width="25%"> + <A HREF="#" onClick="checkInvert(document.getElementsByName('showDatabaseBXD')[0]);"> + <IMG src="/images/invert_selection2_final.jpg" alt="Invert Selection" name="selectinvert" style="border:none;" title="Invert Selection"> + </A> + </TD> + <TD width="25%"> + <A HREF="#"> + <IMG src="/images/add_collection1_final.jpg" alt="Add To Collection" name="addselect" style="border:none;" title="Add To Collection"> + </A> + </TD> + </TR> + <TR> + <TD width="25%"> Select</TD> + <TD width="255"> Deselect</TD> + <TD width="25%"> Invert</TD> + <TD width="25%"> Add</TD> + </TR></TABLE> + </TD> + </TR> + <TR> + <TD height="40"> + <INPUT TYPE="button" NAME="Default_Name" class="button" VALUE="Download Table" onClick="location.href='/tmp/Search_fYr7h2Hn.xls'"> + </TD> + </TR> + <TR> + <TD> + <DIV id="sortable"> + <TABLE class="collap b2" cellpadding="5" cellspacing="1"> + <TR> + <TD class="fs13 fwb ffl b1 cw cbrb" nowrap="ON"> + </TD> + <TD class="fs13 fwb ffl b1 cw cbrb"> + Record + <BR>ID<BR> + <DIV style="float: bottom;"> + <A HREF="javascript:xmlhttpPost('/webqtl/main.py?FormID=AJAX_table', 'sortable', 'sort=record_id&order=up&file=Search_fYr7h2Hn&tableID=sortable&addIndex=1&hiddenColumns=')"> + <IMG src="/images/sortup.gif" alt="sortup.gif" border="0"> + </A> + <A HREF="javascript:xmlhttpPost('/webqtl/main.py?FormID=AJAX_table', 'sortable', 'sort=record_id&order=down&file=Search_fYr7h2Hn&tableID=sortable&addIndex=1&hiddenColumns=')"> + <IMG src="/images/sortdown.gif" alt="sortdown.gif" border="0"> + </A> + </DIV> + </TD> + <TD class="fs13 fwb ffl b1 cw cbrb"> + Symbol<BR><BR> + <DIV style="float: bottom;"> + <IMG src="/images/sortupon.gif" alt="sortupon.gif" border="0"> + <A HREF="javascript:xmlhttpPost('/webqtl/main.py?FormID=AJAX_table', 'sortable', 'sort=symbol&order=down&file=Search_fYr7h2Hn&tableID=sortable&addIndex=1&hiddenColumns=')"> + <IMG src="/images/sortdown.gif" alt="sortdown.gif" border="0"> + </A> + </DIV> + </TD> + <TD class="fs13 fwb ffl b1 cw cbrb"> + Description<BR><BR> + <DIV style="float: bottom;"> + <A HREF="javascript:xmlhttpPost('/webqtl/main.py?FormID=AJAX_table', 'sortable', 'sort=desc&order=up&file=Search_fYr7h2Hn&tableID=sortable&addIndex=1&hiddenColumns=')"> + <IMG src="/images/sortup.gif" alt="sortup.gif" border="0"> + </A> + <A HREF="javascript:xmlhttpPost('/webqtl/main.py?FormID=AJAX_table', 'sortable', 'sort=desc&order=down&file=Search_fYr7h2Hn&tableID=sortable&addIndex=1&hiddenColumns=')"> + <IMG src="/images/sortdown.gif" alt="sortdown.gif" border="0"> + </A> + </DIV> + </TD> + <TD class="fs13 fwb ffl b1 cw cbrb">Location<BR>Chr and Mb<BR> + <DIV style="float: bottom;"> + <A HREF="javascript:xmlhttpPost('/webqtl/main.py?FormID=AJAX_table', 'sortable', 'sort=location&order=up&file=Search_fYr7h2Hn&tableID=sortable&addIndex=1&hiddenColumns=')"> + <IMG src="/images/sortup.gif" alt="sortup.gif" border="0"> + </A> + <A HREF="javascript:xmlhttpPost('/webqtl/main.py?FormID=AJAX_table', 'sortable', 'sort=location&order=down&file=Search_fYr7h2Hn&tableID=sortable&addIndex=1&hiddenColumns=')"> + <IMG src="/images/sortdown.gif" alt="sortdown.gif" border="0"> + </A> + </DIV> + </TD> + <TD class="fs13 fwb ffl b1 cw cbrb">Mean<BR>Expr<BR> + <DIV style="float: bottom;"> + <A HREF="javascript:xmlhttpPost('/webqtl/main.py?FormID=AJAX_table', 'sortable', 'sort=mean&order=up&file=Search_fYr7h2Hn&tableID=sortable&addIndex=1&hiddenColumns=')"> + <IMG src="/images/sortup.gif" alt="sortup.gif" border="0"> + </A> + <A HREF="javascript:xmlhttpPost('/webqtl/main.py?FormID=AJAX_table', 'sortable', 'sort=mean&order=down&file=Search_fYr7h2Hn&tableID=sortable&addIndex=1&hiddenColumns=')"> + <IMG src="/images/sortdown.gif" alt="sortdown.gif" border="0"> + </A> + </DIV> + </TD> + <TD class="fs13 fwb ffl b1 cw cbrb" nowrap="ON">Max<BR>LRS<BR> + <DIV style="float: bottom;"> + <A HREF="javascript:xmlhttpPost('/webqtl/main.py?FormID=AJAX_table', 'sortable', 'sort=lrs&order=up&file=Search_fYr7h2Hn&tableID=sortable&addIndex=1&hiddenColumns=')"> + <IMG src="/images/sortup.gif" alt="sortup.gif" border="0"> + </A> + <A HREF="javascript:xmlhttpPost('/webqtl/main.py?FormID=AJAX_table', 'sortable', 'sort=lrs&order=down&file=Search_fYr7h2Hn&tableID=sortable&addIndex=1&hiddenColumns=')"> + <IMG src="/images/sortdown.gif" alt="sortdown.gif" border="0"> + </A> + </DIV> + </TD> + <TD class="fs13 fwb ffl b1 cw cbrb" nowrap="ON">Max LRS Location<BR>Chr and Mb<BR> + <DIV style="float: bottom;"> + <A HREF="javascript:xmlhttpPost('/webqtl/main.py?FormID=AJAX_table', 'sortable', 'sort=lrs_location&order=up&file=Search_fYr7h2Hn&tableID=sortable&addIndex=1&hiddenColumns=')"> + <IMG src="/images/sortup.gif" alt="sortup.gif" border="0"> + </A> + <A HREF="javascript:xmlhttpPost('/webqtl/main.py?FormID=AJAX_table', 'sortable', 'sort=lrs_location&order=down&file=Search_fYr7h2Hn&tableID=sortable&addIndex=1&hiddenColumns=')"> + <IMG src="/images/sortdown.gif" alt="sortdown.gif" border="0"> + </A> + </DIV> + </TD> + </TR> + {% for thisTrait in traitList %} + <TR id="{{ thisTrait }}"> + <TD class="fs12 fwn ffl b1 c222" nowrap="on">{{ loop.index }} + <INPUT TYPE="checkbox" NAME="searchResult" class="checkbox" VALUE="{{ thisTrait }}" onClick="highlight(this)"> + </TD> + <TD class="fs12 fwn b1 c222"> + <A HREF="javascript:showDatabase3('{{ thisFormName }}','{{thisTrait.db.name}}','{{ thisTrait.name }}','{{ thisTrait.cellid }}')" class="fs12 fwn">{{ thisTrait.name.upper() }}</A> + </TD> + <TD class="fs12 fwn b1 c222 fsI"> + <A HREF="http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?db=gene&cmd=Retrieve&dopt=Graphics&list_uids={{thisTrait.geneid}}" TARGET="_blank" class="font_black fs12 fwn"> + {{ thisTrait.symbol }} + </A> + </TD> + <TD class="fs12 fwn b1 c222">{{ thisTrait.description_display }}</TD> + <TD class="fs12 fwn b1 c222" nowrap="on">{{ thisTrait.trait_location_repr }}</TD> + <TD class="fs12 fwn b1 c222" nowrap="ON" align="right">{{ thisTrait.mean }}</TD> + <TD class="fs12 fwn b1 c222" nowrap="on" align="right">{{ thisTrait.LRS_score_repr }}</TD> + <TD class="fs12 fwn b1 c222" nowrap="on">{{ thisTrait.LRS_location_repr }}</TD> + </TR> + {% endfor %} + </TABLE> + </DIV> + </TD> + </TR> + </TABLE> + <INPUT TYPE="hidden" NAME="Default_Name"> + </FORM> + </TD> + </TR> + </TABLE> + </TD> + </TR> +<!-- End of body --> + +{% endblock %} diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py new file mode 100644 index 00000000..2f686432 --- /dev/null +++ b/wqflask/wqflask/views.py @@ -0,0 +1,23 @@ +from __future__ import absolute_import, division, print_function + +from wqflask import app + +from flask import render_template, request + +from wqflask import search_results + +from pprint import pformat as pf + +@app.route("/") +def index_page(): + return render_template("index_page.html") + + +@app.route("/search") +def search(): + print("request is:", request.args) + the_search = search_results.SearchResultPage(request.args) + print("At rendering...") + print(pf(the_search.__dict__)) + print("yack:", the_search.database[0].genHTML()) + return render_template("search_result_page.html", **the_search.__dict__) |