source: orange-bioinformatics/_bioinformatics/widgets/OWKEGGPathwayBrowser.py @ 1733:548d1187a29f

Revision 1733:548d1187a29f, 32.7 KB checked in by Ales Erjavec <ales.erjavec@…>, 14 months ago (diff)

Porting obiKEGG to use the new REST KEGG API.

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/KEGGPathways.svg</icon>
6"""
7
8from __future__ import absolute_import, with_statement
9
10import sys
11import gc
12from collections import defaultdict
13import webbrowser
14
15import Orange
16import orange
17from Orange.orng import orngMisc, orngServerFiles
18from Orange.orng.orngDataCaching import data_hints
19from Orange.OrangeWidgets import OWGUI
20from Orange.OrangeWidgets.OWWidget import *
21
22from .. import obiTaxonomy
23from .. import obiKEGG
24from .. import obiGeneSets
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       
223        self.signalManager.freeze(self).push()
224       
225        box = OWGUI.widgetBox(self.controlArea, "Gene attribute")
226        self.geneAttrCombo = OWGUI.comboBox(box, self, "geneAttrIndex",
227                                            callback=self.Update)
228       
229        OWGUI.checkBox(box, self, "useAttrNames",
230                       "Use variable names", 
231                       disables=[(-1, self.geneAttrCombo)],
232                       callback=self.UseAttrNamesCallback)
233       
234        self.geneAttrCombo.setDisabled(bool(self.useAttrNames))
235       
236        OWGUI.separator(self.controlArea)
237       
238        OWGUI.checkBox(self.controlArea, self, "useReference",
239                       "From signal",
240                       box="Reference",
241                       callback=self.Update)
242       
243        OWGUI.separator(self.controlArea)
244
245        OWGUI.checkBox(self.controlArea, self, "showOrthology",
246                       "Show pathways in full orthology",
247                       box="Orthology",
248                       callback=self.UpdateListView)
249       
250        OWGUI.checkBox(self.controlArea, self, "autoResize",
251                       "Resize to fit",
252                       box="Image",
253                       callback=self.UpdatePathwayViewTransform)
254       
255        box = OWGUI.widgetBox(self.controlArea, "Cache Control")
256       
257        OWGUI.button(box, self, "Clear cache", 
258                     callback=self.ClearCache,
259                     tooltip="Clear all locally cached KEGG data.")
260       
261        OWGUI.separator(self.controlArea)
262
263        box = OWGUI.widgetBox(self.controlArea, "Selection")
264        OWGUI.checkBox(box, self, "autoCommit", "Commit on update")
265        OWGUI.button(box, self, "Commit", callback=self.Commit, default=True)
266        OWGUI.rubber(self.controlArea)
267       
268        spliter = QSplitter(Qt.Vertical, self.mainArea)
269        self.pathwayView = PathwayView(self, spliter)
270        self.mainArea.layout().addWidget(spliter)
271
272        self.listView = QTreeWidget(spliter)
273        spliter.addWidget(self.listView)
274       
275        self.listView.setAllColumnsShowFocus(1)
276        self.listView.setColumnCount(4)
277        self.listView.setHeaderLabels(["Pathway", "P value", 
278                                       "Genes", "Reference"])
279
280        self.listView.setSelectionMode(QAbstractItemView.SingleSelection)
281           
282        self.listView.setSortingEnabled(True)
283       
284        self.listView.setMaximumHeight(200)
285       
286        self.connect(self.listView,
287                     SIGNAL("itemSelectionChanged()"),
288                     self.UpdatePathwayView)
289       
290        self.connect(self.graphButton,
291                     SIGNAL("clicked()"),
292                     self.saveGraph)
293       
294        self.ctrlPressed = False
295        self.selectedObjects = defaultdict(list)
296        self.data = None
297        self.refData = None
298       
299        self.resize(800, 600)
300       
301        self.connect(self,
302                     SIGNAL("widgetStateChanged(QString, int, QString)"),
303                     self.onStateChange)
304       
305        self.has_new_data = False
306        self.has_new_reference_set = False
307       
308        self.setEnabled(False)
309        QTimer.singleShot(100, self.UpdateOrganismComboBox)
310
311    def UpdateOrganismComboBox(self):
312        # First try to import suds
313        try:
314            import slumber
315        except ImportError:
316            QMessageBox.warning(self,
317                "'slumber' library required.",
318                '<p>Please install '
319                '<a href="http://pypi.python.org/pypi/slumber">slumber</a> '
320                'library to use KEGG Pathways widget.</p>'
321            )
322
323        try:
324            genome = obiKEGG.KEGGGenome()
325
326            self.allOrganismCodes = genome
327
328            essential = genome.essential_organisms()
329            common = genome.common_organisms()
330            common = [c for c in common if c not in essential]
331
332            # TODO: Add option to specify additional organisms not
333            # in the common list.
334
335            self.infoLabel.setText("Fetching organism definitions\n")
336
337            keys = map(genome.org_code_to_entry_key, essential + common)
338
339            self.progressBarInit()
340            genome.pre_cache(keys, progress_callback=self.progressBarSet)
341            self.progressBarFinished()
342
343            codes = []
344            for code, key in zip(essential + common, keys):
345                codes.append((code, genome[key].definition))
346
347            items = [desc for code, desc in codes]
348
349            self.organismCodes = [code for code, desc in codes]
350            self.organismComboBox.addItems(items)
351
352        finally:
353            self.setEnabled(True)
354            self.infoLabel.setText("No data on input\n")
355            self.signalManager.freeze(self).pop()
356
357    def Clear(self):
358        """
359        Clear the widget state.
360        """
361        self.infoLabel.setText("No data on input\n")
362        self.listView.clear()
363        self.ClearPathway()
364
365        self.send("Selected Examples", None)
366        self.send("Unselected Examples", None)
367
368    def ClearPathway(self):
369        self.pathwayView.SetPathway(None)
370        self.selectedObjects = defaultdict(list)
371       
372    def SetData(self, data=None):
373        self.closeContext()
374        self.data = data
375        self.warning(0)
376        if data is not None:
377            self.SetGeneAttrCombo()
378            taxid = data_hints.get_hint(data, "taxid", None)
379            if taxid:
380                try:
381                    code = obiKEGG.from_taxid(taxid)
382                    self.organismIndex = self.organismCodes.index(code)
383                except Exception, ex:
384#                    self.log.exception(self, level=self.log.INFO)
385                    print ex, taxid
386           
387            self.useAttrNames = data_hints.get_hint(data, "genesinrows", self.useAttrNames)
388           
389            self.openContext("", data)
390        else:
391            self.Clear()
392           
393        self.has_new_data = True
394
395    def SetRefData(self, data=None):
396        self.refData = data
397        self.has_new_reference_set = True
398       
399    def handleNewSignals(self):
400        if self.has_new_data or (self.has_new_reference_set and \
401                                 self.useReference):
402            self.Update()
403           
404            self.has_new_data = False
405            self.has_new_reference_set = False
406       
407    def UseAttrNamesCallback(self):
408        self.Update()
409
410    def OrganismSelectionCallback(self):
411        self.Update()
412       
413    def SetGeneAttrCombo(self):
414        self.geneAttrCandidates = self.data.domain.attributes + \
415                                  self.data.domain.getmetas().values()
416        self.geneAttrCandidates = filter(lambda v:v.varType in [orange.VarTypes.Discrete,
417                                                                orange.VarTypes.String],
418                                         self.geneAttrCandidates)
419        self.geneAttrCombo.clear()
420       
421        self.geneAttrCombo.addItems([var.name for var in self.geneAttrCandidates])
422
423    def UpdateListView(self):
424        self.bestPValueItem = None
425        self.listView.clear()
426        if not self.data:
427            return
428
429        allPathways = self.org.pathways()
430        allRefPathways = obiKEGG.pathways("map")
431
432        items = []
433        self.progressBarInit()
434        kegg_pathways = obiKEGG.KEGGPathways()
435        kegg_pathways.pre_cache(self.pathways.keys(),
436                                progress_callback=self.progressBarSet)
437        self.progressBarFinished()
438
439        org_code = self.organismCodes[min(self.organismIndex,
440                                          len(self.organismCodes)-1)]
441
442        if self.showOrthology:
443            self.koOrthology = obiKEGG.KEGGBrite("ko00001")
444            self.listView.setRootIsDecorated(True)
445            path_ids = set([s[-5:] for s in self.pathways.keys()])
446
447            def _walkCollect(koEntry):
448                num = koEntry.title[:5] if koEntry.title else None
449                if num in path_ids:
450                    return [koEntry] + reduce(lambda li, c:li + _walkCollect(c), [child for child in koEntry.entries], [])
451                else:
452                    c = reduce(lambda li, c: li + _walkCollect(c),
453                               [child for child in koEntry.entries], [])
454                    return c + (c and [koEntry] or [])
455
456            allClasses = reduce(lambda li1, li2: li1 + li2,
457                                [_walkCollect(c) for c in self.koOrthology], [])
458
459            def _walkCreate(koEntry, lvItem):
460                item = QTreeWidgetItem(lvItem)
461                id = "path:" + org_code + koEntry.title[:5]
462
463                if koEntry.title[:5] in path_ids:
464                    p = kegg_pathways.get_entry(id)
465                    if p is None:
466                        # In case the genesets still have obsolete entries
467                        name = koEntry.title
468                    else:
469                        name = p.name
470                    genes, p_value, ref = self.pathways[id]
471                    item.setText(0, name)
472                    item.setText(1, "%.5f" % p_value)
473                    item.setText(2, "%i of %i" % (len(genes), len(self.genes)))
474                    item.setText(3, "%i of %i" % (ref, len(self.referenceGenes)))
475                    item.pathway_id = id if p is not None else None
476                else:
477                    if id in allPathways:
478                        text = kegg_pathways.get_entry(id).name
479                    else:
480                        text = koEntry.title
481                    item.setText(0, text)
482
483                    if id in allPathways:
484                        item.pathway_id = id
485                    elif "path:map" + koEntry.title[:5] in allRefPathways:
486                        item.pathway_id = "path:map" + koEntry.title[:5]
487                    else:
488                        item.pathway_id = None
489
490                for child in koEntry.entries:
491                    if child in allClasses:
492                        _walkCreate(child, item)
493
494            for koEntry in self.koOrthology:
495                if koEntry in allClasses:
496                    _walkCreate(koEntry, self.listView)
497
498            self.listView.update()
499        else:
500            self.listView.setRootIsDecorated(False)
501            pathways = self.pathways.items()
502            pathways.sort(lambda a, b: cmp(a[1][1], b[1][1]))
503
504            for id, (genes, p_value, ref) in pathways:
505                item = QTreeWidgetItem(self.listView)
506                item.setText(0, kegg_pathways.get_entry(id).name)
507                item.setText(1, "%.5f" % p_value)
508                item.setText(2, "%i of %i" % (len(genes), len(self.genes)))
509                item.setText(3, "%i of %i" % (ref, len(self.referenceGenes)))
510                item.pathway_id = id
511                items.append(item)
512
513        self.bestPValueItem = items and items[0] or None
514        self.listView.expandAll()
515        for i in range(4):
516            self.listView.resizeColumnToContents(i)
517           
518        if self.bestPValueItem:
519            self.listView.selectionModel().select(self.listView.indexFromItem(self.bestPValueItem), QItemSelectionModel.ClearAndSelect)
520
521    def UpdatePathwayView(self):
522        items = self.listView.selectedItems()
523       
524        if len(items) > 0:
525            item = items[0]
526        else:
527            item = None
528           
529        self.selectedObjects = defaultdict(list)
530        self.Commit()
531        item = item or self.bestPValueItem
532        if not item or not item.pathway_id:
533            self.pathwayView.SetPathway(None)
534            return
535       
536        if USE_THREADING:
537            result = {}
538            def call(pathway_id):
539                result["pathway"] = p = obiKEGG.KEGGPathway(pathway_id)
540                p._get_kgml() # makes sure the kgml file is downloaded
541                p._get_image_filename() # makes sure the image is downloaded
542               
543            self.setEnabled(False)
544            try:
545                thread = threading.Thread(None,
546                                          call,
547                                          name="get_kgml_and_image",
548                                          args=(item.pathway_id,))
549                thread.start()
550                while thread.is_alive():
551                    thread.join(timeout=0.025)
552                    qApp.processEvents()
553            finally:
554                self.setEnabled(True)
555            if "pathway" in result:
556                self.pathway = result["pathway"]
557            else:
558                raise Exception("Could not get kgml and  pathway image")
559        else:
560            self.pathway = obiKEGG.KEGGPathway(item.pathway_id)
561           
562        self.pathwayView.SetPathway(self.pathway, self.pathways.get(item.pathway_id, [[]])[0])
563           
564    def UpdatePathwayViewTransform(self):
565        self.pathwayView.updateTransform()
566       
567    def Update(self):
568        if not self.data:
569            return
570        self.error(0)
571        self.information(0)
572        pb = OWGUI.ProgressBar(self, 100)
573        if self.useAttrNames:
574            genes = [str(v.name).strip() for v in self.data.domain.attributes]
575        elif self.geneAttrCandidates:
576            geneAttr = self.geneAttrCandidates[min(self.geneAttrIndex, len(self.geneAttrCandidates)-1)]
577            genes = [str(e[geneAttr]) for e in self.data if not e[geneAttr].isSpecial()]
578            if any("," in gene for gene in genes):
579                genes = reduce(list.__add__, (split_and_strip(gene, ",") for gene in genes), [])
580                self.information(0, "Separators detected in input gene names. Assuming multiple genes per instance.")
581        else:
582            self.error(0, "Cannot extract gene names from input")
583            genes = []
584        org_code = self.organismCodes[min(self.organismIndex, len(self.organismCodes)-1)]
585       
586        if USE_THREADING:
587            result = {}
588            def callable(*args, **kwargs):
589                result["org"] = org = obiKEGG.KEGGOrganism(org_code)
590                # Make sure genes are cached for global reference set
591                result["genes"] = org.genes.keys()
592               
593            self.setEnabled(False)
594            try:
595                thread = threading.Thread(None, callable,
596                                          name="get_organism_genes",
597                                          )
598                thread.start()
599                while thread.is_alive():
600                    thread.join(timeout=0.025)
601                    qApp.processEvents()
602            finally:
603                self.setEnabled(True)
604           
605            if "org" in result:
606                org = result["org"]
607            else:
608                raise Exception("Could not get organism genes")
609        else:
610            org = obiKEGG.KEGGOrganism(org_code)
611       
612        uniqueGenes, conflicting, unknown = org.get_unique_gene_ids(set(genes), self.caseSensitive)
613        genesCount = len(set(genes))
614        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)) 
615       
616        self.information(1)
617        if self.useReference and self.refData:
618            if self.useAttrNames:
619                reference = [str(v.name).strip() for v in self.refData]
620            else:
621                geneAttr = self.geneAttrCandidates[min(self.geneAttrIndex, len(self.geneAttrCandidates)-1)]
622                reference = [str(e[geneAttr]) for e in self.refData if not e[geneAttr].isSpecial()]
623                if any("," in gene for gene in reference):
624                    reference = reduce(list.__add__, (split_and_strip(gene, ",") for gene in reference), [])
625                    self.information(1, "Separators detected in reference gene names. Assuming multiple genes per example.")
626            uniqueRefGenes, conflicting, unknown = org.get_unique_gene_ids(set(reference), self.caseSensitive)
627            self.referenceGenes = reference = uniqueRefGenes.keys()
628        else:
629            self.referenceGenes = reference = org.get_genes()
630        self.uniqueGenesDict = uniqueGenes
631        self.genes = uniqueGenes.keys()
632        self.revUniqueGenesDict = dict([(val, key) for key, val in self.uniqueGenesDict.items()])
633       
634        taxid = obiKEGG.to_taxid(org.org_code)
635        r_tax_map = dict((v,k) for k, v in obiKEGG.KEGGGenome.TAXID_MAP.items())
636        if taxid in r_tax_map:
637            taxid = r_tax_map[taxid]
638           
639        with orngServerFiles.DownloadProgress.setredirect(self.progressBarSet):
640            orngServerFiles.update(obiGeneSets.sfdomain, "index.pck")
641            kegg_gs_collections = list(obiGeneSets.collections((("KEGG", "pathways"), taxid)))
642       
643        if USE_THREADING:
644            result = {}
645            def callable(*args, **kwargs):
646#                result["result"] = org.get_enriched_pathways(*args, **kwargs)
647                result["result"] = pathway_enrichment(*args, **kwargs)
648           
649            self.setEnabled(False)
650            try:
651                thread = threading.Thread(None, callable,
652                                          name="get_enriched_pathways",
653                                          args=(kegg_gs_collections,
654                                                self.genes, 
655                                                reference),
656                                          kwargs={"callback": 
657                                                  threading_queued_invoke(self,
658                                                  lambda value:self.progressBarSet(value))}
659                                          )
660               
661                thread.start()
662                while thread.is_alive():
663                    thread.join(timeout=0.025)
664                    qApp.processEvents()
665            finally:
666                self.setEnabled(True)
667               
668            if "result" in result:
669                self.pathways = result["result"]
670            else:
671                raise Exception('Could not get enriched pathways')
672           
673           
674        else:
675            self.pathways = org.get_enriched_pathways(self.genes, reference,
676                                                      callback=lambda value: self.progressBarSet(value))
677       
678        self.org = org
679        if not self.pathways:
680            self.warning(0, "No enriched pathways found.")
681        else:
682            self.warning(0)
683       
684        self.UpdateListView()
685        pb.finish()
686   
687
688    def SelectObjects(self, objs):
689        if (not self.selectedObjects or self.ctrlPressed) and not objs:
690            return
691        if self.ctrlPressed:
692            for id, graphics in objs:
693                graphics = tuple(sorted(graphics.items()))
694                if id in self.selectedObjects[graphics]:
695                    self.selectedObjects[graphics].pop(self.selectedObjects[graphics].index(id))
696                    if not self.selectedObjects[graphics]:
697                        del self.selectedObjects[graphics]
698                else:
699                    self.selectedObjects[graphics].append(id)
700        else:
701            self.selectedObjects.clear()
702            for id, graphics in objs:
703                graphics = tuple(sorted(graphics.items()))
704                self.selectedObjects[graphics].append(id)
705        if self.autoCommit:
706            self.Commit()
707           
708
709    def Commit(self):
710        if self.data:
711            selectedItems = self.pathwayView.scene().selectedItems()
712            selectedGenes = reduce(set.union, [item.marked_objects for item in selectedItems], set())
713           
714            if self.useAttrNames:
715                selectedVars = [self.data.domain[self.uniqueGenesDict[gene]] for gene in selectedGenes]
716                newDomain = orange.Domain(selectedVars ,0)
717                data = orange.ExampleTable(newDomain, self.data)
718                self.send("Selected Examples", data)
719            elif self.geneAttrCandidates:
720                geneAttr = self.geneAttrCandidates[min(self.geneAttrIndex, len(self.geneAttrCandidates)-1)]
721                selectedExamples = []
722                otherExamples = []
723                for ex in self.data:
724                    names = [self.revUniqueGenesDict.get(name, None) for name in split_and_strip(str(ex[geneAttr]), ",")]
725                    if any(name and name in selectedGenes for name in names):
726                        selectedExamples.append(ex)
727                    else:
728                        otherExamples.append(ex)
729                       
730                if selectedExamples:
731                    selectedExamples = orange.ExampleTable(selectedExamples)
732                else:
733                    selectedExamples = None
734                   
735                if otherExamples:
736                    otherExamples = orange.ExampleTable(otherExamples)
737                else:
738                    otherExamples = None
739                   
740                self.send("Selected Examples", selectedExamples)
741                self.send("Unselected Examples", otherExamples)
742        else:
743            self.send("Selected Examples", None)
744            self.send("Unselected Examples", None)
745       
746    def ClearCache(self):
747        from ..obiKEGG import caching
748        try:
749            caching.clear_cache()
750        except Exception, ex:
751            QMessageBox.warning(self, "Cache clear", 
752                ex.args[0])
753           
754       
755    def keyPressEvent(self, key):
756        if key.key()==Qt.Key_Control:
757            self.ctrlPressed=True
758        else:
759            OWWidget.keyPressEvent(self, key)
760
761    def keyReleaseEvent(self, key):
762        if key.key()==Qt.Key_Control:
763            self.ctrlPressed=False
764        else:
765            OWWidget.keyReleaseEvent(self, key)
766           
767    def onStateChange(self, stateType, id, text):
768        if stateType == "Warning":
769            self.pathwayView._userMessage = text
770            self.pathwayView.viewport().update()
771           
772    def saveGraph(self):
773        from Orange.OrangeWidgets.OWDlgs import OWChooseImageSizeDlg
774        sizeDlg = OWChooseImageSizeDlg(self.pathwayView.scene(), parent=self)
775        sizeDlg.exec_()
776
777    @pyqtSignature("queuedInvoke(PyQt_PyObject)")
778    def queuedInvoke(self, func):
779        func()
780
781    def progressBarSet(self, value):
782        if not getattr(self, "_in_progress_update", False):
783            self._in_progress_update = True
784            try:
785                OWWidget.progressBarSet(self, value)
786            finally:
787                self._in_progress_update = False
788
789    def onDeleteWidget(self):
790        """ Called before the widget is removed from the canvas.
791        """
792        self.org = None
793        gc.collect()  # Force collection
794       
795    def UpdateToLatestPathways(self):
796        pass       
797         
798from .. import obiProb
799
800def pathway_enrichment(genesets, genes, reference, prob=None, callback=None):
801    result_sets = []
802    p_values = []
803    if prob is None:
804        prob = obiProb.Hypergeometric()
805       
806    for i, gs in enumerate(genesets):
807        cluster = gs.genes.intersection(genes)
808        ref = gs.genes.intersection(reference)
809        k = len(cluster)
810        N = len(reference)
811        m = len(ref)
812        n = len(genes)
813        if k:
814            p_val = prob.p_value(k, N, m, n)
815            result_sets.append((gs.id, cluster, ref))
816            p_values.append(p_val)
817        if callback is not None:
818            callback(100.0 * i / len(genesets))
819   
820    # FDR correction
821    p_values = obiProb.FDR(p_values)
822   
823    return dict([(id, (genes, p_val, len(ref))) \
824                 for (id, genes, ref), p_val in zip(result_sets, p_values)]
825                )
826
827if __name__ == "__main__":
828    app = QApplication(sys.argv)
829    data = orange.ExampleTable("brown-selected.tab")
830    w = OWKEGGPathwayBrowser()
831    w.UpdateOrganismComboBox()
832    w.show()
833    w.SetData(orange.ExampleTable(data[:]))
834    QTimer.singleShot(10, w.handleNewSignals)
835
836    app.exec_()
837    w.saveSettings()
Note: See TracBrowser for help on using the repository browser.