aboutsummaryrefslogtreecommitdiff
path: root/wqflask/utility
diff options
context:
space:
mode:
Diffstat (limited to 'wqflask/utility')
-rwxr-xr-xwqflask/utility/AJAX_table.py153
-rwxr-xr-xwqflask/utility/Plot.py1283
-rwxr-xr-xwqflask/utility/TDCell.py41
-rwxr-xr-xwqflask/utility/THCell.py42
-rwxr-xr-xwqflask/utility/__init__.py12
-rw-r--r--wqflask/utility/formatting.py109
-rwxr-xr-xwqflask/utility/svg.py1068
-rwxr-xr-xwqflask/utility/webqtlUtil.py981
8 files changed, 3689 insertions, 0 deletions
diff --git a/wqflask/utility/AJAX_table.py b/wqflask/utility/AJAX_table.py
new file mode 100755
index 00000000..083d1c0d
--- /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..51a57a6d
--- /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 __future__ import print_function
+
+from pprint import pformat as pf
+
+print("Lysol")
+
+from math import *
+import random
+import sys, os
+from numarray import linear_algebra as la
+from numarray import ones, array, dot, swapaxes
+
+import reaper
+sys.path.append("..")
+print(sys.path)
+from basicStatistics import corestats
+
+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):
+ """Obsolete - use percentile in corestats instead"""
+ 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 find_outliers(vals):
+ """Calculates the upper and lower bounds of a set of sample/case values
+
+
+ >>> find_outliers([3.504, 5.234, 6.123, 7.234, 3.542, 5.341, 7.852, 4.555, 12.537])
+ (11.252500000000001, 0.5364999999999993)
+
+ >>> >>> find_outliers([9,12,15,17,31,50,7,5,6,8])
+ (32.0, -8.0)
+
+ If there are no vals, returns None for the upper and lower bounds,
+ which code that calls it will have to deal with.
+ >>> find_outliers([])
+ (None, None)
+
+ """
+
+ print("xerxes vals is:", pf(vals))
+
+ if vals:
+ #print("vals is:", pf(vals))
+ stats = corestats.Stats(vals)
+ low_hinge = stats.percentile(25)
+ up_hinge = stats.percentile(75)
+ hstep = 1.5 * (up_hinge - low_hinge)
+
+ upper_bound = up_hinge + hstep
+ lower_bound = low_hinge - hstep
+
+ else:
+ upper_bound = None
+ lower_bound = None
+
+ print(pf(locals()))
+ return upper_bound, lower_bound
+
+
+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
+
+
+def _test():
+ import doctest
+ doctest.testmod()
+
+
+if __name__=="__main__":
+ _test()
diff --git a/wqflask/utility/TDCell.py b/wqflask/utility/TDCell.py
new file mode 100755
index 00000000..8de8e050
--- /dev/null
+++ b/wqflask/utility/TDCell.py
@@ -0,0 +1,41 @@
+# 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..dde221b5
--- /dev/null
+++ b/wqflask/utility/THCell.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 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..d0e4a3fa
--- /dev/null
+++ b/wqflask/utility/__init__.py
@@ -0,0 +1,12 @@
+from pprint import pformat as pf
+
+
+class Bunch(object):
+ """Like a dictionary but using object notation"""
+ def __init__(self, **kw):
+ self.__dict__ = kw
+
+ def __repr__(self):
+ return pf(self.__dict__)
+
+
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..512bc9e6
--- /dev/null
+++ b/wqflask/utility/svg.py
@@ -0,0 +1,1068 @@
+# 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("&", "&amp;")
+ data = data.replace("<", "&lt;")
+ data = data.replace(">", "&gt;")
+ 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('"', "&quot;")
+ 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..99451e33
--- /dev/null
+++ b/wqflask/utility/webqtlUtil.py
@@ -0,0 +1,981 @@
+# 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):
+ '''Obsolete - Use built in function any (or all or whatever)
+
+
+ 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