aboutsummaryrefslogtreecommitdiff
path: root/web/webqtl/heatmap
diff options
context:
space:
mode:
Diffstat (limited to 'web/webqtl/heatmap')
-rwxr-xr-xweb/webqtl/heatmap/Heatmap.py437
-rwxr-xr-xweb/webqtl/heatmap/__init__.py0
-rwxr-xr-xweb/webqtl/heatmap/heatmapPage.py116
-rwxr-xr-xweb/webqtl/heatmap/heatmapPage_GN.py522
-rwxr-xr-xweb/webqtl/heatmap/slink.py141
5 files changed, 1216 insertions, 0 deletions
diff --git a/web/webqtl/heatmap/Heatmap.py b/web/webqtl/heatmap/Heatmap.py
new file mode 100755
index 00000000..c4543cee
--- /dev/null
+++ b/web/webqtl/heatmap/Heatmap.py
@@ -0,0 +1,437 @@
+# 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 os
+import string
+import piddle as pid
+import cPickle
+
+from base import webqtlConfig
+from base.webqtlTrait import webqtlTrait
+from dbFunction import webqtlDatabaseFunction
+from utility import webqtlUtil
+from utility import Plot
+import slink
+
+
+# XZ, 09/09/2008: After adding several traits to collection, click "QTL Heatmap" button,
+# XZ, 09/09/2008: This class will generate what you see.
+#########################################
+# QTL heatmap Page
+#########################################
+class Heatmap:
+
+ def __init__(self, fd=None, searchResult=None, colorScheme=None, userPrivilege=None, userName=None):
+ cursor = webqtlDatabaseFunction.getCursor()
+ if (not cursor):
+ return
+ targetDescriptionChecked = fd.formdata.getvalue('targetDescriptionCheck', '')
+ clusterChecked = fd.formdata.getvalue('clusterCheck', '')
+ sessionfile = fd.formdata.getvalue("session")
+ genotype = fd.genotype
+ strainlist = fd.strainlist
+ ppolar = fd.ppolar
+ mpolar = fd.mpolar
+ traitList = []
+ traitDataList = []
+ for item in searchResult:
+ thisTrait = webqtlTrait(fullname=item, cursor=cursor)
+ thisTrait.retrieveInfo()
+ thisTrait.retrieveData(fd.strainlist)
+ traitList.append(thisTrait)
+ traitDataList.append(thisTrait.exportData(fd.strainlist))
+ self.buildCanvas(colorScheme=colorScheme, targetDescriptionChecked=targetDescriptionChecked, clusterChecked=clusterChecked, sessionfile=sessionfile, genotype=genotype, strainlist=strainlist, ppolar=ppolar, mpolar=mpolar, traitList=traitList, traitDataList=traitDataList, userPrivilege=userPrivilege, userName=userName)
+
+ def buildCanvas(self, colorScheme='', targetDescriptionChecked='', clusterChecked='', sessionfile='', genotype=None, strainlist=None, ppolar=None, mpolar=None, traitList=None, traitDataList=None, userPrivilege=None, userName=None):
+ labelFont = pid.Font(ttf="tahoma",size=14,bold=0)
+ topHeight = 0
+ NNN = len(traitList)
+ #XZ: It's necessory to define canvas here
+ canvas = pid.PILCanvas(size=(80+NNN*20,880))
+ names = map(webqtlTrait.displayName, traitList)
+ #XZ, 7/29/2009: create trait display and find max strWidth
+ strWidth = 0
+ for j in range(len(names)):
+ thisTrait = traitList[j]
+ if targetDescriptionChecked:
+ if thisTrait.db.type == 'ProbeSet':
+ if thisTrait.probe_target_description:
+ names[j] += ' [%s at Chr %s @ %2.3fMB, %s]' % (thisTrait.symbol, thisTrait.chr, thisTrait.mb, thisTrait.probe_target_description)
+ else:
+ names[j] += ' [%s at Chr %s @ %2.3fMB]' % (thisTrait.symbol, thisTrait.chr, thisTrait.mb)
+ elif thisTrait.db.type == 'Geno':
+ names[j] += ' [Chr %s @ %2.3fMB]' % (thisTrait.chr, thisTrait.mb)
+ elif thisTrait.db.type == 'Publish':
+ if thisTrait.confidential:
+ if webqtlUtil.hasAccessToConfidentialPhenotypeTrait(privilege=userPrivilege, userName=userName, authorized_users=thisTrait.authorized_users):
+ if thisTrait.post_publication_abbreviation:
+ names[j] += ' [%s]' % (thisTrait.post_publication_abbreviation)
+ else:
+ if thisTrait.pre_publication_abbreviation:
+ names[j] += ' [%s]' % (thisTrait.pre_publication_abbreviation)
+ else:
+ if thisTrait.post_publication_abbreviation:
+ names[j] += ' [%s]' % (thisTrait.post_publication_abbreviation)
+ else:
+ pass
+
+ i = canvas.stringWidth(names[j], font=labelFont)
+ if i > strWidth:
+ strWidth = i
+
+ width = NNN*20
+ xoffset = 40
+ yoffset = 40
+ cellHeight = 3
+ nLoci = reduce(lambda x,y: x+y, map(lambda x: len(x),genotype),0)
+
+ if nLoci > 2000:
+ cellHeight = 1
+ elif nLoci > 1000:
+ cellHeight = 2
+ elif nLoci < 200:
+ cellHeight = 10
+ else:
+ pass
+
+ pos = range(NNN)
+ neworder = []
+ BWs = Plot.BWSpectrum()
+ colors100 = Plot.colorSpectrum()
+ colors = Plot.colorSpectrum(130)
+ finecolors = Plot.colorSpectrum(250)
+ colors100.reverse()
+ colors.reverse()
+ finecolors.reverse()
+
+ scaleFont=pid.Font(ttf="tahoma",size=10,bold=0)
+
+ if not clusterChecked: #XZ: this part is for original order
+ for i in range(len(names)):
+ neworder.append((xoffset+20*(i+1), i))
+
+ canvas = pid.PILCanvas(size=(80+NNN*20+240,80+ topHeight +5+5+strWidth+nLoci*cellHeight+80+20*cellHeight))
+
+ self.drawTraitNameBottom(canvas,names,yoffset,neworder,strWidth,topHeight,labelFont)
+ else: #XZ: this part is to cluster traits
+ topHeight = 400
+ canvas = pid.PILCanvas(size=(80+NNN*20+240,80+ topHeight +5+5+strWidth+nLoci*cellHeight+80+20*cellHeight))
+
+ corArray = [([0] * (NNN))[:] for i in range(NNN)]
+
+ nnCorr = len(strainlist)
+
+ #XZ, 08/04/2009: I commented out pearsonArray, spearmanArray
+ for i, thisTrait in enumerate(traitList):
+ names1 = [thisTrait.db.name, thisTrait.name, thisTrait.cellid]
+ for j, thisTrait2 in enumerate(traitList):
+ names2 = [thisTrait2.db.name, thisTrait2.name, thisTrait2.cellid]
+ if j < i:
+ corr,nOverlap = webqtlUtil.calCorrelation(traitDataList[i], traitDataList[j],nnCorr)
+ if (1-corr) < 0:
+ distance = 0.0
+ else:
+ distance = 1-corr
+ corArray[i][j] = distance
+ corArray[j][i] = distance
+ elif j == i:
+ corArray[i][j] = 0.0
+ else:
+ pass
+
+ #XZ, 7/29/2009: The parameter d has info of cluster (group member and distance). The format of d is tricky. Print it out to see it's format.
+ d = slink.slink(corArray)
+
+ #XZ, 7/29/2009: Attention: The 'neworder' is changed by the 'draw' function
+ #XZ, 7/30/2009: Only toppos[1][0] and top[1][1] are used later. Then what toppos[0] is used for?
+ toppos = self.draw(canvas,names,d,xoffset,yoffset,neworder,topHeight)
+ self.drawTraitNameTop(canvas,names,yoffset,neworder,strWidth,topHeight,labelFont)
+
+ #XZ, 7/29/2009: draw the top vertical line
+ canvas.drawLine(toppos[1][0],toppos[1][1],toppos[1][0],yoffset)
+
+ #XZ: draw string 'distance = 1-r'
+ canvas.drawString('distance = 1-r',neworder[-1][0] + 50, topHeight*3/4,font=labelFont,angle=90)
+
+ #draw Scale
+ scaleFont=pid.Font(ttf="tahoma",size=10,bold=0)
+ x = neworder[-1][0]
+ canvas.drawLine(x+5, topHeight+yoffset, x+5, yoffset, color=pid.black)
+ y = 0
+ while y <=2:
+ canvas.drawLine(x+5, topHeight*y/2.0+yoffset, x+10, topHeight*y/2.0+yoffset)
+ canvas.drawString('%2.1f' % (2-y), x+12, topHeight*y/2.0+yoffset, font=scaleFont)
+ y += 0.5
+
+
+ chrname = 0
+ chrnameFont=pid.Font(ttf="tahoma",size=24,bold=0)
+ Ncol = 0
+
+ nearestMarkers = self.getNearestMarker(traitList, genotype)
+
+ # import cPickle
+ if sessionfile:
+ fp = open(os.path.join(webqtlConfig.TMPDIR, sessionfile + '.session'), 'rb')
+ permData = cPickle.load(fp)
+ fp.close()
+ else:
+ permData = {}
+
+ areas = []
+ #XZ, 7/31/2009: This for loop is to generate the heatmap
+ #XZ: draw trait by trait instead of marker by marker
+ for order in neworder:
+ #startHeight = 40+400+5+5+strWidth
+ startHeight = topHeight + 40+5+5+strWidth
+ startWidth = order[0]-5
+ if Ncol and Ncol % 5 == 0:
+ drawStartPixel = 8
+ else:
+ drawStartPixel = 9
+
+ tempVal = traitDataList[order[1]]
+ _vals = []
+ _strains = []
+ for i in range(len(strainlist)):
+ if tempVal[i] != None:
+ _strains.append(strainlist[i])
+ _vals.append(tempVal[i])
+
+ qtlresult = genotype.regression(strains = _strains, trait = _vals)
+
+ if sessionfile:
+ LRSArray = permData[str(traitList[order[1]])]
+ else:
+ LRSArray = genotype.permutation(strains = _strains, trait = _vals, nperm = 1000)
+ permData[str(traitList[order[1]])] = LRSArray
+
+ sugLRS = LRSArray[369]
+ sigLRS = LRSArray[949]
+ prechr = 0
+ chrstart = 0
+ nearest = nearestMarkers[order[1]]
+ midpoint = []
+
+ for item in qtlresult:
+ if item.lrs > webqtlConfig.MAXLRS:
+ adjustlrs = webqtlConfig.MAXLRS
+ else:
+ adjustlrs = item.lrs
+
+ if item.locus.chr != prechr:
+ if prechr:
+ canvas.drawRect(startWidth-drawStartPixel, startHeight, startWidth+10, startHeight+3,edgeColor=pid.white, edgeWidth=0, fillColor=pid.white)
+ startHeight+= 3
+ if not chrname:
+ canvas.drawString(prechr,xoffset-20,(chrstart+startHeight)/2,font = chrnameFont,color=pid.dimgray)
+ prechr = item.locus.chr
+ chrstart = startHeight
+ if colorScheme == '0':
+ if adjustlrs <= sugLRS:
+ colorIndex = int(65*adjustlrs/sugLRS)
+ else:
+ colorIndex = int(65 + 35*(adjustlrs-sugLRS)/(sigLRS-sugLRS))
+ if colorIndex > 99:
+ colorIndex = 99
+ colorIndex = colors100[colorIndex]
+ elif colorScheme == '1':
+ sugLRS = LRSArray[369]/2.0
+ if adjustlrs <= sugLRS:
+ colorIndex = BWs[20+int(50*adjustlrs/sugLRS)]
+ else:
+ if item.additive > 0:
+ colorIndex = int(80 + 50*(adjustlrs-sugLRS)/(sigLRS-sugLRS))
+ else:
+ colorIndex = int(50 - 50*(adjustlrs-sugLRS)/(sigLRS-sugLRS))
+ if colorIndex > 129:
+ colorIndex = 129
+ if colorIndex < 0:
+ colorIndex = 0
+ colorIndex = colors[colorIndex]
+ elif colorScheme == '2':
+ if item.additive > 0:
+ colorIndex = int(150 + 100*(adjustlrs/sigLRS))
+ else:
+ colorIndex = int(100 - 100*(adjustlrs/sigLRS))
+ if colorIndex > 249:
+ colorIndex = 249
+ if colorIndex < 0:
+ colorIndex = 0
+ colorIndex = finecolors[colorIndex]
+ else:
+ colorIndex = pid.white
+
+ if startHeight > 1:
+ canvas.drawRect(startWidth-drawStartPixel, startHeight, startWidth+10, startHeight+cellHeight,edgeColor=colorIndex, edgeWidth=0, fillColor=colorIndex)
+ else:
+ canvas.drawLine(startWidth-drawStartPixel, startHeight, startWidth+10, startHeight, Color=colorIndex)
+
+ if item.locus.name == nearest:
+ midpoint = [startWidth,startHeight-5]
+ startHeight+=cellHeight
+
+ #XZ, map link to trait name and band
+ COORDS = "%d,%d,%d,%d" %(startWidth-drawStartPixel,topHeight+40,startWidth+10,startHeight)
+ HREF = "javascript:showDatabase2('%s','%s','%s');" % (traitList[order[1]].db.name, traitList[order[1]].name, traitList[order[1]].cellid)
+ area = (COORDS, HREF, '%s' % names[order[1]])
+ areas.append(area)
+
+ if midpoint:
+ traitPixel = ((midpoint[0],midpoint[1]),(midpoint[0]-6,midpoint[1]+12),(midpoint[0]+6,midpoint[1]+12))
+ canvas.drawPolygon(traitPixel,edgeColor=pid.black,fillColor=pid.orange,closed=1)
+
+ if not chrname:
+ canvas.drawString(prechr,xoffset-20,(chrstart+startHeight)/2,font = chrnameFont,color=pid.dimgray)
+ chrname = 1
+ Ncol += 1
+
+
+ #draw Spectrum
+ startSpect = neworder[-1][0] + 30
+ startHeight = topHeight + 40+5+5+strWidth
+
+ if colorScheme == '0':
+ for i in range(100):
+ canvas.drawLine(startSpect+i,startHeight+20,startSpect+i,startHeight+40,color=colors100[i])
+ scaleFont=pid.Font(ttf="tahoma",size=10,bold=0)
+ canvas.drawLine(startSpect,startHeight+45,startSpect,startHeight+39,color=pid.black)
+ canvas.drawString('LRS = 0',startSpect,startHeight+55,font=scaleFont)
+ canvas.drawLine(startSpect+64,startHeight+45,startSpect+64,startHeight+39,color=pid.black)
+ canvas.drawString('Suggestive LRS',startSpect+64,startHeight+55,font=scaleFont)
+ canvas.drawLine(startSpect+99,startHeight+45,startSpect+99,startHeight+39,color=pid.black)
+ canvas.drawString('Significant LRS',startSpect+105,startHeight+40,font=scaleFont)
+ elif colorScheme == '1':
+ for i in range(50):
+ canvas.drawLine(startSpect+i,startHeight,startSpect+i,startHeight+40,color=BWs[20+i])
+ for i in range(50,100):
+ canvas.drawLine(startSpect+i,startHeight,startSpect+i,startHeight+20,color=colors[100-i])
+ canvas.drawLine(startSpect+i,startHeight+20,startSpect+i,startHeight+40,color=colors[30+i])
+
+ canvas.drawLine(startSpect,startHeight+45,startSpect,startHeight+39,color=pid.black)
+ canvas.drawString('LRS = 0',startSpect,startHeight+60,font=scaleFont)
+ canvas.drawLine(startSpect+50,startHeight+45,startSpect+50,startHeight+39,color=pid.black)
+ canvas.drawString('0.5*Suggestive LRS',startSpect+50,startHeight+ 60,font=scaleFont)
+ canvas.drawLine(startSpect+99,startHeight+45,startSpect+99,startHeight+39,color=pid.black)
+ canvas.drawString('Significant LRS',startSpect+105,startHeight+50,font=scaleFont)
+ textFont=pid.Font(ttf="verdana",size=18,bold=0)
+ canvas.drawString('%s +' % ppolar,startSpect+120,startHeight+ 35,font=textFont,color=pid.red)
+ canvas.drawString('%s +' % mpolar,startSpect+120,startHeight+ 15,font=textFont,color=pid.blue)
+ elif colorScheme == '2':
+ for i in range(100):
+ canvas.drawLine(startSpect+i,startHeight,startSpect+i,startHeight+20,color=finecolors[100-i])
+ canvas.drawLine(startSpect+i,startHeight+20,startSpect+i,startHeight+40,color=finecolors[150+i])
+
+ canvas.drawLine(startSpect,startHeight+45,startSpect,startHeight+39,color=pid.black)
+ canvas.drawString('LRS = 0',startSpect,startHeight+60,font=scaleFont)
+ canvas.drawLine(startSpect+99,startHeight+45,startSpect+99,startHeight+39,color=pid.black)
+ canvas.drawString('Significant LRS',startSpect+105,startHeight+50,font=scaleFont)
+ textFont=pid.Font(ttf="verdana",size=18,bold=0)
+ canvas.drawString('%s +' % ppolar,startSpect+120,startHeight+ 35,font=textFont,color=pid.red)
+ canvas.drawString('%s +' % mpolar,startSpect+120,startHeight+ 15,font=textFont,color=pid.blue)
+
+ filename= webqtlUtil.genRandStr("Heatmap_")
+ canvas.save(webqtlConfig.IMGDIR+filename, format='png')
+ if not sessionfile:
+ sessionfile = webqtlUtil.generate_session()
+ webqtlUtil.dump_session(permData, os.path.join(webqtlConfig.TMPDIR, sessionfile +'.session'))
+ self.filename=filename
+ self.areas=areas
+ self.sessionfile=sessionfile
+
+ def getResult(self):
+ return self.filename, self.areas, self.sessionfile
+
+ #XZ, 7/31/2009: This function put the order of traits into parameter neworder,
+ #XZ: return the position of the top vertical line of the hierarchical tree, draw the hierarchical tree.
+ def draw(self,canvas,names,d,xoffset,yoffset,neworder,topHeight):
+ maxDistance = topHeight
+ fontoffset = 4 #XZ, 7/31/2009: used only for drawing tree
+ if type(d[0]) == type(1) and type(d[1]) == type(1):
+ neworder.append((xoffset+20,d[0]))
+ neworder.append((xoffset+40,d[1]))
+ height = d[2]*maxDistance/2
+ canvas.drawLine(xoffset+20-fontoffset,maxDistance+yoffset,xoffset+20-fontoffset,maxDistance-height+yoffset)
+ canvas.drawLine(xoffset+40-fontoffset,maxDistance+yoffset,xoffset+40-fontoffset,maxDistance-height+yoffset)
+ canvas.drawLine(xoffset+40-fontoffset,maxDistance+yoffset-height,xoffset+20-fontoffset,maxDistance-height+yoffset)
+ return (40,(xoffset+30-fontoffset,maxDistance-height+yoffset))
+ elif type(d[0]) == type(1):
+ neworder.append((xoffset+20,d[0]))
+ d2 = self.draw(canvas,names,d[1],xoffset+20,yoffset,neworder,topHeight)
+ height = d[2]*maxDistance/2
+ canvas.drawLine(xoffset+20-fontoffset,maxDistance+yoffset,xoffset+20-fontoffset,maxDistance-height+yoffset)
+ canvas.drawLine(d2[1][0],d2[1][1],d2[1][0],maxDistance-height+yoffset)
+ canvas.drawLine(d2[1][0],maxDistance-height+yoffset,xoffset+20-fontoffset,maxDistance-height+yoffset)
+ return (20+d2[0],((d2[1][0]+xoffset+20-fontoffset)/2,maxDistance-height+yoffset))
+ elif type(d[1]) == type(1):
+ d1 = self.draw(canvas,names,d[0],xoffset,yoffset,neworder,topHeight)
+ neworder.append((xoffset+d1[0]+20,d[1]))
+ height = d[2]*maxDistance/2
+ canvas.drawLine(xoffset+d1[0]+20-fontoffset,maxDistance+yoffset,xoffset+d1[0]+20-fontoffset,maxDistance-height+yoffset)
+ canvas.drawLine(d1[1][0],d1[1][1],d1[1][0],maxDistance-height+yoffset)
+ canvas.drawLine(d1[1][0],maxDistance-height+yoffset,xoffset+d1[0]+20-fontoffset,maxDistance-height+yoffset)
+ return (d1[0]+20,((d1[1][0]+xoffset+d1[0]+20-fontoffset)/2,maxDistance-height+yoffset))
+ else:
+ d1 = self.draw(canvas,names,d[0],xoffset,yoffset,neworder,topHeight)
+ d2 = self.draw(canvas,names,d[1],xoffset+d1[0],yoffset,neworder,topHeight)
+ height = d[2]*maxDistance/2
+ canvas.drawLine(d2[1][0],d2[1][1],d2[1][0],maxDistance-height+yoffset)
+ canvas.drawLine(d1[1][0],d1[1][1],d1[1][0],maxDistance-height+yoffset)
+ canvas.drawLine(d1[1][0],maxDistance-height+yoffset,d2[1][0],maxDistance-height+yoffset)
+ return (d1[0]+d2[0],((d1[1][0]+d2[1][0])/2,maxDistance-height+yoffset))
+
+ #XZ, 7/31/2009: dras trait names
+ def drawTraitNameBottom (self,canvas,names,yoffset,neworder,strWidth,topHeight,labelFont):
+ maxDistance = topHeight
+ for oneOrder in neworder:
+ canvas.drawString(names[oneOrder[1]],oneOrder[0]-5,maxDistance+yoffset+5+strWidth-canvas.stringWidth(names[oneOrder[1]],font=labelFont),font=labelFont,color=pid.black,angle=270)
+
+ def drawTraitNameTop (self,canvas,names,yoffset,neworder,strWidth,topHeight,labelFont):
+ maxDistance = topHeight
+ for oneOrder in neworder:
+ canvas.drawString(names[oneOrder[1]],oneOrder[0]-5,maxDistance+yoffset+5,font=labelFont,color=pid.black,angle=270)
+
+
+ def getNearestMarker(self, traitList, genotype):
+ out = []
+ if not genotype.Mbmap:
+ return [None]* len(traitList)
+ for item in traitList:
+ try:
+ nearest = None
+ for _chr in genotype:
+ if _chr.name != item.chr:
+ continue
+ distance = 1e30
+ for _locus in _chr:
+ if abs(_locus.Mb-item.mb) < distance:
+ distance = abs(_locus.Mb-item.mb)
+ nearest = _locus.name
+ out.append(nearest)
+ except:
+ out.append(None)
+
+ return out
diff --git a/web/webqtl/heatmap/__init__.py b/web/webqtl/heatmap/__init__.py
new file mode 100755
index 00000000..e69de29b
--- /dev/null
+++ b/web/webqtl/heatmap/__init__.py
diff --git a/web/webqtl/heatmap/heatmapPage.py b/web/webqtl/heatmap/heatmapPage.py
new file mode 100755
index 00000000..b407b0c8
--- /dev/null
+++ b/web/webqtl/heatmap/heatmapPage.py
@@ -0,0 +1,116 @@
+# 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 os
+import string
+from htmlgen import HTMLgen2 as HT
+
+from base.templatePage import templatePage
+from base import webqtlConfig
+from heatmap.Heatmap import Heatmap
+
+
+# XZ, 09/09/2008: After adding several traits to collection, click "QTL Heatmap" button,
+# XZ, 09/09/2008: This class will generate what you see.
+#########################################
+# QTL heatmap Page
+#########################################
+class heatmapPage(templatePage):
+
+ def __init__(self,fd):
+
+ templatePage.__init__(self, fd)
+
+ if not self.openMysql():
+ return
+ if not fd.genotype:
+ fd.readGenotype()
+
+ searchResult = fd.formdata.getvalue('searchResult')
+ if not searchResult:
+ heading = 'QTL Heatmap'
+ detail = ['You need to select at least two traits in order to generate QTL heatmap.']
+ self.error(heading=heading,detail=detail)
+ return
+ if type("1") == type(searchResult):
+ searchResult = string.split(searchResult,'\t')
+ if searchResult:
+ if len(searchResult) > webqtlConfig.MAXCORR:
+ heading = 'QTL Heatmap'
+ detail = ['In order to display the QTL heat map properly, do not select more than %d traits for analysis.' % webqtlConfig.MAXCORR]
+ self.error(heading=heading,detail=detail)
+ return
+ else:
+ heading = 'QTL Heatmap'
+ detail = [HT.Font('Error : ',color='red'),HT.Font('Error occurs while retrieving data from database.',color='black')]
+ self.error(heading=heading,detail=detail)
+ return
+ self.dict['title'] = 'QTL heatmap'
+ NNN = len(searchResult)
+ if NNN == 0:
+ heading = "QTL Heatmap"
+ detail = ['No trait was selected for %s data set. No QTL heatmap was generated.' % fd.RISet]
+ self.error(heading=heading,detail=detail)
+ return
+ elif NNN < 2:
+ heading = 'QTL Heatmap'
+ detail = ['You need to select at least two traits in order to generate QTL heatmap.']
+ self.error(heading=heading,detail=detail)
+ return
+ else:
+ colorScheme = fd.formdata.getvalue('colorScheme')
+ if not colorScheme:
+ colorScheme = '1'
+ heatmapObject = Heatmap(fd=fd, searchResult=searchResult, colorScheme=colorScheme, userPrivilege=self.privilege, userName=self.userName)
+ filename, areas, sessionfile = heatmapObject.getResult()
+ gifmap = HT.Map(name='traitMap')
+ for area in areas:
+ Areas = HT.Area(shape='rect', coords=area[0], href=area[1], title=area[2])
+ gifmap.areas.append(Areas)
+ img2=HT.Image('/image/'+filename+'.png',border=0,usemap='#traitMap')
+ imgUrl = 'Right-click or control-click on the link to download this graph as a <a href="/image/%s.png" class="normalsize" target="_blank">PNG file</a>' % filename
+ form = HT.Form(cgi= os.path.join(webqtlConfig.CGIDIR, webqtlConfig.SCRIPTFILE), enctype='multipart/form-data', name='showDatabase', submit=HT.Input(type='hidden'))
+ hddn = {'FormID':'showDatabase','ProbeSetID':'_','database':fd.RISet+"Geno",'CellID':'_','RISet':fd.RISet,'searchResult':string.join(searchResult,'\t')}
+ if fd.incparentsf1:
+ hddn['incparentsf1']='ON'
+ for key in hddn.keys():
+ form.append(HT.Input(name=key, value=hddn[key], type='hidden'))
+ heatmapButton = HT.Input(type='button' ,name='mintmap',value='Redraw QTL Heatmap', onClick="databaseFunc(this.form,'heatmap');",Class="button")
+ spects = {'0':'Single Spectrum','1':'Grey + Blue + Red','2':'Blue + Red'}
+ schemeMenu = HT.Select(name='colorScheme')
+ schemeMenu.append(('Single Spectrum',0))
+ schemeMenu.append(('Grey + Blue + Red',1))
+ schemeMenu.append(('Blue + Red',2))
+ schemeMenu.selected.append(spects[colorScheme])
+ clusterCheck= HT.Input(type='checkbox', Class='checkbox', name='clusterCheck',checked=0)
+ targetDescriptionCheck = HT.Input(type='checkbox', Class='checkbox', name='targetDescriptionCheck',checked=0)
+ form.append(gifmap,schemeMenu, heatmapButton, HT.P(), clusterCheck, ' Cluster traits ', targetDescriptionCheck, ' Add description', HT.P(),img2, HT.P(), imgUrl)
+ form.append(HT.Input(name='session', value=sessionfile, type='hidden'))
+ heatmapHelp = HT.Input(type='button' ,name='heatmapHelpButton',value='Info', onClick="openNewWin('/heatmap.html');",Class="button")
+ heatmapHeading = HT.Paragraph('QTL Heatmap ', heatmapHelp, Class="title")
+ TD_LR = HT.TD(colspan=2,height=200,width="100%",bgColor='#eeeeee')
+ TD_LR.append(heatmapHeading, HT.P(),HT.P(),HT.P(),HT.P(),HT.P(),form)
+ self.dict['body'] = str(TD_LR)
diff --git a/web/webqtl/heatmap/heatmapPage_GN.py b/web/webqtl/heatmap/heatmapPage_GN.py
new file mode 100755
index 00000000..abc5d8aa
--- /dev/null
+++ b/web/webqtl/heatmap/heatmapPage_GN.py
@@ -0,0 +1,522 @@
+# 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 os
+import string
+import piddle as pid
+import cPickle
+from htmlgen import HTMLgen2 as HT
+
+from base.templatePage import templatePage
+from base import webqtlConfig
+from base.webqtlTrait import webqtlTrait
+from utility import webqtlUtil
+from utility import Plot
+import slink
+
+
+# XZ, 09/09/2008: After adding several traits to collection, click "QTL Heatmap" button,
+# XZ, 09/09/2008: This class will generate what you see.
+#########################################
+# QTL heatmap Page
+#########################################
+class heatmapPage(templatePage):
+
+ labelFont=pid.Font(ttf="tahoma",size=14,bold=0)
+
+ topHeight = 0
+
+ def __init__(self,fd):
+
+ templatePage.__init__(self, fd)
+
+ if not self.openMysql():
+ return
+ if not fd.genotype:
+ fd.readGenotype()
+
+
+ self.searchResult = fd.formdata.getvalue('searchResult')
+
+ if not self.searchResult:
+ templatePage.__init__(self, fd)
+ heading = 'QTL Heatmap'
+ detail = ['You need to select at least two traits in order to generate correlation matrix.']
+ self.error(heading=heading,detail=detail)
+ return
+ if type("1") == type(self.searchResult):
+ self.searchResult = string.split(self.searchResult,'\t')
+
+
+ if self.searchResult:
+ if len(self.searchResult) > webqtlConfig.MAXCORR:
+ heading = 'QTL Heatmap'
+ detail = ['In order to display the QTL heat map properly, do not select more than %d traits for analysis.' % webqtlConfig.MAXCORR]
+ self.error(heading=heading,detail=detail)
+ return
+
+ traitList = []
+ traitDataList = []
+ for item in self.searchResult:
+ thisTrait = webqtlTrait(fullname=item, cursor=self.cursor)
+ thisTrait.retrieveInfo()
+ thisTrait.retrieveData(fd.strainlist)
+ traitList.append(thisTrait)
+ traitDataList.append(thisTrait.exportData(fd.strainlist))
+ else:
+ heading = 'QTL Heatmap'
+ detail = [HT.Font('Error : ',color='red'),HT.Font('Error occurs while retrieving data from database.',color='black')]
+ self.error(heading=heading,detail=detail)
+ return
+
+ self.colorScheme = fd.formdata.getvalue('colorScheme')
+ if not self.colorScheme:
+ self.colorScheme = '1'
+
+ self.dict['title'] = 'QTL heatmap'
+
+ NNN = len(traitList)
+
+ if NNN == 0:
+ heading = "QTL Heatmap"
+ detail = ['No trait was selected for %s data set. No QTL heatmap was generated.' % fd.RISet]
+ self.error(heading=heading,detail=detail)
+ return
+ elif NNN < 2:
+ templatePage.__init__(self, fd)
+ heading = 'QTL Heatmap'
+ detail = ['You need to select at least two traits in order to generate QTL heatmap.']
+ self.error(heading=heading,detail=detail)
+ return
+ else:
+ #XZ: It's necessory to define canvas here
+ canvas = pid.PILCanvas(size=(80+NNN*20,880))
+
+ names = map(webqtlTrait.displayName, traitList)
+
+ self.targetDescriptionChecked = fd.formdata.getvalue('targetDescriptionCheck', '')
+
+ #XZ, 7/29/2009: create trait display and find max strWidth
+ strWidth = 0
+ for j in range(len(names)):
+ thisTrait = traitList[j]
+
+ if self.targetDescriptionChecked:
+ if thisTrait.db.type == 'ProbeSet':
+ if thisTrait.probe_target_description:
+ names[j] += ' [%s at Chr %s @ %2.3fMB, %s]' % (thisTrait.symbol, thisTrait.chr, thisTrait.mb, thisTrait.probe_target_description)
+ else:
+ names[j] += ' [%s at Chr %s @ %2.3fMB]' % (thisTrait.symbol, thisTrait.chr, thisTrait.mb)
+ elif thisTrait.db.type == 'Geno':
+ names[j] += ' [Chr %s @ %2.3fMB]' % (thisTrait.chr, thisTrait.mb)
+ elif thisTrait.db.type == 'Publish':
+ if thisTrait.abbreviation:
+ names[j] += ' [%s]' % (thisTrait.abbreviation)
+ else:
+ pass
+ else:
+ pass
+
+ i = canvas.stringWidth(names[j],font=self.labelFont)
+ if i > strWidth:
+ strWidth = i
+
+ width = NNN*20
+ xoffset = 40
+ yoffset = 40
+ cellHeight = 3
+ nLoci = reduce(lambda x,y: x+y, map(lambda x: len(x),fd.genotype),0)
+
+ if nLoci > 2000:
+ cellHeight = 1
+ elif nLoci > 1000:
+ cellHeight = 2
+ elif nLoci < 200:
+ cellHeight = 10
+ else:
+ pass
+
+ pos = range(NNN)
+ neworder = []
+ BWs = Plot.BWSpectrum()
+ colors100 = Plot.colorSpectrum()
+ colors = Plot.colorSpectrum(130)
+ finecolors = Plot.colorSpectrum(250)
+ colors100.reverse()
+ colors.reverse()
+ finecolors.reverse()
+
+ scaleFont=pid.Font(ttf="tahoma",size=10,bold=0)
+
+ self.clusterChecked = fd.formdata.getvalue('clusterCheck', '')
+
+
+ if not self.clusterChecked: #XZ: this part is for original order
+ for i in range(len(names)):
+ neworder.append((xoffset+20*(i+1), i))
+
+ canvas = pid.PILCanvas(size=(80+NNN*20+240,80+ self.topHeight +5+5+strWidth+nLoci*cellHeight+80+20*cellHeight))
+
+ self.drawTraitNameBottom(canvas,names,yoffset,neworder,strWidth)
+ else: #XZ: this part is to cluster traits
+ self.topHeight = 400
+ canvas = pid.PILCanvas(size=(80+NNN*20+240,80+ self.topHeight +5+5+strWidth+nLoci*cellHeight+80+20*cellHeight))
+
+ corArray = [([0] * (NNN))[:] for i in range(NNN)]
+
+ nnCorr = len(fd.strainlist)
+
+ #XZ, 08/04/2009: I commented out pearsonArray, spearmanArray
+ for i, thisTrait in enumerate(traitList):
+ names1 = [thisTrait.db.name, thisTrait.name, thisTrait.cellid]
+ for j, thisTrait2 in enumerate(traitList):
+ names2 = [thisTrait2.db.name, thisTrait2.name, thisTrait2.cellid]
+ if j < i:
+ corr,nOverlap = webqtlUtil.calCorrelation(traitDataList[i],traitDataList[j],nnCorr)
+ if (1-corr) < 0:
+ distance = 0.0
+ else:
+ distance = 1-corr
+ corArray[i][j] = distance
+ corArray[j][i] = distance
+ elif j == i:
+ corArray[i][j] = 0.0
+ else:
+ pass
+
+ #XZ, 7/29/2009: The parameter d has info of cluster (group member and distance). The format of d is tricky. Print it out to see it's format.
+ d = slink.slink(corArray)
+
+ #XZ, 7/29/2009: Attention: The 'neworder' is changed by the 'draw' function
+ #XZ, 7/30/2009: Only toppos[1][0] and top[1][1] are used later. Then what toppos[0] is used for?
+ toppos = self.draw(canvas,names,d,xoffset,yoffset,neworder)
+ self.drawTraitNameTop(canvas,names,yoffset,neworder,strWidth)
+
+ #XZ, 7/29/2009: draw the top vertical line
+ canvas.drawLine(toppos[1][0],toppos[1][1],toppos[1][0],yoffset)
+
+ #XZ: draw string 'distance = 1-r'
+ canvas.drawString('distance = 1-r',neworder[-1][0] + 50, self.topHeight*3/4,font=self.labelFont,angle=90)
+
+ #draw Scale
+ scaleFont=pid.Font(ttf="tahoma",size=10,bold=0)
+ x = neworder[-1][0]
+ canvas.drawLine(x+5, self.topHeight+yoffset, x+5, yoffset, color=pid.black)
+ y = 0
+ while y <=2:
+ canvas.drawLine(x+5, self.topHeight*y/2.0+yoffset, x+10, self.topHeight*y/2.0+yoffset)
+ canvas.drawString('%2.1f' % (2-y), x+12, self.topHeight*y/2.0+yoffset, font=scaleFont)
+ y += 0.5
+
+
+ chrname = 0
+ chrnameFont=pid.Font(ttf="tahoma",size=24,bold=0)
+ Ncol = 0
+
+ gifmap = HT.Map(name='traitMap')
+
+ nearestMarkers = self.getNearestMarker(traitList, fd.genotype)
+
+ # import cPickle
+ sessionfile = fd.formdata.getvalue("session")
+
+ if sessionfile:
+ fp = open(os.path.join(webqtlConfig.TMPDIR, sessionfile + '.session'), 'rb')
+ permData = cPickle.load(fp)
+ fp.close()
+ else:
+ permData = {}
+
+ #XZ, 7/31/2009: This for loop is to generate the heatmap
+ #XZ: draw trait by trait instead of marker by marker
+ for order in neworder:
+ #startHeight = 40+400+5+5+strWidth
+ startHeight = self.topHeight + 40+5+5+strWidth
+ startWidth = order[0]-5
+ if Ncol and Ncol % 5 == 0:
+ drawStartPixel = 8
+ else:
+ drawStartPixel = 9
+
+ tempVal = traitDataList[order[1]]
+ _vals = []
+ _strains = []
+ for i in range(len(fd.strainlist)):
+ if tempVal[i] != None:
+ _strains.append(fd.strainlist[i])
+ _vals.append(tempVal[i])
+
+ qtlresult = fd.genotype.regression(strains = _strains, trait = _vals)
+
+ if sessionfile:
+ LRSArray = permData[str(traitList[order[1]])]
+ else:
+ LRSArray = fd.genotype.permutation(strains = _strains, trait = _vals, nperm = 1000)
+ permData[str(traitList[order[1]])] = LRSArray
+
+ sugLRS = LRSArray[369]
+ sigLRS = LRSArray[949]
+ prechr = 0
+ chrstart = 0
+ nearest = nearestMarkers[order[1]]
+ midpoint = []
+
+ for item in qtlresult:
+ if item.lrs > webqtlConfig.MAXLRS:
+ adjustlrs = webqtlConfig.MAXLRS
+ else:
+ adjustlrs = item.lrs
+
+ if item.locus.chr != prechr:
+ if prechr:
+ canvas.drawRect(startWidth-drawStartPixel, startHeight, startWidth+10, startHeight+3,edgeColor=pid.white, edgeWidth=0, fillColor=pid.white)
+ startHeight+= 3
+ if not chrname:
+ canvas.drawString(prechr,xoffset-20,(chrstart+startHeight)/2,font = chrnameFont,color=pid.dimgray)
+ prechr = item.locus.chr
+ chrstart = startHeight
+ if self.colorScheme == '0':
+ if adjustlrs <= sugLRS:
+ colorIndex = int(65*adjustlrs/sugLRS)
+ else:
+ colorIndex = int(65 + 35*(adjustlrs-sugLRS)/(sigLRS-sugLRS))
+ if colorIndex > 99:
+ colorIndex = 99
+ colorIndex = colors100[colorIndex]
+ elif self.colorScheme == '1':
+ sugLRS = LRSArray[369]/2.0
+ if adjustlrs <= sugLRS:
+ colorIndex = BWs[20+int(50*adjustlrs/sugLRS)]
+ else:
+ if item.additive > 0:
+ colorIndex = int(80 + 50*(adjustlrs-sugLRS)/(sigLRS-sugLRS))
+ else:
+ colorIndex = int(50 - 50*(adjustlrs-sugLRS)/(sigLRS-sugLRS))
+ if colorIndex > 129:
+ colorIndex = 129
+ if colorIndex < 0:
+ colorIndex = 0
+ colorIndex = colors[colorIndex]
+ elif self.colorScheme == '2':
+ if item.additive > 0:
+ colorIndex = int(150 + 100*(adjustlrs/sigLRS))
+ else:
+ colorIndex = int(100 - 100*(adjustlrs/sigLRS))
+ if colorIndex > 249:
+ colorIndex = 249
+ if colorIndex < 0:
+ colorIndex = 0
+ colorIndex = finecolors[colorIndex]
+ else:
+ colorIndex = pid.white
+
+ if startHeight > 1:
+ canvas.drawRect(startWidth-drawStartPixel, startHeight, startWidth+10, startHeight+cellHeight,edgeColor=colorIndex, edgeWidth=0, fillColor=colorIndex)
+ else:
+ canvas.drawLine(startWidth-drawStartPixel, startHeight, startWidth+10, startHeight, Color=colorIndex)
+
+ if item.locus.name == nearest:
+ midpoint = [startWidth,startHeight-5]
+ startHeight+=cellHeight
+
+ #XZ, map link to trait name and band
+ COORDS = "%d,%d,%d,%d" %(startWidth-drawStartPixel,self.topHeight+40,startWidth+10,startHeight)
+ HREF = "javascript:showDatabase2('%s','%s','%s');" % (traitList[order[1]].db.name, traitList[order[1]].name, traitList[order[1]].cellid)
+ Areas = HT.Area(shape='rect',coords=COORDS,href=HREF, title='%s' % names[order[1]])
+ gifmap.areas.append(Areas)
+
+ if midpoint:
+ traitPixel = ((midpoint[0],midpoint[1]),(midpoint[0]-6,midpoint[1]+12),(midpoint[0]+6,midpoint[1]+12))
+ canvas.drawPolygon(traitPixel,edgeColor=pid.black,fillColor=pid.orange,closed=1)
+
+ if not chrname:
+ canvas.drawString(prechr,xoffset-20,(chrstart+startHeight)/2,font = chrnameFont,color=pid.dimgray)
+ chrname = 1
+ Ncol += 1
+
+
+ #draw Spectrum
+ startSpect = neworder[-1][0] + 30
+ startHeight = self.topHeight + 40+5+5+strWidth
+
+ if self.colorScheme == '0':
+ for i in range(100):
+ canvas.drawLine(startSpect+i,startHeight+20,startSpect+i,startHeight+40,color=colors100[i])
+ scaleFont=pid.Font(ttf="tahoma",size=10,bold=0)
+ canvas.drawLine(startSpect,startHeight+45,startSpect,startHeight+39,color=pid.black)
+ canvas.drawString('LRS = 0',startSpect,startHeight+55,font=scaleFont)
+ canvas.drawLine(startSpect+64,startHeight+45,startSpect+64,startHeight+39,color=pid.black)
+ canvas.drawString('Suggestive LRS',startSpect+64,startHeight+55,font=scaleFont)
+ canvas.drawLine(startSpect+99,startHeight+45,startSpect+99,startHeight+39,color=pid.black)
+ canvas.drawString('Significant LRS',startSpect+105,startHeight+40,font=scaleFont)
+ elif self.colorScheme == '1':
+ for i in range(50):
+ canvas.drawLine(startSpect+i,startHeight,startSpect+i,startHeight+40,color=BWs[20+i])
+ for i in range(50,100):
+ canvas.drawLine(startSpect+i,startHeight,startSpect+i,startHeight+20,color=colors[100-i])
+ canvas.drawLine(startSpect+i,startHeight+20,startSpect+i,startHeight+40,color=colors[30+i])
+
+ canvas.drawLine(startSpect,startHeight+45,startSpect,startHeight+39,color=pid.black)
+ canvas.drawString('LRS = 0',startSpect,startHeight+60,font=scaleFont)
+ canvas.drawLine(startSpect+50,startHeight+45,startSpect+50,startHeight+39,color=pid.black)
+ canvas.drawString('0.5*Suggestive LRS',startSpect+50,startHeight+ 60,font=scaleFont)
+ canvas.drawLine(startSpect+99,startHeight+45,startSpect+99,startHeight+39,color=pid.black)
+ canvas.drawString('Significant LRS',startSpect+105,startHeight+50,font=scaleFont)
+ textFont=pid.Font(ttf="verdana",size=18,bold=0)
+ canvas.drawString('%s +' % fd.ppolar,startSpect+120,startHeight+ 35,font=textFont,color=pid.red)
+ canvas.drawString('%s +' % fd.mpolar,startSpect+120,startHeight+ 15,font=textFont,color=pid.blue)
+ elif self.colorScheme == '2':
+ for i in range(100):
+ canvas.drawLine(startSpect+i,startHeight,startSpect+i,startHeight+20,color=finecolors[100-i])
+ canvas.drawLine(startSpect+i,startHeight+20,startSpect+i,startHeight+40,color=finecolors[150+i])
+
+ canvas.drawLine(startSpect,startHeight+45,startSpect,startHeight+39,color=pid.black)
+ canvas.drawString('LRS = 0',startSpect,startHeight+60,font=scaleFont)
+ canvas.drawLine(startSpect+99,startHeight+45,startSpect+99,startHeight+39,color=pid.black)
+ canvas.drawString('Significant LRS',startSpect+105,startHeight+50,font=scaleFont)
+ textFont=pid.Font(ttf="verdana",size=18,bold=0)
+ canvas.drawString('%s +' % fd.ppolar,startSpect+120,startHeight+ 35,font=textFont,color=pid.red)
+ canvas.drawString('%s +' % fd.mpolar,startSpect+120,startHeight+ 15,font=textFont,color=pid.blue)
+
+
+ filename= webqtlUtil.genRandStr("Heatmap_")
+ canvas.save(webqtlConfig.IMGDIR+filename, format='png')
+ img2=HT.Image('/image/'+filename+'.png',border=0,usemap='#traitMap')
+ imgUrl = 'Right-click or control-click on the link to download this graph as a <a href="/image/%s.png" class="normalsize" target="_blank">PNG file</a>' % filename
+
+ form = HT.Form(cgi= os.path.join(webqtlConfig.CGIDIR, webqtlConfig.SCRIPTFILE), enctype='multipart/form-data', name='showDatabase', submit=HT.Input(type='hidden'))
+ hddn = {'FormID':'showDatabase','ProbeSetID':'_','database':fd.RISet+"Geno",'CellID':'_','RISet':fd.RISet,'searchResult':string.join(self.searchResult,'\t')}
+ if fd.incparentsf1:
+ hddn['incparentsf1']='ON'
+ for key in hddn.keys():
+ form.append(HT.Input(name=key, value=hddn[key], type='hidden'))
+
+ heatmap = HT.Input(type='button' ,name='mintmap',value='Redraw QTL Heatmap', onClick="databaseFunc(this.form,'heatmap');",Class="button")
+ spects = {'0':'Single Spectrum','1':'Grey + Blue + Red','2':'Blue + Red'}
+ schemeMenu = HT.Select(name='colorScheme')
+ schemeMenu.append(('Single Spectrum',0))
+ schemeMenu.append(('Grey + Blue + Red',1))
+ schemeMenu.append(('Blue + Red',2))
+ schemeMenu.selected.append(spects[self.colorScheme])
+
+ clusterCheck= HT.Input(type='checkbox', Class='checkbox', name='clusterCheck',checked=0)
+ targetDescriptionCheck = HT.Input(type='checkbox', Class='checkbox', name='targetDescriptionCheck',checked=0)
+
+ form.append(gifmap,schemeMenu, heatmap, HT.P(), clusterCheck, ' Cluster traits ', targetDescriptionCheck, ' Add description', HT.P(),img2, HT.P(), imgUrl)
+
+ if not sessionfile:
+ filename = webqtlUtil.generate_session()
+ webqtlUtil.dump_session(permData, os.path.join(webqtlConfig.TMPDIR, filename +'.session'))
+ sessionfile=filename
+
+ form.append(HT.Input(name='session', value=sessionfile, type='hidden'))
+
+ heatmapHelp = HT.Input(type='button' ,name='heatmapHelpButton',value='Info', onClick="openNewWin('/heatmap.html');",Class="button")
+
+ heatmapHeading = HT.Paragraph('QTL Heatmap ', heatmapHelp, Class="title")
+
+ TD_LR = HT.TD(colspan=2,height=200,width="100%",bgColor='#eeeeee')
+ TD_LR.append(heatmapHeading, HT.P(),HT.P(),HT.P(),HT.P(),HT.P(),form)
+
+ self.dict['body'] = str(TD_LR)
+
+ #XZ, 7/31/2009: This function put the order of traits into parameter neworder,
+ #XZ: return the position of the top vertical line of the hierarchical tree, draw the hierarchical tree.
+ def draw(self,canvas,names,d,xoffset,yoffset,neworder):
+ maxDistance = self.topHeight
+ fontoffset = 4 #XZ, 7/31/2009: used only for drawing tree
+
+ if type(d[0]) == type(1) and type(d[1]) == type(1):
+ neworder.append((xoffset+20,d[0]))
+ neworder.append((xoffset+40,d[1]))
+ height = d[2]*maxDistance/2
+ canvas.drawLine(xoffset+20-fontoffset,maxDistance+yoffset,xoffset+20-fontoffset,maxDistance-height+yoffset)
+ canvas.drawLine(xoffset+40-fontoffset,maxDistance+yoffset,xoffset+40-fontoffset,maxDistance-height+yoffset)
+ canvas.drawLine(xoffset+40-fontoffset,maxDistance+yoffset-height,xoffset+20-fontoffset,maxDistance-height+yoffset)
+ return (40,(xoffset+30-fontoffset,maxDistance-height+yoffset))
+ elif type(d[0]) == type(1):
+ neworder.append((xoffset+20,d[0]))
+ d2 = self.draw(canvas,names,d[1],xoffset+20,yoffset,neworder)
+ height = d[2]*maxDistance/2
+ canvas.drawLine(xoffset+20-fontoffset,maxDistance+yoffset,xoffset+20-fontoffset,maxDistance-height+yoffset)
+ canvas.drawLine(d2[1][0],d2[1][1],d2[1][0],maxDistance-height+yoffset)
+ canvas.drawLine(d2[1][0],maxDistance-height+yoffset,xoffset+20-fontoffset,maxDistance-height+yoffset)
+ return (20+d2[0],((d2[1][0]+xoffset+20-fontoffset)/2,maxDistance-height+yoffset))
+ elif type(d[1]) == type(1):
+ d1 = self.draw(canvas,names,d[0],xoffset,yoffset,neworder)
+ neworder.append((xoffset+d1[0]+20,d[1]))
+ height = d[2]*maxDistance/2
+ canvas.drawLine(xoffset+d1[0]+20-fontoffset,maxDistance+yoffset,xoffset+d1[0]+20-fontoffset,maxDistance-height+yoffset)
+ canvas.drawLine(d1[1][0],d1[1][1],d1[1][0],maxDistance-height+yoffset)
+ canvas.drawLine(d1[1][0],maxDistance-height+yoffset,xoffset+d1[0]+20-fontoffset,maxDistance-height+yoffset)
+ return (d1[0]+20,((d1[1][0]+xoffset+d1[0]+20-fontoffset)/2,maxDistance-height+yoffset))
+ else:
+ d1 = self.draw(canvas,names,d[0],xoffset,yoffset,neworder)
+ d2 = self.draw(canvas,names,d[1],xoffset+d1[0],yoffset,neworder)
+ height = d[2]*maxDistance/2
+ canvas.drawLine(d2[1][0],d2[1][1],d2[1][0],maxDistance-height+yoffset)
+ canvas.drawLine(d1[1][0],d1[1][1],d1[1][0],maxDistance-height+yoffset)
+ canvas.drawLine(d1[1][0],maxDistance-height+yoffset,d2[1][0],maxDistance-height+yoffset)
+ return (d1[0]+d2[0],((d1[1][0]+d2[1][0])/2,maxDistance-height+yoffset))
+
+ #XZ, 7/31/2009: dras trait names
+ def drawTraitNameBottom (self,canvas,names,yoffset,neworder,strWidth):
+ maxDistance = self.topHeight
+
+ for oneOrder in neworder:
+ canvas.drawString(names[oneOrder[1]],oneOrder[0]-5,maxDistance+yoffset+5+strWidth-canvas.stringWidth(names[oneOrder[1]],font=self.labelFont),font=self.labelFont,color=pid.black,angle=270)
+
+ def drawTraitNameTop (self,canvas,names,yoffset,neworder,strWidth):
+ maxDistance = self.topHeight
+
+ for oneOrder in neworder:
+ canvas.drawString(names[oneOrder[1]],oneOrder[0]-5,maxDistance+yoffset+5,font=self.labelFont,color=pid.black,angle=270)
+
+
+ def getNearestMarker(self,traitList, genotype):
+ out = []
+ if not genotype.Mbmap:
+ return [None]* len(traitList)
+ for item in traitList:
+ try:
+ nearest = None
+ for _chr in genotype:
+ if _chr.name != item.chr:
+ continue
+ distance = 1e30
+ for _locus in _chr:
+ if abs(_locus.Mb-item.mb) < distance:
+ distance = abs(_locus.Mb-item.mb)
+ nearest = _locus.name
+ out.append(nearest)
+ except:
+ out.append(None)
+
+ return out
+
+
+
+
diff --git a/web/webqtl/heatmap/slink.py b/web/webqtl/heatmap/slink.py
new file mode 100755
index 00000000..3de41de4
--- /dev/null
+++ b/web/webqtl/heatmap/slink.py
@@ -0,0 +1,141 @@
+# 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
+
+#--Only imported by correlationPage.py.
+#
+#Functions:
+#slink(lists) -- the only function called outside of this file.
+#nearest(lists,i,j) -- some sort of recursive function.
+#printarray(array,n) -- prints n elements of the given array
+#this is a myseterious piece of code in GN that Kev Adler and Rob Williams do not understand.
+#but is used in some way by the Traits Correlation function
+#Kev and Rob suspect that the d2 matrix below is unused
+#We do not understand the signifance of "d" but Kev suspects it is unimportant
+#These comments by Kev and Rob: May 23, 2008
+
+d = [[0,9,3,6,11],[9,0,7,5,10],[3,7,0,9,2],[6,5,9,0,8],[11,10,2,8,0]]
+d2 = [[0,9,5.5,6,11],[9,0,7,5,10],[5.5,7,0,9,2],[6,5,9,0,3],[11,10,2,3,0]]
+
+def nearest(lists,i,j):
+ if type(i) == type(1) and type(j) == type(1):
+ return lists[i][j]
+ elif type(i) == type(1):
+ dist = 1e10
+ for itemj in j[:-1]:
+ d = nearest(lists,i,itemj)
+ if dist > d:
+ dist = d
+ elif type(j) == type(1):
+ dist = 1e10
+ for itemi in i[:-1]:
+ d = nearest(lists,itemi,j)
+ if dist > d:
+ dist = d
+ else:
+ dist = 1e10
+ for itemi in i[:-1]:
+ for itemj in j[:-1]:
+ d = nearest(lists,itemi,itemj)
+ if dist > d:
+ dist = d
+ return dist
+
+def printarray(array,n):
+ print "\n"
+ for i in range(n):
+ print array[i][:n]
+ print "\n"
+
+def slink(lists):
+ try:
+ if type(lists) != type([]) and type(lists) != type(()):
+ raise 'FormatError'
+ else:
+ size = len(lists)
+ for item in lists:
+ if type(item) != type([]) and type(item) != type(()):
+ raise 'FormatError'
+ else:
+ if len(item) != size:
+ raise 'LengthError'
+ for i in range(size):
+ if lists[i][i] != 0:
+ raise 'ValueError'
+ for j in range(0,i):
+ if lists[i][j] < 0:
+ raise 'ValueError'
+ if lists[i][j] != lists[j][i]:
+ raise 'MirrorError'
+ except 'FormatError':
+ print "the format of the list is incorrect!"
+ return []
+ except 'LengthError':
+ print "the list is not a square list!"
+ return []
+ except 'MirrorError':
+ print "the list is not symmetric!"
+ return []
+ except 'ValueError':
+ print "the distance is negative value!"
+ return []
+ except:
+ print "Unknown Error"
+ return []
+ listindex = range(size)
+ listindexcopy = range(size)
+ listscopy = []
+ for i in range(size):
+ listscopy.append(lists[i][:])
+ initSize = size
+ candidate = []
+ while initSize >2:
+ mindist = 1e10
+ for i in range(initSize):
+ for j in range(i+1,initSize):
+ if listscopy[i][j] < mindist:
+ mindist = listscopy[i][j]
+ candidate=[[i,j]]
+ elif listscopy[i][j] == mindist:
+ mindist = listscopy[i][j]
+ candidate.append([i,j])
+ else:
+ pass
+ newmem = (listindexcopy[candidate[0][0]],listindexcopy[candidate[0][1]],mindist)
+ listindexcopy.pop(candidate[0][1])
+ listindexcopy[candidate[0][0]] = newmem
+
+ initSize -= 1
+ for i in range(initSize):
+ for j in range(i+1,initSize):
+ listscopy[i][j] = nearest(lists,listindexcopy[i],listindexcopy[j])
+ listscopy[j][i] = listscopy[i][j]
+ #print listindexcopy
+ #printarray(listscopy,initSize)
+ listindexcopy.append(nearest(lists,listindexcopy[0],listindexcopy[1]))
+ return listindexcopy
+
+
+