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.

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