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.

RevLine 
[188]1"""
[1462]2<name>KEGG Pathways</name>
[1051]3<description>Browse KEGG pathways that include an input set of genes.</description>
[1052]4<priority>2030</priority>
[1726]5<icon>icons/KEGGPathways.svg</icon>
[188]6"""
[1632]7
[1733]8from __future__ import absolute_import, with_statement
[1712]9
[188]10import sys
[1733]11import gc
[1632]12from collections import defaultdict
[1142]13import webbrowser
14
[1712]15import Orange
[1632]16import orange
[1643]17from Orange.orng import orngMisc, orngServerFiles
[1632]18from Orange.orng.orngDataCaching import data_hints
19from Orange.OrangeWidgets import OWGUI
20from Orange.OrangeWidgets.OWWidget import *
[188]21
[1632]22from .. import obiTaxonomy
[1716]23from .. import obiKEGG
[1632]24from .. import obiGeneSets
[1118]25
[1534]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   
[211]39def split_and_strip(string, sep=None):
40    return [s.strip() for s in string.split(sep)]
41
[1142]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={}):
[1577]96        for entry in self.pathway.entries() if self.pathway else []:
[1142]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())
[188]139
[195]140class PathwayView(QGraphicsView):
[188]141    def __init__(self, master, *args):
[195]142        QGraphicsView.__init__(self, *args)
[188]143        self.master = master
[1142]144       
[195]145        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
146        self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
147       
[1142]148        self.setRenderHints(QPainter.Antialiasing)
149        scene = QGraphicsScene(self)
150        self.pixmapGraphicsItem = QGraphicsPixmapItem(None, scene) 
151        self.setScene(scene)
[195]152       
[188]153        self.setMouseTracking(True)
154        self.viewport().setMouseTracking(True)
155       
[1248]156        self.setFocusPolicy(Qt.WheelFocus)
157       
[188]158    def SetPathway(self, pathway=None, objects=[]):
[1142]159        self.scene().clear()
[188]160        self.pathway = pathway
161        self.objects = objects
[1142]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)
[188]173        else:
[1142]174            self.setTransform(QTransform())
[1248]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()
[1000]185       
[188]186   
187class OWKEGGPathwayBrowser(OWWidget):
[1142]188    settingsList = ["organismIndex", "geneAttrIndex", "autoCommit", "autoResize", "useReference", "useAttrNames", "caseSensitive", "showOrthology"]
[188]189    contextHandlers = {"":DomainContextHandler("",[ContextField("organismIndex", DomainContextHandler.Required + DomainContextHandler.IncludeMetaAttributes),
190                                                   ContextField("geneAttrIndex", DomainContextHandler.Required + DomainContextHandler.IncludeMetaAttributes),
191                                                   ContextField("useAttrNames", DomainContextHandler.Required + DomainContextHandler.IncludeMetaAttributes)])}
[1462]192    def __init__(self, parent=None, signalManager=None, name="KEGG Pathways"):
[1525]193        OWWidget.__init__(self, parent, signalManager, name, wantGraph=True)
[188]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
[214]201        self.useAttrNames = 0
[188]202        self.caseSensitive = True
[519]203        self.showOrthology = True
[188]204        self.autoFindBestOrg = False
205        self.loadSettings()
206
207        self.controlArea.setMaximumWidth(250)
[1248]208        box = OWGUI.widgetBox(self.controlArea, "Info")
209        self.infoLabel = OWGUI.widgetLabel(box, "No data on input\n")
[1000]210       
[1003]211        self.allOrganismCodes = {} 
[1534]212       
[1003]213        self.organismCodes = []
[188]214       
[1534]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()
[1003]224       
225        box = OWGUI.widgetBox(self.controlArea, "Gene attribute")
[1534]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       
[216]234        self.geneAttrCombo.setDisabled(bool(self.useAttrNames))
235       
[188]236        OWGUI.separator(self.controlArea)
237       
[1534]238        OWGUI.checkBox(self.controlArea, self, "useReference",
239                       "From signal",
240                       box="Reference",
241                       callback=self.Update)
242       
[188]243        OWGUI.separator(self.controlArea)
244
[1534]245        OWGUI.checkBox(self.controlArea, self, "showOrthology",
246                       "Show pathways in full orthology",
247                       box="Orthology",
248                       callback=self.UpdateListView)
[188]249       
[1534]250        OWGUI.checkBox(self.controlArea, self, "autoResize",
251                       "Resize to fit",
252                       box="Image",
253                       callback=self.UpdatePathwayViewTransform)
254       
[1606]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       
[188]261        OWGUI.separator(self.controlArea)
262
263        box = OWGUI.widgetBox(self.controlArea, "Selection")
264        OWGUI.checkBox(box, self, "autoCommit", "Commit on update")
[1378]265        OWGUI.button(box, self, "Commit", callback=self.Commit, default=True)
[188]266        OWGUI.rubber(self.controlArea)
[195]267       
[188]268        spliter = QSplitter(Qt.Vertical, self.mainArea)
269        self.pathwayView = PathwayView(self, spliter)
[195]270        self.mainArea.layout().addWidget(spliter)
[188]271
[195]272        self.listView = QTreeWidget(spliter)
273        spliter.addWidget(self.listView)
274       
275        self.listView.setAllColumnsShowFocus(1)
276        self.listView.setColumnCount(4)
[1534]277        self.listView.setHeaderLabels(["Pathway", "P value", 
278                                       "Genes", "Reference"])
[195]279
280        self.listView.setSelectionMode(QAbstractItemView.SingleSelection)
281           
282        self.listView.setSortingEnabled(True)
[1534]283       
[188]284        self.listView.setMaximumHeight(200)
285       
[1534]286        self.connect(self.listView,
287                     SIGNAL("itemSelectionChanged()"),
288                     self.UpdatePathwayView)
[188]289       
[1534]290        self.connect(self.graphButton,
291                     SIGNAL("clicked()"),
292                     self.saveGraph)
[1525]293       
[195]294        self.ctrlPressed = False
[188]295        self.selectedObjects = defaultdict(list)
[212]296        self.data = None
[188]297        self.refData = None
298       
[898]299        self.resize(800, 600)
300       
[1534]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)
[1733]310
[1003]311    def UpdateOrganismComboBox(self):
[1582]312        # First try to import suds
313        try:
[1733]314            import slumber
[1582]315        except ImportError:
316            QMessageBox.warning(self,
[1733]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
[1003]323        try:
[1534]324            genome = obiKEGG.KEGGGenome()
[1733]325
326            self.allOrganismCodes = genome
327
[1003]328            essential = genome.essential_organisms()
[1534]329            common = genome.common_organisms()
330            common = [c for c in common if c not in essential]
331
[1733]332            # TODO: Add option to specify additional organisms not
[1534]333            # in the common list.
334
[1733]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]
[1003]350            self.organismComboBox.addItems(items)
[1733]351
[1003]352        finally:
[1534]353            self.setEnabled(True)
354            self.infoLabel.setText("No data on input\n")
[1733]355            self.signalManager.freeze(self).pop()
[1003]356
[1534]357    def Clear(self):
[1733]358        """
359        Clear the widget state.
360        """
[1534]361        self.infoLabel.setText("No data on input\n")
362        self.listView.clear()
363        self.ClearPathway()
[1733]364
[1534]365        self.send("Selected Examples", None)
366        self.send("Unselected Examples", None)
[1733]367
[1534]368    def ClearPathway(self):
369        self.pathwayView.SetPathway(None)
370        self.selectedObjects = defaultdict(list)
[1003]371       
[188]372    def SetData(self, data=None):
373        self.closeContext()
374        self.data = data
[1248]375        self.warning(0)
[1534]376        if data is not None:
[1142]377            self.SetGeneAttrCombo()
[1118]378            taxid = data_hints.get_hint(data, "taxid", None)
[1142]379            if taxid:
380                try:
381                    code = obiKEGG.from_taxid(taxid)
382                    self.organismIndex = self.organismCodes.index(code)
383                except Exception, ex:
[1534]384#                    self.log.exception(self, level=self.log.INFO)
[1142]385                    print ex, taxid
[1099]386           
[1118]387            self.useAttrNames = data_hints.get_hint(data, "genesinrows", self.useAttrNames)
[1099]388           
[188]389            self.openContext("", data)
390        else:
[1534]391            self.Clear()
392           
393        self.has_new_data = True
[188]394
395    def SetRefData(self, data=None):
396        self.refData = data
[1534]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):
[188]402            self.Update()
[1534]403           
404            self.has_new_data = False
405            self.has_new_reference_set = False
406       
[188]407    def UseAttrNamesCallback(self):
408        self.Update()
409
[1534]410    def OrganismSelectionCallback(self):
411        self.Update()
412       
[1142]413    def SetGeneAttrCombo(self):
[1534]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)
[188]419        self.geneAttrCombo.clear()
[1534]420       
[195]421        self.geneAttrCombo.addItems([var.name for var in self.geneAttrCandidates])
[1733]422
[188]423    def UpdateListView(self):
[1248]424        self.bestPValueItem = None
[188]425        self.listView.clear()
[212]426        if not self.data:
427            return
[1733]428
[1003]429        allPathways = self.org.pathways()
430        allRefPathways = obiKEGG.pathways("map")
[1733]431
[188]432        items = []
[1606]433        self.progressBarInit()
[1534]434        kegg_pathways = obiKEGG.KEGGPathways()
[1606]435        kegg_pathways.pre_cache(self.pathways.keys(),
436                                progress_callback=self.progressBarSet)
437        self.progressBarFinished()
[1733]438
439        org_code = self.organismCodes[min(self.organismIndex,
440                                          len(self.organismCodes)-1)]
441
[519]442        if self.showOrthology:
[1003]443            self.koOrthology = obiKEGG.KEGGBrite("ko00001")
[188]444            self.listView.setRootIsDecorated(True)
445            path_ids = set([s[-5:] for s in self.pathways.keys()])
[1733]446
[1000]447            def _walkCollect(koEntry):
448                num = koEntry.title[:5] if koEntry.title else None
[1733]449                if num in path_ids:
450                    return [koEntry] + reduce(lambda li, c:li + _walkCollect(c), [child for child in koEntry.entries], [])
[188]451                else:
[1733]452                    c = reduce(lambda li, c: li + _walkCollect(c),
453                               [child for child in koEntry.entries], [])
[1000]454                    return c + (c and [koEntry] or [])
[1733]455
456            allClasses = reduce(lambda li1, li2: li1 + li2,
457                                [_walkCollect(c) for c in self.koOrthology], [])
458
[1000]459            def _walkCreate(koEntry, lvItem):
[195]460                item = QTreeWidgetItem(lvItem)
[1733]461                id = "path:" + org_code + koEntry.title[:5]
462
[1000]463                if koEntry.title[:5] in path_ids:
[1733]464                    p = kegg_pathways.get_entry(id)
[1534]465                    if p is None:
[1733]466                        # In case the genesets still have obsolete entries
[1534]467                        name = koEntry.title
468                    else:
469                        name = p.name
[188]470                    genes, p_value, ref = self.pathways[id]
[1534]471                    item.setText(0, name)
[188]472                    item.setText(1, "%.5f" % p_value)
[1733]473                    item.setText(2, "%i of %i" % (len(genes), len(self.genes)))
474                    item.setText(3, "%i of %i" % (ref, len(self.referenceGenes)))
[1534]475                    item.pathway_id = id if p is not None else None
[188]476                else:
[1733]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
[188]483                    if id in allPathways:
484                        item.pathway_id = id
[1000]485                    elif "path:map" + koEntry.title[:5] in allRefPathways:
486                        item.pathway_id = "path:map" + koEntry.title[:5]
[188]487                    else:
488                        item.pathway_id = None
[1733]489
[1577]490                for child in koEntry.entries:
[188]491                    if child in allClasses:
[1000]492                        _walkCreate(child, item)
[1733]493
[1000]494            for koEntry in self.koOrthology:
495                if koEntry in allClasses:
496                    _walkCreate(koEntry, self.listView)
[1733]497
[195]498            self.listView.update()
[188]499        else:
500            self.listView.setRootIsDecorated(False)
501            pathways = self.pathways.items()
[1733]502            pathways.sort(lambda a, b: cmp(a[1][1], b[1][1]))
503
[188]504            for id, (genes, p_value, ref) in pathways:
[206]505                item = QTreeWidgetItem(self.listView)
[1534]506                item.setText(0, kegg_pathways.get_entry(id).name)
[188]507                item.setText(1, "%.5f" % p_value)
[1733]508                item.setText(2, "%i of %i" % (len(genes), len(self.genes)))
509                item.setText(3, "%i of %i" % (ref, len(self.referenceGenes)))
[188]510                item.pathway_id = id
511                items.append(item)
[1733]512
[188]513        self.bestPValueItem = items and items[0] or None
[195]514        self.listView.expandAll()
[898]515        for i in range(4):
516            self.listView.resizeColumnToContents(i)
[1248]517           
518        if self.bestPValueItem:
519            self.listView.selectionModel().select(self.listView.indexFromItem(self.bestPValueItem), QItemSelectionModel.ClearAndSelect)
[188]520
[195]521    def UpdatePathwayView(self):
522        items = self.listView.selectedItems()
[188]523       
[195]524        if len(items) > 0:
525            item = items[0]
[1248]526        else:
527            item = None
[195]528           
[1248]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
[1534]535       
536        if USE_THREADING:
537            result = {}
538            def call(pathway_id):
539                result["pathway"] = p = obiKEGG.KEGGPathway(pathway_id)
[1579]540                p._get_kgml() # makes sure the kgml file is downloaded
541                p._get_image_filename() # makes sure the image is downloaded
[1534]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           
[1248]562        self.pathwayView.SetPathway(self.pathway, self.pathways.get(item.pathway_id, [[]])[0])
[195]563           
[1534]564    def UpdatePathwayViewTransform(self):
565        self.pathwayView.updateTransform()
566       
[188]567    def Update(self):
568        if not self.data:
569            return
570        self.error(0)
[211]571        self.information(0)
[1016]572        pb = OWGUI.ProgressBar(self, 100)
[188]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()]
[211]578            if any("," in gene for gene in genes):
579                genes = reduce(list.__add__, (split_and_strip(gene, ",") for gene in genes), [])
[1534]580                self.information(0, "Separators detected in input gene names. Assuming multiple genes per instance.")
[188]581        else:
[1534]582            self.error(0, "Cannot extract gene names from input")
[188]583            genes = []
[1003]584        org_code = self.organismCodes[min(self.organismIndex, len(self.organismCodes)-1)]
[1534]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)
[1331]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)) 
[1534]615       
[211]616        self.information(1)
[188]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()]
[211]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.")
[1534]626            uniqueRefGenes, conflicting, unknown = org.get_unique_gene_ids(set(reference), self.caseSensitive)
[188]627            self.referenceGenes = reference = uniqueRefGenes.keys()
628        else:
[1534]629            self.referenceGenes = reference = org.get_genes()
[188]630        self.uniqueGenesDict = uniqueGenes
631        self.genes = uniqueGenes.keys()
632        self.revUniqueGenesDict = dict([(val, key) for key, val in self.uniqueGenesDict.items()])
[1534]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):
[1554]640            orngServerFiles.update(obiGeneSets.sfdomain, "index.pck")
641            kegg_gs_collections = list(obiGeneSets.collections((("KEGG", "pathways"), taxid)))
[1534]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,
[1606]658                                                  lambda value:self.progressBarSet(value))}
[1534]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')
[1606]672           
673           
[1534]674        else:
675            self.pathways = org.get_enriched_pathways(self.genes, reference,
[1606]676                                                      callback=lambda value: self.progressBarSet(value))
[1534]677       
678        self.org = org
[1248]679        if not self.pathways:
680            self.warning(0, "No enriched pathways found.")
681        else:
682            self.warning(0)
[1534]683       
[188]684        self.UpdateListView()
[1016]685        pb.finish()
[1534]686   
[188]687
688    def SelectObjects(self, objs):
689        if (not self.selectedObjects or self.ctrlPressed) and not objs:
690            return
691        if self.ctrlPressed:
[1000]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]
[188]698                else:
[1000]699                    self.selectedObjects[graphics].append(id)
[188]700        else:
701            self.selectedObjects.clear()
[1000]702            for id, graphics in objs:
703                graphics = tuple(sorted(graphics.items()))
704                self.selectedObjects[graphics].append(id)
[188]705        if self.autoCommit:
706            self.Commit()
707           
708
709    def Commit(self):
[212]710        if self.data:
[1142]711            selectedItems = self.pathwayView.scene().selectedItems()
712            selectedGenes = reduce(set.union, [item.marked_objects for item in selectedItems], set())
713           
[212]714            if self.useAttrNames:
715                selectedVars = [self.data.domain[self.uniqueGenesDict[gene]] for gene in selectedGenes]
716                newDomain = orange.Domain(selectedVars ,0)
[1099]717                data = orange.ExampleTable(newDomain, self.data)
718                self.send("Selected Examples", data)
[1142]719            elif self.geneAttrCandidates:
[212]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)
[1099]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)
[188]742        else:
[212]743            self.send("Selected Examples", None)
744            self.send("Unselected Examples", None)
[188]745       
[1606]746    def ClearCache(self):
[1716]747        from ..obiKEGG import caching
[1606]748        try:
749            caching.clear_cache()
750        except Exception, ex:
751            QMessageBox.warning(self, "Cache clear", 
752                ex.args[0])
753           
754       
[188]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)
[1248]766           
767    def onStateChange(self, stateType, id, text):
768        if stateType == "Warning":
769            self.pathwayView._userMessage = text
770            self.pathwayView.viewport().update()
771           
[1525]772    def saveGraph(self):
[1632]773        from Orange.OrangeWidgets.OWDlgs import OWChooseImageSizeDlg
[1525]774        sizeDlg = OWChooseImageSizeDlg(self.pathwayView.scene(), parent=self)
775        sizeDlg.exec_()
[188]776
[1534]777    @pyqtSignature("queuedInvoke(PyQt_PyObject)")
778    def queuedInvoke(self, func):
779        func()
[1733]780
[1534]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
[1733]788
[1534]789    def onDeleteWidget(self):
790        """ Called before the widget is removed from the canvas.
791        """
792        self.org = None
[1733]793        gc.collect()  # Force collection
[1534]794       
795    def UpdateToLatestPathways(self):
796        pass       
797         
[1632]798from .. import obiProb
[1534]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:
[1554]818            callback(100.0 * i / len(genesets))
[1534]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                )
[1733]826
827if __name__ == "__main__":
[188]828    app = QApplication(sys.argv)
[1534]829    data = orange.ExampleTable("brown-selected.tab")
[188]830    w = OWKEGGPathwayBrowser()
[1142]831    w.UpdateOrganismComboBox()
[188]832    w.show()
[1554]833    w.SetData(orange.ExampleTable(data[:]))
[1534]834    QTimer.singleShot(10, w.handleNewSignals)
[1733]835
[206]836    app.exec_()
[188]837    w.saveSettings()
Note: See TracBrowser for help on using the repository browser.