source: orange-bioinformatics/_bioinformatics/widgets/OWKEGGPathwayBrowser.py @ 1751:a3db39d180ab

Revision 1751:a3db39d180ab, 33.5 KB checked in by Ales Erjavec <ales.erjavec@…>, 12 months ago (diff)

Fixed KEGG Pathway Browser organism list initialization.

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
[1748]302        if self.signalManager:
303            self.signalManager.freeze(self).push()
[1739]304
305        # Selection of genes attribute
[1003]306        box = OWGUI.widgetBox(self.controlArea, "Gene attribute")
[1534]307        self.geneAttrCombo = OWGUI.comboBox(box, self, "geneAttrIndex",
308                                            callback=self.Update)
[1739]309
[1534]310        OWGUI.checkBox(box, self, "useAttrNames",
[1739]311                       "Use variable names",
[1534]312                       disables=[(-1, self.geneAttrCombo)],
313                       callback=self.UseAttrNamesCallback)
[1739]314
[216]315        self.geneAttrCombo.setDisabled(bool(self.useAttrNames))
[1739]316
[188]317        OWGUI.separator(self.controlArea)
[1739]318
[1534]319        OWGUI.checkBox(self.controlArea, self, "useReference",
320                       "From signal",
321                       box="Reference",
322                       callback=self.Update)
[1739]323
[188]324        OWGUI.separator(self.controlArea)
325
[1534]326        OWGUI.checkBox(self.controlArea, self, "showOrthology",
327                       "Show pathways in full orthology",
328                       box="Orthology",
329                       callback=self.UpdateListView)
[1739]330
[1534]331        OWGUI.checkBox(self.controlArea, self, "autoResize",
332                       "Resize to fit",
333                       box="Image",
334                       callback=self.UpdatePathwayViewTransform)
[1739]335
[1606]336        box = OWGUI.widgetBox(self.controlArea, "Cache Control")
[1739]337
338        OWGUI.button(box, self, "Clear cache",
[1606]339                     callback=self.ClearCache,
340                     tooltip="Clear all locally cached KEGG data.")
[1739]341
[188]342        OWGUI.separator(self.controlArea)
343
344        box = OWGUI.widgetBox(self.controlArea, "Selection")
345        OWGUI.checkBox(box, self, "autoCommit", "Commit on update")
[1378]346        OWGUI.button(box, self, "Commit", callback=self.Commit, default=True)
[188]347        OWGUI.rubber(self.controlArea)
[1739]348
[188]349        spliter = QSplitter(Qt.Vertical, self.mainArea)
350        self.pathwayView = PathwayView(self, spliter)
[195]351        self.mainArea.layout().addWidget(spliter)
[188]352
[195]353        self.listView = QTreeWidget(spliter)
354        spliter.addWidget(self.listView)
[1739]355
[195]356        self.listView.setAllColumnsShowFocus(1)
357        self.listView.setColumnCount(4)
[1739]358        self.listView.setHeaderLabels(["Pathway", "P value",
[1534]359                                       "Genes", "Reference"])
[195]360
[1739]361        self.listView.setSelectionMode(QTreeWidget.SingleSelection)
362
[195]363        self.listView.setSortingEnabled(True)
[1739]364
[188]365        self.listView.setMaximumHeight(200)
[1739]366
[1534]367        self.connect(self.listView,
368                     SIGNAL("itemSelectionChanged()"),
369                     self.UpdatePathwayView)
[1739]370
[1534]371        self.connect(self.graphButton,
372                     SIGNAL("clicked()"),
373                     self.saveGraph)
[1739]374
[195]375        self.ctrlPressed = False
[188]376        self.selectedObjects = defaultdict(list)
[212]377        self.data = None
[188]378        self.refData = None
[1739]379
[898]380        self.resize(800, 600)
[1739]381
[1534]382        self.connect(self,
383                     SIGNAL("widgetStateChanged(QString, int, QString)"),
384                     self.onStateChange)
[1739]385
[1534]386        self.has_new_data = False
387        self.has_new_reference_set = False
[1739]388
[1534]389        self.setEnabled(False)
[1751]390        self.infoLabel.setText("Fetching organism definitions\n")
[1534]391        QTimer.singleShot(100, self.UpdateOrganismComboBox)
[1733]392
[1003]393    def UpdateOrganismComboBox(self):
[1739]394        # First try to import slumber
[1582]395        try:
[1733]396            import slumber
[1582]397        except ImportError:
398            QMessageBox.warning(self,
[1733]399                "'slumber' library required.",
400                '<p>Please install '
401                '<a href="http://pypi.python.org/pypi/slumber">slumber</a> '
402                'library to use KEGG Pathways widget.</p>'
403            )
404
[1003]405        try:
[1534]406            genome = obiKEGG.KEGGGenome()
[1733]407
408            self.allOrganismCodes = genome
409
[1003]410            essential = genome.essential_organisms()
[1534]411            common = genome.common_organisms()
412            common = [c for c in common if c not in essential]
413
[1733]414            # TODO: Add option to specify additional organisms not
[1534]415            # in the common list.
416
[1733]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]
[1751]430            self.organismComboBox.clear()
[1003]431            self.organismComboBox.addItems(items)
[1751]432            self.organismComboBox.setCurrentIndex(self.organismIndex)
[1003]433        finally:
[1534]434            self.setEnabled(True)
435            self.infoLabel.setText("No data on input\n")
[1748]436            if self.signalManager:
437                self.signalManager.freeze(self).pop()
[1003]438
[1534]439    def Clear(self):
[1733]440        """
441        Clear the widget state.
442        """
[1534]443        self.infoLabel.setText("No data on input\n")
444        self.listView.clear()
445        self.ClearPathway()
[1733]446
[1534]447        self.send("Selected Examples", None)
448        self.send("Unselected Examples", None)
[1733]449
[1534]450    def ClearPathway(self):
451        self.pathwayView.SetPathway(None)
452        self.selectedObjects = defaultdict(list)
[1739]453
[188]454    def SetData(self, data=None):
455        self.closeContext()
456        self.data = data
[1248]457        self.warning(0)
[1534]458        if data is not None:
[1142]459            self.SetGeneAttrCombo()
[1118]460            taxid = data_hints.get_hint(data, "taxid", None)
[1142]461            if taxid:
462                try:
463                    code = obiKEGG.from_taxid(taxid)
464                    self.organismIndex = self.organismCodes.index(code)
465                except Exception, ex:
466                    print ex, taxid
[1739]467
468            self.useAttrNames = data_hints.get_hint(data, "genesinrows",
469                                                    self.useAttrNames)
470
[188]471            self.openContext("", data)
472        else:
[1534]473            self.Clear()
[1739]474
[1534]475        self.has_new_data = True
[188]476
477    def SetRefData(self, data=None):
478        self.refData = data
[1534]479        self.has_new_reference_set = True
[1739]480
[1534]481    def handleNewSignals(self):
482        if self.has_new_data or (self.has_new_reference_set and \
483                                 self.useReference):
[188]484            self.Update()
[1739]485
[1534]486            self.has_new_data = False
487            self.has_new_reference_set = False
[1739]488
[188]489    def UseAttrNamesCallback(self):
490        self.Update()
491
[1534]492    def OrganismSelectionCallback(self):
493        self.Update()
[1739]494
[1142]495    def SetGeneAttrCombo(self):
[1739]496        self.geneAttrCandidates = self.data.domain.variables + \
[1534]497                                  self.data.domain.getmetas().values()
[1739]498        self.geneAttrCandidates = filter(
499            lambda v: isinstance(v, (Orange.feature.Discrete,
500                                     Orange.feature.String)),
501            self.geneAttrCandidates)
502
[188]503        self.geneAttrCombo.clear()
[1739]504
505        self.geneAttrCombo.addItems([var.name for var in
506                                     self.geneAttrCandidates])
[1733]507
[1740]508        names_lower = [v.name.lower() for v in self.geneAttrCandidates]
509
510        scores = [(name == "gene", "gene" in name)
511                  for name in names_lower]
512        imax, _ = max(enumerate(scores), key=itemgetter(1))
513        self.geneAttrIndex = imax
514
[188]515    def UpdateListView(self):
[1248]516        self.bestPValueItem = None
[188]517        self.listView.clear()
[212]518        if not self.data:
519            return
[1733]520
[1003]521        allPathways = self.org.pathways()
522        allRefPathways = obiKEGG.pathways("map")
[1733]523
[188]524        items = []
[1606]525        self.progressBarInit()
[1534]526        kegg_pathways = obiKEGG.KEGGPathways()
[1606]527        kegg_pathways.pre_cache(self.pathways.keys(),
528                                progress_callback=self.progressBarSet)
529        self.progressBarFinished()
[1733]530
531        org_code = self.organismCodes[min(self.organismIndex,
[1739]532                                          len(self.organismCodes) - 1)]
[1733]533
[519]534        if self.showOrthology:
[1003]535            self.koOrthology = obiKEGG.KEGGBrite("ko00001")
[188]536            self.listView.setRootIsDecorated(True)
537            path_ids = set([s[-5:] for s in self.pathways.keys()])
[1733]538
[1000]539            def _walkCollect(koEntry):
540                num = koEntry.title[:5] if koEntry.title else None
[1733]541                if num in path_ids:
[1739]542                    return ([koEntry] +
543                            reduce(lambda li, c: li + _walkCollect(c),
544                                   [child for child in koEntry.entries],
545                                   []))
[188]546                else:
[1733]547                    c = reduce(lambda li, c: li + _walkCollect(c),
[1739]548                               [child for child in koEntry.entries],
549                               [])
[1000]550                    return c + (c and [koEntry] or [])
[1733]551
552            allClasses = reduce(lambda li1, li2: li1 + li2,
[1739]553                                [_walkCollect(c) for c in self.koOrthology],
554                                [])
[1733]555
[1000]556            def _walkCreate(koEntry, lvItem):
[195]557                item = QTreeWidgetItem(lvItem)
[1733]558                id = "path:" + org_code + koEntry.title[:5]
559
[1000]560                if koEntry.title[:5] in path_ids:
[1733]561                    p = kegg_pathways.get_entry(id)
[1534]562                    if p is None:
[1733]563                        # In case the genesets still have obsolete entries
[1534]564                        name = koEntry.title
565                    else:
566                        name = p.name
[188]567                    genes, p_value, ref = self.pathways[id]
[1534]568                    item.setText(0, name)
[188]569                    item.setText(1, "%.5f" % p_value)
[1733]570                    item.setText(2, "%i of %i" % (len(genes), len(self.genes)))
571                    item.setText(3, "%i of %i" % (ref, len(self.referenceGenes)))
[1534]572                    item.pathway_id = id if p is not None else None
[188]573                else:
[1733]574                    if id in allPathways:
575                        text = kegg_pathways.get_entry(id).name
576                    else:
577                        text = koEntry.title
578                    item.setText(0, text)
579
[188]580                    if id in allPathways:
581                        item.pathway_id = id
[1000]582                    elif "path:map" + koEntry.title[:5] in allRefPathways:
583                        item.pathway_id = "path:map" + koEntry.title[:5]
[188]584                    else:
585                        item.pathway_id = None
[1733]586
[1577]587                for child in koEntry.entries:
[188]588                    if child in allClasses:
[1000]589                        _walkCreate(child, item)
[1733]590
[1000]591            for koEntry in self.koOrthology:
592                if koEntry in allClasses:
593                    _walkCreate(koEntry, self.listView)
[1733]594
[195]595            self.listView.update()
[188]596        else:
597            self.listView.setRootIsDecorated(False)
598            pathways = self.pathways.items()
[1733]599            pathways.sort(lambda a, b: cmp(a[1][1], b[1][1]))
600
[188]601            for id, (genes, p_value, ref) in pathways:
[206]602                item = QTreeWidgetItem(self.listView)
[1534]603                item.setText(0, kegg_pathways.get_entry(id).name)
[188]604                item.setText(1, "%.5f" % p_value)
[1733]605                item.setText(2, "%i of %i" % (len(genes), len(self.genes)))
606                item.setText(3, "%i of %i" % (ref, len(self.referenceGenes)))
[188]607                item.pathway_id = id
608                items.append(item)
[1733]609
[188]610        self.bestPValueItem = items and items[0] or None
[195]611        self.listView.expandAll()
[898]612        for i in range(4):
613            self.listView.resizeColumnToContents(i)
[1739]614
[1248]615        if self.bestPValueItem:
[1739]616            index = self.listView.indexFromItem(self.bestPValueItem)
617            self.listView.selectionModel().select(
618                index, QItemSelectionModel.ClearAndSelect
619            )
[188]620
[195]621    def UpdatePathwayView(self):
622        items = self.listView.selectedItems()
[1739]623
[195]624        if len(items) > 0:
625            item = items[0]
[1248]626        else:
627            item = None
[1739]628
[1248]629        self.selectedObjects = defaultdict(list)
630        self.Commit()
631        item = item or self.bestPValueItem
632        if not item or not item.pathway_id:
633            self.pathwayView.SetPathway(None)
634            return
[1739]635
[1534]636        if USE_THREADING:
637            result = {}
[1739]638
[1534]639            def call(pathway_id):
640                result["pathway"] = p = obiKEGG.KEGGPathway(pathway_id)
[1739]641                p._get_kgml()  # makes sure the kgml file is downloaded
642                p._get_image_filename()  # makes sure the image is downloaded
643
[1534]644            self.setEnabled(False)
645            try:
[1739]646                thread = threading.Thread(None, call,
[1534]647                                          name="get_kgml_and_image",
648                                          args=(item.pathway_id,))
649                thread.start()
650                while thread.is_alive():
651                    thread.join(timeout=0.025)
652                    qApp.processEvents()
653            finally:
654                self.setEnabled(True)
655            if "pathway" in result:
656                self.pathway = result["pathway"]
657            else:
658                raise Exception("Could not get kgml and  pathway image")
659        else:
660            self.pathway = obiKEGG.KEGGPathway(item.pathway_id)
[1739]661
662        self.pathwayView.SetPathway(self.pathway,
663                                    self.pathways.get(item.pathway_id, [[]])[0])
664
[1534]665    def UpdatePathwayViewTransform(self):
666        self.pathwayView.updateTransform()
[1739]667
[188]668    def Update(self):
669        if not self.data:
670            return
671        self.error(0)
[211]672        self.information(0)
[1016]673        pb = OWGUI.ProgressBar(self, 100)
[188]674        if self.useAttrNames:
675            genes = [str(v.name).strip() for v in self.data.domain.attributes]
676        elif self.geneAttrCandidates:
[1739]677            geneAttr = self.geneAttrCandidates[min(self.geneAttrIndex,
678                                                   len(self.geneAttrCandidates) - 1)]
679            genes = [str(e[geneAttr]) for e in self.data
680                     if not e[geneAttr].isSpecial()]
[211]681            if any("," in gene for gene in genes):
[1739]682                genes = reduce(add, (split_and_strip(gene, ",")
683                                     for gene in genes),
684                               [])
685                self.information(0,
686                                 "Separators detected in input gene names. "
687                                 "Assuming multiple genes per instance.")
[188]688        else:
[1534]689            self.error(0, "Cannot extract gene names from input")
[188]690            genes = []
[1739]691        org_code = self.organismCodes[min(self.organismIndex,
692                                          len(self.organismCodes) - 1)]
693
[1534]694        if USE_THREADING:
695            result = {}
[1739]696
[1534]697            def callable(*args, **kwargs):
698                result["org"] = org = obiKEGG.KEGGOrganism(org_code)
699                # Make sure genes are cached for global reference set
700                result["genes"] = org.genes.keys()
[1739]701
[1534]702            self.setEnabled(False)
703            try:
704                thread = threading.Thread(None, callable,
705                                          name="get_organism_genes",
706                                          )
707                thread.start()
708                while thread.is_alive():
709                    thread.join(timeout=0.025)
710                    qApp.processEvents()
711            finally:
712                self.setEnabled(True)
[1739]713
[1534]714            if "org" in result:
715                org = result["org"]
716            else:
717                raise Exception("Could not get organism genes")
718        else:
719            org = obiKEGG.KEGGOrganism(org_code)
[1739]720
721        uniqueGenes, _, _ = org.get_unique_gene_ids(set(genes),
722                                                    self.caseSensitive)
[1331]723        genesCount = len(set(genes))
[1739]724        self.infoLabel.setText("%i unique gene names on input\n%i (%.1f%%) "
725                               "genes names matched" %
726                               (genesCount, len(uniqueGenes),
727                                100.0 * len(uniqueGenes) / genesCount if genes else 0.0))
728
[211]729        self.information(1)
[188]730        if self.useReference and self.refData:
731            if self.useAttrNames:
732                reference = [str(v.name).strip() for v in self.refData]
733            else:
[1739]734                geneAttr = self.geneAttrCandidates[min(self.geneAttrIndex,
735                                                       len(self.geneAttrCandidates) - 1)]
736                reference = [str(e[geneAttr]) for e in self.refData
737                             if not e[geneAttr].isSpecial()]
[211]738                if any("," in gene for gene in reference):
[1739]739                    reference = reduce(add, (split_and_strip(gene, ",")
740                                             for gene in reference),
741                                       [])
742                    self.information(1,
743                                     "Separators detected in reference gene "
744                                     "names. Assuming multiple genes per "
745                                     "example.")
746            uniqueRefGenes, _, _ = org.get_unique_gene_ids(set(reference),
747                                                           self.caseSensitive)
[188]748            self.referenceGenes = reference = uniqueRefGenes.keys()
749        else:
[1534]750            self.referenceGenes = reference = org.get_genes()
[188]751        self.uniqueGenesDict = uniqueGenes
752        self.genes = uniqueGenes.keys()
[1739]753        self.revUniqueGenesDict = dict([(val, key) for key, val in
754                                        self.uniqueGenesDict.items()])
755
[1534]756        taxid = obiKEGG.to_taxid(org.org_code)
[1739]757        r_tax_map = dict((v, k) for k, v in
758                         obiKEGG.KEGGGenome.TAXID_MAP.items())
[1534]759        if taxid in r_tax_map:
760            taxid = r_tax_map[taxid]
[1739]761
[1534]762        with orngServerFiles.DownloadProgress.setredirect(self.progressBarSet):
[1554]763            orngServerFiles.update(obiGeneSets.sfdomain, "index.pck")
[1739]764            kegg_gs_collections = \
765                list(obiGeneSets.collections((("KEGG", "pathways"), taxid)))
766
[1534]767        if USE_THREADING:
768            result = {}
[1739]769
[1534]770            def callable(*args, **kwargs):
771#                result["result"] = org.get_enriched_pathways(*args, **kwargs)
772                result["result"] = pathway_enrichment(*args, **kwargs)
[1739]773
[1534]774            self.setEnabled(False)
775            try:
[1739]776                thread = threading.Thread(
777                    None, callable,
778                    name="get_enriched_pathways",
779                    args=(kegg_gs_collections,
780                          self.genes,
781                          reference),
782                    kwargs={"callback":
783                            threading_queued_invoke(
784                                self,
785                                lambda value: self.progressBarSet(value))}
786                )
787
[1534]788                thread.start()
789                while thread.is_alive():
790                    thread.join(timeout=0.025)
791                    qApp.processEvents()
792            finally:
793                self.setEnabled(True)
[1739]794
[1534]795            if "result" in result:
796                self.pathways = result["result"]
797            else:
798                raise Exception('Could not get enriched pathways')
[1739]799
[1534]800        else:
[1739]801            self.pathways = org.get_enriched_pathways(
802                self.genes, reference,
803                callback=self.progressBarSet
804            )
805
[1534]806        self.org = org
[1248]807        if not self.pathways:
808            self.warning(0, "No enriched pathways found.")
809        else:
810            self.warning(0)
[1739]811
[188]812        self.UpdateListView()
[1016]813        pb.finish()
[188]814
815    def Commit(self):
[212]816        if self.data:
[1142]817            selectedItems = self.pathwayView.scene().selectedItems()
[1739]818            selectedGenes = reduce(set.union, [item.marked_objects
819                                               for item in selectedItems],
820                                   set())
821
[212]822            if self.useAttrNames:
[1739]823                selectedVars = [self.data.domain[self.uniqueGenesDict[gene]]
824                                for gene in selectedGenes]
825                newDomain = Orange.data.Domain(selectedVars, 0)
826                data = Orange.data.Table(newDomain, self.data)
[1099]827                self.send("Selected Examples", data)
[1142]828            elif self.geneAttrCandidates:
[1739]829                geneAttr = self.geneAttrCandidates[min(self.geneAttrIndex,
830                                                       len(self.geneAttrCandidates) - 1)]
[212]831                selectedExamples = []
832                otherExamples = []
833                for ex in self.data:
[1739]834                    names = [self.revUniqueGenesDict.get(name, None)
835                             for name in split_and_strip(str(ex[geneAttr]), ",")]
[212]836                    if any(name and name in selectedGenes for name in names):
837                        selectedExamples.append(ex)
838                    else:
839                        otherExamples.append(ex)
[1739]840
[1099]841                if selectedExamples:
[1739]842                    selectedExamples = Orange.data.Table(selectedExamples)
[1099]843                else:
844                    selectedExamples = None
[1739]845
[1099]846                if otherExamples:
[1739]847                    otherExamples = Orange.data.Table(otherExamples)
[1099]848                else:
849                    otherExamples = None
[1739]850
[1099]851                self.send("Selected Examples", selectedExamples)
852                self.send("Unselected Examples", otherExamples)
[188]853        else:
[212]854            self.send("Selected Examples", None)
855            self.send("Unselected Examples", None)
[1739]856
[1606]857    def ClearCache(self):
[1716]858        from ..obiKEGG import caching
[1606]859        try:
860            caching.clear_cache()
861        except Exception, ex:
[1739]862            QMessageBox.warning(self, "Cache clear", ex.args[0])
[188]863
[1248]864    def onStateChange(self, stateType, id, text):
865        if stateType == "Warning":
866            self.pathwayView._userMessage = text
867            self.pathwayView.viewport().update()
[1739]868
[1525]869    def saveGraph(self):
[1632]870        from Orange.OrangeWidgets.OWDlgs import OWChooseImageSizeDlg
[1525]871        sizeDlg = OWChooseImageSizeDlg(self.pathwayView.scene(), parent=self)
872        sizeDlg.exec_()
[188]873
[1534]874    @pyqtSignature("queuedInvoke(PyQt_PyObject)")
875    def queuedInvoke(self, func):
876        func()
[1733]877
[1534]878    def progressBarSet(self, value):
879        if not getattr(self, "_in_progress_update", False):
880            self._in_progress_update = True
881            try:
882                OWWidget.progressBarSet(self, value)
883            finally:
884                self._in_progress_update = False
[1733]885
[1534]886    def onDeleteWidget(self):
[1739]887        """
888        Called before the widget is removed from the canvas.
[1534]889        """
890        self.org = None
[1733]891        gc.collect()  # Force collection
[1739]892
893
[1632]894from .. import obiProb
[1534]895
[1739]896
[1534]897def pathway_enrichment(genesets, genes, reference, prob=None, callback=None):
898    result_sets = []
899    p_values = []
900    if prob is None:
901        prob = obiProb.Hypergeometric()
[1739]902
[1534]903    for i, gs in enumerate(genesets):
904        cluster = gs.genes.intersection(genes)
905        ref = gs.genes.intersection(reference)
906        k = len(cluster)
907        N = len(reference)
908        m = len(ref)
909        n = len(genes)
910        if k:
911            p_val = prob.p_value(k, N, m, n)
912            result_sets.append((gs.id, cluster, ref))
913            p_values.append(p_val)
914        if callback is not None:
[1554]915            callback(100.0 * i / len(genesets))
[1739]916
[1534]917    # FDR correction
918    p_values = obiProb.FDR(p_values)
[1739]919
920    return dict([(id, (genes, p_val, len(ref)))
921                 for (id, genes, ref), p_val in zip(result_sets, p_values)])
922
[1733]923
924if __name__ == "__main__":
[188]925    app = QApplication(sys.argv)
[1751]926    w = OWKEGGPathwayBrowser()
927    w.show()
928
[1739]929    data = Orange.data.Table("brown-selected.tab")
[1751]930
931    QTimer.singleShot(1000, lambda: w.SetData(data))
932    QTimer.singleShot(1500, w.handleNewSignals)
[1733]933
[206]934    app.exec_()
[188]935    w.saveSettings()
Note: See TracBrowser for help on using the repository browser.