source: orange-bioinformatics/orangecontrib/bio/widgets/OWSetEnrichment.py @ 1879:3e9c962d89f8

Revision 1879:3e9c962d89f8, 28.4 KB checked in by Marko Toplak <marko.toplak@…>, 6 months ago (diff)

Merged in ales_erjavec/orange-bioinformatics (pull request #2)

Move 'anonymous' _bioinformatics package into orangecontrib namespace

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