source: orange-bioinformatics/orangecontrib/bio/widgets/OWSetEnrichment.py @ 1878:8b1e95b04793

Revision 1878:8b1e95b04793, 27.3 KB checked in by Ales Erjavec <ales.erjavec@…>, 7 months ago (diff)

Merged biolab/orange-bioinformatics into default

RevLine 
[1478]1"""<name>Gene Set Enrichment</name>
[1726]2<icon>icons/GeneSetEnrichment.svg</icon>
[1478]3"""
4
[1632]5from __future__ import absolute_import, with_statement
[1478]6
7import math
8from collections import defaultdict
9
[1632]10from Orange.orng import orngEnviron, orngServerFiles
11from Orange.orng.orngDataCaching import data_hints
12from Orange.OrangeWidgets import OWGUI
13from Orange.OrangeWidgets.OWGUI import LinkStyledItemDelegate, LinkRole
14from Orange.OrangeWidgets.OWGUI import BarItemDelegate
15from Orange.OrangeWidgets.OWWidget import *
16
17from .. import obiGene, obiGeneSets, obiProb, obiTaxonomy
[1478]18
[1874]19NAME = "Gene Set Enrichment"
20DESCRIPTION = ""
21ICON = "icons/GeneSetEnrichment.svg"
22PRIORITY = 5000
23
24INPUTS = [("Data", Orange.data.Table, "setData", Default),
25          ("Reference", Orange.data.Table, "setReference")]
26OUTPUTS = [("Data subset", Orange.data.Table)]
27
28REPLACES = ["_bioinformatics.widgets.OWSetEnrichment.OWSetEnrichment"]
29
30
[1861]31def gsname(geneset):
32    return geneset.name if geneset.name else geneset.id
33
34
[1498]35def _toPyObject(variant):
36    val = variant.toPyObject()
37    if isinstance(val, type(NotImplemented)): # PyQt 4.4 converts python int, floats ... to C types
38        qtype = variant.type()
39        if qtype == QVariant.Double:
40            val, ok = variant.toDouble()
41        elif qtype == QVariant.Int:
42            val, ok = variant.toInt()
43        elif qtype == QVariant.LongLong:
44            val, ok = variant.toLongLong()
45        elif qtype == QVariant.String:
46            val = variant.toString()
47    return val
[1478]48
49class MyTreeWidget(QTreeWidget):
50    def paintEvent(self, event):
51        QTreeWidget.paintEvent(self, event)
52        if getattr(self, "_userMessage", None):
53            painter = QPainter(self.viewport())
54            font = QFont(self.font())
55            font.setPointSize(15)
56            painter.setFont(font)
57            painter.drawText(self.viewport().geometry(), Qt.AlignCenter, self._userMessage)
58            painter.end()
[1761]59
[1498]60class MyTreeWidgetItem(QTreeWidgetItem):
61    def __lt__(self, other):
62        if not self.treeWidget():
63            return id(self) < id(other)
64        column = self.treeWidget().sortColumn()
[1791]65        if column == 4:
66            lhs = _toPyObject(self.data(column, 42))
67            rhs = _toPyObject(other.data(column, 42))
68        else:
69            lhs = _toPyObject(self.data(column, Qt.DisplayRole))
70            rhs = _toPyObject(other.data(column, Qt.DisplayRole))
[1498]71        return lhs < rhs
[1761]72
[1574]73def name_or_none(id):
74    """Return organism name for ncbi taxid or None if not found.
75    """
76    try:
77        return obiTaxonomy.name(id)
78    except obiTaxonomy.UnknownSpeciesIdentifier:
79        return None
[1761]80
[1478]81class OWSetEnrichment(OWWidget):
82    settingsList = ["speciesIndex", "genesinrows", "geneattr", "categoriesCheckState"]
83    contextHandlers = {"":DomainContextHandler("", ["speciesIndex", "genesinrows", "geneattr", "categoriesCheckState"])}
[1761]84
[1863]85    def refreshHierarchy(self):
86        self.setHierarchy(*self.getHierarchy(taxid=self.taxid_list[self.speciesIndex]))
87
[1498]88    def __init__(self, parent=None, signalManager=None, name="Gene Set Enrichment Analysis", **kwargs):
[1478]89        OWWidget.__init__(self, parent, signalManager, name, **kwargs)
[1810]90        self.inputs = [("Data", ExampleTable, self.setData, Default), ("Reference", ExampleTable, self.setReference)]
91        self.outputs = [("Data subset", ExampleTable)]
[1761]92
[1478]93        self.speciesIndex = 0
94        self.genesinrows = False
95        self.geneattr = 0
96        self.geneMatcherSettings = [False, False, True, False]
97        self.useReferenceData = False
98        self.useMinCountFilter = True
99        self.useMaxPValFilter = True
100        self.minClusterCount = 0
101        self.maxPValue = 0.01
[1761]102
[1478]103        self.useFDR = True
[1761]104
[1478]105        self.categoriesCheckState = {}
[1761]106
[1478]107        self.loadSettings()
[1761]108
[1748]109        if self.signalManager:
110            self.signalManager.freeze(self).push()
[1478]111        QTimer.singleShot(50, self.updateHierarchy)
[1761]112
[1478]113        box = OWGUI.widgetBox(self.controlArea, "Info")
114        self.infoBox = OWGUI.widgetLabel(box, "Info")
115        self.infoBox.setText("No data on input")
[1761]116
[1478]117        self.speciesComboBox = OWGUI.comboBox(self.controlArea, self,
118                      "speciesIndex", "Species",
[1863]119                      callback=lambda: (self.refreshHierarchy(), self.data and self.updateAnnotations()),
[1478]120                      debuggingEnabled=0)
[1761]121
[1478]122        box = OWGUI.widgetBox(self.controlArea, "Gene names")
123        self.geneAttrComboBox = OWGUI.comboBox(box, self, "geneattr",
124                                "Gene attribute",
125                                sendSelectedValue=0,
126                                callback=self.updateAnnotations)
[1761]127
[1478]128        cb = OWGUI.checkBox(box, self, "genesinrows", "Use attribute names",
129                            callback=lambda :self.data and self.updateAnnotations(),
130                            disables=[(-1, self.geneAttrComboBox)])
131        cb.makeConsistent()
[1761]132
[1478]133        OWGUI.button(box, self, "Gene matcher settings",
134                     callback=self.updateGeneMatcherSettings,
135                     tooltip="Open gene matching settings dialog",
136                     debuggingEnabled=0)
[1761]137
[1478]138        self.referenceRadioBox = OWGUI.radioButtonsInBox(self.controlArea,
139                    self, "useReferenceData", ["Entire genome", "Reference set (input)"],
140                    tooltips=["Use entire genome for reference",
141                              "Use genes from Referece Examples input signal as reference"],
142                    box="Reference", callback=self.updateAnnotations)
[1761]143
144        box = OWGUI.widgetBox(self.controlArea, "Gene Sets")
[1478]145        self.groupsWidget = QTreeWidget(self)
146        self.groupsWidget.setHeaderLabels(["Category"])
147        box.layout().addWidget(self.groupsWidget)
148
149        hLayout = QHBoxLayout()
150        hLayout.setSpacing(10)
[1498]151        hWidget = OWGUI.widgetBox(self.mainArea, orientation=hLayout)
152        sb, sbcb = OWGUI.spin(hWidget, self, "minClusterCount",
[1761]153                              0, 100, label="Genes",
[1478]154                              tooltip="Minimum gene count",
155                              callback=self.filterAnnotationsChartView,
156                              callbackOnReturn=True,
157                              checked="useMinCountFilter",
158                              checkCallback=self.filterAnnotationsChartView)
[1761]159
[1498]160        dsp, dspcb = OWGUI.doubleSpin(hWidget, self,
[1478]161                        "maxPValue", 0.0, 1.0, 0.0001,
[1794]162                        label="FDR adjusted P-Value",
163                        tooltip="Maximum (FDR adjusted) P-Value",
[1478]164                        callback=self.filterAnnotationsChartView,
165                        callbackOnReturn=True,
166                        checked="useMaxPValFilter",
167                        checkCallback=self.filterAnnotationsChartView)
[1761]168
[1632]169        from Orange.OrangeWidgets import OWGUIEx
[1478]170        self.filterLineEdit = OWGUIEx.QLineEditWithActions(self)
171        self.filterLineEdit.setPlaceholderText("Filter ...")
172        action = QAction(QIcon(os.path.join(orngEnviron.canvasDir,
173                        "icons", "delete_gray.png")), "Clear", self)
[1761]174
[1478]175        self.filterLineEdit.addAction(action, 0, Qt.AlignHCenter)
176        self.connect(action, SIGNAL("triggered()"), self.filterLineEdit.clear)
[1761]177
[1478]178        self.filterCompleter = QCompleter(self.filterLineEdit)
179        self.filterCompleter.setCaseSensitivity(Qt.CaseInsensitive)
180        self.filterLineEdit.setCompleter(self.filterCompleter)
[1761]181
[1478]182        hLayout.addWidget(self.filterLineEdit)
[1498]183        self.mainArea.layout().addWidget(hWidget)
[1761]184
[1478]185        self.connect(self.filterLineEdit, SIGNAL("textChanged(QString)"),
186                     self.filterAnnotationsChartView)
[1761]187
[1478]188        self.annotationsChartView = MyTreeWidget(self)
189        self.annotationsChartView.setHeaderLabels(["Category", "Term",
190                            "Count", "Reference count", "P-Value", "Enrichment"])
191        self.annotationsChartView.setAlternatingRowColors(True)
192        self.annotationsChartView.setSortingEnabled(True)
193        self.annotationsChartView.setSelectionMode(QAbstractItemView.ExtendedSelection)
194        self.annotationsChartView.setRootIsDecorated(False)
195        self.annotationsChartView.viewport().setMouseTracking(True)
196#        self.annotationsChartView.viewport().setAttribute(Qt.WA_Hover)
197        self.mainArea.layout().addWidget(self.annotationsChartView)
[1761]198
[1478]199        contextEventFilter = OWGUI.VisibleHeaderSectionContextEventFilter(self.annotationsChartView)
200        self.annotationsChartView.header().installEventFilter(contextEventFilter)
[1761]201
[1478]202        self.taxid_list = []
[1761]203
[1478]204        self.connect(self.groupsWidget, SIGNAL("itemClicked(QTreeWidgetItem *, int)"), self.subsetSelectionChanged)
[1761]205
[1478]206        OWGUI.button(self.controlArea, self, "Commit", callback=self.commit)
[1761]207
[1478]208        self.loadedGenematcher = "None"
209        self.referenceData = None
210        self.data = None
[1761]211
[1478]212        self.treeItems = []
[1761]213
[1478]214        self.resize(1024, 600)
[1761]215
[1478]216        self.connect(self, SIGNAL("widgetStateChanged(QString, int, QString)"), self.onStateChange)
[1761]217
[1498]218        self.updatingAnnotationsFlag = False
[1761]219
[1478]220    def updateHierarchy(self):
221        try:
222            self.progressBarInit()
223            with orngServerFiles.DownloadProgress.setredirect(self.progressBarSet):
224                all, local = obiGeneSets.list_all(), obiGeneSets.list_local()
[1809]225                organisms = set(obiTaxonomy.essential_taxids() + filter(None, [t[1] for t in all]))
[1478]226            self.progressBarFinished()
[1761]227
[1574]228            organism_names = map(name_or_none, organisms)
229            organisms = [taxid for taxid, name in zip(organisms, organism_names) \
230                         if name is not None]
[1761]231
[1478]232            self.taxid_list = list(organisms)
233            self.speciesComboBox.clear()
234            self.speciesComboBox.addItems([obiTaxonomy.name(id) for id in self.taxid_list])
235            self.genesets = all
236        finally:
[1748]237            if self.signalManager:
[1761]238                self.signalManager.freeze(self).pop() #setFreeze(self.signalManager.freezing - 1)
239
[1478]240    def setData(self, data=None):
241        self.data = data
242        self.error(0)
243        self.closeContext("")
244        self.geneAttrComboBox.clear()
245        self.groupsWidget.clear()
246        self.annotationsChartView.clear()
[1761]247
[1478]248        if not getattr(self,"taxid_list", None):
249            QTimer.singleShot(100, lambda data=data: self.setData(data))
[1761]250            return
[1478]251        if data:
252            self.geneAttrs = [attr for attr in data.domain.variables + data.domain.getmetas().values() \
253                              if attr.varType != orange.VarTypes.Continuous]
[1761]254
[1478]255            self.geneAttrComboBox.addItems([attr.name for attr in self.geneAttrs])
256            self.geneattr = min(self.geneattr, len(self.geneAttrs) - 1)
[1761]257
[1478]258            taxid = data_hints.get_hint(data, "taxid", "")
259            try:
260                self.speciesIndex = self.taxid_list.index(taxid)
261            except ValueError, ex:
262                pass
263            self.genesinrows = data_hints.get_hint(data, "genesinrows", self.genesinrows)
[1761]264
[1478]265            self.openContext("", data)
[1863]266       
267            self.refreshHierarchy()
[1761]268
[1478]269            self.loadedGenematcher = "None"
270            self.updateAnnotations()
[1761]271
[1478]272    def setReference(self, data=None):
273        self.referenceData = data
274        self.referenceRadioBox.setEnabled(bool(data))
[1761]275
[1478]276    def getHierarchy(self, taxid):
277        def recursive_dict():
278            return defaultdict(recursive_dict)
279        collection = recursive_dict()
[1761]280
[1478]281        def collect(col, hier):
282            if hier:
283                collect(col[hier[0]], hier[1:])
[1761]284
[1478]285        for hierarchy, t_id, _ in self.genesets:
286            collect(collection[t_id], hierarchy)
[1809]287
[1861]288        return (taxid, collection[taxid]), (None, collection[None])
[1761]289
[1861]290    def setHierarchy(self, hierarchy, hierarchy_noorg):
[1478]291        self.groupsWidgetItems = {}
[1861]292        def fill(col, parent, full=(), org=""):
[1478]293            for key, value in sorted(col.items()):
294                full_cat = full + (key,)
295                item = QTreeWidgetItem(parent, [key])
296                item.setFlags(item.flags() | Qt.ItemIsUserCheckable | Qt.ItemIsSelectable | Qt.ItemIsEnabled)
297                if value:
298                    item.setFlags(item.flags() | Qt.ItemIsTristate)
[1761]299
[1478]300                item.setData(0, Qt.CheckStateRole, QVariant(self.categoriesCheckState.get(full_cat, Qt.Checked)))
301                item.setExpanded(True)
302                item.category = full_cat
[1861]303                item.organism = org
[1478]304                self.groupsWidgetItems[full_cat] = item
[1861]305                fill(value, item, full_cat, org=org)
[1761]306
[1863]307        self.groupsWidget.clear()
[1861]308        fill(hierarchy[1], self.groupsWidget, org=hierarchy[0])
309        fill(hierarchy_noorg[1], self.groupsWidget, org=hierarchy_noorg[0])
[1761]310
[1478]311#    def updateCategoryCounts(self):
312#        for cat, item in self.groupWidgetItem:
313#            item.setData(1, QVariant(), Qt.DisplayRole)
[1761]314
[1478]315    def selectedCategories(self):
[1861]316        return [(key, org) for (key, org), check in self.getHierarchyCheckState().items() if check == Qt.Checked]
[1478]317
318    def getHierarchyCheckState(self):
319        def collect(item, full=()):
320            checked = item.checkState(0)
321            name = str(item.data(0, Qt.DisplayRole).toString())
322            full_cat = full + (name,)
[1861]323            result = [((full_cat, item.organism), checked)]
[1478]324            for i in range(item.childCount()):
325                result.extend(collect(item.child(i), full_cat))
326            return result
[1761]327
[1478]328        items = [self.groupsWidget.topLevelItem(i) for i in range(self.groupsWidget.topLevelItemCount())]
329        states = reduce(list.__add__, [collect(item) for item in items], [])
330        return dict(states)
[1761]331
[1478]332    def subsetSelectionChanged(self, item, column):
[1861]333        #FIXME this should also recompute FDR
[1478]334        self.categoriesCheckState = self.getHierarchyCheckState()
335        categories = self.selectedCategories()
[1863]336       
[1478]337        if not set(categories) <= set(self.currentAnnotatedCategories):
338            self.updateAnnotations()
339        else:
340            self.filterAnnotationsChartView()
[1863]341       
[1761]342
[1478]343    def updateGeneMatcherSettings(self):
[1632]344        from .OWGOEnrichmentAnalysis import GeneMatcherDialog
[1478]345        dialog = GeneMatcherDialog(self, defaults=self.geneMatcherSettings, enabled=[True] * 4, modal=True)
346        if dialog.exec_():
347            self.geneMatcherSettings = [getattr(dialog, item[0]) for item in dialog.items]
348            self.loadedGenematcher = "None"
349            if self.data:
350                self.updateAnnotations()
[1761]351
[1478]352    def updateGenematcher(self):
353        taxid = self.taxid_list[self.speciesIndex]
354        if taxid != self.loadedGenematcher:
355            self.progressBarInit()
356            call = self.asyncCall(obiGene.matcher, name="Gene Matcher", blocking=True, thread=self.thread())
357            call.connect(call, SIGNAL("progressChanged(float)"), self.progressBarSet)
358            with orngServerFiles.DownloadProgress.setredirect(call.emitProgressChanged):
359#            with orngServerFiles.DownloadProgress.setredirect(self.progressBarSet):
360                matchers = [obiGene.GMGO, obiGene.GMKEGG, obiGene.GMNCBI, obiGene.GMAffy]
361                if any(self.geneMatcherSettings):
362                    call.__call__([gm(taxid) for gm, use in zip(matchers, self.geneMatcherSettings) if use])
363                    self.genematcher = call.get_result()
364#                    self.genematcher = obiGene.matcher([gm(taxid) for gm, use in zip(matchers, self.geneMatcherSettings) if use])
365                else:
366                    self.genematcher = obiGene.GMDirect()
367#                self.genematcher.set_targets(self.referenceGenes())
368                self.loadedGenematcher = taxid
369            self.progressBarFinished()
[1761]370
[1478]371    def genesFromExampleTable(self, table):
372        if self.genesinrows:
373            genes = [attr.name for attr in table.domain.attributes]
374        else:
375            geneattr = self.geneAttrs[self.geneattr]
376            genes = [str(ex[geneattr]) for ex in table]
377        return genes
[1761]378
[1478]379    def clusterGenes(self):
380        return self.genesFromExampleTable(self.data)
[1761]381
[1478]382    def referenceGenes(self):
383        if self.referenceData and self.useReferenceData:
384            return self.genesFromExampleTable(self.referenceData)
385        else:
386            taxid = self.taxid_list[self.speciesIndex]
387            call = self.asyncCall(obiGene.NCBIGeneInfo, (taxid,), name="Load reference genes", blocking=True, thread=self.thread())
388            call.connect(call, SIGNAL("progressChanged(float)"), self.progressBarSet)
389            with orngServerFiles.DownloadProgress.setredirect(call.emitProgressChanged):
390                call.__call__()
391                return call.get_result()
[1761]392
[1478]393    def _cached_name_lookup(self, func, cache):
394        def f(name, cache=cache):
395            if name not in cache:
396                cache[name] = func(name)
397            return cache[name]
398        return f
[1761]399
[1478]400    def mapGeneNames(self, names, cache=None, passUnknown=False):
401        if cache is not None:
402            umatch = self._cached_name_lookup(self.genematcher.umatch, cache)
403        else:
404            umatch = self.genematcher.umatch
405        if passUnknown:
406            return [umatch(name) or name for name in names]
407#            return [(mapped_name or name, mapped_name is not None) for mapped_name, name in zip(mapped, names)]
408        return [n for n in [umatch(name) for name in names] if n is not None]
[1761]409
[1478]410    def enrichment(self, geneset, cluster, reference, pval=obiProb.Hypergeometric(), cache=None):
411        genes = set(self.mapGeneNames(geneset.genes, cache, passUnknown=False))
[1761]412
[1478]413        cmapped = genes.intersection(cluster)
414        rmapped = genes.intersection(reference)
415        return (cmapped, rmapped, pval.p_value(len(cmapped), len(reference), len(rmapped), len(cluster)), float(len(cmapped)) / (len(cluster) or 1) / (float(len(rmapped) or 1) / (len(reference) or 1))) # TODO: compute all statistics here
[1761]416
[1478]417    def updateAnnotations(self):
418        self.updatingAnnotationsFlag = True
419        self.annotationsChartView.clear()
420        self.error([0, 1])
421        if not self.genesinrows and len(self.geneAttrs) == 0:
422            self.error(0, "Input data contains no attributes with gene names")
423            return
[1761]424
[1804]425        self.updateGenematcher()
426
[1478]427        self.progressBarInit()
428        self.currentAnnotatedCategories = categories = self.selectedCategories()
[1761]429
[1478]430        ## Load collections in a worker thread
431        call = self.asyncCall(obiGeneSets.collections, categories, name="Loading collections", blocking=True, thread=self.thread())
432        call.connect(call, SIGNAL("progressChanged(float)"), self.progressBarSet)
433        with orngServerFiles.DownloadProgress.setredirect(call.emitProgressChanged):
434            call.__call__()
435            collections = list(call.get_result())
[1761]436
[1478]437#        with orngServerFiles.DownloadProgress.setredirect(self.progressBarSet):
[1761]438#            collections = list(obiGeneSets.collections(*categories))
[1478]439        clusterGenes, referenceGenes = self.clusterGenes(), self.referenceGenes()
440        cache = {}
441
442        self.genematcher.set_targets(referenceGenes)
[1761]443
[1478]444        countAll = len(set(clusterGenes))
445        infoText = "%i unique gene names on input\n" % countAll
446        referenceGenes = set(self.mapGeneNames(referenceGenes, cache, passUnknown=False))
447        self.progressBarSet(1)
448        clusterGenes = set(self.mapGeneNames(clusterGenes, cache, passUnknown=False))
449        self.progressBarSet(2)
450        infoText += "%i (%.1f) gene names matched" % (len(clusterGenes), 100.0 * len(clusterGenes) / countAll)
451        self.infoBox.setText(infoText)
[1761]452
[1478]453        results = []
[1632]454        from Orange.orng.orngMisc import progressBarMilestones
[1761]455
[1478]456        milestones = progressBarMilestones(len(collections), 100)
457        for i, geneset in enumerate(collections):
458            results.append((geneset, self.enrichment(geneset, clusterGenes, referenceGenes, cache=cache)))
459            if i in milestones:
460                self.progressBarSet(100.0 * i / len(collections))
[1761]461
[1478]462        if self.useFDR:
463            results = sorted(results, key=lambda a:a[1][2])
464            pvals = obiProb.FDR([pval for _, (_, _, pval, _) in results])
465            results = [(geneset, (cmapped, rmapped, pvals[i], es)) for i, (geneset, (cmapped, rmapped, _, es)) in enumerate(results)]
[1761]466
[1478]467        fmt = lambda score, max_decimals=10: "%%.%if" % min(int(abs(math.log(max(score, 1e-10)))) + 2, max_decimals) if score > math.pow(10, -max_decimals) and score < 1 else "%.1f"
468        self.annotationsChartView.clear()
[1761]469
[1478]470        maxCount = max([len(cm) for _, (cm, _, _, _) in results] + [1])
471        maxRefCount = max([len(rc) for _, (_, rc, _, _) in results] + [1])
472        countSpaces = int(math.ceil(math.log10(maxCount)))
[1761]473        #print maxRefCount
[1478]474        refSpaces = int(math.ceil(math.log(maxRefCount)))
475        countFmt = "%"+str(countSpaces) + "s  (%.2f%%)"
476        refFmt = "%"+str(refSpaces) + "s  (%.2f%%)"
[1761]477
[1478]478        self.filterCompleter.setModel(None)
479        linkFont = QFont(self.annotationsChartView.viewOptions().font)
480        linkFont.setUnderline(True)
481        self.treeItems = []
482        for i, (geneset, (cmapped, rmapped, p_val, enrichment)) in enumerate(results):
483            if len(cmapped) > 0:
[1861]484                item = MyTreeWidgetItem(self.annotationsChartView, [" ".join(geneset.hierarchy), gsname(geneset)])
[1478]485                item.setData(2, Qt.DisplayRole, QVariant(countFmt % (len(cmapped), 100.0*len(cmapped)/countAll)))
[1498]486                item.setData(2, Qt.ToolTipRole, QVariant(len(cmapped))) # For filtering
[1478]487                item.setData(3, Qt.DisplayRole, QVariant(refFmt % (len(rmapped), 100.0*len(rmapped)/len(referenceGenes))))
[1824]488                item.setData(4, Qt.DisplayRole, QVariant("%0.6f" % p_val)) if p_val > 0.001 else item.setData(4, Qt.DisplayRole, QVariant("%0.2e" % p_val))
[1863]489                item.setData(4, 42, QVariant(p_val)) #sorting
[1761]490                item.setData(4, Qt.ToolTipRole, QVariant("%0.10f" % p_val))
[1478]491                item.setData(5, Qt.DisplayRole, QVariant(enrichment))
492                item.setData(5, Qt.ToolTipRole, QVariant("%.3f" % enrichment))
493                item.geneset= geneset
494                self.treeItems.append(item)
495                if geneset.link:
496                    item.setData(1, LinkRole, QVariant(geneset.link))
497                    item.setToolTip(1, geneset.link)
498                    item.setFont(1, linkFont)
499                    item.setForeground(1, QColor(Qt.blue))
[1761]500
[1478]501        if not self.treeItems:
502            self.warning(0, "No enriched sets found.")
503        else:
504            self.warning(0)
[1761]505
[1478]506        replace = lambda s:s.replace(",", " ").replace("(", " ").replace(")", " ")
[1861]507        self._completerModel = completerModel = QStringListModel(sorted(reduce(set.union, [[gsname(geneset)] + replace(gsname(geneset)).split() for geneset, (c, _, _, _) in results if c], set())))
[1478]508        self.filterCompleter.setModel(completerModel)
[1761]509
[1478]510        self.annotationsChartView.setItemDelegateForColumn(5, BarItemDelegate(self, scale=(0.0, max(t[1][3] for t in results))))
511        self.annotationsChartView.setItemDelegateForColumn(1, LinkStyledItemDelegate(self.annotationsChartView))
[1761]512
[1478]513        for i in range(self.annotationsChartView.columnCount()):
514            self.annotationsChartView.resizeColumnToContents(i)
[1761]515
[1478]516        self.annotationsChartView.setColumnWidth(1, min(self.annotationsChartView.columnWidth(1), 300))
517        self.progressBarFinished()
518        QTimer.singleShot(10, self.filterAnnotationsChartView)
519        self.updatingAnnotationsFlag = False
[1761]520
[1478]521    def filterAnnotationsChartView(self, filterString=""):
522        if self.updatingAnnotationsFlag:
523            return
524        categories = set(" ".join(cat) for cat, taxid in self.selectedCategories())
[1863]525
526        #compute FDR after selection categories
527   
[1478]528        filterString = str(self.filterLineEdit.text()).lower()
529        itemsHidden = []
530        for item in self.treeItems:
531            item_cat = str(item.data(0, Qt.EditRole).toString())
[1761]532            count, pval = _toPyObject(item.data(2, Qt.ToolTipRole)), _toPyObject(item.data(4, 42))
[1861]533            geneset = gsname(item.geneset).lower()
[1478]534            hidden = item_cat not in categories or (self.useMinCountFilter and count < self.minClusterCount) or \
535                     (self.useMaxPValFilter and pval > self.maxPValue) or filterString not in geneset
536            item.setHidden(hidden)
537            itemsHidden.append(hidden)
[1761]538
[1478]539        if self.treeItems and all(itemsHidden):
540            self.information(0, "All sets were filtered out.")
541        else:
542            self.information(0)
[1761]543
544
[1478]545    def commit(self):
546        selected = self.annotationsChartView.selectedItems()
547        genesets = [item.geneset for item in selected]
548        cache = {}
549        mappedNames = set(self.mapGeneNames(reduce(set.union, [geneset.genes for geneset in genesets], set()), cache))
550        if self.genesinrows:
551            mapped = [attr for attr in self.data.domain.attributes if self.genematcher.umatch(attr.name) in mappedNames]
552            newdomain = orange.Domain(mapped, self.data.domain.classVar)
553            newdomain.addmetas(self.data.domain.getmetas())
554            data = orange.ExampleTable(newdomain, self.data)
555        else:
556            geneattr = self.geneAttrs[self.geneattr]
[1761]557            selected = [1 if self.genematcher.umatch(str(ex[geneattr])) in mappedNames else 0 for ex in self.data]
[1478]558            data = self.data.select(selected)
[1761]559
[1478]560#            if self.appendAnnotations:
561#                meta = orange.StringVariable("Annotations")
562#                data.domain.addmeta(orange.newmetaid(), meta)
563#                for ex in data:
564#                    geneattr = self.geneAttrs[self.geneattr]
565#                    gene = str(ex[geneattr])
566#                    annotations = getgene
[1761]567
[1478]568        self.send("Selected Examples", data)
[1761]569
[1478]570    def sendReport(self):
571        self.reportSettings("Settings", [("Organism", obiTaxonomy.name(self.taxid_list[self.speciesIndex]))])
572        self.reportSettings("Filter", [("Min cluster size", self.minClusterCount if self.useMinCountFilter else 0),
573                                       ("Max p-value", self.maxPValue if self.useMaxPValFilter else 1.0)])
[1761]574
[1478]575        self.reportSubsection("Annotations")
576        self.reportRaw(reportItemView(self.annotationsChartView))
[1761]577
[1478]578    def onStateChange(self, stateType, id, text):
579        if stateType == "Warning" or stateType == "Info":
580            self.annotationsChartView._userMessage = text
581            self.annotationsChartView.viewport().update()
[1761]582
583
[1478]584def reportItemView(view):
585    model = view.model()
586    return reportItemModel(view, model)
[1761]587
[1478]588def reportItemModel(view, model, index=QModelIndex()):
589    if not index.isValid() or model.hasChildren(index):
590        columnCount, rowCount = model.columnCount(index), model.rowCount(index)
591        if not index.isValid():
592            text = '<table>\n<tr>' + ''.join('<th>%s</th>' % model.headerData(i, Qt.Horizontal, Qt.DisplayRole).toString() for i in range(columnCount)) +'</tr>\n'
593        else:
594#            variant = model.data(index, Qt.DisplayRole)
595#            text = '<table' + (' caption="%s"' % variant.toString() if variant.isValid() else '') + '>\n'
596            pass
597        text += ''.join('<tr>' + ''.join('<td>' + reportItemModel(view, model, model.index(row, column, index)) + '</td>' for column in range(columnCount)) + '</tr>\n' for row in range(rowCount) if not view.isRowHidden(row, index))
598        text += '</table>'
599        return text
600    else:
601        variant = model.data(index, Qt.DisplayRole)
602        return str(variant.toString()) if variant.isValid() else ""
603
[1761]604
605
[1825]606if __name__ == "__main__": 
[1478]607    import cProfile
[1761]608
[1478]609    app = QApplication(sys.argv)
610    w = OWSetEnrichment()
[1761]611    data = orange.ExampleTable("yeast-class-RPR.tab")
[1863]612    #data = orange.ExampleTable("/home/marko/Downloads/tmp.tab")
[1478]613#    data = orange.ExampleTable("../human")
614#    print cProfile.runctx("w.setData(data)", globals(), locals())
615    w.setData(data)
616    w.show()
617    app.exec_()
618    w.saveSettings()
[1761]619
620
Note: See TracBrowser for help on using the repository browser.