source: orange-bioinformatics/Orange/bioinformatics/widgets/prototypes/OWGenomeMap.py @ 1633:b8852fdd1a0f

Revision 1633:b8852fdd1a0f, 30.1 KB checked in by mitar, 2 years ago (diff)

Fixing imports.

Line 
1"""
2<name>Genome Map</name>
3<description>Shows the locations of genes.</description>
4<contact>Tomaz Curk</contact>
5<icon>icons/GenomeMap.png</icon>
6<priority>200</priority>
7"""
8
9import math, glob
10import os.path # to find out where the local files are
11
12import orange
13from Orange.OrangeWidgets import OWGUI
14from Orange.OrangeWidgets.OWGraph import ColorPaletteHSV
15from Orange.OrangeWidgets.OWWidget import *
16
17DEBUG = 0
18
19##############################################################################
20# main class
21
22# z coordinates for graphical objects
23zchrom = 100; zchrombb=110; zgenes = 50; zticks = 40; zsel=10
24
25## chrom definition .tab file must have the following attributes (columns):
26#   geneID
27#   chromosome
28#   start
29#   stop
30#
31# chromosome definitions should be in the first lines
32# chromosome definitions are those entries with column start == 0
33
34class OWGenomeMap(OWWidget):
35    settingsList = ["MinGeneWidth", "ShowTicks", "ColorByClass", "RecentGenomeMaps"]
36
37    def __init__(self, parent=None, signalManager = None):
38        OWWidget.__init__(self, parent, signalManager, 'GenomeMap')
39#        self.setWFlags(Qt.WResizeNoErase | Qt.WRepaintNoErase) #this works like magic.. no flicker during repaint!
40#        self.parent = parent       
41
42#        self.callbackDeposit = [] # deposit for OWGUI callback functions
43        self.MinGeneWidth = 5
44        self.ColorByClass = 1
45        self.ShowTicks = 1
46        self.RecentGenomeMaps = []
47        self.GenomeMapIndx = 0
48        self.genesInGenomeMapFile = {}
49        self.GenomeMapLoaded = 0
50        self.loadSettings()
51
52        # received and decided based on input signal
53        self.candidateGeneIDsFromSignal = [] ## list of discrete attributes present in clusterSet data signal
54        self.geneIDattrIndx = 0 ## index of attribute in candidateGeneIDsFromSignal that was selected to represent the gene IDs
55        self.geneIDattr = None ## self.geneIDattr is set accordingly
56
57        # check if genome maps exist and remove those that don't
58        # check that all files in directories "Genome Map" are included in the list
59        self.RecentGenomeMaps = filter(os.path.exists, self.RecentGenomeMaps)
60        widgetDir = os.path.dirname(os.path.abspath(__file__)) + "/"
61        gmapList = glob.glob(widgetDir + 'Genome Map/*.tab')
62        for f in gmapList:
63            f = os.path.abspath(f)
64            if f not in self.RecentGenomeMaps:
65                self.RecentGenomeMaps.append( f)
66        genesInRecentGenomeMapFile = {}
67        #
68
69        self.classColors = []
70        self.geneCoordinates = {}
71        self.data = None
72        self.mid = orange.newmetaid() # meta id for a marker if a gene has a known position
73        self.graph = ChromosomeGraph(self)
74
75        # inputs and outputs
76        self.inputs=[("Examples", ExampleTable, self.dataset, Default)]
77        self.outputs = [("Examples", ExampleTable, Default)]
78
79        # GUI definition
80        self.controls = OWGUI.widgetBox(self.controlArea, "Graph Options")
81#        self.controls = QVGroupBox(self.controlArea)
82        box = OWGUI.widgetBox(self.controls, "Graph Options")
83#        box = QVButtonGroup("Graph Options", self.controls)
84#        box.setMaximumSize(250, 80)
85        OWGUI.qwtHSlider(box, self, "MinGeneWidth", label='Min. mark width: ', 
86                         labelWidth=80, minValue=1, maxValue=10, step=1,
87                         callback=self.graph.repaintGenes)
88       
89        self.colorByClassCB = OWGUI.checkBox(box, self, "ColorByClass", 
90                                             "Gene colors wrt class",
91                                             callback=self.graph.repaintGenes,
92                                             disabled=1)
93
94#        box=QBoxLayout(self.mainArea, QVBoxLayout.TopToBottom, 0)
95        self.view = ChromosomeGraphView(self.graph, self.mainArea)
96        self.view.setMinimumWidth(500)
97        self.mainArea.layout().addWidget(self.view)
98#        box.addWidget(self.view)
99
100#        box = QHButtonGroup("Genome Map", self.controls)
101        box = OWGUI.widgetBox(self.controls, "Genome Map", orientation="horizontal")
102#        box.setMaximumSize(250, 50)
103        self.genomeMapCombo = OWGUI.comboBox(box, self, 'GenomeMapIndx',
104                                             callback=self.loadGenomeMap)
105       
106#        self.genomeMapCombo.setMaximumSize(160, 20)
107
108        self.setFilelist(self.genomeMapCombo, self.RecentGenomeMaps)
109        self.genomeMapBrowse = OWGUI.button(box, self, 'Browse',
110                                            callback=self.browseGenomeMap)
111#        self.genomeMapBrowse.setMaximumSize(50, 30)
112
113        box = OWGUI.widgetBox(self.controls, "Gene ID Attribute")
114#        box = QHButtonGroup("Gene ID attribute", self.controls)
115#        box.setMaximumSize(250, 50)
116        self.geneIDAttrCombo = OWGUI.comboBox(box, self, 'geneIDattrIndx',
117                                              callback=self.geneIDchanged)
118#        self.geneIDAttrCombo.setMaximumSize(160, 20)
119        self.setGeneIDAttributeList()
120       
121        OWGUI.rubber(self.controlArea)
122
123    def geneIDchanged(self):
124        if len(self.candidateGeneIDsFromSignal) > self.geneIDattrIndx:
125            self.geneIDAttrCombo.setCurrentIndex(self.geneIDattrIndx)
126            self.geneIDattr = self.candidateGeneIDsFromSignal[self.geneIDattrIndx]
127        else:
128            self.geneIDattr = None
129        if DEBUG: print "changing geneID attribute to: " + str(self.geneIDattr)
130        self.datasetChanged() ## recalculate the selected genes
131        self.geneIDAttrCombo.setDisabled(len(self.candidateGeneIDsFromSignal) == 0)
132
133    def setGeneIDAttributeList(self):
134        ## refresh the list
135        self.geneIDAttrCombo.clear()
136        for f in self.candidateGeneIDsFromSignal:
137            self.geneIDAttrCombo.addItem(str(f.name))
138        self.geneIDAttrCombo.setDisabled(len(self.candidateGeneIDsFromSignal) == 0)
139
140    def setFilelist(self, filecombo, fileList):
141        filecombo.clear()
142        if fileList != []:
143            for file in fileList:
144                (dir, filename) = os.path.split(file)
145                #leave out the path
146                fnToDisp = filename
147                filecombo.addItem(fnToDisp)
148            filecombo.setDisabled(False)
149        else:
150            filecombo.addItem("(none)")
151            filecombo.setDisabled(True)
152
153    def loadChromosomeDefinitions(self, filename):
154        self.geneCoordinates = {}
155        chrom = []
156        try:
157            chromData = orange.ExampleTable(filename, dontCheckStored=1)
158        except:
159            self.graph.chrom = []
160            self.GenomeMapLoaded = 0
161            return
162        id2desc = {}
163        geneIDs = [] # all geneIDs in this file
164        for d in chromData:
165            geneID = str(d['geneID'])
166            if int(d['start']) == 0: ## loading chromosomes definitions
167                chrom.append((int(d['start']), int(d['stop']), int(d['chromosome']), geneID))
168                id2desc[int(d['chromosome'])] = len(chrom)-1
169            else: ## loading genes positions
170                tmpl = self.geneCoordinates.get(geneID, [])
171                tmpl.append( (int(d['start']), int(d['stop']), id2desc[int(d['chromosome'])] ) )
172                self.geneCoordinates[geneID] = tmpl
173#                self.geneCoordinates[geneID] = (int(d['start']), int(d['stop']), id2desc[int(d['chromosome'])] )
174            geneIDs.append( geneID)
175        self.genesInGenomeMapFile[filename] = geneIDs ## update with new data (in case file has changed)
176        self.GenomeMapLoaded = 1
177        self.graph.chrom = chrom
178
179    def repaintChromeGraph(self):
180        self.view.resetMargins(0, max([10]+ [x[1] for x in self.graph.chrom]))
181        self.graph.setMargins()
182        self.graph.paint()
183
184    def loadGenomeMap(self, change=1):
185        if self.GenomeMapIndx < len(self.RecentGenomeMaps):
186            fn = self.RecentGenomeMaps[self.GenomeMapIndx]
187            if fn != "(none)":
188                # remember the recent file list
189                if fn in self.RecentGenomeMaps: # if already in list, remove it
190                    self.RecentGenomeMaps.remove(fn)
191                self.RecentGenomeMaps.insert(0, fn) # add to beginning of list
192                self.setFilelist(self.genomeMapCombo, self.RecentGenomeMaps) # update combo
193                self.loadChromosomeDefinitions(fn)
194                if change:
195                    self.datasetChanged() ## repaint
196
197    def browseGenomeMap(self):
198        if self.RecentGenomeMaps == []:
199            startfile = "."
200        else:
201            startfile = self.RecentGenomeMaps[0]
202        filename = QFileDialog.getOpenFileName(self, 'Genome Map File', startfile, 'Genome Map files (*.tab)\nAll files(*.*)')
203        fn = str(filename)
204        fn = os.path.abspath(fn)
205        if fn in self.RecentGenomeMaps: # if already in list, remove it
206            self.RecentGenomeMaps.remove(fn)
207        self.RecentGenomeMaps.insert(0, fn)
208        self.GenomeMapIndx = 0
209        self.loadGenomeMap()
210
211    def findMostAppropriateGeneIDandGenomeMap(self):
212        if self.data == None:
213            self.candidateGeneIDsFromSignal = []
214            self.geneIDattrIndx = -1
215            self.geneIDattr = None
216            self.setGeneIDAttributeList()
217            return
218
219        ## all discrete and string type attributes are good candidates
220        self.candidateGeneIDsFromSignal = [a for a in self.data.domain.attributes +\
221                    self.data.domain.getmetas().values() \
222                    if a.varType == orange.VarTypes.Discrete or \
223                    a.varType == orange.VarTypes.Other or \
224                    a.varType == orange.VarTypes.String]
225        self.setGeneIDAttributeList()
226        self.geneIDAttrCombo.setDisabled(True)
227
228        ## check if there are new genome map files present
229        ## remove from geneID2genomeMapfile those not present in the RecentGenomeMaps list
230        ## geneID is key, item is list of indexes in self.RecentGenomeMaps that have that geneID
231        geneID2genomeMapfile = {}
232        cn = 0
233        for f in self.RecentGenomeMaps:
234            if f not in self.genesInGenomeMapFile.keys():
235                if DEBUG: print "loading", f
236                try:
237                    chromData = orange.ExampleTable(f, dontCheckStored=1)
238                    geneIDs = [str(d['geneID']) for d in chromData] # all geneIDs in this file
239                    self.genesInGenomeMapFile[f] = geneIDs # update with new data (in case file has changed)
240                except:
241                    self.genesInGenomeMapFile[f] = [] # update with new data (in case file has changed)
242            for geneID in self.genesInGenomeMapFile[f]:
243                tmpl = geneID2genomeMapfile.get(geneID, [])
244                if cn not in tmpl:
245                    tmpl.append(cn)
246                    geneID2genomeMapfile[geneID] = tmpl
247            cn += 1
248
249        ## for each attribute look how many genesID are there, that are also present in geneID2genomeMapfile
250        ## if current self.geneIDattr has count 0
251        ## then select attribute with highest count
252        ## else keep self.geneIDattr
253
254        ## when best attribute selected, check if the loaded genome map is ok
255        ## otherwise suggest the most appropriate genome map
256        bestAttr = '' ## key is attribute, item is number of recognized geneIDs
257        bestCn = 0
258        bestGenomeMap = 0
259        lst = self.candidateGeneIDsFromSignal
260        if self.geneIDattr is not None and self.geneIDattr in self.candidateGeneIDsFromSignal:
261            lst = [self.geneIDattr] + lst
262
263        for attr in lst:
264            vals = [ex[attr] for ex in self.data]
265
266            ## calculate the frequency of each annotation file to which this geneID belongs to
267            genomeMapFrequency = {}
268            cn = 0
269            for v in vals:
270                v = str(v)
271                i = geneID2genomeMapfile.get(v, -1) ## -1, not present
272                if i != -1:
273                    for ai in i:
274                        af = genomeMapFrequency.get(ai, 0)
275                        genomeMapFrequency[ai] = af + 1
276                    cn += 1
277            if cn > bestCn or (cn > 0 and attr == self.geneIDattr):
278                bestAttr = attr
279                bestCn = cn
280                gmfs = [(f, gmindex) for (gmindex, f) in genomeMapFrequency.iteritems()]
281                if len(gmfs) > 0:
282                    gmfs = sorted(gmfs, reverse=True)
283#                    gmfs.sort()
284#                    gmfs.reverse() ## most frequent first
285                    bestGenomeMap = gmfs[0][1]
286                else:
287                    bestGenomeMap = 0 ## keep current
288        if DEBUG: print "best attribute: " + str(bestAttr) + " with " + str(bestCn) + " gene IDs from genome map"
289        if DEBUG: print "bestGenomeMap: " + str(self.RecentGenomeMaps[bestGenomeMap])
290
291        self.geneIDattr = bestAttr
292        try:
293            self.geneIDattrIndx = self.candidateGeneIDsFromSignal.index(self.geneIDattr)
294        except:
295            self.geneIDattrIndx = 0
296
297        ## load annotation if a better one found
298        if bestGenomeMap != 0 or not(self.GenomeMapLoaded):
299            self.GenomeMapIndx = bestGenomeMap
300            self.loadGenomeMap(0)
301##            self.loadChromosomeDefinitions(self.RecentGenomeMaps[self.GenomeMapIndx])
302
303        ## select the geneID, and rerun the GO term finding
304        if DEBUG: print "geneID changed"
305        self.geneIDchanged()
306
307    def dataset(self, data):
308        self.data = data
309        self.findMostAppropriateGeneIDandGenomeMap() ## select most appropriate attribute only when first receiving the signal
310        self.graph.selection = []
311        self.datasetChanged()
312
313    def datasetChanged(self):
314        if self.geneIDattr == None:
315            self.coord = []
316            if self.data:
317                for (i,d) in enumerate(self.data):
318                    d[self.mid] = 0
319            self.repaintChromeGraph() ## paint empty graph
320            return
321
322        ## in chrome data mark those records
323        ## where the geneID matches that from geneCoordinates
324        if self.data:
325            ## make a self.coord the same size as input signal data
326            self.coord = [None] * len(self.data)
327            for (i,d) in enumerate(self.data):
328                geneID = str(d[str(self.geneIDattr.name)])
329                if self.geneCoordinates.has_key(geneID):
330                    self.coord[i] = self.geneCoordinates[geneID]
331                    d[self.mid] = 1
332                else:
333                    ### XXX issue a warning
334                    d[self.mid] = 0
335##                    print 'no key for', geneID
336
337            ## create color map
338            self.colorByClassCB.setDisabled(self.data.domain.classVar == None)
339            if self.data.domain.classVar:
340                self.classColors = ColorPaletteHSV(len(self.data.domain.classVar.values))
341            self.repaintChromeGraph()
342
343##############################################################################
344# graph with chromosomes and genes
345
346xoffset = 20; yoffset = 30; yspace = 50; ychrom = 20; ytick = 3
347multiples = [(2., math.log10(2.)), (5., math.log10(5.))]
348selectionColor = QColor(230,230,230)
349gSelectionColor = QColor(190,190,190)
350geneColor = QColor(60,60,60)
351##geneColor = Qt.gray
352##gSelectionColor = Qt.yellow
353
354class ChromosomeGraph(QGraphicsScene):
355    def __init__(self, master, parent=None, chrom = []):
356        QGraphicsScene.__init__(self, parent)
357        self.master = master
358        self.chrom = chrom
359        self.selection = []
360
361    def setMargins(self):
362        view = self.master.view
363        self.bpL, self.bpR = view.margins[-1]
364        self.bpW = float(self.bpR - self.bpL)
365        self.ticks = []
366        ## find longest chrome
367        for c in self.chrom:
368            self.ticks.append(self.getTicks(max(self.bpL, c[0]), min(self.bpR, c[1]), self.bpL, self.bpR))
369
370    # converts bp index to canvas position
371    def bp2x(self, bp):
372        r = (bp - self.bpL) / self.bpW
373        return int(xoffset + r * self.gwidth)
374
375    def x2bp(self, x):
376        r = (x - xoffset) / float(self.gwidth)
377        return int(self.bpL + r * self.bpW)
378
379    def paint(self):
380        view = self.master.view
381        self.setSceneRect(QRectF(0, 0, view.width()-20, max(view.height()-5, yoffset+(len(self.chrom)+1)*(ychrom+yspace) - yspace)))
382#        self.resize(view.width()-20, max(view.height()-5, yoffset+(len(self.chrom)+1)*(ychrom+yspace) - yspace))
383        self.gwidth = self.width() - 2*xoffset
384
385        # remove everything on present canvas
386        for item in self.items():
387            self.removeItem(item)
388
389        for (i, c) in enumerate(self.chrom):
390            self.paintChrom(yoffset+i*(ychrom+yspace), max(self.bpL, c[0]), min(self.bpR, c[1]), i)
391        self.paintGenes()
392        self.paintSelection()
393        self.update()
394       
395    def paintChrom(self, y, bpL, bpR, indx):
396        chrom = self.chrom[indx]
397        xL, xR = self.bp2x(bpL), self.bp2x(bpR)
398        if xR-xL <= 0:
399            return
400
401        # paint the chromosome box
402        # relW = (bpR-bpL)/float(self.bpR-self.bpL) # relative width of the displayed chromosome (0..1)
403        # adjust the ticks to that
404
405#        r = QCanvasRectangle(xoffset, y, xR-xL+1, ychrom+1, self)
406        r = QGraphicsRectItem(xoffset, y, xR-xL+1, ychrom+1, self)
407        r.setPen(QPen(Qt.white))
408        r.y = y; r.id = indx
409        r.setZValue(zchrom)
410        r.show()
411       
412        lu = QGraphicsLineItem(0, 0, xR-xL, 0, self)
413#        lu = QCanvasLine(self); lu.setPoints(0, 0, xR-xL, 0)
414        ld = QGraphicsLineItem(0, ychrom, xR-xL, ychrom, self)
415#        ld = QCanvasLine(self); ld.setPoints(0, ychrom, xR-xL, ychrom)
416        lines = [lu, ld]
417        if bpL == chrom[0]:
418            ll = QGraphicsLineItem(0, 0, 0, ychrom, self)
419#            ll = QCanvasLine(self); ll.setPoints(0, 0, 0, ychrom)
420            lines.append(ll)
421        if bpR == chrom[1]:
422            lr = QGraphicsLineItem(xR-xL, 0, xR-xL, ychrom, self)
423#            lr = QCanvasLine(self); lr.setPoints(xR-xL, 0, xR-xL, ychrom)
424            lines.append(lr)
425        for l in lines:
426            l.setPos(xoffset, y)
427            l.setZValue(zchrombb)
428#            l.setX(xoffset); l.setY(y); l.setZ(zchrombb)
429            l.show()
430
431        # paint chromosome name
432        label = QGraphicsSimpleTextItem(chrom[3], self)           
433#        label = QCanvasText(chrom[3], self)
434        label.setPos(xoffset, y-label.boundingRect().height()-1)
435        label.setZValue(zticks)
436#        label.setX(xoffset); label.setY(y-label.boundingRect().height()-1); label.setZ(zticks)
437        label.show()
438
439        # paint the ticks
440        if self.parent.ShowTicks:
441            ticks = self.ticks[indx]
442            for (bp, str) in ticks:
443                x = self.bp2x(bp)
444                tick = QGraphicsLineItem(x, 0, x, ytick)
445                tixk.setPos(0, y+ychrom)
446                tick.setZValue(zticks)
447#                tick = QCanvasLine(self); tick.setPoints(x, 0, x, ytick)
448#                tick.setX(0); tick.setY(y+ychrom); tick.setZ(zticks)
449                tick.show()
450
451                label = QGraphicsSimpleTextItem(str, self)
452                label.setPos(x - label.boundingRect().width()/2, y+ychrom+ytick)
453#                label = QCanvasText(str, self)
454#                label.setX(x - label.boundingRect().width()/2); label.setY(y+ychrom+ytick); label.setZ(zticks)
455                label.show()
456
457    # paint the genes
458    def paintGenes(self):
459        mid = self.master.mid
460        if not self.master.data:
461            return
462        data = self.master.data
463        lborder, rborder = xoffset, self.width()-xoffset
464        colorclass = data.domain.classVar and self.master.ColorByClass
465        colors = self.master.classColors
466        for (i,d) in enumerate(data):
467            if not int(d[mid]):
468                continue # position not known for this gene
469            coords = self.master.coord[i]
470            for coord in coords:
471                if not(coord[0]>self.bpR or coord[1]<self.bpL):  # is gene in the visible area of the chromosome?
472                    l, r = max(coord[0], self.bpL),  min(coord[1], self.bpR)
473                    lp, rp = self.bp2x(l), self.bp2x(r)
474                    if rp-lp < self.master.MinGeneWidth:
475                        diff = int((self.master.MinGeneWidth - (rp-lp)) / 2)
476                        lp, rp = max(lp-diff, lborder), min(rp+diff, rborder)
477                    y = yoffset + coord[2]*(ychrom+yspace)
478                    r = QGraphicsRectItem(lp, y, max(self.master.MinGeneWidth, rp-lp), ychrom+1, self)
479#                    r = QCanvasRectangle(lp, y, max(self.parent.MinGeneWidth, rp-lp), ychrom+1, self)
480                    if colorclass:
481                        color = colors[int(d.getclass())]
482                    else:
483                        color = geneColor
484                    r.instance = d
485                    r.setBrush(QBrush(color))
486                    r.setPen(QPen(color))
487                    r.setZValue(zgenes)
488                    r.show()
489
490    def repaintGenes(self):
491        for item in filter(lambda i,z=zgenes: i.zValue() == z, self.items()):
492            self.removeItem(item)
493       
494        self.paintGenes()
495        self.update()
496
497    def addSelection(self, x1, x2, cID, rect, replace=1):
498        bp1 = self.x2bp(min(x1,x2)); bp2 = self.x2bp(max(x1,x2))
499        if replace:
500            self.selection = [(bp1, bp2, cID)]
501        else:
502            self.selection.append((bp1, bp2, cID))
503        self.exportSelection()
504
505    # finds which genes intersect with selection, makes and example table and sends it out
506    def exportSelection(self):
507        if not self.selection:
508            return
509        ex = []
510        for i in filter(lambda i,z=zgenes: i.zValue() == zsel, self.items()):
511            genes =  filter(lambda i,z=zgenes: i.zValue() == zgenes, self.collidingItems(i))
512            for g in genes:
513                ex.append(g.instance)
514        if len(ex):
515            data = self.master.data
516            selectedData = orange.ExampleTable(data.domain, ex)
517
518            # Reduce the number of class values, if class is defined
519            cl = clo = data[0].domain.classVar
520##            if cl:
521##                cl = orange.RemoveUnusedValues(cl, ex, removeOneValued = 1)
522
523            # Construct a new domain only if the class has changed
524            # (ie to lesser number of values or to one value (alias None))
525            if cl != clo:
526                domain = orange.Domain(data[0].domain.attributes, cl)
527                domain.addmetas(data[0].domain.getmetas())
528#                metas = data[0].domain.getmetas()
529#                for key in metas:
530#                    domain.addmeta(key, metas[key])
531            else:
532                domain = data[0].domain
533
534            selectedData = orange.ExampleTable(domain, ex)
535            if selectedData.domain.classVar:
536                self.parent.send("Classified Examples", selectedData)
537            else:
538                self.parent.send("Classified Examples", None)
539            self.parent.send("Examples", selectedData)
540
541
542    def paintSelection(self):
543        for (bp1, bp2, c) in self.selection:
544            if not(bp1>self.bpR or bp2<self.bpL):
545                l, r = max(bp1, self.bpL),  min(bp2, self.bpR)
546                lp, rp = self.bp2x(l), self.bp2x(r)
547                if rp<lp:
548                    break
549                r = QGraphicsRectItem(lp, yoffset+c*(ychrom+yspace), rp-lp, ychrom, self)
550#                r = QCanvasRectangle(lp, yoffset+c*(ychrom+yspace), rp-lp, ychrom, self)
551                r.setZValue(zsel)
552                r.setBrush(QBrush(gSelectionColor))
553                r.setPen(QPen(gSelectionColor))
554                r.show()
555       
556    def getTicks(self, lower, upper, abslower, absupper):
557        ideal = (upper-lower)/2.
558        absideal = (absupper - abslower)/2
559        ideal = max(absideal /4.0, ideal) ## don't display a too fine scale if the rest is quite big
560        if ideal<=0:
561            return []
562##        print 'iii %d (%d-%d)' % (ideal, upper, lower)
563        log = math.log10(ideal)
564        power = math.floor(log)
565        fraction = log-power
566        factor = 1.
567        error = fraction
568        for f, lf in multiples:
569            e = math.fabs(fraction-lf)
570            if e < error:
571                error = e
572                factor = f
573        grid = factor * 10.**power
574        digits = max(1, int(power))
575        if power >= 6:
576            format = '%dM'
577            scale = 1000000
578        elif power == 5:
579            format = '%1.1fM'
580            scale = 1000000
581        elif power >= 3:
582            format = '%dk'
583            scale = 1000
584        elif power == 2:
585            format = '%1.1fk'
586            scale = 1000
587        else:
588            format = '%d'
589            scale = 1
590
591        ticks = []
592        t = -grid*math.floor(-lower/grid)
593        while t <= upper and len(ticks) < 200:
594            ticks.append((t, format % (t/scale,)))
595            t = t + grid
596        return ticks
597
598##############################################################################
599# the event manager
600
601class ChromosomeGraphView(QGraphicsView):
602    def __init__(self, canvas, parent=None):
603        QGraphicsView.__init__(self, canvas, parent)
604        self.setMouseTracking(True)
605        self.viewport().setMouseTracking(1)
606        self.setFocusPolicy(Qt.WheelFocus)
607        self.setFocus()
608        self.margins = []
609        self.selStart = None  # starting point of the current gene selection
610        self.zoomStart = None # starting point for zooming
611        self.shiftPressed = 0
612       
613    def resizeEvent(self, event):
614        QGraphicsView.resizeEvent(self,event)
615        if self.scene():
616            self.scene().paint()
617
618    def resetMargins(self, left, right):
619        self.margins = []
620        self.setMargins(left, right)
621
622    def setMargins(self, left, right):
623        self.margins.append((max(0, left), right))
624        self.scene().setMargins()
625
626    def retractMargins(self):
627        if len(self.margins) > 1:
628            self.margins.pop(-1)
629            self.scene().setMargins()
630            self.scene().paint()
631
632    def mousePressEvent(self, event):
633        if not self.scene():
634            return
635        if event.button() == Qt.RightButton:
636            self.retractMargins()
637        elif event.button() == Qt.LeftButton:
638            pos = self.mapToScene(event.pos())
639            items = [i for i in self.scene().items(pos) if i.zValue() == zchrom]
640            # items = self.canvas().collisions(event.pos())
641           
642            if items: # user pressed mouse on a chromosome
643                self.addSelection = event.modifiers() & Qt.ShiftModifier #self.shiftPressed
644                if not self.addSelection:
645                    for i in filter(lambda i,z=zgenes: i.zValue()==zsel, self.scene().items()):
646                        self.scene().removeItem(i)
647#                        i.setCanvas(None)
648                self.chrom = items[0]
649                self.selStart = pos.x()
650                self.selRect = QGraphicsRectItem(self.scene())
651#                self.selRect = QCanvasRectangle(self.canvas())
652                self.selRect.setPos(self.selStart, self.chrom.y)
653                self.selRect.setZValue(zsel)
654#                self.selRect.setY(self.chrom.y); self.selRect.setZ(zsel)
655                self.selRect.setBrush(QBrush(gSelectionColor))
656                self.selRect.setPen(QPen(gSelectionColor))
657                self.selRect.show()
658                self.drawSel(self.selStart, self.selStart)
659            else: # zooming
660                self.zoomStart = pos.x()
661                self.zoomRect = QGraphicsRectItem(self.scene())
662#                self.zoomRect = QCanvasRectangle(self.canvas())
663                self.zoomRect.setPos(self.zoomStart, 0)
664                self.zoomRect.setZValue(0)
665#                self.zoomRect.setY(0); self.zoomRect.setZ(0)
666                self.zoomRect.setBrush(QBrush(selectionColor))
667                self.zoomRect.setPen(QPen(selectionColor))
668                self.zoomRect.show()
669                self.drawZoom(self.zoomStart, self.zoomStart)
670
671    def mouseMoveEvent(self, event):
672        pos = self.mapToScene(event.pos())
673        x = pos.x()
674        if self.zoomStart is not None:
675            self.drawZoom(self.zoomStart, x)
676        if self.selStart is not None:
677            self.drawSel(self.selStart, x)
678
679    def mouseReleaseEvent(self, event):
680        pos = self.mapToScene(event.pos())
681        x = pos.x()
682        if self.zoomStart is not None:
683            zoomStart = self.zoomStart ## remember is locally, and set it to None right away
684            self.zoomStart = None
685            left = self.scene().x2bp(min(zoomStart, x))
686            right = self.scene().x2bp(max(zoomStart, x))
687            if abs(right-left) < 50:
688                self.scene().removeItem(self.zoomRect)
689#                self.zoomRect.setCanvas(None)
690#                self.canvas().update()
691            else:
692                self.setMargins(left, right)
693                self.scene().paint()
694        if self.selStart is not None:
695            selStart = self.selStart ## remember is locally, and set it to None right away
696            self.selStart = None     ## otherwise the selection continues when other widgets process
697            self.scene().addSelection(selStart, x, self.chrom.id, self.selRect, replace=not self.addSelection)
698
699#    def keyPressEvent(self, e):
700#        if e.key() == 4128:
701#            self.shiftPressed = True
702#        else:
703#            QCanvasView.keyPressEvent(self, e)
704#
705#    def keyReleaseEvent(self, e):       
706#        if e.key() == 4128:
707#            self.shiftPressed = False
708#        else:
709#            QCanvasView.keyReleaseEvent(self, e)
710
711    def drawZoom(self, left, right):
712        self.zoomRect.setPos(left, self.zoomRect.y())
713#        self.zoomRect.setX(left)
714        self.zoomRect.setRect(QRectF(self.zoomRect.rect().topLeft(),
715                                     QSizeF(right-left, self.scene().height())))
716#        self.zoomRect.setSize(right-left, self.canvas().height())
717#        self.scene().update()
718
719    def drawSel(self, left, right):
720        self.selRect.setPos(left, self.selRect.y())
721#        self.selRect.setX(left)
722        self.selRect.setRect(QRectF(self.selRect.rect().topLeft(),
723                                    QSizeF(right-left, ychrom)))
724#        self.selRect.setSize(right-left, ychrom)
725#        self.scene().update()
726
727##############################################################################
728# test widget's appearance
729
730if __name__=="__main__":
731    a=QApplication(sys.argv)
732    ow=OWGenomeMap()
733#    a.setMainWidget(ow)
734#    data = orange.ExampleTable("wtclassed.tab")
735    data = orange.ExampleTable("hj.tab")
736    ow.show()
737    ow.dataset(data)
738    a.exec_()
739    # save settings
740    ow.saveSettings()
Note: See TracBrowser for help on using the repository browser.