source: orange-bioinformatics/widgets/OWKEGGPathwayBrowser.py @ 1579:364880120934

Revision 1579:364880120934, 31.8 KB checked in by ales_erjavec, 2 years ago (diff)

Only download the .xml kgml files in a separate thread, don't parse it (pyexpat in a thread seems to crash Qt).

Line 
1"""
2<name>KEGG Pathways</name>
3<description>Browse KEGG pathways that include an input set of genes.</description>
4<priority>2030</priority>
5<icon>icons/KEGG.png</icon>
6"""
7from __future__ import with_statement
8
9import sys
10import orange
11import obiKEGG, orngServerFiles
12import obiTaxonomy
13
14import obiKEGG2 as obiKEGG
15import obiGeneSets
16import orngMisc
17
18import webbrowser
19
20from OWWidget import *
21import OWGUI
22from collections import defaultdict
23
24from orngDataCaching import data_hints
25
26USE_THREADING = True
27
28if USE_THREADING:
29    import threading
30    from functools import partial
31    def threading_queued_invoke(qobj, func):
32        def safe_wrapper(*args, **kwargs):
33            QMetaObject.invokeMethod(qobj, "queuedInvoke", 
34                                     Qt.QueuedConnection, 
35                                     Q_ARG("PyQt_PyObject",
36                                           partial(func, *args, **kwargs)))
37        return safe_wrapper
38   
39def split_and_strip(string, sep=None):
40    return [s.strip() for s in string.split(sep)]
41
42class EntryGraphicsItem(QGraphicsPathItem):
43    def __init__(self, graphics, *args):
44        QGraphicsPathItem.__init__(self, *args)
45        path = QPainterPath()
46        x, y, w, h = [int(graphics.get(c, 0)) for c in ["x", "y", "width", "height"]]
47        type = graphics.get("type", "rectangle")
48        if type == "rectangle":
49            path.addRect(QRectF(x - w/2, y - h/2, w, h))
50        elif type == "roundrectangle":
51            path.addRoundedRect(QRectF(x - w/2, y - h/2, w, h), 10, 10)
52        elif type == "circle":
53            path.addEllipse(QRectF(x - w/2, y - h/2, w, h))
54           
55        self.setPath(path)
56        self.setAcceptHoverEvents(True)
57        self._actions = []
58        self.link = None
59       
60    def hoverEnterEvent(self, event):
61        self.setBrush(QBrush(QColor(0, 100, 0, 100)))
62       
63    def hoverLeaveEvent(self, event):
64        self.setBrush(QBrush(Qt.NoBrush))
65       
66    def contextMenuEvent(self, event):
67        if self._actions:
68            self._menu = menu = QMenu()
69            for action in self._actions:
70                menu.addAction(action)
71            menu.popup(event.screenPos())
72           
73    def itemChange(self, change, value):
74        if change == QGraphicsItem.ItemSelectedHasChanged:
75            self.setPen(QPen(Qt.red if self.isSelected() else Qt.blue, 2))
76           
77        return QGraphicsPathItem.itemChange(self, change, value)
78           
79class GraphicsPathwayItem(QGraphicsPixmapItem):
80    def __init__(self, pathway, objects, *args, **kwargs):
81        QGraphicsPixmapItem.__init__(self, *args)
82        self.setTransformationMode(Qt.SmoothTransformation)
83        self.setPathway(pathway)
84        self.setMarkedObjects(objects, name_mapper=kwargs.get("name_mapper", {}))
85       
86    def setPathway(self, pathway):
87        self.pathway = pathway
88        if pathway:
89            image_filename = pathway.get_image()
90            self._pixmap = QPixmap(image_filename)
91        else:
92            self._pixmap = QPixmap()
93        self.setPixmap(self._pixmap)
94       
95    def setMarkedObjects(self, objects, name_mapper={}):
96        for entry in self.pathway.entries() if self.pathway else []:
97            if entry.type == "group":
98                continue
99            graphics = entry.graphics
100            contained_objects = [obj for obj in objects if obj in entry.name]
101            item = EntryGraphicsItem(graphics, self, self.scene())
102            item.setToolTip(self.tooltip(entry, contained_objects, name_mapper))
103            item._actions = self.actions(entry, contained_objects)
104            item.marked_objects = contained_objects
105            if contained_objects:
106                item.setPen(QPen(Qt.blue, 2))
107                item.setFlag(QGraphicsItem.ItemIsSelectable, True)
108   
109    def actions(self, entry, marked_objects=[]):
110        actions = []
111        type = entry.type
112        if marked_objects:
113            action = QAction("View genes on kegg website", None)
114            org = set([s.split(":")[0] for s in marked_objects]).pop()
115            genes = [s.split(":")[-1] for s in marked_objects]
116            address = "http://www.genome.jp/dbget-bin/www_bget?" + "+".join([org] + genes)
117            QObject.connect(action, SIGNAL("triggered()"), lambda toggled=False, address=address: webbrowser.open(address))
118            actions.append(action)
119        elif hasattr(entry, "link"):
120            action = QAction("View %s on KEGG website" % str(type), None)
121            QObject.connect(action, SIGNAL("triggered()"), lambda toggled=False, address=entry.link: webbrowser.open(address))
122            actions.append(action)
123        return actions
124   
125    def tooltip(self, entry, objects, name_mapper={}):
126        names = [obj for obj in objects if obj in entry.name]
127        names = [name_mapper.get(name, name) for name in names]
128        text = "<p>%s</p>" % (entry.name[:16] + " ..." if len(entry.name) > 20 else entry.name)
129        if names:
130            text += "<br>".join(names)
131        return text
132   
133    def contextMenuEvent(self, event):
134        self._menu = menu = QMenu()
135        action = menu.addAction("View this pathway on KEGG website")
136        address ="http://www.kegg.jp/kegg-bin/show_pathway?%s%s" % (self.pathway.org, self.pathway.number)
137        QObject.connect(action, SIGNAL("triggered()"), lambda : webbrowser.open(address))
138        menu.popup(event.screenPos())
139
140class PathwayView(QGraphicsView):
141    def __init__(self, master, *args):
142        QGraphicsView.__init__(self, *args)
143        self.master = master
144       
145        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
146        self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
147       
148        self.setRenderHints(QPainter.Antialiasing)
149        scene = QGraphicsScene(self)
150        self.pixmapGraphicsItem = QGraphicsPixmapItem(None, scene) 
151        self.setScene(scene)
152       
153        self.setMouseTracking(True)
154        self.viewport().setMouseTracking(True)
155       
156        self.setFocusPolicy(Qt.WheelFocus)
157       
158    def SetPathway(self, pathway=None, objects=[]):
159        self.scene().clear()
160        self.pathway = pathway
161        self.objects = objects
162        self.pathwayItem = GraphicsPathwayItem(pathway, objects, None, self.scene(), name_mapper=getattr(self.master, "uniqueGenesDict", {}))
163        self.scene().setSceneRect(self.pathwayItem.boundingRect())
164        self.updateTransform()
165   
166    def resizeEvent(self, event):
167        self.updateTransform()
168        return QGraphicsView.resizeEvent(self, event)
169           
170    def updateTransform(self):
171        if self.master.autoResize:
172            self.fitInView(self.scene().sceneRect().adjusted(-1, -1, 1, 1), Qt.KeepAspectRatio)
173        else:
174            self.setTransform(QTransform())
175           
176    def paintEvent(self, event):
177        QGraphicsView.paintEvent(self, event)
178        if getattr(self, "_userMessage", None):
179            painter = QPainter(self.viewport())
180            font = QFont(self.font())
181            font.setPointSize(15)
182            painter.setFont(font)
183            painter.drawText(self.viewport().geometry(), Qt.AlignCenter, self._userMessage)
184            painter.end()
185       
186   
187class OWKEGGPathwayBrowser(OWWidget):
188    settingsList = ["organismIndex", "geneAttrIndex", "autoCommit", "autoResize", "useReference", "useAttrNames", "caseSensitive", "showOrthology"]
189    contextHandlers = {"":DomainContextHandler("",[ContextField("organismIndex", DomainContextHandler.Required + DomainContextHandler.IncludeMetaAttributes),
190                                                   ContextField("geneAttrIndex", DomainContextHandler.Required + DomainContextHandler.IncludeMetaAttributes),
191                                                   ContextField("useAttrNames", DomainContextHandler.Required + DomainContextHandler.IncludeMetaAttributes)])}
192    def __init__(self, parent=None, signalManager=None, name="KEGG Pathways"):
193        OWWidget.__init__(self, parent, signalManager, name, wantGraph=True)
194        self.inputs = [("Examples", ExampleTable, self.SetData), ("Reference", ExampleTable, self.SetRefData)]
195        self.outputs = [("Selected Examples", ExampleTable), ("Unselected Examples", ExampleTable)]
196        self.organismIndex = 0
197        self.geneAttrIndex = 0
198        self.autoCommit = False
199        self.autoResize = True
200        self.useReference = False
201        self.useAttrNames = 0
202        self.caseSensitive = True
203        self.showOrthology = True
204        self.autoFindBestOrg = False
205        self.loadSettings()
206
207        self.controlArea.setMaximumWidth(250)
208        box = OWGUI.widgetBox(self.controlArea, "Info")
209        self.infoLabel = OWGUI.widgetLabel(box, "No data on input\n")
210       
211        self.allOrganismCodes = {} 
212       
213        self.organismCodes = []
214       
215        box = OWGUI.widgetBox(self.controlArea, "Organism")
216        self.organismComboBox = cb = OWGUI.comboBox(box, self,
217                                "organismIndex", 
218                                items=[],
219                                callback=self.OrganismSelectionCallback, 
220                                addSpace=True,
221                                debuggingEnabled=0)
222#        OWGUI.button(box, self, "Update Pathways", callback=self.UpdateToLatestPathways)
223       
224#        cb.setMaximumWidth(200)
225       
226        self.signalManager.freeze(self).push()
227       
228        box = OWGUI.widgetBox(self.controlArea, "Gene attribute")
229        self.geneAttrCombo = OWGUI.comboBox(box, self, "geneAttrIndex",
230                                            callback=self.Update)
231       
232        OWGUI.checkBox(box, self, "useAttrNames",
233                       "Use variable names", 
234                       disables=[(-1, self.geneAttrCombo)],
235                       callback=self.UseAttrNamesCallback)
236       
237        self.geneAttrCombo.setDisabled(bool(self.useAttrNames))
238       
239        OWGUI.separator(self.controlArea)
240       
241        OWGUI.checkBox(self.controlArea, self, "useReference",
242                       "From signal",
243                       box="Reference",
244                       callback=self.Update)
245       
246        OWGUI.separator(self.controlArea)
247
248        OWGUI.checkBox(self.controlArea, self, "showOrthology",
249                       "Show pathways in full orthology",
250                       box="Orthology",
251                       callback=self.UpdateListView)
252       
253        OWGUI.checkBox(self.controlArea, self, "autoResize",
254                       "Resize to fit",
255                       box="Image",
256                       callback=self.UpdatePathwayViewTransform)
257       
258        OWGUI.separator(self.controlArea)
259
260        box = OWGUI.widgetBox(self.controlArea, "Selection")
261        OWGUI.checkBox(box, self, "autoCommit", "Commit on update")
262        OWGUI.button(box, self, "Commit", callback=self.Commit, default=True)
263        OWGUI.rubber(self.controlArea)
264       
265        spliter = QSplitter(Qt.Vertical, self.mainArea)
266        self.pathwayView = PathwayView(self, spliter)
267        self.mainArea.layout().addWidget(spliter)
268
269        self.listView = QTreeWidget(spliter)
270        spliter.addWidget(self.listView)
271       
272        self.listView.setAllColumnsShowFocus(1)
273        self.listView.setColumnCount(4)
274        self.listView.setHeaderLabels(["Pathway", "P value", 
275                                       "Genes", "Reference"])
276
277        self.listView.setSelectionMode(QAbstractItemView.SingleSelection)
278           
279        self.listView.setSortingEnabled(True)
280       
281        self.listView.setMaximumHeight(200)
282       
283        self.connect(self.listView,
284                     SIGNAL("itemSelectionChanged()"),
285                     self.UpdatePathwayView)
286       
287        self.connect(self.graphButton,
288                     SIGNAL("clicked()"),
289                     self.saveGraph)
290       
291        self.ctrlPressed = False
292        self.selectedObjects = defaultdict(list)
293        self.data = None
294        self.refData = None
295       
296        self.resize(800, 600)
297       
298        self.connect(self,
299                     SIGNAL("widgetStateChanged(QString, int, QString)"),
300                     self.onStateChange)
301       
302        self.has_new_data = False
303        self.has_new_reference_set = False
304       
305        self.setEnabled(False)
306        QTimer.singleShot(100, self.UpdateOrganismComboBox)
307       
308       
309    def UpdateOrganismComboBox(self):
310        try:
311            genome = obiKEGG.KEGGGenome()
312            all_codes = list(genome)
313           
314            self.allOrganismCodes = genome
315   
316            essential = genome.essential_organisms()
317            common = genome.common_organisms()
318            common = [c for c in common if c not in essential]
319           
320            self.infoLabel.setText("Fetching organism definitions\n")
321           
322            pb = OWGUI.ProgressBar(self, len(essential + common))
323            codes = []
324            for i, code in enumerate(essential + common):
325                codes.append((code, genome[code].definition))
326                pb.advance()
327            pb.finish()
328            self.organismCodes = codes
329           
330            items = [desc for code, desc in self.organismCodes]
331           
332            self.organismCodes = [code for code, desc in self.organismCodes]
333
334            # TODO: Add option to specify additional organisms not
335            # in the common list.
336
337            self.organismComboBox.addItems(items)
338        finally:
339            self.setEnabled(True)
340            self.infoLabel.setText("No data on input\n")
341            self.signalManager.freeze(self).pop() #setFreeze(0)
342
343    def Clear(self):
344        self.infoLabel.setText("No data on input\n")
345        self.listView.clear()
346        self.ClearPathway()
347       
348        self.send("Selected Examples", None)
349        self.send("Unselected Examples", None)
350       
351    def ClearPathway(self):
352        self.pathwayView.SetPathway(None)
353        self.selectedObjects = defaultdict(list)
354       
355    def SetData(self, data=None):
356        self.closeContext()
357        self.data = data
358        self.warning(0)
359        if data is not None:
360            self.SetGeneAttrCombo()
361            taxid = data_hints.get_hint(data, "taxid", None)
362            if taxid:
363                try:
364                    code = obiKEGG.from_taxid(taxid)
365                    self.organismIndex = self.organismCodes.index(code)
366                except Exception, ex:
367#                    self.log.exception(self, level=self.log.INFO)
368                    print ex, taxid
369           
370            self.useAttrNames = data_hints.get_hint(data, "genesinrows", self.useAttrNames)
371           
372            self.openContext("", data)
373        else:
374            self.Clear()
375           
376        self.has_new_data = True
377
378    def SetRefData(self, data=None):
379        self.refData = data
380        self.has_new_reference_set = True
381       
382    def handleNewSignals(self):
383        if self.has_new_data or (self.has_new_reference_set and \
384                                 self.useReference):
385            self.Update()
386           
387            self.has_new_data = False
388            self.has_new_reference_set = False
389       
390    def UseAttrNamesCallback(self):
391        self.Update()
392
393    def OrganismSelectionCallback(self):
394        self.Update()
395       
396    def SetGeneAttrCombo(self):
397        self.geneAttrCandidates = self.data.domain.attributes + \
398                                  self.data.domain.getmetas().values()
399        self.geneAttrCandidates = filter(lambda v:v.varType in [orange.VarTypes.Discrete,
400                                                                orange.VarTypes.String],
401                                         self.geneAttrCandidates)
402        self.geneAttrCombo.clear()
403       
404        self.geneAttrCombo.addItems([var.name for var in self.geneAttrCandidates])
405           
406    def UpdateListView(self):
407        self.bestPValueItem = None
408        self.listView.clear()
409        if not self.data:
410            return
411        allPathways = self.org.pathways()
412        allRefPathways = obiKEGG.pathways("map")
413#        self.progressBarFinished()
414        items = []
415        kegg_pathways = obiKEGG.KEGGPathways()
416        kegg_pathways.pre_cache(self.pathways.keys())
417       
418        if self.showOrthology:
419            self.koOrthology = obiKEGG.KEGGBrite("ko00001")
420            self.listView.setRootIsDecorated(True)
421            path_ids = set([s[-5:] for s in self.pathways.keys()])
422            def _walkCollect(koEntry):
423                num = koEntry.title[:5] if koEntry.title else None
424                if num  in path_ids:
425                    return [koEntry] + reduce(lambda li,c:li+_walkCollect(c), [child for child in koEntry.entries], [])
426                else:
427                    c = reduce(lambda li,c:li+_walkCollect(c), [child for child in koEntry.entries], [])
428                    return c + (c and [koEntry] or [])
429            allClasses = reduce(lambda li1, li2: li1+li2, [_walkCollect(c) for c in self.koOrthology], [])
430            def _walkCreate(koEntry, lvItem):
431                item = QTreeWidgetItem(lvItem)
432                id = "path:"+self.organismCodes[min(self.organismIndex, len(self.organismCodes)-1)] + koEntry.title[:5]
433                p = kegg_pathways.get_entry(id)
434                if koEntry.title[:5] in path_ids:
435                    if p is None:
436                        # In case the genesets still have obsolete entries
437                        name = koEntry.title
438                    else:
439                        name = p.name
440                    genes, p_value, ref = self.pathways[id]
441                    item.setText(0, name)
442                    item.setText(1, "%.5f" % p_value)
443                    item.setText(2, "%i of %i" %(len(genes), len(self.genes)))
444                    item.setText(3, "%i of %i" %(ref, len(self.referenceGenes)))
445                    item.pathway_id = id if p is not None else None
446                else:
447                    item.setText(0, p.name if id in allPathways else koEntry.title)
448                    if id in allPathways:
449                        item.pathway_id = id
450                    elif "path:map" + koEntry.title[:5] in allRefPathways:
451                        item.pathway_id = "path:map" + koEntry.title[:5]
452                    else:
453                        item.pathway_id = None
454               
455                for child in koEntry.entries:
456                    if child in allClasses:
457                        _walkCreate(child, item)
458           
459            for koEntry in self.koOrthology:
460                if koEntry in allClasses:
461                    _walkCreate(koEntry, self.listView)
462                   
463            self.listView.update()
464        else:
465            self.listView.setRootIsDecorated(False)
466            pathways = self.pathways.items()
467            pathways.sort(lambda a,b:cmp(a[1][1], b[1][1]))
468            for id, (genes, p_value, ref) in pathways:
469                item = QTreeWidgetItem(self.listView)
470                item.setText(0, kegg_pathways.get_entry(id).name)
471                item.setText(1, "%.5f" % p_value)
472                item.setText(2, "%i of %i" %(len(genes), len(self.genes)))
473                item.setText(3, "%i of %i" %(ref, len(self.referenceGenes)))
474                item.pathway_id = id
475                items.append(item)
476               
477        self.bestPValueItem = items and items[0] or None
478        self.listView.expandAll()
479        for i in range(4):
480            self.listView.resizeColumnToContents(i)
481           
482        if self.bestPValueItem:
483            self.listView.selectionModel().select(self.listView.indexFromItem(self.bestPValueItem), QItemSelectionModel.ClearAndSelect)
484
485    def UpdatePathwayView(self):
486        items = self.listView.selectedItems()
487       
488        if len(items) > 0:
489            item = items[0]
490        else:
491            item = None
492           
493        self.selectedObjects = defaultdict(list)
494        self.Commit()
495        item = item or self.bestPValueItem
496        if not item or not item.pathway_id:
497            self.pathwayView.SetPathway(None)
498            return
499       
500        if USE_THREADING:
501            result = {}
502            def call(pathway_id):
503                result["pathway"] = p = obiKEGG.KEGGPathway(pathway_id)
504                p._get_kgml() # makes sure the kgml file is downloaded
505                p._get_image_filename() # makes sure the image is downloaded
506               
507            self.setEnabled(False)
508            try:
509                thread = threading.Thread(None,
510                                          call,
511                                          name="get_kgml_and_image",
512                                          args=(item.pathway_id,))
513                thread.start()
514                while thread.is_alive():
515                    thread.join(timeout=0.025)
516                    qApp.processEvents()
517            finally:
518                self.setEnabled(True)
519            if "pathway" in result:
520                self.pathway = result["pathway"]
521            else:
522                raise Exception("Could not get kgml and  pathway image")
523        else:
524            self.pathway = obiKEGG.KEGGPathway(item.pathway_id)
525           
526        self.pathwayView.SetPathway(self.pathway, self.pathways.get(item.pathway_id, [[]])[0])
527           
528    def UpdatePathwayViewTransform(self):
529        self.pathwayView.updateTransform()
530       
531    def Update(self):
532        if not self.data:
533            return
534        self.error(0)
535        self.information(0)
536        pb = OWGUI.ProgressBar(self, 100)
537        if self.useAttrNames:
538            genes = [str(v.name).strip() for v in self.data.domain.attributes]
539        elif self.geneAttrCandidates:
540            geneAttr = self.geneAttrCandidates[min(self.geneAttrIndex, len(self.geneAttrCandidates)-1)]
541            genes = [str(e[geneAttr]) for e in self.data if not e[geneAttr].isSpecial()]
542            if any("," in gene for gene in genes):
543                genes = reduce(list.__add__, (split_and_strip(gene, ",") for gene in genes), [])
544                self.information(0, "Separators detected in input gene names. Assuming multiple genes per instance.")
545        else:
546            self.error(0, "Cannot extract gene names from input")
547            genes = []
548        org_code = self.organismCodes[min(self.organismIndex, len(self.organismCodes)-1)]
549       
550        if USE_THREADING:
551            result = {}
552            def callable(*args, **kwargs):
553                result["org"] = org = obiKEGG.KEGGOrganism(org_code)
554                # Make sure genes are cached for global reference set
555                result["genes"] = org.genes.keys()
556               
557            self.setEnabled(False)
558            try:
559                thread = threading.Thread(None, callable,
560                                          name="get_organism_genes",
561                                          )
562                thread.start()
563                while thread.is_alive():
564                    thread.join(timeout=0.025)
565                    qApp.processEvents()
566            finally:
567                self.setEnabled(True)
568           
569            if "org" in result:
570                org = result["org"]
571            else:
572                raise Exception("Could not get organism genes")
573        else:
574            org = obiKEGG.KEGGOrganism(org_code)
575       
576        uniqueGenes, conflicting, unknown = org.get_unique_gene_ids(set(genes), self.caseSensitive)
577        genesCount = len(set(genes))
578        self.infoLabel.setText("%i unique gene names on input\n%i (%.1f%%) genes names matched" % (genesCount, len(uniqueGenes), 100.0*len(uniqueGenes)/genesCount if genes else 0.0)) 
579       
580        self.information(1)
581        if self.useReference and self.refData:
582            if self.useAttrNames:
583                reference = [str(v.name).strip() for v in self.refData]
584            else:
585                geneAttr = self.geneAttrCandidates[min(self.geneAttrIndex, len(self.geneAttrCandidates)-1)]
586                reference = [str(e[geneAttr]) for e in self.refData if not e[geneAttr].isSpecial()]
587                if any("," in gene for gene in reference):
588                    reference = reduce(list.__add__, (split_and_strip(gene, ",") for gene in reference), [])
589                    self.information(1, "Separators detected in reference gene names. Assuming multiple genes per example.")
590            uniqueRefGenes, conflicting, unknown = org.get_unique_gene_ids(set(reference), self.caseSensitive)
591            self.referenceGenes = reference = uniqueRefGenes.keys()
592        else:
593            self.referenceGenes = reference = org.get_genes()
594        self.uniqueGenesDict = uniqueGenes
595        self.genes = uniqueGenes.keys()
596        self.revUniqueGenesDict = dict([(val, key) for key, val in self.uniqueGenesDict.items()])
597       
598        taxid = obiKEGG.to_taxid(org.org_code)
599        r_tax_map = dict((v,k) for k, v in obiKEGG.KEGGGenome.TAXID_MAP.items())
600        if taxid in r_tax_map:
601            taxid = r_tax_map[taxid]
602           
603        with orngServerFiles.DownloadProgress.setredirect(self.progressBarSet):
604            orngServerFiles.update(obiGeneSets.sfdomain, "index.pck")
605            kegg_gs_collections = list(obiGeneSets.collections((("KEGG", "pathways"), taxid)))
606       
607#        print self.genes
608#        print taxid
609#        print kegg_gs_collections
610        if USE_THREADING:
611            result = {}
612            def callable(*args, **kwargs):
613#                result["result"] = org.get_enriched_pathways(*args, **kwargs)
614                result["result"] = pathway_enrichment(*args, **kwargs)
615           
616            self.setEnabled(False)
617            try:
618                thread = threading.Thread(None, callable,
619                                          name="get_enriched_pathways",
620                                          args=(kegg_gs_collections,
621                                                self.genes, 
622                                                reference),
623                                          kwargs={"callback": 
624                                                  threading_queued_invoke(self,
625                                                  lambda value:pb.advance())}
626                                          )
627               
628                thread.start()
629                while thread.is_alive():
630                    thread.join(timeout=0.025)
631                    qApp.processEvents()
632            finally:
633                self.setEnabled(True)
634               
635            if "result" in result:
636                self.pathways = result["result"]
637            else:
638                raise Exception('Could not get enriched pathways')
639        else:
640            self.pathways = org.get_enriched_pathways(self.genes, reference,
641                                                      callback=lambda value: pb.advance())
642       
643        self.org = org
644        if not self.pathways:
645            self.warning(0, "No enriched pathways found.")
646        else:
647            self.warning(0)
648       
649        self.UpdateListView()
650        pb.finish()
651   
652
653    def SelectObjects(self, objs):
654        if (not self.selectedObjects or self.ctrlPressed) and not objs:
655            return
656        if self.ctrlPressed:
657            for id, graphics in objs:
658                graphics = tuple(sorted(graphics.items()))
659                if id in self.selectedObjects[graphics]:
660                    self.selectedObjects[graphics].pop(self.selectedObjects[graphics].index(id))
661                    if not self.selectedObjects[graphics]:
662                        del self.selectedObjects[graphics]
663                else:
664                    self.selectedObjects[graphics].append(id)
665        else:
666            self.selectedObjects.clear()
667            for id, graphics in objs:
668                graphics = tuple(sorted(graphics.items()))
669                self.selectedObjects[graphics].append(id)
670        if self.autoCommit:
671            self.Commit()
672           
673
674    def Commit(self):
675        if self.data:
676            selectedItems = self.pathwayView.scene().selectedItems()
677            selectedGenes = reduce(set.union, [item.marked_objects for item in selectedItems], set())
678           
679            if self.useAttrNames:
680                selectedVars = [self.data.domain[self.uniqueGenesDict[gene]] for gene in selectedGenes]
681                newDomain = orange.Domain(selectedVars ,0)
682                data = orange.ExampleTable(newDomain, self.data)
683                self.send("Selected Examples", data)
684            elif self.geneAttrCandidates:
685                geneAttr = self.geneAttrCandidates[min(self.geneAttrIndex, len(self.geneAttrCandidates)-1)]
686                selectedExamples = []
687                otherExamples = []
688                for ex in self.data:
689                    names = [self.revUniqueGenesDict.get(name, None) for name in split_and_strip(str(ex[geneAttr]), ",")]
690                    if any(name and name in selectedGenes for name in names):
691                        selectedExamples.append(ex)
692                    else:
693                        otherExamples.append(ex)
694                       
695                if selectedExamples:
696                    selectedExamples = orange.ExampleTable(selectedExamples)
697                else:
698                    selectedExamples = None
699                   
700                if otherExamples:
701                    otherExamples = orange.ExampleTable(otherExamples)
702                else:
703                    otherExamples = None
704                   
705                self.send("Selected Examples", selectedExamples)
706                self.send("Unselected Examples", otherExamples)
707        else:
708            self.send("Selected Examples", None)
709            self.send("Unselected Examples", None)
710       
711    def keyPressEvent(self, key):
712        if key.key()==Qt.Key_Control:
713            self.ctrlPressed=True
714        else:
715            OWWidget.keyPressEvent(self, key)
716
717    def keyReleaseEvent(self, key):
718        if key.key()==Qt.Key_Control:
719            self.ctrlPressed=False
720        else:
721            OWWidget.keyReleaseEvent(self, key)
722           
723    def onStateChange(self, stateType, id, text):
724        if stateType == "Warning":
725            self.pathwayView._userMessage = text
726            self.pathwayView.viewport().update()
727           
728    def saveGraph(self):
729        from OWDlgs import OWChooseImageSizeDlg
730        sizeDlg = OWChooseImageSizeDlg(self.pathwayView.scene(), parent=self)
731        sizeDlg.exec_()
732
733    @pyqtSignature("queuedInvoke(PyQt_PyObject)")
734    def queuedInvoke(self, func):
735#        print "queued invoke of", func
736        func()
737       
738    def progressBarSet(self, value):
739#        print "Enter"
740        if not getattr(self, "_in_progress_update", False):
741            self._in_progress_update = True
742            try:
743                OWWidget.progressBarSet(self, value)
744            finally:
745                self._in_progress_update = False
746#        else:
747#            print "====="
748       
749#        print "Exit"
750   
751    def onDeleteWidget(self):
752        """ Called before the widget is removed from the canvas.
753        """
754        self.org = None
755        import gc
756        gc.collect() # Force collection
757       
758    def UpdateToLatestPathways(self):
759        pass       
760         
761import obiProb
762
763def pathway_enrichment(genesets, genes, reference, prob=None, callback=None):
764    result_sets = []
765    p_values = []
766    if prob is None:
767        prob = obiProb.Hypergeometric()
768       
769    for i, gs in enumerate(genesets):
770        cluster = gs.genes.intersection(genes)
771        ref = gs.genes.intersection(reference)
772        k = len(cluster)
773        N = len(reference)
774        m = len(ref)
775        n = len(genes)
776        if k:
777            p_val = prob.p_value(k, N, m, n)
778            result_sets.append((gs.id, cluster, ref))
779            p_values.append(p_val)
780        if callback is not None:
781            callback(100.0 * i / len(genesets))
782   
783    # FDR correction
784    p_values = obiProb.FDR(p_values)
785   
786    return dict([(id, (genes, p_val, len(ref))) \
787                 for (id, genes, ref), p_val in zip(result_sets, p_values)]
788                )
789   
790if __name__=="__main__":
791    app = QApplication(sys.argv)
792    data = orange.ExampleTable("brown-selected.tab")
793    w = OWKEGGPathwayBrowser()
794    w.UpdateOrganismComboBox()
795##    app.setMainWidget(w)
796    w.show()
797    w.SetData(orange.ExampleTable(data[:]))
798    QTimer.singleShot(10, w.handleNewSignals)
799    app.exec_()
800    w.saveSettings()
Note: See TracBrowser for help on using the repository browser.