source: orange-bioinformatics/_bioinformatics/widgets/OWGOEnrichmentAnalysis.py @ 1710:b36fc0b5814c

Revision 1710:b36fc0b5814c, 47.3 KB checked in by Ales Erjavec <ales.erjavec@…>, 21 months ago (diff)

Added 'Enrichment Report' output to the GO Browser widget.

RevLine 
[188]1"""
[1462]2<name>GO Browser</name>
[764]3<description>Enrichment analysis for Gene Ontology terms.</description>
[188]4<contact>Ales Erjavec</contact>
[1701]5<icon>icons/GO Browser.svg</icon>
[1052]6<priority>2020</priority>
[188]7"""
8
[1632]9from __future__ import absolute_import, with_statement
[857]10
[188]11from collections import defaultdict
[638]12from functools import partial
[1632]13import gc
14import sys, os, tarfile, math
15from os.path import join as p_join
[188]16
[1632]17from Orange.orng import orngServerFiles
18from Orange.orng.orngDataCaching import data_hints
19from Orange.OrangeWidgets import OWGUI
20from Orange.OrangeWidgets.OWWidget import *
21
22from .. import obiGene, obiGO, obiProb, obiTaxonomy
[1118]23
[638]24dataDir = orngServerFiles.localpath("GO")
[511]25
[811]26def listAvailable():
[540]27    files = orngServerFiles.listfiles("GO")
28    ret = {}
29    for file in files:
30        tags = orngServerFiles.info("GO", file)["tags"]
31        td = dict([tuple(tag.split(":")) for tag in tags if tag.startswith("#") and ":" in tag])
[545]32        if "association" in file.lower():
33            ret[td.get("#organism", file)] = file
[811]34    orgMap = {"352472":"44689"}
[988]35    essential = ["gene_association.%s.tar.gz" % obiGO.from_taxid(id) for id in obiTaxonomy.essential_taxids() if obiGO.from_taxid(id)]
[985]36    essentialNames = [obiTaxonomy.name(id) for id in obiTaxonomy.essential_taxids() if obiGO.from_taxid(id)]
[811]37    ret.update(zip(essentialNames, essential))
[540]38    return ret
[511]39
[964]40class _disablegc(object):
41    def __enter__(self):
42        gc.disable()
43    def __exit__(self, *args):
44        gc.enable()
45
[511]46def getOrgFileName(org):
[1632]47    from Orange.orng import orngServerFiles
[511]48    files = orngServerFiles.listfiles("go")
49    return [f for f in files if org in f].pop()
50
[188]51class TreeNode(object):
52    def __init__(self, tuple, children):
53        self.tuple = tuple
54        self.children = children
[638]55
56class GOTreeWidget(QTreeWidget):
57    def contextMenuEvent(self, event):
58        QTreeWidget.contextMenuEvent(self, event)
[646]59##        print event.x(), event.y()
[638]60        term = self.itemAt(event.pos()).term
61        self._currMenu = QMenu()
62        self._currAction = self._currMenu.addAction("View term on AmiGO website")
63##        self.connect(self, SIGNAL("triggered(QAction*)"), partial(self.BrowserAction, term))
64        self.connect(self._currAction, SIGNAL("triggered()"), lambda :self.BrowserAction(term))
65        self._currMenu.popup(event.globalPos())
66
67    def BrowserAction(self, term):
68        import webbrowser
[1340]69        if isinstance(term, obiGO.Term):
70            term = term.id
[638]71        webbrowser.open("http://amigo.geneontology.org/cgi-bin/amigo/term-details.cgi?term="+term)
[1248]72       
73    def paintEvent(self, event):
74        QTreeWidget.paintEvent(self, event)
75        if getattr(self, "_userMessage", None):
76            painter = QPainter(self.viewport())
77            font = QFont(self.font())
78            font.setPointSize(15)
79            painter.setFont(font)
80            painter.drawText(self.viewport().geometry(), Qt.AlignCenter, self._userMessage)
81            painter.end()
[638]82
[1710]83
[188]84class OWGOEnrichmentAnalysis(OWWidget):
[1710]85    settingsList = ["annotationIndex", "useReferenceDataset", "aspectIndex",
86                    "geneAttrIndex", "geneMatcherSettings",
87                    "filterByNumOfInstances", "minNumOfInstances",
88                    "filterByPValue", "maxPValue", "selectionDirectAnnotation",
89                    "selectionDisjoint", "selectionType",
90                    "selectionAddTermAsClass", "useAttrNames", "probFunc",
91                    "useFDR"
92                    ]
93
94    contextHandlers = {"": DomainContextHandler(
95                                "",
96                                ["geneAttrIndex", "useAttrNames",
97                                 "annotationIndex", "geneMatcherSettings"],
98                                matchValues=1)
99                       }
100
[1462]101    def __init__(self, parent=None, signalManager=None, name="GO Browser"):
[188]102        OWWidget.__init__(self, parent, signalManager, name)
[1710]103        self.inputs = [("Cluster Examples", ExampleTable,
104                        self.SetClusterDataset, Default),
105                       ("Reference Examples", ExampleTable,
106                        self.SetReferenceDataset, Single + NonDefault)]
107
108        self.outputs = [("Selected Examples", ExampleTable, Default),
109                        ("Unselected Examples", ExampleTable, Default),
110                        ("Example With Unknown Genes", ExampleTable, Default),
111                        ("Enrichment Report", ExampleTable)]
[188]112
113        self.annotationIndex = 0
114        self.autoFindBestOrg = False
[1710]115        self.useReferenceDataset = 0
[188]116        self.aspectIndex = 0
117        self.geneAttrIndex = 0
118        self.useAttrNames = False
[988]119        self.geneMatcherSettings = [True, False, False, False]
[188]120        self.filterByNumOfInstances = False
121        self.minNumOfInstances = 1
122        self.filterByPValue = True
123        self.maxPValue = 0.1
[801]124        self.probFunc = 0
125        self.useFDR = True
[188]126        self.selectionDirectAnnotation = 0
127        self.selectionDisjoint = 0
128        self.selectionAddTermAsClass = 0
[219]129        self.selectionChanging = 0
130       
[188]131        # check usage of all evidences
[540]132        for etype in obiGO.evidenceTypesOrdered:
[1328]133            varName = "useEvidence" + etype
134            if varName not in self.settingsList: 
135                self.settingsList.append(varName)
[188]136            code = compile("self.%s = True" % (varName), ".", "single")
137            exec(code)
[865]138        self.annotationCodes = []
139       
[1328]140        self.loadSettings()
141       
[188]142        #############
143        ##GUI
144        #############
[196]145        self.tabs = OWGUI.tabWidget(self.controlArea)
[188]146        ##Input tab
[196]147        self.inputTab = OWGUI.createTabPage(self.tabs, "Input")
[770]148        box = OWGUI.widgetBox(self.inputTab, "Info")
149        self.infoLabel = OWGUI.widgetLabel(box, "No data on input\n")
[1248]150       
[1328]151        OWGUI.button(box, self, "Ontology/Annotation Info", callback=self.ShowInfo,
152                     tooltip="Show information on loaded ontology and annotations",
153                     debuggingEnabled=0)
[770]154        box = OWGUI.widgetBox(self.inputTab, "Organism", addSpace=True)
[1328]155        self.annotationComboBox = OWGUI.comboBox(box, self, "annotationIndex",
156                            items = self.annotationCodes, callback=self.Update,
157                            tooltip="Select organism", debuggingEnabled=0)
[865]158       
[1328]159        # freeze until annotation combo box is updateded with available annotations.
160        self.signalManager.freeze(self).push()
[865]161        QTimer.singleShot(0, self.UpdateOrganismComboBox)
162       
[1328]163        self.geneAttrIndexCombo = OWGUI.comboBox(self.inputTab, self, "geneAttrIndex",
164                            box="Gene names", callback=self.Update,
165                            tooltip="Use this attribute to extract gene names from input data")
166        OWGUI.checkBox(self.geneAttrIndexCombo.box, self, "useAttrNames", "Use data attributes names",
167                       disables=[(-1, self.geneAttrIndexCombo)], callback=self.Update, 
168                       tooltip="Use attribute names for gene names")
169        OWGUI.button(self.geneAttrIndexCombo.box, self, "Gene matcher settings", 
170                     callback=self.UpdateGeneMatcher, 
171                     tooltip="Open gene matching settings dialog", 
172                     debuggingEnabled=0)
[801]173       
[1328]174        self.referenceRadioBox = OWGUI.radioButtonsInBox(self.inputTab, self, "useReferenceDataset", 
175                                                         ["Entire genome", "Reference set (input)"],
176                                                         tooltips=["Use entire genome for reference",
177                                                                   "Use genes from Referece Examples input signal as reference"],
178                                                         box="Reference", callback=self.Update)
[770]179        self.referenceRadioBox.buttons[1].setDisabled(True)
[1328]180        OWGUI.radioButtonsInBox(self.inputTab, self, "aspectIndex", ["Biological process",
181                                                                     "Cellular component",
182                                                                     "Molecular function"], 
183                                box="Aspect", callback=self.Update)
184       
[215]185        self.geneAttrIndexCombo.setDisabled(bool(self.useAttrNames))
[188]186       
187        ##Filter tab
[196]188        self.filterTab = OWGUI.createTabPage(self.tabs, "Filter")
[188]189        box = OWGUI.widgetBox(self.filterTab, "Filter GO Term Nodes", addSpace=True)
[1328]190        OWGUI.checkBox(box, self, "filterByNumOfInstances", "Genes",
191                       callback=self.FilterAndDisplayGraph, 
192                       tooltip="Filter by number of input genes mapped to a term")
193        OWGUI.spin(OWGUI.indentedBox(box), self, 'minNumOfInstances', 1, 100, 
194                   step=1, label='#:', labelWidth=15, 
195                   callback=self.FilterAndDisplayGraph, 
196                   callbackOnReturn=True, 
197                   tooltip="Min. number of input genes mapped to a term")
198       
199        OWGUI.checkBox(box, self, "filterByPValue", "Significance",
200                       callback=self.FilterAndDisplayGraph, 
201                       tooltip="Filter by term p-value")
202        OWGUI.doubleSpin(OWGUI.indentedBox(box), self, 'maxPValue', 1e-8, 1, 
203                         step=1e-8,  label='p:', labelWidth=15, 
204                         callback=self.FilterAndDisplayGraph, 
205                         callbackOnReturn=True, 
206                         tooltip="Max term p-value")
[801]207        box = OWGUI.widgetBox(box, "Significance test")
[1328]208        OWGUI.radioButtonsInBox(box, self, "probFunc", ["Binomial", "Hypergeometric"], 
209                                tooltips=["Use binomial distribution test", 
210                                          "Use hypergeometric distribution test"], 
211                                callback=self.Update)
212        OWGUI.checkBox(box, self, "useFDR", "Use FDR (False Discovery Rate)", 
213                       callback=self.Update, 
214                       tooltip="Use False Discovery Rate correction")
215        box = OWGUI.widgetBox(self.filterTab, "Evidence codes in annotation", 
216                              addSpace=True)
[188]217        self.evidenceCheckBoxDict = {}
[540]218        for etype in obiGO.evidenceTypesOrdered:
[1328]219            self.evidenceCheckBoxDict[etype] = OWGUI.checkBox(box, self, "useEvidence"+etype, etype,
220                                            callback=self.Update, tooltip=obiGO.evidenceTypes[etype])
[188]221       
222        ##Select tab
[196]223        self.selectTab = OWGUI.createTabPage(self.tabs, "Select")
[1328]224        box = OWGUI.radioButtonsInBox(self.selectTab, self, "selectionDirectAnnotation", 
225                                      ["Directly or Indirectly", "Directly"], 
226                                      box="Annotated genes", 
227                                      callback=self.ExampleSelection)
228       
[188]229        box = OWGUI.widgetBox(self.selectTab, "Output", addSpace=True)
[1328]230        OWGUI.radioButtonsInBox(box, self, "selectionDisjoint", 
231                                btnLabels=["All selected genes", 
232                                           "Term-specific genes", 
233                                           "Common term genes"], 
234                                tooltips=["Outputs genes annotated to all selected GO terms", 
235                                          "Outputs genes that appear in only one of selected GO terms", 
236                                          "Outputs genes common to all selected GO terms"], 
237                                callback=[self.ExampleSelection,
238                                          self.UpdateAddClassButton])
239        self.addClassCB = OWGUI.checkBox(box, self, "selectionAddTermAsClass",
240                                         "Add GO Term as class", 
241                                         callback=self.ExampleSelection)
[188]242
243        # ListView for DAG, and table for significant GOIDs
[851]244        self.DAGcolumns = ['GO term', 'Cluster', 'Reference', 'p value', 'Genes', 'Enrichment']
[1328]245       
[196]246        self.splitter = QSplitter(Qt.Vertical, self.mainArea)
247        self.mainArea.layout().addWidget(self.splitter)
[188]248
249        # list view
[638]250        self.listView = GOTreeWidget(self.splitter)
[843]251        self.listView.setSelectionMode(QAbstractItemView.ExtendedSelection)
[188]252        self.listView.setAllColumnsShowFocus(1)
[196]253        self.listView.setColumnCount(len(self.DAGcolumns))
254        self.listView.setHeaderLabels(self.DAGcolumns)
255       
[200]256        self.listView.header().setClickable(True)
257        self.listView.header().setSortIndicatorShown(True)
258        self.listView.setSortingEnabled(True)
[416]259        self.listView.setItemDelegateForColumn(5, EnrichmentColumnItemDelegate(self))
[641]260        self.listView.setRootIsDecorated(True)
261
[200]262       
[196]263        self.connect(self.listView, SIGNAL("itemSelectionChanged()"), self.ViewSelectionChanged)
[641]264       
[188]265        # table of significant GO terms
[511]266        self.sigTerms = QTreeWidget(self.splitter)
267        self.sigTerms.setColumnCount(len(self.DAGcolumns))
268        self.sigTerms.setHeaderLabels(self.DAGcolumns)
[641]269        self.sigTerms.setSortingEnabled(True)
[843]270        self.sigTerms.setSelectionMode(QAbstractItemView.ExtendedSelection)
[641]271       
[511]272        self.connect(self.sigTerms, SIGNAL("itemSelectionChanged()"), self.TableSelectionChanged)
[188]273        self.splitter.show()
274
275        self.sigTableTermsSorted = []
276        self.graph = {}
[854]277       
[188]278        self.loadedAnnotationCode = "---"
[196]279       
280        self.inputTab.layout().addStretch(1)
281        self.filterTab.layout().addStretch(1)
282        self.selectTab.layout().addStretch(1)
283       
[899]284        self.resize(1000, 800)
[188]285
286        self.clusterDataset = None
[854]287        self.referenceDataset = None
[540]288        self.ontology = None
289        self.annotations = None
[1139]290        self.treeStructRootKey = None
[801]291        self.probFunctions = [obiProb.Binomial(), obiProb.Hypergeometric()]
[1002]292        self.selectedTerms = []
[188]293       
[1248]294        self.connect(self, SIGNAL("widgetStateChanged(QString, int, QString)"), self.onStateChanged)
295       
[865]296    def UpdateOrganismComboBox(self):
297        try:
298            if self.annotationCodes and len(self.annotationCodes) > self.annotationIndex:
299                currAnnotationCode = self.annotationCodes[self.annotationIndex]
300            else:
301                currAnnotationCode = None
302            self.progressBarInit()
303            with orngServerFiles.DownloadProgress.setredirect(self.progressBarSet):
304                self.annotationFiles = listAvailable()
305            self.progressBarFinished()
306            self.annotationCodes = sorted(self.annotationFiles.keys())
307            self.annotationComboBox.clear()
308            self.annotationComboBox.addItems(self.annotationCodes)
309            self.annotationComboBox.setCurrentIndex(self.annotationIndex)
310        finally:
[1328]311            self.signalManager.freeze(self).pop()
[988]312           
313    def UpdateGeneMatcher(self):
314        dialog = GeneMatcherDialog(self, defaults=self.geneMatcherSettings, modal=True)
315        if dialog.exec_():
316            self.geneMatcherSettings = [getattr(dialog, item[0]) for item in dialog.items]
317            if self.annotations:
318                self.SetGeneMatcher()
319                if self.clusterDataset:
320                    self.Update()
321               
[188]322    def Update(self):
323        if self.clusterDataset:
[1014]324            pb = OWGUI.ProgressBar(self, 100)
325            self.Load(pb=pb)
[188]326            self.FilterUnknownGenes()
[1014]327            graph = self.Enrichment(pb=pb)
[188]328            self.SetGraph(graph)
329
[511]330    def UpdateGOAndAnnotation(self, tags=[]):
[1632]331        from .OWUpdateGenomicsDatabases import OWUpdateGenomicsDatabases
[511]332        w = OWUpdateGenomicsDatabases(parent = self, searchString=" ".join(tags))
[396]333        w.setModal(True)
[188]334        w.show()
[511]335        self.UpdateAnnotationComboBox()
[188]336
337    def UpdateAnnotationComboBox(self):
[396]338        if self.annotationCodes:
[540]339            curr = self.annotationCodes[min(self.annotationIndex, len(self.annotationCodes)-1)]
[396]340        else:
341            curr = None
[811]342        self.annotationFiles = listAvailable()
[540]343        self.annotationCodes = self.annotationFiles.keys()
[396]344        index = curr and self.annotationCodes.index(curr) or 0
[188]345        self.annotationComboBox.clear()
[396]346        self.annotationComboBox.addItems(self.annotationCodes)
347        self.annotationComboBox.setCurrentIndex(index)
348        if not self.annotationCodes:
349            self.error(0, "No downloaded annotations!!\nClick the update button and update annotationa for at least one organism!")
350        else:
351            self.error(0)
[188]352
353    def SetGenesComboBox(self):
[389]354        self.candidateGeneAttrs = self.clusterDataset.domain.variables + self.clusterDataset.domain.getmetas().values()
[1328]355        self.candidateGeneAttrs = filter(lambda v: v.varType in [orange.VarTypes.String,
356                                                                 orange.VarTypes.Other,
357                                                                 orange.VarTypes.Discrete], 
358                                         self.candidateGeneAttrs)
[188]359        self.geneAttrIndexCombo.clear()
[196]360        self.geneAttrIndexCombo.addItems([a.name for a in  self.candidateGeneAttrs])
[188]361
362    def FindBestGeneAttrAndOrganism(self):
363        if self.autoFindBestOrg: 
364            organismGenes = dict([(o,set(go.getCachedGeneNames(o))) for o in self.annotationCodes])
365        else:
[540]366            currCode = self.annotationCodes[min(self.annotationIndex, len(self.annotationCodes)-1)]
367            filename = p_join(dataDir, self.annotationFiles[currCode])
[638]368            try:
369                f = tarfile.open(filename)
370                info = [info for info in f.getmembers() if info.name.startswith("gene_names")].pop()
371                geneNames = cPickle.loads(f.extractfile(info).read().replace("\r\n", "\n"))
372            except Exception, ex:
373                geneNames = cPickle.loads(open(p_join(filename, "gene_names.pickle")).read().replace("\r\n", "\n"))
[511]374            organismGenes = {currCode: set(geneNames)}
[188]375        candidateGeneAttrs = self.clusterDataset.domain.attributes + self.clusterDataset.domain.getmetas().values()
[1328]376        candidateGeneAttrs = filter(lambda v: v.varType in [orange.VarTypes.String, 
377                                                            orange.VarTypes.Other, 
378                                                            orange.VarTypes.Discrete], 
379                                    candidateGeneAttrs)
[188]380        attrNames = [v.name for v in self.clusterDataset.domain.variables]
381        cn = {}
382        for attr in candidateGeneAttrs:
383            vals = [str(e[attr]) for e in self.clusterDataset]
[209]384            if any("," in val for val in vals):
385                vals = reduce(list.__add__, (val.split(",") for val in vals))
[188]386            for organism, s in organismGenes.items():
387                l = filter(lambda a: a in s, vals)
[540]388                cn[(attr,organism)] = len(set(l))
[188]389        for organism, s in organismGenes.items():
390            l = filter(lambda a: a in s, attrNames)
[540]391            cn[("_var_names_", organism)] = len(set(l))
[188]392           
393        cn = cn.items()
394        cn.sort(lambda a,b:-cmp(a[1],b[1]))
[390]395        ((bestAttr, organism), count) = cn[0]
396        if bestAttr=="_var_names_" and count<=len(attrNames)/10.0 or \
397           bestAttr!="_var_names_" and count<=len(self.clusterDataset)/10.0:
398            return
399       
400        self.annotationIndex = self.annotationCodes.index(organism)
[188]401        if bestAttr=="_var_names_":
402            self.useAttrNames = True
403            self.geneAttrIndex = 0
404        else:
405            self.useAttrNames = False
406            self.geneAttrIndex = candidateGeneAttrs.index(bestAttr)
[1710]407
[188]408    def SetClusterDataset(self, data=None):
[1254]409        if not self.annotationCodes:
410            QTimer.singleShot(200, lambda: self.SetClusterDataset(data))
411            return
[416]412        self.closeContext()
[188]413        self.clusterDataset = data
[770]414        self.infoLabel.setText("\n")
[188]415        if data:
416            self.SetGenesComboBox()
[1118]417            try:
418                taxid = data_hints.get_hint(data, "taxid", "")
419                code = obiGO.from_taxid(taxid)
420                filename = "gene_association.%s.tar.gz" % code
421                if filename in self.annotationFiles.values():
[1710]422                    self.annotationIndex = \
423                            [i for i, name in enumerate(self.annotationCodes) \
424                             if self.annotationFiles[name] == filename].pop()
[1118]425            except Exception:
426                pass
[1710]427            self.useAttrNames = data_hints.get_hint(data, "genesinrows",
428                                                    self.useAttrNames)
[416]429            self.openContext("", data)
[985]430            self.Update()
[188]431        else:
[770]432            self.infoLabel.setText("No data on input\n")
[1248]433            self.warning(0)
434            self.warning(1)
[416]435            self.openContext("", None)
[188]436            self.ClearGraph()
437            self.send("Selected Examples", None)
438            self.send("Unselected Examples", None)
439            self.send("Example With Unknown Genes", None)
[1710]440            self.send("Enrichment Report", None)
[188]441
442    def SetReferenceDataset(self, data=None):
[1710]443        self.referenceDataset = data
[770]444        self.referenceRadioBox.buttons[1].setDisabled(not bool(data))
[921]445        self.referenceRadioBox.buttons[1].setText("Reference set")
[854]446        if self.clusterDataset and self.useReferenceDataset:
[921]447            self.useReferenceDataset = 0 if not data else 1
[854]448            graph = self.Enrichment()
[188]449            self.SetGraph(graph)
[921]450        elif self.clusterDataset:
451            self.UpdateReferenceSetButton()
[1710]452
[921]453    def UpdateReferenceSetButton(self):
454        allgenes, refgenes = None, None
455        if self.referenceDataset:
456            try:
457                allgenes = self.GenesFromExampleTable(self.referenceDataset)
458            except Exception:
459                allgenes = []
460            refgenes, unknown = self.FilterAnnotatedGenes(allgenes)
461        self.referenceRadioBox.buttons[1].setDisabled(not bool(allgenes))
462        self.referenceRadioBox.buttons[1].setText("Reference set " + ("(%i genes, %i matched)" % (len(allgenes), len(refgenes)) if allgenes and refgenes else ""))
[188]463
[921]464    def GenesFromExampleTable(self, data):
465        if self.useAttrNames:
466            genes = [v.name for v in data.domain.variables]
467        else:
468            attr = self.candidateGeneAttrs[min(self.geneAttrIndex, len(self.candidateGeneAttrs) - 1)]
469            genes = [str(ex[attr]) for ex in data if not ex[attr].isSpecial()]
470            if any("," in gene for gene in genes):
471                self.information(0, "Separators detected in gene names. Assuming multiple genes per example.")
472                genes = reduce(list.__add__, (genes.split(",") for genes in genes))
473        return genes
474       
475    def FilterAnnotatedGenes(self, genes):
476        matchedgenes = self.annotations.GetGeneNamesTranslator(genes).values()
477        return matchedgenes, [gene for gene in genes if gene not in matchedgenes]
478       
[188]479    def FilterUnknownGenes(self):
[1153]480        if not self.useAttrNames and self.candidateGeneAttrs:
[559]481            geneAttr = self.candidateGeneAttrs[min(self.geneAttrIndex, len(self.candidateGeneAttrs)-1)]
[188]482            examples = []
483            for ex in self.clusterDataset:
[988]484                if not any(self.annotations.genematcher.match(n.strip()) for n in str(ex[geneAttr]).split(",")):
[188]485                    examples.append(ex)
[921]486
[188]487            self.send("Example With Unknown Genes", examples and orange.ExampleTable(examples) or None)
488        else:
489            self.send("Example With Unknown Genes", None)
490
[1014]491    def Load(self, pb=None):
[985]492        go_files, tax_files = orngServerFiles.listfiles("GO"), orngServerFiles.listfiles("Taxonomy")
493        calls = []
[1014]494        pb, finish = (OWGUI.ProgressBar(self, 0), True) if pb is None else (pb, False)
[985]495        count = 0
496        if not tax_files:
497            calls.append(("Taxonomy", "ncbi_taxnomy.tar.gz"))
498            count += 1
499        org = self.annotationCodes[min(self.annotationIndex, len(self.annotationCodes)-1)]
500        if org != self.loadedAnnotationCode:
501            count += 1
[988]502            if self.annotationFiles[org] not in go_files:
503                calls.append(("GO", self.annotationFiles[org]))
[985]504                count += 1
505               
506        if "gene_ontology_edit.obo.tar.gz" not in go_files:
507            calls.append(("GO", "gene_ontology_edit.obo.tar.gz"))
508            count += 1
509        if not self.ontology:
510            count += 1
[1014]511        pb.iter += count*100
[1328]512       
[985]513        for i, args in enumerate(calls):
[1014]514            orngServerFiles.localpath_download(*args, **dict(callback=pb.advance))
[985]515           
516        i = len(calls)
517        if not self.ontology:
[1328]518            self.ontology = obiGO.Ontology(progressCallback=lambda value: pb.advance())
[985]519            i+=1
520        if org != self.loadedAnnotationCode:
[1352]521            self.annotations = None
522            gc.collect() # Force run garbage collection.
[988]523            code = self.annotationFiles[org].split(".")[-3]
[1328]524            self.annotations = obiGO.Annotations(code, genematcher=obiGene.GMDirect(), progressCallback=lambda value: pb.advance())
[985]525            i+=1
526            self.loadedAnnotationCode = org
[188]527            count = defaultdict(int)
528            geneSets = defaultdict(set)
[921]529
[540]530            for anno in self.annotations.annotations:
[188]531                count[anno.evidence]+=1
532                geneSets[anno.evidence].add(anno.geneName)
[540]533            for etype in obiGO.evidenceTypesOrdered:
[188]534                self.evidenceCheckBoxDict[etype].setEnabled(bool(count[etype]))
535                self.evidenceCheckBoxDict[etype].setText(etype+": %i annots(%i genes)" % (count[etype], len(geneSets[etype])))
[1014]536        if finish:
537            pb.finish()
[985]538           
[988]539    def SetGeneMatcher(self):
540        if self.annotations:
541            taxid = self.annotations.taxid
542            matchers = []
543            for matcher, use in zip([obiGene.GMGO, obiGene.GMKEGG, obiGene.GMNCBI, obiGene.GMAffy], self.geneMatcherSettings):
544                if use:
545                    try:
[1064]546                        if taxid == "352472":
[1330]547                            matchers.extend([matcher(taxid), obiGene.GMDicty(),
548                                            [matcher(taxid), obiGene.GMDicty()]])
549                            # The reason machers are duplicated is that we want `matcher` or `GMDicty` to
550                            # match genes by them self if possible. Only use the joint matcher if they fail.   
[1064]551                        else:
552                            matchers.append(matcher(taxid))
[988]553                    except Exception, ex:
554                        print ex
555            self.annotations.genematcher = obiGene.matcher(matchers)
[1014]556            self.annotations.genematcher.set_targets(self.annotations.geneNames)
[988]557           
[1014]558    def Enrichment(self, pb=None):
559        pb = OWGUI.ProgressBar(self, 100) if pb is None else pb
[559]560        if not self.annotations.ontology:
561            self.annotations.ontology = self.ontology
[921]562           
[988]563        if isinstance(self.annotations.genematcher, obiGene.GMDirect):
564            self.SetGeneMatcher()
[1153]565        self.error(1)
[1248]566        self.warning([0, 1])
[1153]567        try:   
568            if self.useAttrNames:
569                clusterGenes = [v.name for v in self.clusterDataset.domain.variables]
570                self.information(0)
[209]571            else:
[1153]572                geneAttr = self.candidateGeneAttrs[min(self.geneAttrIndex, len(self.candidateGeneAttrs)-1)]
573                clusterGenes = [str(ex[geneAttr]) for ex in self.clusterDataset if not ex[geneAttr].isSpecial()]
574                if any("," in gene for gene in clusterGenes):
575                    self.information(0, "Separators detected in cluster gene names. Assuming multiple genes per example.")
576                    clusterGenes = reduce(list.__add__, (genes.split(",") for genes in clusterGenes))
577                else:
578                    self.information(0)
579        except Exception, ex:
580            self.error(1, "Failed to extract gene names from input dataset! %s" % str(ex))
581            return {}
[770]582        genesCount = len(clusterGenes)
[1330]583        genesSetCount = len(set(clusterGenes))
[921]584       
[988]585        self.clusterGenes = clusterGenes = self.annotations.GetGeneNamesTranslator(clusterGenes).values()
586       
587#        self.clusterGenes = clusterGenes = filter(lambda g: g in self.annotations.aliasMapper or g in self.annotations.additionalAliases, clusterGenes)
[1330]588        self.infoLabel.setText("%i unique genes on input\n%i (%.1f%%) genes with known annotations" % (genesSetCount, len(clusterGenes), 100.0*len(clusterGenes)/genesSetCount if genesSetCount else 0.0))
[921]589       
[188]590        referenceGenes = None
[921]591        if self.referenceDataset:
[188]592            try:
593                if self.useAttrNames:
594                    referenceGenes = [v.name for v in self.referenceDataset.domain.variables]
[209]595                    self.information(1)
[188]596                else:
597                    referenceGenes = [str(ex[geneAttr]) for ex in self.referenceDataset if not ex[geneAttr].isSpecial()]
[209]598                    if any("," in gene for gene in clusterGenes):
599                        self.information(1, "Separators detected in reference gene names. Assuming multiple genes per example.")
600                        referenceGenes = reduce(list.__add__, (genes.split(",") for genes in referenceGenes))
601                    else:
602                        self.information(1)
[921]603
604                refc = len(referenceGenes)
[988]605#                referenceGenes = filter(lambda g: g in self.annotations.aliasMapper or g in self.annotations.additionalAliases, referenceGenes)
606                referenceGenes = self.annotations.GetGeneNamesTranslator(referenceGenes).values()
[921]607                self.referenceRadioBox.buttons[1].setText("Reference set (%i genes, %i matched)" % (refc, len(referenceGenes)))
608                self.referenceRadioBox.buttons[1].setDisabled(False)
[209]609                self.information(2)
[188]610            except Exception, er:
[921]611                if not self.referenceDataset:
612                    self.information(2, "Unable to extract gene names from reference dataset. Using entire genome for reference")
613                else:
614                    self.referenceRadioBox.buttons[1].setText("Reference set")
615                    self.referenceRadioBox.buttons[1].setDisabled(True)
[845]616                referenceGenes = self.annotations.geneNames
[854]617                self.useReferenceDataset = 0
[188]618        else:
[921]619            self.useReferenceDataset = 0
620        if not self.useReferenceDataset:
[209]621            self.information(2)
[921]622            self.information(1)
[540]623            referenceGenes = self.annotations.geneNames
[209]624        self.referenceGenes = referenceGenes
[188]625        evidences = []
[540]626        for etype in obiGO.evidenceTypesOrdered:
[188]627            if getattr(self, "useEvidence"+etype):
628                evidences.append(etype)
[217]629        aspect = ["P", "C", "F"][self.aspectIndex]
[1328]630       
[188]631        if clusterGenes:
[801]632            self.terms = terms = self.annotations.GetEnrichedTerms(clusterGenes, referenceGenes, evidences, aspect=aspect,
[1099]633                                                                   prob=self.probFunctions[self.probFunc], useFDR=self.useFDR,
[1328]634                                                                   progressCallback=lambda value:pb.advance() )
[188]635        else:
636            self.terms = terms = {}
[438]637        if not self.terms:
[1248]638            self.warning(0, "No enriched terms found.")
[438]639        else:
640            self.warning(0)
[1328]641           
[1014]642        pb.finish()
[188]643        self.treeStructDict = {}
644        ids = self.terms.keys()
[1139]645       
646        self.treeStructRootKey = None
[1352]647       
648        parents = {}
649        for id in ids:
650            parents[id] = set([term for typeId, term in self.ontology[id].related])
651           
652        children = {}
[188]653        for term in self.terms:
[1352]654            children[term] = set([id for id in ids if term in parents[id]])
655           
656        for term in self.terms:
657            self.treeStructDict[term] = TreeNode(self.terms[term], children[term])
[799]658            if not self.ontology[term].related and not getattr(self.ontology[term], "is_obsolete", False):
[188]659                self.treeStructRootKey = term
660        return terms
661       
662    def FilterGraph(self, graph):
663        if self.filterByPValue:
[540]664            graph = obiGO.filterByPValue(graph, self.maxPValue)
[188]665        if self.filterByNumOfInstances:
666            graph = dict(filter(lambda (id,(genes, p, rc)):len(genes)>=self.minNumOfInstances, graph.items()))
667        return graph
668
669    def FilterAndDisplayGraph(self):
670        if self.clusterDataset:
671            self.graph = self.FilterGraph(self.originalGraph)
[1248]672            if self.originalGraph and not self.graph:
673                self.warning(1, "All found terms were filtered out.")
674            else:
675                self.warning(1)
[188]676            self.ClearGraph()
677            self.DisplayGraph()
678
679    def SetGraph(self, graph=None):
680        self.originalGraph = graph
681        if graph:
682            self.FilterAndDisplayGraph()
683        else:
684            self.graph = {}
685            self.ClearGraph()
686
687    def ClearGraph(self):
688        self.listView.clear()
689        self.listViewItems=[]
[511]690        self.sigTerms.clear()
[188]691
692    def DisplayGraph(self):
693        fromParentDict = {}
694        self.termListViewItemDict = {}
[1710]695        self.listViewItems = []
[188]696        enrichment = lambda t:float(len(t[0])) / t[2] * (float(len(self.referenceGenes))/len(self.clusterGenes))
697        maxFoldEnrichment = max([enrichment(term) for term in self.graph.values()] or [1])
[1710]698
[188]699        def addNode(term, parent, parentDisplayNode):
700            if (parent, term) in fromParentDict:
701                return
702            if term in self.graph:
[851]703                displayNode = GOTreeWidgetItem(self.ontology[term], self.graph[term], len(self.clusterGenes), len(self.referenceGenes), maxFoldEnrichment, parentDisplayNode)
[921]704                displayNode.goId = term
[188]705                self.listViewItems.append(displayNode)
706                if term in self.termListViewItemDict:
707                    self.termListViewItemDict[term].append(displayNode)
708                else:
709                    self.termListViewItemDict[term] = [displayNode]
710                fromParentDict[(parent, term)] = True
711                parent = term
712            else:
713                displayNode = parentDisplayNode
[1710]714
[188]715            for c in self.treeStructDict[term].children:
716                addNode(c, parent, displayNode)
[1710]717
[1139]718        if self.treeStructDict:
719            addNode(self.treeStructRootKey, None, self.listView)
[188]720
721        terms = self.graph.items()
[1352]722        terms = sorted(terms, key=lambda item: item[1][1])
[188]723        self.sigTableTermsSorted = [t[0] for t in terms]
[1710]724
[511]725        self.sigTerms.clear()
[1710]726        for i, (t_id, (genes, p_value, refCount)) in enumerate(terms):
727            item = GOTreeWidgetItem(self.ontology[t_id],
728                                    (genes, p_value, refCount),
729                                    len(self.clusterGenes),
730                                    len(self.referenceGenes),
731                                    maxFoldEnrichment,
732                                    self.sigTerms)
733            item.goId = t_id
734
[196]735        self.listView.expandAll()
[899]736        for i in range(4):
737            self.listView.resizeColumnToContents(i)
738            self.sigTerms.resizeColumnToContents(i)
739        self.sigTerms.resizeColumnToContents(5)
740        width = min(self.listView.columnWidth(0), 350)
[851]741        self.listView.setColumnWidth(0, width)
742        self.sigTerms.setColumnWidth(0, width)
[1710]743
744        # Create and send the enrichemnt report table.
745        termsDomain = orange.Domain(
746            [orange.StringVariable("GO Term Id"),
747             orange.StringVariable("GO Term Name"),
748             orange.FloatVariable("Cluster Frequency"),
749             orange.FloatVariable("Reference Frequency"),
750             orange.FloatVariable("P-value"),
751             orange.FloatVariable("Enrichment"),
752             orange.StringVariable("Genes")
753             ], None)
754
755        terms = [[t_id,
756                  self.ontology[t_id].name,
757                  float(len(genes)) / len(self.clusterGenes),
758                  float(r_count) / len(self.referenceGenes),
759                  p_value,
760                  float(len(genes)) / len(self.clusterGenes) * \
761                  float(len(self.referenceGenes)) / r_count,
762                  ",".join(genes)
763                  ]
764                 for t_id, (genes, p_value, r_count) in terms]
765
766        if terms:
767            termsTable = orange.ExampleTable(termsDomain, terms)
768        else:
769            termsTable = orange.ExampleTable(termsDomain)
770        self.send("Enrichment Report", termsTable)
771
[188]772    def ViewSelectionChanged(self):
[219]773        if self.selectionChanging:
774            return
[1710]775
[219]776        self.selectionChanging = 1
777        self.selectedTerms = []
778        selected = self.listView.selectedItems()
[921]779        self.selectedTerms = list(set([lvi.term.id for lvi in selected]))
[188]780        self.ExampleSelection()
[219]781        self.selectionChanging = 0
[1710]782
[188]783    def TableSelectionChanged(self):
[219]784        if self.selectionChanging:
785            return
786       
787        self.selectionChanging = 1
[196]788        self.selectedTerms = []
[731]789        selectedIds = set([self.sigTerms.itemFromIndex(index).goId for index in self.sigTerms.selectedIndexes()])
[219]790       
[731]791        for i in range(self.sigTerms.topLevelItemCount()):
792            item = self.sigTerms.topLevelItem(i)
793            selected = item.goId in selectedIds
794            term = item.goId
[219]795           
[188]796            if selected:
797                self.selectedTerms.append(term)
[219]798               
[188]799            for lvi in self.termListViewItemDict[term]:
800                try:
801                    lvi.setSelected(selected)
[196]802                    if selected: lvi.setExpanded(True)
[188]803                except RuntimeError:    ##Underlying C/C++ object deleted (why??)
804                    pass
[196]805               
[188]806        self.ExampleSelection()
[219]807        self.selectionChanging = 0
[188]808           
809   
[1328]810    def UpdateAddClassButton(self):
811        self.addClassCB.setEnabled(self.selectionDisjoint == 1)
812       
[188]813    def ExampleSelection(self):
814        selectedExamples = []
815        unselectedExamples = []
816        selectedGenes = []
[1099]817       
[854]818        #change by Marko. don't do anything if there is no3 dataset
[188]819        if not self.clusterDataset:
820            return
[860]821       
822        selectedGenes = reduce(set.union, [v[0] for id, v in self.graph.items() if id in self.selectedTerms], set())
823        evidences = []
824        for etype in obiGO.evidenceTypesOrdered:
825            if getattr(self, "useEvidence"+etype):
826                evidences.append(etype)
[1328]827        allTerms = self.annotations.GetAnnotatedTerms(selectedGenes, 
828                          directAnnotationOnly=self.selectionDirectAnnotation, 
829                          evidenceCodes=evidences)
[188]830           
831        if self.selectionDisjoint:
[860]832            count = defaultdict(int)
[188]833            for term in self.selectedTerms:
[860]834                for g in allTerms.get(term, []):
[188]835                    count[g]+=1
[860]836            ccount = 1 if self.selectionDisjoint==1 else len(self.selectedTerms)
837            selectedGenes = [gene for gene, c in count.items() if c==ccount and gene in selectedGenes]
838        else:
839            selectedGenes = reduce(set.union, [allTerms.get(term, []) for term in self.selectedTerms], set())
[188]840
841        if self.useAttrNames:
842            vars = [self.clusterDataset.domain[gene] for gene in set(selectedGenes)]
[209]843            newDomain = orange.Domain(vars, self.clusterDataset.domain.classVar)
[1099]844            newdata = orange.ExampleTable(newDomain, self.clusterDataset)
845            self.send("Selected Examples", newdata)
[188]846            self.send("Unselected Examples", None)
[1160]847        elif self.candidateGeneAttrs:
[559]848            geneAttr = self.candidateGeneAttrs[min(self.geneAttrIndex, len(self.candidateGeneAttrs)-1)]
[1328]849            if self.selectionDisjoint == 1:
850                goVar = orange.EnumVariable("GO Term", values=list(self.selectedTerms))
851                newDomain = orange.Domain(self.clusterDataset.domain.variables, goVar)
852                newDomain.addmetas(self.clusterDataset.domain.getmetas())
853#            else:
854#                goVar = orange.StringVariable("GO Terms")
855#                newDomain = orange.Domain(self.clusterDataset.domain)
856#                newDomain.addmeta(orange.newmetaid(), goVar)
857           
858           
[188]859            for ex in self.clusterDataset:
[209]860                if not ex[geneAttr].isSpecial() and any(gene in selectedGenes for gene in str(ex[geneAttr]).split(",")):
[1328]861                    if self.selectionDisjoint == 1 and self.selectionAddTermAsClass:
862                        terms = filter(lambda term: any(gene in self.graph[term][0] for gene in str(ex[geneAttr]).split(",")) , self.selectedTerms)
863                        term = sorted(terms)[0]
[188]864                        ex =  orange.Example(newDomain, ex)
[1328]865                        ex[goVar] = goVar(term)
866#                        ex.setclass(newClass(term))
[188]867                    selectedExamples.append(ex)
868                else:
869                    unselectedExamples.append(ex)
[1099]870                   
871            if selectedExamples:
872                selectedExamples = orange.ExampleTable(selectedExamples)
873            else:
874                selectedExamples = None
875               
876            if unselectedExamples:
877                unselectedExamples = orange.ExampleTable(unselectedExamples)
878            else:
879                unselectedExamples = None
[1710]880
[1099]881            self.send("Selected Examples", selectedExamples)
882            self.send("Unselected Examples", unselectedExamples)
[638]883
[642]884    def ShowInfo(self):
885        dialog = QDialog(self)
[854]886        dialog.setModal(False)
[642]887        dialog.setLayout(QVBoxLayout())
888        label = QLabel(dialog)
889        label.setText("Ontology:\n"+self.ontology.header if self.ontology else "Ontology not loaded!")
890        dialog.layout().addWidget(label)
891
892        label = QLabel(dialog)
893        label.setText("Annotations:\n"+self.annotations.header.replace("!", "") if self.annotations else "Annotations not loaded!")
894        dialog.layout().addWidget(label)
895        dialog.show()
[985]896       
[799]897    def sendReport(self):
[802]898        self.reportSettings("Settings", [("Organism", self.annotationCodes[min(self.annotationIndex, len(self.annotationCodes) - 1)]),
899                                         ("Significance test", ("Binomial" if self.probFunc == 0 else "Hypergeometric") + (" with FDR" if self.useFDR else ""))])
900        self.reportSettings("Filter", ([("Min cluster size", self.minNumOfInstances)] if self.filterByNumOfInstances else []) + \
901                                      ([("Max p-value", self.maxPValue)] if self.filterByPValue else []))
[921]902
903        def treeDepth(item):
904            return 1 + max([treeDepth(item.child(i)) for i in range(item.childCount())] +[0])
905       
906        def printTree(item, level, treeDepth):
907            text = '<tr>' + '<td width=16px></td>' * level
908            text += '<td colspan="%i">%s: %s</td>' % (treeDepth - level, item.term.id, item.term.name)
[854]909            text += ''.join('<td>%s</td>' % item.text(i) for i in range(1, 4) + [5]) + '</tr>\n'
910            for i in range(item.childCount()):
[921]911                text += printTree(item.child(i), level + 1, treeDepth)
912            return text
913       
914        treeDepth = max([treeDepth(self.listView.topLevelItem(i)) for i in range(self.listView.topLevelItemCount())] + [0])
915       
916        tableText = '<table>\n<tr>' + ''.join('<th>%s</th>' % s for s in ["Term:", "List:", "Reference:", "P-value:", "Enrichment:"]) + '</tr>'
917       
918        treeText = '<table>\n' +  '<th colspan="%i">%s</th>' % (treeDepth, "Term:") 
919        treeText += ''.join('<th>%s</th>' % s for s in ["List:", "Reference:", "P-value:", "Enrichment:"]) + '</tr>'
[854]920       
921        for index in range(self.sigTerms.topLevelItemCount()):
922            item = self.sigTerms.topLevelItem(index)
[921]923            tableText += printTree(item, 0, 1) 
[854]924        tableText += '</table>' 
925       
926        for index in range(self.listView.topLevelItemCount()):
927            item = self.listView.topLevelItem(index)
[921]928            treeText += printTree(item, 0, treeDepth)
[854]929       
[921]930        self.reportSection("Enriched Terms")
[854]931        self.reportRaw(tableText)
[921]932       
933        self.reportSection("Enriched Terms in the Ontology Tree")
[854]934        self.reportRaw(treeText)
[1248]935       
936    def onStateChanged(self, stateType, id, text):
937        if stateType == "Warning":
938            self.listView._userMessage = text
939            self.listView.viewport().update()
[1411]940           
941    def onDeleteWidget(self):
942        """ Called before the widget is removed from the canvas.
943        """
944        self.annotations = None
945        self.ontology = None
946        gc.collect() # Force collection
947       
[799]948
[851]949class GOTreeWidgetItem(QTreeWidgetItem):
950    def __init__(self, term, enrichmentResult, nClusterGenes, nRefGenes, maxFoldEnrichment, parent):
951        QTreeWidgetItem.__init__(self, parent)
952        self.term = term
953        self.enrichmentResult = enrichmentResult
954        self.nClusterGenes = nClusterGenes
955        self.nRefGenes = nRefGenes
956        self.maxFoldEnrichment = maxFoldEnrichment
957        self.enrichment = enrichment = lambda t:float(len(t[0])) / t[2] * (float(nRefGenes)/nClusterGenes)
958        self.setText(0, term.name)
959        fmt = "%" + str(-int(math.log(nClusterGenes))) + "i (%.2f%%)"
960        self.setText(1, fmt % (len(enrichmentResult[0]), 100.0*len(self.enrichmentResult[0])/nClusterGenes))
961        fmt = "%" + str(-int(math.log(nRefGenes))) + "i (%.2f%%)"
962        self.setText(2, fmt % (enrichmentResult[2], 100.0*enrichmentResult[2]/nRefGenes))
963        self.setText(3, "%.4f" % enrichmentResult[1])
964        self.setText(4, ", ".join(enrichmentResult[0]))
[1328]965        self.setText(5, "%.2f" % (enrichment(enrichmentResult)))
[851]966        self.setToolTip(0, "<p>" + term.__repr__()[6:].strip().replace("\n", "<br>"))
967        self.sortByData = [term.name, len(self.enrichmentResult[0]), enrichmentResult[2], enrichmentResult[1], ", ".join(enrichmentResult[0]), enrichment(enrichmentResult)]
968
969    def data(self, col, role):
970        if role == Qt.UserRole:
971            return QVariant(self.enrichment(self.enrichmentResult) / self.maxFoldEnrichment)
972        else:
973            return QTreeWidgetItem.data(self, col, role)
974
975    def __lt__(self, other):
976        col = self.treeWidget().sortColumn()
977        return self.sortByData[col] < other.sortByData[col]
978   
[416]979class EnrichmentColumnItemDelegate(QItemDelegate):
980    def paint(self, painter, option, index):
981        self.drawBackground(painter, option, index)
[851]982        value, ok = index.data(Qt.UserRole).toDouble()
[416]983        if ok:
984            painter.save()
985            painter.setBrush(QBrush(Qt.white, Qt.SolidPattern))
986            painter.drawRect(option.rect)
987            painter.setBrush(QBrush(Qt.blue, Qt.SolidPattern))
988            painter.drawRect(option.rect.x(), option.rect.y(), value*(option.rect.width()-1), option.rect.height()-1)
989            painter.restore()
[188]990        else:
[416]991            QItemDelegate.paint(self, painter, option, index)
992       
993       
[988]994class GeneMatcherDialog(OWWidget):
995    items = [("useGO", "Use gene names from Gene Ontology annotations"),
996             ("useKEGG", "Use gene names from KEGG Genes database"),
997             ("useNCBI", "Use gene names from NCBI Gene info database"),
998             ("useAffy", "Use Affymetrix platform reference ids")]
999    settingsList = [item[0] for item in items]
1000    def __init__(self, parent=None, defaults=[True, False, False, False], enabled=[False, True, True, True], **kwargs):
1001        OWWidget.__init__(self, parent, **kwargs)
1002        for item, default in zip(self.items, defaults):
1003            setattr(self, item[0], default)
1004           
1005        self.loadSettings()
1006        for item, enable in zip(self.items, enabled):
1007            cb = OWGUI.checkBox(self, self, *item)
1008            cb.setEnabled(enable)
1009           
1010        box = OWGUI.widgetBox(self, orientation="horizontal")
1011        OWGUI.button(box, self, "OK", callback=self.accept)
1012        OWGUI.button(box, self, "Cancel", callback=self.reject)
1013       
1014       
[188]1015if __name__=="__main__":
1016    import sys
1017    app = QApplication(sys.argv)
1018    w=OWGOEnrichmentAnalysis()
[1099]1019    data = orange.ExampleTable("../../../doc/datasets/brown-selected.tab")
[416]1020    w.show()
[188]1021    w.SetClusterDataset(data)
[416]1022    app.exec_()
[188]1023    w.saveSettings()
1024       
Note: See TracBrowser for help on using the repository browser.