source: orange-bioinformatics/_bioinformatics/widgets/prototypes/OWGenomeMap.py @ 1637:dde4ef52193b

Revision 1637:dde4ef52193b, 29.8 KB checked in by mitar, 2 years ago (diff)

Removing __file__ usage.

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