source: orange-bioinformatics/widgets/OWFunctionalAnnotation.py @ 1332:0a48d6c732ac

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