source: orange-bioinformatics/_bioinformatics/widgets/OWKEGGPathwayBrowser.py @ 1740:0ef1058694a2

Revision 1740:0ef1058694a2, 33.4 KB checked in by Ales Erjavec <ales.erjavec@…>, 13 months ago (diff)

Try guessing the gene attribute name.

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
[1740]16from operator import add, itemgetter
[1739]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
[1740]505        names_lower = [v.name.lower() for v in self.geneAttrCandidates]
506
507        scores = [(name == "gene", "gene" in name)
508                  for name in names_lower]
509        imax, _ = max(enumerate(scores), key=itemgetter(1))
510        self.geneAttrIndex = imax
511
[188]512    def UpdateListView(self):
[1248]513        self.bestPValueItem = None
[188]514        self.listView.clear()
[212]515        if not self.data:
516            return
[1733]517
[1003]518        allPathways = self.org.pathways()
519        allRefPathways = obiKEGG.pathways("map")
[1733]520
[188]521        items = []
[1606]522        self.progressBarInit()
[1534]523        kegg_pathways = obiKEGG.KEGGPathways()
[1606]524        kegg_pathways.pre_cache(self.pathways.keys(),
525                                progress_callback=self.progressBarSet)
526        self.progressBarFinished()
[1733]527
528        org_code = self.organismCodes[min(self.organismIndex,
[1739]529                                          len(self.organismCodes) - 1)]
[1733]530
[519]531        if self.showOrthology:
[1003]532            self.koOrthology = obiKEGG.KEGGBrite("ko00001")
[188]533            self.listView.setRootIsDecorated(True)
534            path_ids = set([s[-5:] for s in self.pathways.keys()])
[1733]535
[1000]536            def _walkCollect(koEntry):
537                num = koEntry.title[:5] if koEntry.title else None
[1733]538                if num in path_ids:
[1739]539                    return ([koEntry] +
540                            reduce(lambda li, c: li + _walkCollect(c),
541                                   [child for child in koEntry.entries],
542                                   []))
[188]543                else:
[1733]544                    c = reduce(lambda li, c: li + _walkCollect(c),
[1739]545                               [child for child in koEntry.entries],
546                               [])
[1000]547                    return c + (c and [koEntry] or [])
[1733]548
549            allClasses = reduce(lambda li1, li2: li1 + li2,
[1739]550                                [_walkCollect(c) for c in self.koOrthology],
551                                [])
[1733]552
[1000]553            def _walkCreate(koEntry, lvItem):
[195]554                item = QTreeWidgetItem(lvItem)
[1733]555                id = "path:" + org_code + koEntry.title[:5]
556
[1000]557                if koEntry.title[:5] in path_ids:
[1733]558                    p = kegg_pathways.get_entry(id)
[1534]559                    if p is None:
[1733]560                        # In case the genesets still have obsolete entries
[1534]561                        name = koEntry.title
562                    else:
563                        name = p.name
[188]564                    genes, p_value, ref = self.pathways[id]
[1534]565                    item.setText(0, name)
[188]566                    item.setText(1, "%.5f" % p_value)
[1733]567                    item.setText(2, "%i of %i" % (len(genes), len(self.genes)))
568                    item.setText(3, "%i of %i" % (ref, len(self.referenceGenes)))
[1534]569                    item.pathway_id = id if p is not None else None
[188]570                else:
[1733]571                    if id in allPathways:
572                        text = kegg_pathways.get_entry(id).name
573                    else:
574                        text = koEntry.title
575                    item.setText(0, text)
576
[188]577                    if id in allPathways:
578                        item.pathway_id = id
[1000]579                    elif "path:map" + koEntry.title[:5] in allRefPathways:
580                        item.pathway_id = "path:map" + koEntry.title[:5]
[188]581                    else:
582                        item.pathway_id = None
[1733]583
[1577]584                for child in koEntry.entries:
[188]585                    if child in allClasses:
[1000]586                        _walkCreate(child, item)
[1733]587
[1000]588            for koEntry in self.koOrthology:
589                if koEntry in allClasses:
590                    _walkCreate(koEntry, self.listView)
[1733]591
[195]592            self.listView.update()
[188]593        else:
594            self.listView.setRootIsDecorated(False)
595            pathways = self.pathways.items()
[1733]596            pathways.sort(lambda a, b: cmp(a[1][1], b[1][1]))
597
[188]598            for id, (genes, p_value, ref) in pathways:
[206]599                item = QTreeWidgetItem(self.listView)
[1534]600                item.setText(0, kegg_pathways.get_entry(id).name)
[188]601                item.setText(1, "%.5f" % p_value)
[1733]602                item.setText(2, "%i of %i" % (len(genes), len(self.genes)))
603                item.setText(3, "%i of %i" % (ref, len(self.referenceGenes)))
[188]604                item.pathway_id = id
605                items.append(item)
[1733]606
[188]607        self.bestPValueItem = items and items[0] or None
[195]608        self.listView.expandAll()
[898]609        for i in range(4):
610            self.listView.resizeColumnToContents(i)
[1739]611
[1248]612        if self.bestPValueItem:
[1739]613            index = self.listView.indexFromItem(self.bestPValueItem)
614            self.listView.selectionModel().select(
615                index, QItemSelectionModel.ClearAndSelect
616            )
[188]617
[195]618    def UpdatePathwayView(self):
619        items = self.listView.selectedItems()
[1739]620
[195]621        if len(items) > 0:
622            item = items[0]
[1248]623        else:
624            item = None
[1739]625
[1248]626        self.selectedObjects = defaultdict(list)
627        self.Commit()
628        item = item or self.bestPValueItem
629        if not item or not item.pathway_id:
630            self.pathwayView.SetPathway(None)
631            return
[1739]632
[1534]633        if USE_THREADING:
634            result = {}
[1739]635
[1534]636            def call(pathway_id):
637                result["pathway"] = p = obiKEGG.KEGGPathway(pathway_id)
[1739]638                p._get_kgml()  # makes sure the kgml file is downloaded
639                p._get_image_filename()  # makes sure the image is downloaded
640
[1534]641            self.setEnabled(False)
642            try:
[1739]643                thread = threading.Thread(None, call,
[1534]644                                          name="get_kgml_and_image",
645                                          args=(item.pathway_id,))
646                thread.start()
647                while thread.is_alive():
648                    thread.join(timeout=0.025)
649                    qApp.processEvents()
650            finally:
651                self.setEnabled(True)
652            if "pathway" in result:
653                self.pathway = result["pathway"]
654            else:
655                raise Exception("Could not get kgml and  pathway image")
656        else:
657            self.pathway = obiKEGG.KEGGPathway(item.pathway_id)
[1739]658
659        self.pathwayView.SetPathway(self.pathway,
660                                    self.pathways.get(item.pathway_id, [[]])[0])
661
[1534]662    def UpdatePathwayViewTransform(self):
663        self.pathwayView.updateTransform()
[1739]664
[188]665    def Update(self):
666        if not self.data:
667            return
668        self.error(0)
[211]669        self.information(0)
[1016]670        pb = OWGUI.ProgressBar(self, 100)
[188]671        if self.useAttrNames:
672            genes = [str(v.name).strip() for v in self.data.domain.attributes]
673        elif self.geneAttrCandidates:
[1739]674            geneAttr = self.geneAttrCandidates[min(self.geneAttrIndex,
675                                                   len(self.geneAttrCandidates) - 1)]
676            genes = [str(e[geneAttr]) for e in self.data
677                     if not e[geneAttr].isSpecial()]
[211]678            if any("," in gene for gene in genes):
[1739]679                genes = reduce(add, (split_and_strip(gene, ",")
680                                     for gene in genes),
681                               [])
682                self.information(0,
683                                 "Separators detected in input gene names. "
684                                 "Assuming multiple genes per instance.")
[188]685        else:
[1534]686            self.error(0, "Cannot extract gene names from input")
[188]687            genes = []
[1739]688        org_code = self.organismCodes[min(self.organismIndex,
689                                          len(self.organismCodes) - 1)]
690
[1534]691        if USE_THREADING:
692            result = {}
[1739]693
[1534]694            def callable(*args, **kwargs):
695                result["org"] = org = obiKEGG.KEGGOrganism(org_code)
696                # Make sure genes are cached for global reference set
697                result["genes"] = org.genes.keys()
[1739]698
[1534]699            self.setEnabled(False)
700            try:
701                thread = threading.Thread(None, callable,
702                                          name="get_organism_genes",
703                                          )
704                thread.start()
705                while thread.is_alive():
706                    thread.join(timeout=0.025)
707                    qApp.processEvents()
708            finally:
709                self.setEnabled(True)
[1739]710
[1534]711            if "org" in result:
712                org = result["org"]
713            else:
714                raise Exception("Could not get organism genes")
715        else:
716            org = obiKEGG.KEGGOrganism(org_code)
[1739]717
718        uniqueGenes, _, _ = org.get_unique_gene_ids(set(genes),
719                                                    self.caseSensitive)
[1331]720        genesCount = len(set(genes))
[1739]721        self.infoLabel.setText("%i unique gene names on input\n%i (%.1f%%) "
722                               "genes names matched" %
723                               (genesCount, len(uniqueGenes),
724                                100.0 * len(uniqueGenes) / genesCount if genes else 0.0))
725
[211]726        self.information(1)
[188]727        if self.useReference and self.refData:
728            if self.useAttrNames:
729                reference = [str(v.name).strip() for v in self.refData]
730            else:
[1739]731                geneAttr = self.geneAttrCandidates[min(self.geneAttrIndex,
732                                                       len(self.geneAttrCandidates) - 1)]
733                reference = [str(e[geneAttr]) for e in self.refData
734                             if not e[geneAttr].isSpecial()]
[211]735                if any("," in gene for gene in reference):
[1739]736                    reference = reduce(add, (split_and_strip(gene, ",")
737                                             for gene in reference),
738                                       [])
739                    self.information(1,
740                                     "Separators detected in reference gene "
741                                     "names. Assuming multiple genes per "
742                                     "example.")
743            uniqueRefGenes, _, _ = org.get_unique_gene_ids(set(reference),
744                                                           self.caseSensitive)
[188]745            self.referenceGenes = reference = uniqueRefGenes.keys()
746        else:
[1534]747            self.referenceGenes = reference = org.get_genes()
[188]748        self.uniqueGenesDict = uniqueGenes
749        self.genes = uniqueGenes.keys()
[1739]750        self.revUniqueGenesDict = dict([(val, key) for key, val in
751                                        self.uniqueGenesDict.items()])
752
[1534]753        taxid = obiKEGG.to_taxid(org.org_code)
[1739]754        r_tax_map = dict((v, k) for k, v in
755                         obiKEGG.KEGGGenome.TAXID_MAP.items())
[1534]756        if taxid in r_tax_map:
757            taxid = r_tax_map[taxid]
[1739]758
[1534]759        with orngServerFiles.DownloadProgress.setredirect(self.progressBarSet):
[1554]760            orngServerFiles.update(obiGeneSets.sfdomain, "index.pck")
[1739]761            kegg_gs_collections = \
762                list(obiGeneSets.collections((("KEGG", "pathways"), taxid)))
763
[1534]764        if USE_THREADING:
765            result = {}
[1739]766
[1534]767            def callable(*args, **kwargs):
768#                result["result"] = org.get_enriched_pathways(*args, **kwargs)
769                result["result"] = pathway_enrichment(*args, **kwargs)
[1739]770
[1534]771            self.setEnabled(False)
772            try:
[1739]773                thread = threading.Thread(
774                    None, callable,
775                    name="get_enriched_pathways",
776                    args=(kegg_gs_collections,
777                          self.genes,
778                          reference),
779                    kwargs={"callback":
780                            threading_queued_invoke(
781                                self,
782                                lambda value: self.progressBarSet(value))}
783                )
784
[1534]785                thread.start()
786                while thread.is_alive():
787                    thread.join(timeout=0.025)
788                    qApp.processEvents()
789            finally:
790                self.setEnabled(True)
[1739]791
[1534]792            if "result" in result:
793                self.pathways = result["result"]
794            else:
795                raise Exception('Could not get enriched pathways')
[1739]796
[1534]797        else:
[1739]798            self.pathways = org.get_enriched_pathways(
799                self.genes, reference,
800                callback=self.progressBarSet
801            )
802
[1534]803        self.org = org
[1248]804        if not self.pathways:
805            self.warning(0, "No enriched pathways found.")
806        else:
807            self.warning(0)
[1739]808
[188]809        self.UpdateListView()
[1016]810        pb.finish()
[188]811
812    def Commit(self):
[212]813        if self.data:
[1142]814            selectedItems = self.pathwayView.scene().selectedItems()
[1739]815            selectedGenes = reduce(set.union, [item.marked_objects
816                                               for item in selectedItems],
817                                   set())
818
[212]819            if self.useAttrNames:
[1739]820                selectedVars = [self.data.domain[self.uniqueGenesDict[gene]]
821                                for gene in selectedGenes]
822                newDomain = Orange.data.Domain(selectedVars, 0)
823                data = Orange.data.Table(newDomain, self.data)
[1099]824                self.send("Selected Examples", data)
[1142]825            elif self.geneAttrCandidates:
[1739]826                geneAttr = self.geneAttrCandidates[min(self.geneAttrIndex,
827                                                       len(self.geneAttrCandidates) - 1)]
[212]828                selectedExamples = []
829                otherExamples = []
830                for ex in self.data:
[1739]831                    names = [self.revUniqueGenesDict.get(name, None)
832                             for name in split_and_strip(str(ex[geneAttr]), ",")]
[212]833                    if any(name and name in selectedGenes for name in names):
834                        selectedExamples.append(ex)
835                    else:
836                        otherExamples.append(ex)
[1739]837
[1099]838                if selectedExamples:
[1739]839                    selectedExamples = Orange.data.Table(selectedExamples)
[1099]840                else:
841                    selectedExamples = None
[1739]842
[1099]843                if otherExamples:
[1739]844                    otherExamples = Orange.data.Table(otherExamples)
[1099]845                else:
846                    otherExamples = None
[1739]847
[1099]848                self.send("Selected Examples", selectedExamples)
849                self.send("Unselected Examples", otherExamples)
[188]850        else:
[212]851            self.send("Selected Examples", None)
852            self.send("Unselected Examples", None)
[1739]853
[1606]854    def ClearCache(self):
[1716]855        from ..obiKEGG import caching
[1606]856        try:
857            caching.clear_cache()
858        except Exception, ex:
[1739]859            QMessageBox.warning(self, "Cache clear", ex.args[0])
[188]860
[1248]861    def onStateChange(self, stateType, id, text):
862        if stateType == "Warning":
863            self.pathwayView._userMessage = text
864            self.pathwayView.viewport().update()
[1739]865
[1525]866    def saveGraph(self):
[1632]867        from Orange.OrangeWidgets.OWDlgs import OWChooseImageSizeDlg
[1525]868        sizeDlg = OWChooseImageSizeDlg(self.pathwayView.scene(), parent=self)
869        sizeDlg.exec_()
[188]870
[1534]871    @pyqtSignature("queuedInvoke(PyQt_PyObject)")
872    def queuedInvoke(self, func):
873        func()
[1733]874
[1534]875    def progressBarSet(self, value):
876        if not getattr(self, "_in_progress_update", False):
877            self._in_progress_update = True
878            try:
879                OWWidget.progressBarSet(self, value)
880            finally:
881                self._in_progress_update = False
[1733]882
[1534]883    def onDeleteWidget(self):
[1739]884        """
885        Called before the widget is removed from the canvas.
[1534]886        """
887        self.org = None
[1733]888        gc.collect()  # Force collection
[1739]889
890
[1632]891from .. import obiProb
[1534]892
[1739]893
[1534]894def pathway_enrichment(genesets, genes, reference, prob=None, callback=None):
895    result_sets = []
896    p_values = []
897    if prob is None:
898        prob = obiProb.Hypergeometric()
[1739]899
[1534]900    for i, gs in enumerate(genesets):
901        cluster = gs.genes.intersection(genes)
902        ref = gs.genes.intersection(reference)
903        k = len(cluster)
904        N = len(reference)
905        m = len(ref)
906        n = len(genes)
907        if k:
908            p_val = prob.p_value(k, N, m, n)
909            result_sets.append((gs.id, cluster, ref))
910            p_values.append(p_val)
911        if callback is not None:
[1554]912            callback(100.0 * i / len(genesets))
[1739]913
[1534]914    # FDR correction
915    p_values = obiProb.FDR(p_values)
[1739]916
917    return dict([(id, (genes, p_val, len(ref)))
918                 for (id, genes, ref), p_val in zip(result_sets, p_values)])
919
[1733]920
921if __name__ == "__main__":
[188]922    app = QApplication(sys.argv)
[1739]923    data = Orange.data.Table("brown-selected.tab")
[188]924    w = OWKEGGPathwayBrowser()
[1142]925    w.UpdateOrganismComboBox()
[188]926    w.show()
[1739]927    w.SetData(Orange.data.Table(data[:]))
[1534]928    QTimer.singleShot(10, w.handleNewSignals)
[1733]929
[206]930    app.exec_()
[188]931    w.saveSettings()
Note: See TracBrowser for help on using the repository browser.