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

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

KEGG Pathways widget code style fixes

Line 
1"""
2<name>KEGG Pathways</name>
3<description>Browse KEGG pathways that include an input set of genes.</description>
4<priority>2030</priority>
5<icon>icons/KEGGPathways.svg</icon>
6"""
7
8from __future__ import absolute_import, with_statement
9
10import sys
11import gc
12import webbrowser
13import threading
14from functools import partial
15from collections import defaultdict
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)
28
29import Orange
30
31from Orange.orng import orngMisc, orngServerFiles
32from Orange.orng.orngDataCaching import data_hints
33
34from Orange.OrangeWidgets import OWGUI
35from Orange.OrangeWidgets.OWWidget import *
36
37from .. import obiTaxonomy
38from .. import obiKEGG
39from .. import obiGeneSets
40
41USE_THREADING = True
42
43if USE_THREADING:
44
45    def threading_queued_invoke(qobj, func):
46        def safe_wrapper(*args, **kwargs):
47            QMetaObject.invokeMethod(qobj, "queuedInvoke",
48                                     Qt.QueuedConnection,
49                                     Q_ARG("PyQt_PyObject",
50                                           partial(func, *args, **kwargs)))
51        return safe_wrapper
52
53
54def split_and_strip(string, sep=None):
55    return [s.strip() for s in string.split(sep)]
56
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
79class EntryGraphicsItem(QGraphicsPathItem):
80    """
81    An Graphics Item with actions for an overlay of a KEGG pathway image.
82    """
83    def __init__(self, graphics, *args):
84        QGraphicsPathItem.__init__(self, *args)
85        path = path_from_graphics(graphics)
86        self.setPath(path)
87        self.setAcceptHoverEvents(True)
88        self._actions = []
89        self.link = None
90
91    def hoverEnterEvent(self, event):
92        self.setBrush(QBrush(QColor(0, 100, 0, 100)))
93
94    def hoverLeaveEvent(self, event):
95        self.setBrush(QBrush(Qt.NoBrush))
96
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())
103
104    def itemChange(self, change, value):
105        if change == QGraphicsItem.ItemSelectedHasChanged:
106            self.setPen(QPen(Qt.red if self.isSelected() else Qt.blue, 2))
107
108        return QGraphicsPathItem.itemChange(self, change, value)
109
110
111class GraphicsPathwayItem(QGraphicsPixmapItem):
112    """
113    A Graphics Item displaying a KEGG Pathway image with optional
114    marked objects.
115
116    """
117    def __init__(self, pathway, objects, *args, **kwargs):
118        QGraphicsPixmapItem.__init__(self, *args)
119        self.setTransformationMode(Qt.SmoothTransformation)
120        self.setPathway(pathway)
121        self.setMarkedObjects(objects,
122                              name_mapper=kwargs.get("name_mapper", {}))
123
124    def setPathway(self, pathway):
125        """
126        Set pathway
127        """
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)
135
136    def setMarkedObjects(self, objects, name_mapper={}):
137        for entry in self.pathway.entries() if self.pathway else []:
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())
143            item.setToolTip(self.tooltip(entry, contained_objects,
144                                         name_mapper))
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)
150
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]
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))
164            actions.append(action)
165        elif hasattr(entry, "link"):
166            action = QAction("View %s on KEGG website" % str(type), None)
167            action.connect(action,
168                           SIGNAL("triggered()"),
169                           lambda toggled=False, address=entry.link: \
170                               webbrowser.open(address))
171            actions.append(action)
172        return actions
173
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]
177        text = entry.name[:16] + " ..." if len(entry.name) > 20 else entry.name
178        text = "<p>%s</p>" % text
179        if names:
180            text += "<br>".join(names)
181        return text
182
183    def contextMenuEvent(self, event):
184        self._menu = menu = QMenu()
185        action = menu.addAction("View this pathway on KEGG website")
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))
190        menu.popup(event.screenPos())
191
192
193class PathwayView(QGraphicsView):
194    def __init__(self, master, *args):
195        QGraphicsView.__init__(self, *args)
196        self.master = master
197
198        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
199        self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
200
201        self.setRenderHints(QPainter.Antialiasing)
202        scene = QGraphicsScene(self)
203        self.pixmapGraphicsItem = QGraphicsPixmapItem(None, scene)
204        self.setScene(scene)
205
206        self.setMouseTracking(True)
207        self.viewport().setMouseTracking(True)
208
209        self.setFocusPolicy(Qt.WheelFocus)
210
211    def SetPathway(self, pathway=None, objects=[]):
212        self.scene().clear()
213        self.pathway = pathway
214        self.objects = objects
215        self.pathwayItem = GraphicsPathwayItem(
216            pathway, objects, None,
217            name_mapper=getattr(self.master, "uniqueGenesDict", {})
218        )
219
220        self.scene().addItem(self.pathwayItem)
221        self.scene().setSceneRect(self.pathwayItem.boundingRect())
222        self.updateTransform()
223
224    def resizeEvent(self, event):
225        self.updateTransform()
226        return QGraphicsView.resizeEvent(self, event)
227
228    def updateTransform(self):
229        if self.master.autoResize:
230            self.fitInView(self.scene().sceneRect().adjusted(-1, -1, 1, 1),
231                           Qt.KeepAspectRatio)
232        else:
233            self.setTransform(QTransform())
234
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)
242            painter.drawText(self.viewport().geometry(), Qt.AlignCenter,
243                             self._userMessage)
244            painter.end()
245
246
247class OWKEGGPathwayBrowser(OWWidget):
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
267    def __init__(self, parent=None, signalManager=None, name="KEGG Pathways"):
268        OWWidget.__init__(self, parent, signalManager, name, wantGraph=True)
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)]
273        self.organismIndex = 0
274        self.geneAttrIndex = 0
275        self.autoCommit = False
276        self.autoResize = True
277        self.useReference = False
278        self.useAttrNames = 0
279        self.caseSensitive = True
280        self.showOrthology = True
281        self.autoFindBestOrg = False
282        self.loadSettings()
283
284        self.controlArea.setMaximumWidth(250)
285        box = OWGUI.widgetBox(self.controlArea, "Info")
286        self.infoLabel = OWGUI.widgetLabel(box, "No data on input\n")
287
288        self.allOrganismCodes = {}
289
290        self.organismCodes = []
291
292        # Organism selection.
293        box = OWGUI.widgetBox(self.controlArea, "Organism")
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
302        self.signalManager.freeze(self).push()
303
304        # Selection of genes attribute
305        box = OWGUI.widgetBox(self.controlArea, "Gene attribute")
306        self.geneAttrCombo = OWGUI.comboBox(box, self, "geneAttrIndex",
307                                            callback=self.Update)
308
309        OWGUI.checkBox(box, self, "useAttrNames",
310                       "Use variable names",
311                       disables=[(-1, self.geneAttrCombo)],
312                       callback=self.UseAttrNamesCallback)
313
314        self.geneAttrCombo.setDisabled(bool(self.useAttrNames))
315
316        OWGUI.separator(self.controlArea)
317
318        OWGUI.checkBox(self.controlArea, self, "useReference",
319                       "From signal",
320                       box="Reference",
321                       callback=self.Update)
322
323        OWGUI.separator(self.controlArea)
324
325        OWGUI.checkBox(self.controlArea, self, "showOrthology",
326                       "Show pathways in full orthology",
327                       box="Orthology",
328                       callback=self.UpdateListView)
329
330        OWGUI.checkBox(self.controlArea, self, "autoResize",
331                       "Resize to fit",
332                       box="Image",
333                       callback=self.UpdatePathwayViewTransform)
334
335        box = OWGUI.widgetBox(self.controlArea, "Cache Control")
336
337        OWGUI.button(box, self, "Clear cache",
338                     callback=self.ClearCache,
339                     tooltip="Clear all locally cached KEGG data.")
340
341        OWGUI.separator(self.controlArea)
342
343        box = OWGUI.widgetBox(self.controlArea, "Selection")
344        OWGUI.checkBox(box, self, "autoCommit", "Commit on update")
345        OWGUI.button(box, self, "Commit", callback=self.Commit, default=True)
346        OWGUI.rubber(self.controlArea)
347
348        spliter = QSplitter(Qt.Vertical, self.mainArea)
349        self.pathwayView = PathwayView(self, spliter)
350        self.mainArea.layout().addWidget(spliter)
351
352        self.listView = QTreeWidget(spliter)
353        spliter.addWidget(self.listView)
354
355        self.listView.setAllColumnsShowFocus(1)
356        self.listView.setColumnCount(4)
357        self.listView.setHeaderLabels(["Pathway", "P value",
358                                       "Genes", "Reference"])
359
360        self.listView.setSelectionMode(QTreeWidget.SingleSelection)
361
362        self.listView.setSortingEnabled(True)
363
364        self.listView.setMaximumHeight(200)
365
366        self.connect(self.listView,
367                     SIGNAL("itemSelectionChanged()"),
368                     self.UpdatePathwayView)
369
370        self.connect(self.graphButton,
371                     SIGNAL("clicked()"),
372                     self.saveGraph)
373
374        self.ctrlPressed = False
375        self.selectedObjects = defaultdict(list)
376        self.data = None
377        self.refData = None
378
379        self.resize(800, 600)
380
381        self.connect(self,
382                     SIGNAL("widgetStateChanged(QString, int, QString)"),
383                     self.onStateChange)
384
385        self.has_new_data = False
386        self.has_new_reference_set = False
387
388        self.setEnabled(False)
389        QTimer.singleShot(100, self.UpdateOrganismComboBox)
390
391    def UpdateOrganismComboBox(self):
392        # First try to import slumber
393        try:
394            import slumber
395        except ImportError:
396            QMessageBox.warning(self,
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
403        try:
404            genome = obiKEGG.KEGGGenome()
405
406            self.allOrganismCodes = genome
407
408            essential = genome.essential_organisms()
409            common = genome.common_organisms()
410            common = [c for c in common if c not in essential]
411
412            # TODO: Add option to specify additional organisms not
413            # in the common list.
414
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]
430            self.organismComboBox.addItems(items)
431        finally:
432            self.setEnabled(True)
433            self.infoLabel.setText("No data on input\n")
434            self.signalManager.freeze(self).pop()
435
436    def Clear(self):
437        """
438        Clear the widget state.
439        """
440        self.infoLabel.setText("No data on input\n")
441        self.listView.clear()
442        self.ClearPathway()
443
444        self.send("Selected Examples", None)
445        self.send("Unselected Examples", None)
446
447    def ClearPathway(self):
448        self.pathwayView.SetPathway(None)
449        self.selectedObjects = defaultdict(list)
450
451    def SetData(self, data=None):
452        self.closeContext()
453        self.data = data
454        self.warning(0)
455        if data is not None:
456            self.SetGeneAttrCombo()
457            taxid = data_hints.get_hint(data, "taxid", None)
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
464
465            self.useAttrNames = data_hints.get_hint(data, "genesinrows",
466                                                    self.useAttrNames)
467
468            self.openContext("", data)
469        else:
470            self.Clear()
471
472        self.has_new_data = True
473
474    def SetRefData(self, data=None):
475        self.refData = data
476        self.has_new_reference_set = True
477
478    def handleNewSignals(self):
479        if self.has_new_data or (self.has_new_reference_set and \
480                                 self.useReference):
481            self.Update()
482
483            self.has_new_data = False
484            self.has_new_reference_set = False
485
486    def UseAttrNamesCallback(self):
487        self.Update()
488
489    def OrganismSelectionCallback(self):
490        self.Update()
491
492    def SetGeneAttrCombo(self):
493        self.geneAttrCandidates = self.data.domain.variables + \
494                                  self.data.domain.getmetas().values()
495        self.geneAttrCandidates = filter(
496            lambda v: isinstance(v, (Orange.feature.Discrete,
497                                     Orange.feature.String)),
498            self.geneAttrCandidates)
499
500        self.geneAttrCombo.clear()
501
502        self.geneAttrCombo.addItems([var.name for var in
503                                     self.geneAttrCandidates])
504
505    def UpdateListView(self):
506        self.bestPValueItem = None
507        self.listView.clear()
508        if not self.data:
509            return
510
511        allPathways = self.org.pathways()
512        allRefPathways = obiKEGG.pathways("map")
513
514        items = []
515        self.progressBarInit()
516        kegg_pathways = obiKEGG.KEGGPathways()
517        kegg_pathways.pre_cache(self.pathways.keys(),
518                                progress_callback=self.progressBarSet)
519        self.progressBarFinished()
520
521        org_code = self.organismCodes[min(self.organismIndex,
522                                          len(self.organismCodes) - 1)]
523
524        if self.showOrthology:
525            self.koOrthology = obiKEGG.KEGGBrite("ko00001")
526            self.listView.setRootIsDecorated(True)
527            path_ids = set([s[-5:] for s in self.pathways.keys()])
528
529            def _walkCollect(koEntry):
530                num = koEntry.title[:5] if koEntry.title else None
531                if num in path_ids:
532                    return ([koEntry] +
533                            reduce(lambda li, c: li + _walkCollect(c),
534                                   [child for child in koEntry.entries],
535                                   []))
536                else:
537                    c = reduce(lambda li, c: li + _walkCollect(c),
538                               [child for child in koEntry.entries],
539                               [])
540                    return c + (c and [koEntry] or [])
541
542            allClasses = reduce(lambda li1, li2: li1 + li2,
543                                [_walkCollect(c) for c in self.koOrthology],
544                                [])
545
546            def _walkCreate(koEntry, lvItem):
547                item = QTreeWidgetItem(lvItem)
548                id = "path:" + org_code + koEntry.title[:5]
549
550                if koEntry.title[:5] in path_ids:
551                    p = kegg_pathways.get_entry(id)
552                    if p is None:
553                        # In case the genesets still have obsolete entries
554                        name = koEntry.title
555                    else:
556                        name = p.name
557                    genes, p_value, ref = self.pathways[id]
558                    item.setText(0, name)
559                    item.setText(1, "%.5f" % p_value)
560                    item.setText(2, "%i of %i" % (len(genes), len(self.genes)))
561                    item.setText(3, "%i of %i" % (ref, len(self.referenceGenes)))
562                    item.pathway_id = id if p is not None else None
563                else:
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
570                    if id in allPathways:
571                        item.pathway_id = id
572                    elif "path:map" + koEntry.title[:5] in allRefPathways:
573                        item.pathway_id = "path:map" + koEntry.title[:5]
574                    else:
575                        item.pathway_id = None
576
577                for child in koEntry.entries:
578                    if child in allClasses:
579                        _walkCreate(child, item)
580
581            for koEntry in self.koOrthology:
582                if koEntry in allClasses:
583                    _walkCreate(koEntry, self.listView)
584
585            self.listView.update()
586        else:
587            self.listView.setRootIsDecorated(False)
588            pathways = self.pathways.items()
589            pathways.sort(lambda a, b: cmp(a[1][1], b[1][1]))
590
591            for id, (genes, p_value, ref) in pathways:
592                item = QTreeWidgetItem(self.listView)
593                item.setText(0, kegg_pathways.get_entry(id).name)
594                item.setText(1, "%.5f" % p_value)
595                item.setText(2, "%i of %i" % (len(genes), len(self.genes)))
596                item.setText(3, "%i of %i" % (ref, len(self.referenceGenes)))
597                item.pathway_id = id
598                items.append(item)
599
600        self.bestPValueItem = items and items[0] or None
601        self.listView.expandAll()
602        for i in range(4):
603            self.listView.resizeColumnToContents(i)
604
605        if self.bestPValueItem:
606            index = self.listView.indexFromItem(self.bestPValueItem)
607            self.listView.selectionModel().select(
608                index, QItemSelectionModel.ClearAndSelect
609            )
610
611    def UpdatePathwayView(self):
612        items = self.listView.selectedItems()
613
614        if len(items) > 0:
615            item = items[0]
616        else:
617            item = None
618
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
625
626        if USE_THREADING:
627            result = {}
628
629            def call(pathway_id):
630                result["pathway"] = p = obiKEGG.KEGGPathway(pathway_id)
631                p._get_kgml()  # makes sure the kgml file is downloaded
632                p._get_image_filename()  # makes sure the image is downloaded
633
634            self.setEnabled(False)
635            try:
636                thread = threading.Thread(None, call,
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)
651
652        self.pathwayView.SetPathway(self.pathway,
653                                    self.pathways.get(item.pathway_id, [[]])[0])
654
655    def UpdatePathwayViewTransform(self):
656        self.pathwayView.updateTransform()
657
658    def Update(self):
659        if not self.data:
660            return
661        self.error(0)
662        self.information(0)
663        pb = OWGUI.ProgressBar(self, 100)
664        if self.useAttrNames:
665            genes = [str(v.name).strip() for v in self.data.domain.attributes]
666        elif self.geneAttrCandidates:
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()]
671            if any("," in gene for gene in genes):
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.")
678        else:
679            self.error(0, "Cannot extract gene names from input")
680            genes = []
681        org_code = self.organismCodes[min(self.organismIndex,
682                                          len(self.organismCodes) - 1)]
683
684        if USE_THREADING:
685            result = {}
686
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()
691
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)
703
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)
710
711        uniqueGenes, _, _ = org.get_unique_gene_ids(set(genes),
712                                                    self.caseSensitive)
713        genesCount = len(set(genes))
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
719        self.information(1)
720        if self.useReference and self.refData:
721            if self.useAttrNames:
722                reference = [str(v.name).strip() for v in self.refData]
723            else:
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()]
728                if any("," in gene for gene in reference):
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)
738            self.referenceGenes = reference = uniqueRefGenes.keys()
739        else:
740            self.referenceGenes = reference = org.get_genes()
741        self.uniqueGenesDict = uniqueGenes
742        self.genes = uniqueGenes.keys()
743        self.revUniqueGenesDict = dict([(val, key) for key, val in
744                                        self.uniqueGenesDict.items()])
745
746        taxid = obiKEGG.to_taxid(org.org_code)
747        r_tax_map = dict((v, k) for k, v in
748                         obiKEGG.KEGGGenome.TAXID_MAP.items())
749        if taxid in r_tax_map:
750            taxid = r_tax_map[taxid]
751
752        with orngServerFiles.DownloadProgress.setredirect(self.progressBarSet):
753            orngServerFiles.update(obiGeneSets.sfdomain, "index.pck")
754            kegg_gs_collections = \
755                list(obiGeneSets.collections((("KEGG", "pathways"), taxid)))
756
757        if USE_THREADING:
758            result = {}
759
760            def callable(*args, **kwargs):
761#                result["result"] = org.get_enriched_pathways(*args, **kwargs)
762                result["result"] = pathway_enrichment(*args, **kwargs)
763
764            self.setEnabled(False)
765            try:
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
778                thread.start()
779                while thread.is_alive():
780                    thread.join(timeout=0.025)
781                    qApp.processEvents()
782            finally:
783                self.setEnabled(True)
784
785            if "result" in result:
786                self.pathways = result["result"]
787            else:
788                raise Exception('Could not get enriched pathways')
789
790        else:
791            self.pathways = org.get_enriched_pathways(
792                self.genes, reference,
793                callback=self.progressBarSet
794            )
795
796        self.org = org
797        if not self.pathways:
798            self.warning(0, "No enriched pathways found.")
799        else:
800            self.warning(0)
801
802        self.UpdateListView()
803        pb.finish()
804
805    def Commit(self):
806        if self.data:
807            selectedItems = self.pathwayView.scene().selectedItems()
808            selectedGenes = reduce(set.union, [item.marked_objects
809                                               for item in selectedItems],
810                                   set())
811
812            if self.useAttrNames:
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)
817                self.send("Selected Examples", data)
818            elif self.geneAttrCandidates:
819                geneAttr = self.geneAttrCandidates[min(self.geneAttrIndex,
820                                                       len(self.geneAttrCandidates) - 1)]
821                selectedExamples = []
822                otherExamples = []
823                for ex in self.data:
824                    names = [self.revUniqueGenesDict.get(name, None)
825                             for name in split_and_strip(str(ex[geneAttr]), ",")]
826                    if any(name and name in selectedGenes for name in names):
827                        selectedExamples.append(ex)
828                    else:
829                        otherExamples.append(ex)
830
831                if selectedExamples:
832                    selectedExamples = Orange.data.Table(selectedExamples)
833                else:
834                    selectedExamples = None
835
836                if otherExamples:
837                    otherExamples = Orange.data.Table(otherExamples)
838                else:
839                    otherExamples = None
840
841                self.send("Selected Examples", selectedExamples)
842                self.send("Unselected Examples", otherExamples)
843        else:
844            self.send("Selected Examples", None)
845            self.send("Unselected Examples", None)
846
847    def ClearCache(self):
848        from ..obiKEGG import caching
849        try:
850            caching.clear_cache()
851        except Exception, ex:
852            QMessageBox.warning(self, "Cache clear", ex.args[0])
853
854    def onStateChange(self, stateType, id, text):
855        if stateType == "Warning":
856            self.pathwayView._userMessage = text
857            self.pathwayView.viewport().update()
858
859    def saveGraph(self):
860        from Orange.OrangeWidgets.OWDlgs import OWChooseImageSizeDlg
861        sizeDlg = OWChooseImageSizeDlg(self.pathwayView.scene(), parent=self)
862        sizeDlg.exec_()
863
864    @pyqtSignature("queuedInvoke(PyQt_PyObject)")
865    def queuedInvoke(self, func):
866        func()
867
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
875
876    def onDeleteWidget(self):
877        """
878        Called before the widget is removed from the canvas.
879        """
880        self.org = None
881        gc.collect()  # Force collection
882
883
884from .. import obiProb
885
886
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()
892
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:
905            callback(100.0 * i / len(genesets))
906
907    # FDR correction
908    p_values = obiProb.FDR(p_values)
909
910    return dict([(id, (genes, p_val, len(ref)))
911                 for (id, genes, ref), p_val in zip(result_sets, p_values)])
912
913
914if __name__ == "__main__":
915    app = QApplication(sys.argv)
916    data = Orange.data.Table("brown-selected.tab")
917    w = OWKEGGPathwayBrowser()
918    w.UpdateOrganismComboBox()
919    w.show()
920    w.SetData(Orange.data.Table(data[:]))
921    QTimer.singleShot(10, w.handleNewSignals)
922
923    app.exec_()
924    w.saveSettings()
Note: See TracBrowser for help on using the repository browser.