source: orange-bioinformatics/_bioinformatics/widgets/OWKEGGPathwayBrowser.py @ 1739:939281048915

Revision 1739:939281048915, 33.1 KB checked in by Ales Erjavec <ales.erjavec@…>, 13 months ago (diff)

KEGG Pathways widget code style fixes

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