source: orange-bioinformatics/orangecontrib/bio/widgets/OWGeneInfo.py @ 1947:29931e1c32be

Revision 1947:29931e1c32be, 25.9 KB checked in by Ales Erjavec <ales.erjavec@…>, 3 months ago (diff)

Fixed Gene Info report.

Line 
1"""
2<name>Gene Info</name>
3<description>Displays gene information from NCBI and other sources.</description>
4<priority>2010</priority>
5<contact>Ales Erjavec (ales.erjavec(@at@)fri.uni-lj.si)</contact>
6<icon>icons/GeneInfo.svg</icon>
7"""
8
9from __future__ import absolute_import, with_statement
10
11import sys
12from collections import defaultdict
13from functools import partial
14
15from PyQt4.QtCore import pyqtSlot as Slot
16
17from Orange.orng import orngServerFiles
18from Orange.orng.orngDataCaching import data_hints
19from Orange.OrangeWidgets import OWGUI
20from Orange.OrangeWidgets.OWWidget import *
21
22from Orange.OrangeWidgets.OWConcurrent import \
23    ThreadExecutor, Task, methodinvoke
24
25from Orange.utils import progress_bar_milestones
26
27import orange
28
29from .. import obiGene, obiTaxonomy
30
31
32NAME = "Gene Info"
33DESCRIPTION = "Displays gene information from NCBI and other sources."
34ICON = "icons/GeneInfo.svg"
35PRIORITY = 2010
36
37INPUTS = [("Examples", Orange.data.Table, "setData")]
38OUTPUTS = [("Selected Examples", Orange.data.Table)]
39
40REPLACES = ["_bioinformatics.widgets.OWGeneInfo.OWGeneInfo"]
41
42
43class TreeModel(QAbstractItemModel):
44    def __init__(self, data, header, parent):
45        QAbstractItemModel.__init__(self, parent)
46        self._data = [[QVariant(s) for s in row] for row in data]
47        self._dataDict = {}
48        self._header = header
49        self._roleData = {Qt.DisplayRole:self._data}
50        self._roleData = partial(defaultdict, partial(defaultdict, partial(defaultdict, QVariant)))(self._roleData)
51   
52    def setColumnLinks(self, column, links):
53        font =QFont()
54        font.setUnderline(True)
55        font = QVariant(font)
56        for i, link in enumerate(links):
57            self._roleData[LinkRole][i][column] = QVariant(link)
58            self._roleData[Qt.FontRole][i][column] = font
59            self._roleData[Qt.ForegroundRole][i][column] = QVariant(QColor(Qt.blue))
60   
61    def setRoleData(self, role, row, col, data):
62        self._roleData[role][row][col] = data
63       
64    def data(self, index, role=Qt.DisplayRole):
65        row, col = index.row(), index.column()
66        return self._roleData[role][row][col]
67       
68    def index(self, row, col, parent=QModelIndex()):
69        return self.createIndex(row, col, 0)
70   
71    def parent(self, index):
72        return QModelIndex()
73   
74    def rowCount(self, index=QModelIndex()):
75        if index.isValid():
76            return 0
77        else:
78            return len(self._data)
79       
80    def columnCount(self, index=QModelIndex()):
81        return len(self._header)
82
83    def headerData(self, section, orientation, role=Qt.DisplayRole):
84        if role==Qt.DisplayRole:
85            return QVariant(self._header[section])
86        return QVariant()
87
88from Orange.OrangeWidgets.OWGUI import LinkStyledItemDelegate, LinkRole
89
90def lru_cache(maxsize=100):
91    """ A least recently used cache function decorator.
92    """
93   
94    def decorating_function(func):
95        import functools
96        cache = {}
97       
98        @functools.wraps(func)
99        def wrapped(*args, **kwargs):
100            key = args + tuple(sorted(kwargs.items()))
101            if key not in cache:
102                res = func(*args, **kwargs)
103                cache[key] = (time.time(), res)
104                if len(cache) > maxsize:
105                    key, (_, _) = min(cache.iteritems(), key=lambda item: item[1][0])
106                    del cache[key]
107            else:
108                _, res = cache[key]
109                cache[key] = (time.time(), res) # update the time
110               
111            return res
112       
113        def clear():
114            cache.clear()
115       
116        wrapped.clear = clear
117       
118        return wrapped
119    return decorating_function
120               
121class LinkFmt(object):
122    def __init__(self, link_fmt, name):
123        self.link_fmt = link_fmt
124        self.name = name
125       
126    def format(self, *args, **kwargs):
127        return Link(self.link_fmt.format(*args, **kwargs), **kwargs)
128   
129    def __repr__(self):
130        return "<LinkFmt " + repr(self.name) + " >"
131   
132    def __str__(self):
133        return self.name
134   
135class Link(object):
136    def __init__(self, link, text=None, **kwargs):
137        self.link = link
138        self.text = text if text is not None else "link"
139        self.__dict__.update(kwargs)
140       
141    def str(self):
142        return link
143   
144   
145@lru_cache(maxsize=2)
146def get_ncbi_info(taxid):
147    return obiGene.NCBIGeneInfo(taxid)
148
149def ncbi_info(taxid, genes):
150    info = get_ncbi_info(taxid)
151    schema_link = LinkFmt("http://www.ncbi.nlm.nih.gov/sites/entrez?Db=gene&Cmd=ShowDetailView&TermToSearch={gene_id}", name="NCBI ID")
152    schema = [schema_link, "Symbol", "Locus Tag", "Chromosome",
153              "Description", "Synonyms", "Nomenclature"]
154    ret = []
155    for gene in genes:
156        gi = info.get_info(gene)
157        if gi:
158            ret.append([schema_link.format(gene_id=gi.gene_id, text=gi.gene_id),
159                        gi.symbol + " (%s)" % gene if gene != gi.symbol else gi.symbol,
160                        gi.locus_tag or "",
161                        gi.chromosome or "",
162                        gi.description or "",
163                        ", ".join(gi.synonyms),
164                        gi.symbol_from_nomenclature_authority or ""
165                        ])
166        else:
167            ret.append(None)
168    return schema, ret
169   
170def dicty_info(taxid, genes):
171    from .. import obiDicty
172    info = obiDicty.DictyBase()
173    name_matcher = obiGene.GMDicty()
174    name_matcher.set_targets(info.info.keys())
175    schema_link = LinkFmt("http://dictybase.org/db/cgi-bin/gene_page.pl?dictybaseid={gene_id}", name="Dicty Base Id")
176    schema = [schema_link, "Name", "Synonyms", "Gene Products"]
177   
178    ret = []
179    for gene in genes:
180        gene = name_matcher.umatch(gene)
181        gi = info.info.get(gene, None)
182        if gi:
183            ret.append([schema_link.format(gene_id=gene, text=gene),
184                        gi[0] + " (%s)" % gene if gene != gi[0] else gi[0], # Gene Name
185                        ", ".join(gi[1]), # Synonyms
186                        gi[2] or "", # Gene Products
187                        ])
188           
189        else:
190            ret.append(None)
191   
192    return schema, ret
193
194
195INFO_SOURCES = {
196    "default": [("NCBI Info", ncbi_info)],
197    "352472": [("NCBI Info", ncbi_info),
198               ("Dicty Base", dicty_info)]
199}
200
201
202class OWGeneInfo(OWWidget):
203    settingsList = ["organismIndex", "geneAttr", "useAttr", "autoCommit",
204                    "taxid"]
205    contextHandlers = {
206        "": DomainContextHandler(
207            "", ["organismIndex", "geneAttr", "useAttr", "useAltSource",
208                 "taxid"]
209        )
210    }
211
212    def __init__(self, parent=None, signalManager=None, name="Gene Info"):
213        OWWidget.__init__(self, parent, signalManager, name)
214
215        self.inputs = [("Examples", ExampleTable, self.setData)]
216        self.outputs = [("Selected Examples", ExampleTable)]
217
218        self.organismIndex = 0
219        self.taxid = None
220        self.geneAttr = 0
221        self.useAttr = False
222        self.autoCommit = False
223        self.searchString = ""
224        self.selectionChangedFlag = False
225        self.useAltSource = 0
226        self.loadSettings()
227
228        self.__initialized = False
229        self.initfuture = None
230        self.itemsfuture = None
231
232        self.infoLabel = OWGUI.widgetLabel(
233            OWGUI.widgetBox(self.controlArea, "Info", addSpace=True),
234            "Initializing\n"
235        )
236
237        self.organisms = None
238        self.organismBox = OWGUI.widgetBox(
239            self.controlArea, "Organism", addSpace=True)
240
241        self.organismComboBox = OWGUI.comboBox(
242            self.organismBox, self, "organismIndex",
243            callback=self._onSelectedOrganismChanged,
244            debuggingEnabled=0)
245
246        # For now only support one alt source, with a checkbox
247        # In the future this can be extended to multiple selections
248        self.altSourceCheck = OWGUI.checkBox(self.organismBox, self,
249                            "useAltSource", "Show information from dictyBase",
250                            callback=self.onAltSourceChange,
251#                            debuggingEnabled=0,
252                            )
253        self.altSourceCheck.hide()
254       
255        box = OWGUI.widgetBox(self.controlArea, "Gene names", addSpace=True)
256        self.geneAttrComboBox = OWGUI.comboBox(box, self, "geneAttr",
257                                "Gene atttibute", callback=self.updateInfoItems)
258       
259        c = OWGUI.checkBox(box, self, "useAttr", "Use attribute names",
260                           callback=self.updateInfoItems,
261                           disables=[(-1, self.geneAttrComboBox)])
262       
263        self.geneAttrComboBox.setDisabled(bool(self.useAttr))
264
265        box = OWGUI.widgetBox(self.controlArea, "Commit", addSpace=True)
266        b = OWGUI.button(box, self, "Commit", callback=self.commit)
267        c = OWGUI.checkBox(box, self, "autoCommit", "Commit on change")
268        OWGUI.setStopper(self, b, c, "selectionChangedFlag",
269                         callback=self.commit)
270       
271        ## A label for dictyExpress link
272        self.dictyExpressBox = OWGUI.widgetBox(self.controlArea, "Dicty Express")
273        self.linkLabel = OWGUI.widgetLabel(self.dictyExpressBox, "")
274        self.linkLabel.setOpenExternalLinks(False)
275        self.connect(self.linkLabel, SIGNAL("linkActivated(QString)"),
276                     self.onDictyExpressLink)
277        self.dictyExpressBox.hide()
278       
279        OWGUI.rubber(self.controlArea)
280
281        OWGUI.lineEdit(self.mainArea, self, "searchString", "Filter",
282                       callbackOnType=True, callback=self.searchUpdate)
283       
284        self.treeWidget = QTreeView(self.mainArea)
285        self.treeWidget.setRootIsDecorated(False)
286        self.treeWidget.setSelectionMode(QAbstractItemView.ExtendedSelection)
287        self.treeWidget.setItemDelegate(LinkStyledItemDelegate(self.treeWidget))
288        self.treeWidget.setUniformRowHeights(True)
289        self.treeWidget.viewport().setMouseTracking(True)
290        self.treeWidget.setSortingEnabled(True)
291        self.mainArea.layout().addWidget(self.treeWidget)
292       
293        box = OWGUI.widgetBox(self.mainArea, "",
294                              orientation="horizontal")
295        OWGUI.button(box, self, "Select Filtered",
296                     callback=self.selectFiltered)
297        OWGUI.button(box, self, "Clear Selection",
298                     callback=self.treeWidget.clearSelection)
299       
300        self.resize(1000, 700)
301
302        self.geneinfo = []
303        self.cells = []
304        self.row2geneinfo = {}
305        self.data = None
306
307        #: (# input genes, # matches genes)
308        self.matchedInfo = 0, 0
309        self.selectionUpdateInProgress = False
310
311        self.setBlocking(True)
312        self.executor = ThreadExecutor(self)
313
314        self.progressBarInit()
315
316        task = Task(
317            function=partial(
318                obiTaxonomy.ensure_downloaded,
319                callback=methodinvoke(self, "advance", ())
320            )
321        )
322
323        task.resultReady.connect(self.initialize)
324        task.exceptionReady.connect(self._onInitializeError)
325
326        self.initfuture = self.executor.submit(task)
327
328    @Slot()
329    def advance(self):
330        assert self.thread() is QThread.currentThread()
331
332        self.progressBarSet(self.progressBarValue + 1,
333                            processEventsFlags=None)
334
335    def initialize(self):
336        if self.__initialized:
337            # Already initialized
338            return
339
340        self.progressBarFinished()
341
342        self.organisms = sorted(
343            set([name.split(".")[-2] for name in
344                 orngServerFiles.listfiles("NCBI_geneinfo")] +
345                obiGene.NCBIGeneInfo.essential_taxids())
346        )
347
348        self.organismComboBox.addItems(
349            [obiTaxonomy.name(tax_id) for tax_id in self.organisms]
350        )
351        if self.taxid in self.organisms:
352            self.organismIndex = self.organisms.index(self.taxid)
353
354        self.infoLabel.setText("No data on input\n")
355        self.__initialized = True
356        self.initfuture = None
357
358        self.setBlocking(False)
359
360    def _onInitializeError(self, exc):
361        sys.excepthook(type(exc), exc.args, None)
362        self.error(0, "Could not download the necessary files.")
363
364    def _onSelectedOrganismChanged(self):
365        self.taxid = self.organisms[self.organismIndex]
366        if self.data is not None:
367            self.updateInfoItems()
368
369    def setData(self, data=None):
370        if not self.__initialized:
371            self.initfuture.result()
372            self.initialize()
373
374        if self.itemsfuture is not None:
375            raise Exception("Already processing")
376
377        self.closeContext()
378        self.data = data
379
380        if data:
381            self.geneAttrComboBox.clear()
382            self.attributes = [attr for attr in self.data.domain.variables + \
383                               self.data.domain.getmetas().values() \
384                               if attr.varType in [orange.VarTypes.String,
385                                                   orange.VarTypes.Discrete]]
386            self.geneAttrComboBox.addItems([attr.name for attr in self.attributes])
387
388            self.taxid = data_hints.get_hint(self.data, "taxid", self.taxid)
389            self.useAttr = data_hints.get_hint(self.data, "genesinrows",  self.useAttr)
390
391            self.openContext("", data)
392            self.geneAttr = min(self.geneAttr, len(self.attributes) - 1)
393
394            if self.taxid in self.organisms:
395                self.organismIndex = self.organisms.index(self.taxid)
396
397            self.useAttr = data_hints.get_hint(self.data, "genesinrows",  self.useAttr)
398
399            self.updateInfoItems()
400        else:
401            self.clear()
402
403    def infoSource(self):
404        """ Return the current selected info source getter function from
405        INFO_SOURCES
406        """
407        org = self.organisms[min(self.organismIndex, len(self.organisms) - 1)]
408        if org not in INFO_SOURCES:
409            org = "default"
410        sources = INFO_SOURCES[org]
411        name, func =  sources[min(self.useAltSource, len(sources) - 1)]
412        return name, func
413
414    def inputGenes(self):
415        if self.useAttr:
416            genes = [attr.name for attr in self.data.domain.attributes]
417        elif self.attributes:
418            attr = self.attributes[self.geneAttr]
419            genes = [str(ex[attr]) for ex in self.data if not ex[attr].isSpecial()]
420        else:
421            genes = []
422        return genes
423
424    def updateInfoItems(self):
425        self.warning(0)
426        if not self.data:
427            return
428
429        genes = self.inputGenes()
430        if self.useAttr:
431            genes = [attr.name for attr in self.data.domain.attributes]
432        elif self.attributes:
433            attr = self.attributes[self.geneAttr]
434            genes = [str(ex[attr]) for ex in self.data if not ex[attr].isSpecial()]
435        else:
436            genes = []
437        if not genes:
438            self.warning(0, "Could not extract genes from input dataset.")
439
440        self.warning(1)
441        org = self.organisms[min(self.organismIndex, len(self.organisms) - 1)]
442        source_name, info_getter = self.infoSource()
443
444        self.error(0)
445
446        self.updateDictyExpressLink(genes, show=org == "352472")
447        self.altSourceCheck.setVisible(org == "352472")
448
449        self.progressBarInit()
450        self.setBlocking(True)
451        self.setEnabled(False)
452        self.infoLabel.setText("Retrieving info records.\n")
453
454        self.genes = genes
455
456        task = Task(function=partial(info_getter, org, genes))
457        self.itemsfuture = self.executor.submit(task)
458        task.finished.connect(self._onItemsCompleted)
459
460    def _onItemsCompleted(self):
461        self.setBlocking(False)
462        self.progressBarFinished()
463        self.setEnabled(True)
464
465        try:
466            schema, geneinfo = self.itemsfuture.result()
467        finally:
468            self.itemsfuture = None
469
470        self.geneinfo = geneinfo = list(zip(self.genes, geneinfo))
471        self.cells = cells = []
472        self.row2geneinfo = {}
473        links = []
474        for i, (_, gi) in enumerate(geneinfo):
475            if gi:
476                row = []
477                for _, item in zip(schema, gi):
478                    if isinstance(item, Link):
479                        # TODO: This should be handled by delegates
480                        row.append(item.text)
481                        links.append(item.link)
482                    else:
483                        row.append(item)
484                cells.append(row)
485                self.row2geneinfo[len(cells) - 1] = i
486
487        model = TreeModel(cells, [str(col) for col in schema], None)
488
489        model.setColumnLinks(0, links)
490        proxyModel = QSortFilterProxyModel(self)
491        proxyModel.setSourceModel(model)
492        self.treeWidget.setModel(proxyModel)
493        self.connect(self.treeWidget.selectionModel(),
494                     SIGNAL("selectionChanged(QItemSelection , QItemSelection )"),
495                     self.commitIf)
496
497        for i in range(7):
498            self.treeWidget.resizeColumnToContents(i)
499            self.treeWidget.setColumnWidth(i, min(self.treeWidget.columnWidth(i), 200))
500
501        self.infoLabel.setText("%i genes\n%i matched NCBI's IDs" %
502                               (len(self.genes), len(cells)))
503        self.matchedInfo = len(self.genes), len(cells)
504
505    def clear(self):
506        self.infoLabel.setText("No data on input\n")
507        self.treeWidget.setModel(TreeModel([], ["NCBI ID", "Symbol", "Locus Tag",
508                                            "Chromosome", "Description", "Synonyms",
509                                            "Nomenclature"], self.treeWidget))
510        self.geneAttrComboBox.clear()
511        self.send("Selected Examples", None)
512
513    def commitIf(self, *args):
514        if self.autoCommit and not self.selectionUpdateInProgress:
515            self.commit()
516        else:
517            self.selectionChangedFlag = True
518
519    def commit(self):
520        if not self.data:
521            return
522        model = self.treeWidget.model()
523        mapToSource = model.mapToSource
524        selectedIds = [self.cells[mapToSource(index).row()][0] for index in self.treeWidget.selectedIndexes()]
525        selectedRows = self.treeWidget.selectedIndexes()
526        selectedRows = [mapToSource(index).row() for index in selectedRows]
527        model = model.sourceModel()
528       
529        selectedGeneids = [self.row2geneinfo[row] for row in selectedRows]
530        selectedIds = [self.geneinfo[i][0] for i in selectedGeneids]
531        selectedIds = set(selectedIds)
532        gene2row = dict((self.geneinfo[self.row2geneinfo[row]][0], row) \
533                        for row in selectedRows)
534       
535        if self.useAttr:
536            def is_selected(attr):
537                return attr.name in selectedIds
538            attrs = [attr for attr in self.data.domain.attributes if is_selected(attr)]
539            domain = orange.Domain(attrs, self.data.domain.classVar)
540            domain.addmetas(self.data.domain.getmetas())
541            newdata = orange.ExampleTable(domain, self.data)
542            self.send("Selected Examples", newdata)
543        elif self.attributes:
544            attr = self.attributes[self.geneAttr]
545            geneinfo = dict(self.geneinfo)
546            examples = [ex for ex in self.data if str(ex[attr]) in selectedIds]
547            if True:  # Add gene info
548                domain = orange.Domain(self.data.domain, self.data.domain.classVar)
549                domain.addmetas(self.data.domain.getmetas())
550                n_columns = model.columnCount()
551
552                headers = [str(model.headerData(i, Qt.Horizontal, Qt.DisplayRole).toString()) \
553                           for i in range(n_columns)]
554                new_meta_attrs = [(orange.newmetaid(), orange.StringVariable(name)) \
555                                  for name in headers]
556                domain.addmetas(dict(new_meta_attrs))
557                examples = [orange.Example(domain, ex) for ex in examples]
558                for ex in examples:
559                    for i, (_, meta) in enumerate(new_meta_attrs):
560                        row = gene2row[str(ex[attr])]
561                        ex[meta] = str(model.data(model.index(row, i), Qt.DisplayRole).toString())
562
563            if examples:
564                newdata = orange.ExampleTable(examples)
565            else:
566                newdata = None
567            self.send("Selected Examples", newdata)
568        else:
569            self.send("Selected Examples", None)
570           
571    def rowFiltered(self, row):
572        searchStrings = self.searchString.lower().split()
573        row = unicode(" ".join(self.cells[row]).lower(), errors="ignore")
574        return not all([s in row for s in searchStrings])
575   
576    def searchUpdate(self):
577        if not self.data:
578            return
579        searchStrings = self.searchString.lower().split()
580        index = self.treeWidget.model().sourceModel().index
581        mapFromSource = self.treeWidget.model().mapFromSource
582        for i, row in enumerate(self.cells):
583            row = unicode(" ".join(row).lower(), errors="ignore")
584            self.treeWidget.setRowHidden(mapFromSource(index(i, 0)).row(), QModelIndex(), not all([s in row for s in searchStrings]))
585        #self.treeWidget.model().setFilterRegExp(QRegExp(self.searchString, Qt.CaseInsensitive, QRegExp.FixedString))
586           
587    def selectFiltered(self):
588        if not self.data:
589            return
590        itemSelection = QItemSelection()
591       
592        index = self.treeWidget.model().sourceModel().index
593        mapFromSource = self.treeWidget.model().mapFromSource
594        for i, row in enumerate(self.cells):
595            if not self.rowFiltered(i):
596                itemSelection.select(mapFromSource(index(i, 0)), mapFromSource(index(i, 0)))
597        self.treeWidget.selectionModel().select(itemSelection, QItemSelectionModel.Select | QItemSelectionModel.Rows)
598       
599    def sendReport(self):
600        from Orange.OrangeWidgets import OWReport
601        genes, matched = self.matchedInfo
602
603        if self.organisms:
604            org = self.organisms[min(self.organismIndex,
605                                     len(self.organisms) - 1)]
606            org_name = obiTaxonomy.name(org)
607        else:
608            org = None
609            org_name = None
610        if self.data is not None:
611            self.reportRaw(
612                "<p>Input: %i genes of which %i (%.1f%%) matched NCBI synonyms"
613                "<br>"
614                "Organism: %s"
615                "<br>"
616                "Filter: %s"
617                "</p>" % (genes, matched, 100.0 * matched / genes, org_name,
618                          self.searchString)
619            )
620            self.reportSubsection("Gene list")
621            self.reportRaw(reportItemView(self.treeWidget))
622        else:
623            self.reportRaw("<p>No input</p>")
624
625    def updateDictyExpressLink(self, genes, show=False):
626        def fix(ddb):
627            if ddb.startswith("DDB"): 
628                if not ddb.startswith("DDB_G"):
629                    ddb = ddb.replace("DDB", "DDB_G")
630                return ddb
631            return None 
632        if show:
633            genes = [fix(gene) for gene in genes if fix(gene)]
634            link1 = '<a href="http://dictyexpress.biolab.si/run/index.php?gene=%s">Microarray profile</a>'
635            link2 = '<a href="http://dictyexpress.biolab.si/run/index.php?gene=%s&db=rnaseq">RNA-Seq profile</a>'
636            self.linkLabel.setText(link1 + "<br/>" + link2)
637           
638            show = any(genes)
639               
640        if show:
641            self.dictyExpressBox.show()
642        else:
643            self.dictyExpressBox.hide()
644
645    def onDictyExpressLink(self, link):
646        if not self.data:
647            return
648
649        selectedIndexes = self.treeWidget.selectedIndexes()
650        if not len(selectedIndexes):
651            QMessageBox.information(self, "No gene ids selected", "Please select some genes and try again.")
652            return
653        model = self.treeWidget.model()
654        mapToSource = model.mapToSource
655        selectedIds = [self.cells[mapToSource(index).row()][0] for index in selectedIndexes]
656        selectedRows = self.treeWidget.selectedIndexes()
657        selectedRows = [mapToSource(index).row() for index in selectedRows]
658        model = model.sourceModel()
659
660        selectedGeneids = [self.row2geneinfo[row] for row in selectedRows]
661        selectedIds = [self.geneinfo[i][0] for i in selectedGeneids]
662        selectedIds = set(selectedIds)
663
664        def fix(ddb):
665            if ddb.startswith("DDB"):
666                if not ddb.startswith("DDB_G"):
667                    ddb = ddb.replace("DDB", "DDB_G")
668                return ddb
669            return None
670
671        genes = [fix(gene) for gene in selectedIds if fix(gene)]
672        url = str(link) % " ".join(genes)
673        QDesktopServices.openUrl(QUrl(url))
674           
675    def onAltSourceChange(self):
676        self.updateInfoItems()
677
678    def onDeleteWidget(self):
679        OWWidget.onDeleteWidget(self)
680
681        # try to cancel pending tasks
682        if self.initfuture:
683            self.initfuture.cancel()
684        if self.itemsfuture:
685            self.itemsfuture.cancel()
686
687        self.executor.shutdown()
688
689
690def reportItemView(view):
691    model = view.model()
692    return reportItemModel(view, model)
693   
694def reportItemModel(view, model, index=QModelIndex()):
695    if not index.isValid() or model.hasChildren(index):
696        columnCount, rowCount = model.columnCount(index), model.rowCount(index)
697        if not index.isValid():
698            text = '<table>\n<tr>' + ''.join('<th>%s</th>' % model.headerData(i, Qt.Horizontal, Qt.DisplayRole).toString() for i in range(columnCount)) +'</tr>\n'
699        else:
700#            variant = model.data(index, Qt.DisplayRole)
701#            text = '<table' + (' caption="%s"' % variant.toString() if variant.isValid() else '') + '>\n'
702            pass
703        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))
704        text += '</table>'
705        return text
706    else:
707        variant = model.data(index, Qt.DisplayRole)
708        return str(variant.toString()) if variant.isValid() else ""
709       
710if __name__ == "__main__":
711    app = QApplication(sys.argv)
712    data = orange.ExampleTable("brown-selected.tab")
713    w = OWGeneInfo()
714    w.show()
715
716    w.setData(data)
717    app.exec_()
718    w.saveSettings()
Note: See TracBrowser for help on using the repository browser.