Changeset 1336:c983e0920ffa in orange-bioinformatics for widgets/OWGeneInfo.py


Ignore:
Timestamp:
02/28/11 15:08:17 (3 years ago)
Author:
ales_erjavec <ales.erjavec@…>
Branch:
default
Convert:
d413292cec1d4e02fd3e0a231b06976a8c66bc9e
Message:
  • added dictyBase as data info source
File:
1 edited

Legend:

Unmodified
Added
Removed
  • widgets/OWGeneInfo.py

    r1272 r1336  
    11""" 
    22<name>Gene Info</name> 
    3 <description>Displays gene information from NCBI.</description> 
     3<description>Displays gene information from NCBI and other sources.</description> 
    44<priority>2010</priority> 
    5 <contact>Ales Erjavec (ales.erjevec(@at@)fri.uni-lj.si)</contact> 
     5<contact>Ales Erjavec (ales.erjavec(@at@)fri.uni-lj.si)</contact> 
    66<icon>icons/GeneInfo.png</icon> 
    77""" 
     
    6666 
    6767from OWGUI import LinkStyledItemDelegate, LinkRole 
    68          
     68 
     69def lru_cache(maxsize=100): 
     70    """ A least recently used cache function decorator. 
     71    """ 
     72     
     73    def decorating_function(func): 
     74        import functools 
     75        cache = {} 
     76         
     77        functools.wraps(func) 
     78        def wrapped(*args, **kwargs): 
     79            key = args + tuple(sorted(kwargs.items())) 
     80            if key not in cache: 
     81                res = func(*args, **kwargs) 
     82                cache[key] = (time.time(), res) 
     83                if len(cache) > maxsize: 
     84                    key, (_, _) = min(cache.iteritems(), key=lambda item: item[1][0]) 
     85                    del cache[key] 
     86            else: 
     87                _, res = cache[key] 
     88                cache[key] = (time.time(), res) # update the time 
     89                 
     90            return res 
     91         
     92        def clear(): 
     93            cache.clear() 
     94         
     95        wrapped.clear = clear 
     96         
     97        return wrapped 
     98    return decorating_function 
     99                 
     100class LinkFmt(object): 
     101    def __init__(self, link_fmt, name): 
     102        self.link_fmt = link_fmt 
     103        self.name = name 
     104         
     105    def format(self, *args, **kwargs): 
     106        return Link(self.link_fmt.format(*args, **kwargs), **kwargs) 
     107     
     108    def __repr__(self): 
     109        return "<LinkFmt " + repr(self.name) + " >" 
     110     
     111    def __str__(self): 
     112        return self.name 
     113     
     114class Link(object): 
     115    def __init__(self, link, text=None, **kwargs): 
     116        self.link = link 
     117        self.text = text if text is not None else "link" 
     118        self.__dict__.update(kwargs) 
     119         
     120    def str(self): 
     121        return link 
     122     
     123     
     124@lru_cache(maxsize=2) 
     125def get_ncbi_info(taxid): 
     126    return obiGene.NCBIGeneInfo(taxid) 
     127 
     128def ncbi_info(taxid, genes): 
     129    info = get_ncbi_info(taxid) 
     130    schema_link = LinkFmt("http://www.ncbi.nlm.nih.gov/sites/entrez?Db=gene&Cmd=ShowDetailView&TermToSearch={gene_id}", name="NCBI ID") 
     131    schema = [schema_link, "Symbol", "Locus Tag", "Chromosome", 
     132              "Description", "Synonyms", "Nomenclature"] 
     133    ret = [] 
     134    for gene in genes: 
     135        gi = info.get_info(gene) 
     136        if gi: 
     137            ret.append([schema_link.format(gene_id=gi.gene_id, text=gi.gene_id), 
     138                        gi.symbol + " (%s)" % gene if gene != gi.symbol else gi.symbol, 
     139                        gi.locus_tag or "", 
     140                        gi.chromosome or "", 
     141                        gi.description or "", 
     142                        ", ".join(gi.synonyms), 
     143                        gi.symbol_from_nomenclature_authority or "" 
     144                        ]) 
     145        else: 
     146            ret.append(None) 
     147    return schema, ret 
     148     
     149def dicty_info(taxid, genes): 
     150    import obiDicty  
     151    info = obiDicty.DictyBase() 
     152    name_matcher = obiGene.GMDicty() 
     153    name_matcher.set_targets(info.info.keys()) 
     154    schema_link = LinkFmt("http://dictybase.org/db/cgi-bin/gene_page.pl?dictybaseid={gene_id}", name="Dicty Base Id") 
     155    schema = [schema_link, "Name", "Synonyms", "Gene Products"] 
     156     
     157    ret = [] 
     158    for gene in genes: 
     159        gene = name_matcher.umatch(gene) 
     160        gi = info.info.get(gene, None) 
     161        if gi: 
     162            ret.append([schema_link.format(gene_id=gene, text=gene), 
     163                        gi[0] + " (%s)" % gene if gene != gi[0] else gi[0], # Gene Name 
     164                        ", ".join(gi[1]), # Synonyms 
     165                        gi[2] or "", # Gene Products 
     166                        ]) 
     167             
     168        else: 
     169            ret.append(None) 
     170     
     171    return schema, ret 
     172     
     173     
     174INFO_SOURCES = {"default": [("NCBI Info", ncbi_info)], 
     175                "352472": [("NCBI Info", ncbi_info), 
     176                           ("Dicty Base", dicty_info) 
     177                           ] 
     178                } 
     179 
    69180class OWGeneInfo(OWWidget): 
    70181    settingsList = ["organismIndex", "geneAttr", "useAttr", "autoCommit"] 
    71     contextHandlers = {"":DomainContextHandler("", ["organismIndex", "geneAttr", "useAttr"])} 
     182    contextHandlers = {"":DomainContextHandler("", ["organismIndex", 
     183                                "geneAttr", "useAttr", "useAltSource"])} 
    72184    def __init__(self, parent=None, signalManager=None, name="Gene Info"): 
    73185        OWWidget.__init__(self, parent, signalManager, name) 
     
    82194        self.searchString = "" 
    83195        self.selectionChangedFlag = False 
     196        self.useAltSource = 0 
    84197        self.loadSettings() 
    85198         
    86         self.infoLabel = OWGUI.widgetLabel(OWGUI.widgetBox(self.controlArea, "Info", addSpace=True), "No data on input\n") 
    87         self.organisms = sorted(set([name.split(".")[-2] for name in orngServerFiles.listfiles("NCBI_geneinfo")] + obiGene.NCBIGeneInfo.essential_taxids())) 
    88      
    89         self.orgaismsComboBox = OWGUI.comboBox(self.controlArea, self, "organismIndex", "Organism", items=[obiTaxonomy.name(id) for id in self.organisms], callback=self.setItems, debuggingEnabled=0) 
    90         OWGUI.separator(self.controlArea) 
     199        self.infoLabel = OWGUI.widgetLabel(OWGUI.widgetBox(self.controlArea, 
     200                                                    "Info", addSpace=True), 
     201                                           "No data on input\n") 
     202        self.organisms = sorted(set([name.split(".")[-2] for name in \ 
     203                            orngServerFiles.listfiles("NCBI_geneinfo")] + \ 
     204                            obiGene.NCBIGeneInfo.essential_taxids())) 
     205     
     206        self.organismBox = OWGUI.widgetBox(self.controlArea, "Organism", 
     207                                           addSpace=True) 
     208        self.organismComboBox = OWGUI.comboBox(self.organismBox, self, 
     209                                "organismIndex", "Organism", 
     210                                items=[obiTaxonomy.name(id) for id in self.organisms], 
     211                                callback=self.setItems, 
     212                                debuggingEnabled=0) 
     213         
     214        # For now only support one alt source, with a checkbox 
     215        # In the future this can be extended to multiple selections 
     216        self.altSourceCheck = OWGUI.checkBox(self.organismBox, self, 
     217                            "useAltSource", "Use information from dictyBase", 
     218                            callback=self.onAltSourceChange, 
     219#                            debuggingEnabled=0, 
     220                            ) 
     221        self.altSourceCheck.hide() 
     222         
    91223        box = OWGUI.widgetBox(self.controlArea, "Gene names", addSpace=True) 
    92         self.geneAttrComboBox = OWGUI.comboBox(box, self, "geneAttr", "Gene atttibute", callback=self.setItems) 
    93         c = OWGUI.checkBox(box, self, "useAttr", "Use attribute names", callback=self.setItems, disables=[(-1, self.geneAttrComboBox)]) 
     224        self.geneAttrComboBox = OWGUI.comboBox(box, self, "geneAttr", 
     225                                "Gene atttibute", callback=self.setItems) 
     226         
     227        c = OWGUI.checkBox(box, self, "useAttr", "Use attribute names", 
     228                           callback=self.setItems, 
     229                           disables=[(-1, self.geneAttrComboBox)]) 
     230         
    94231        self.geneAttrComboBox.setDisabled(bool(self.useAttr)) 
    95232 
     
    97234        b = OWGUI.button(box, self, "Commit", callback=self.commit) 
    98235        c = OWGUI.checkBox(box, self, "autoCommit", "Commit on change") 
    99         OWGUI.setStopper(self, b, c, "selectionChangedFlag", callback=self.commit) 
    100          
    101         ##A label for dictyExpress link 
     236        OWGUI.setStopper(self, b, c, "selectionChangedFlag", 
     237                         callback=self.commit) 
     238         
     239        ## A label for dictyExpress link 
    102240        self.dictyExpressBox = OWGUI.widgetBox(self.controlArea, "Dicty Express") 
    103241        self.linkLabel = OWGUI.widgetLabel(self.dictyExpressBox, "") 
     
    107245        OWGUI.rubber(self.controlArea) 
    108246 
    109         OWGUI.lineEdit(self.mainArea, self, "searchString", "Filter", callbackOnType=True, callback=self.searchUpdate) 
    110 #        self.treeWidget = QTreeWidget(self.mainArea) 
     247        OWGUI.lineEdit(self.mainArea, self, "searchString", "Filter", 
     248                       callbackOnType=True, callback=self.searchUpdate) 
     249         
    111250        self.treeWidget = QTreeView(self.mainArea) 
    112         #self.treeWidget.setHeaderLabels(["NCBI ID", "Symbol", "Locus Tag", "Chromosome", "Description", "Synonyms", "Nomenclature"]) 
    113251        self.treeWidget.setRootIsDecorated(False) 
    114252        self.treeWidget.setSelectionMode(QAbstractItemView.ExtendedSelection) 
     
    119257        self.mainArea.layout().addWidget(self.treeWidget) 
    120258         
    121         box = OWGUI.widgetBox(self.mainArea, "", orientation="horizontal") 
    122         OWGUI.button(box, self, "Select Filtered", callback=self.selectFiltered) 
    123         OWGUI.button(box, self, "Clear Selection", callback=self.treeWidget.clearSelection) 
     259        box = OWGUI.widgetBox(self.mainArea, "", 
     260                              orientation="horizontal") 
     261        OWGUI.button(box, self, "Select Filtered", 
     262                     callback=self.selectFiltered) 
     263        OWGUI.button(box, self, "Clear Selection", 
     264                     callback=self.treeWidget.clearSelection) 
    124265         
    125266        self.resize(1000, 700)         
     
    127268        self.geneinfo = [] 
    128269        self.cells = [] 
     270        self.row2geneinfo = {} 
    129271        self.data = None 
    130272        self.currentLoaded = None, None 
     
    136278        if data: 
    137279            self.geneAttrComboBox.clear() 
    138             self.attributes = [attr for attr in self.data.domain.variables + self.data.domain.getmetas().values() if attr.varType in [orange.VarTypes.String, orange.VarTypes.Discrete]] 
     280            self.attributes = [attr for attr in self.data.domain.variables + \ 
     281                               self.data.domain.getmetas().values() \ 
     282                               if attr.varType in [orange.VarTypes.String, 
     283                                                   orange.VarTypes.Discrete]] 
    139284            self.geneAttrComboBox.addItems([attr.name for attr in self.attributes]) 
    140285            self.openContext("", data) 
     
    151296            self.clear() 
    152297 
     298    def infoSource(self): 
     299        """ Return the current selected info source getter function from  
     300        INFO_SOURCES 
     301        """ 
     302        org = self.organisms[min(self.organismIndex, len(self.organisms) - 1)] 
     303        if org not in INFO_SOURCES: 
     304            org = "default" 
     305        sources = INFO_SOURCES[org] 
     306        name, func =  sources[min(self.useAltSource, len(sources) - 1)] 
     307        return name, func 
     308         
    153309    def setItems(self): 
    154310        self.warning(0) 
     
    166322        self.warning(1) 
    167323        org = self.organisms[min(self.organismIndex, len(self.organisms) - 1)] 
     324        source_name, info_getter = self.infoSource() 
    168325        info , currorg = self.currentLoaded 
    169326        self.error(0) 
    170         if currorg != org: 
    171             self.progressBarInit() 
    172              
    173             ## Load the gene info in a worker thread 
    174             call = self.asyncCall(obiGene.NCBIGeneInfo, (org,), name="Loading NCBI Gene info", blocking=False) 
    175             call.connect(call, SIGNAL("progressChanged(float)"), self.progressBarSet, Qt.QueuedConnection) 
    176             with orngServerFiles.DownloadProgress.setredirect(call.emitProgressChanged): 
    177                 call.__call__() 
    178                 info = call.get_result() 
    179  
    180 #            with orngServerFiles.DownloadProgress.setredirect(self.progressBarSet): 
    181 #                info = obiGene.NCBIGeneInfo(self.organisms[min(self.organismIndex, len(self.organisms) - 1)]) 
    182             self.progressBarFinished() 
    183             self.currentLoaded = info, org 
    184              
     327#        if currorg != org: 
     328#            self.progressBarInit() 
     329#             
     330#            ## Load the gene info in a worker thread 
     331#            call = self.asyncCall(obiGene.NCBIGeneInfo, (org,), name="Loading NCBI Gene info", blocking=False) 
     332#            call.connect(call, SIGNAL("progressChanged(float)"), self.progressBarSet, Qt.QueuedConnection) 
     333#            with orngServerFiles.DownloadProgress.setredirect(call.emitProgressChanged): 
     334#                call.__call__() 
     335#                info = call.get_result() 
     336# 
     337##            with orngServerFiles.DownloadProgress.setredirect(self.progressBarSet): 
     338##                info = obiGene.NCBIGeneInfo(self.organisms[min(self.organismIndex, len(self.organisms) - 1)]) 
     339#            self.progressBarFinished() 
     340#            self.currentLoaded = info, org 
     341         
    185342        self.updateDictyExpressLink(genes, show=org == "352472") 
    186              
    187         self.geneinfo = geneinfo = [(gene, info.get_info(gene, None)) for gene in genes] 
     343        self.altSourceCheck.setVisible(org == "352472") 
     344         
     345        # get the info for the genes in a separate thread 
     346        self.progressBarInit() 
     347        call = self.asyncCall(info_getter, (org, genes), 
     348                              name="Load NCBI Gene Info", 
     349                              blocking=False) 
     350#        call.connect(call, SIGNAL("progressChanged(float)"), self.progressBarSet, Qt.QueuedConnection) 
     351        with orngServerFiles.DownloadProgress.setredirect(call.emitProgressChanged): 
     352            call.__call__() 
     353            schema, geneinfo = call.get_result() 
     354#        call.__call__() 
     355#        schema, geneinfo = call.get_result() 
     356        self.progressBarFinished() 
     357        # schema, geneinfo = info_getter(org, genes)  
     358 
     359        self.geneinfo = geneinfo = list(zip(genes, geneinfo)) 
    188360 
    189361        self.progressBarInit() 
    190362        milestones = set([i for i in range(0, len(geneinfo), max(len(geneinfo)/100, 1))]) 
    191363        self.cells = cells = [] 
     364        self.row2geneinfo = {} 
    192365        links = [] 
    193366        for i, (gene, gi) in enumerate(geneinfo): 
    194367            if gi: 
    195                 cells.append([gi.gene_id, gi.symbol + " (%s)" % gene if gene != gi.symbol else gi.symbol, 
    196                             gi.locus_tag or "", gi.chromosome or "", gi.description or "", 
    197                             ", ".join(gi.synonyms), gi.symbol_from_nomenclature_authority or ""]) 
    198                 links.append("http://www.ncbi.nlm.nih.gov/sites/entrez?Db=gene&Cmd=ShowDetailView&TermToSearch=%s" % gi.gene_id) 
     368                row = [] 
     369                for sch, item in zip(schema, gi): 
     370                    if isinstance(item, Link): # TODO: This should be handled by delegates  
     371                        row.append(item.text) 
     372                        links.append(item.link) 
     373                    else: 
     374                        row.append(item) 
     375                cells.append(row) 
     376                self.row2geneinfo[len(cells) - 1] = i 
     377#                cells.append([gi.gene_id, gi.symbol + " (%s)" % gene if gene != gi.symbol else gi.symbol, 
     378#                            gi.locus_tag or "", gi.chromosome or "", gi.description or "", 
     379#                            ", ".join(gi.synonyms), gi.symbol_from_nomenclature_authority or ""]) 
     380#                links.append("http://www.ncbi.nlm.nih.gov/sites/entrez?Db=gene&Cmd=ShowDetailView&TermToSearch=%s" % gi.gene_id) 
     381                 
    199382 
    200383            if i in milestones: 
    201384                self.progressBarSet(100.0*i/len(geneinfo)) 
    202         model = TreeModel(cells, ["NCBI ID", "Symbol", "Locus Tag", "Chromosome", "Description", "Synonyms", "Nomenclature"], self.treeWidget) 
     385        model = TreeModel(cells, [str(col) for col in schema], self.treeWidget) 
     386         
    203387        model.setColumnLinks(0, links) 
    204388        proxyModel = QSortFilterProxyModel(self) 
     
    217401    def clear(self): 
    218402        self.infoLabel.setText("No data on input\n") 
    219         self.treeWidget.setModel(TreeModel([], ["NCBI ID", "Symbol", "Locus Tag", "Chromosome", "Description", "Synonyms", "Nomenclature"], self.treeWidget)) 
     403        self.treeWidget.setModel(TreeModel([], ["NCBI ID", "Symbol", "Locus Tag", 
     404                                            "Chromosome", "Description", "Synonyms", 
     405                                            "Nomenclature"], self.treeWidget)) 
    220406        self.geneAttrComboBox.clear() 
    221407        self.send("Selected Examples", None) 
     
    233419        mapToSource = self.treeWidget.model().mapToSource 
    234420        selectedIds = [self.cells[mapToSource(index).row()][0] for index in self.treeWidget.selectedIndexes()] 
    235          
    236         selected = [gi for gene, gi in self.geneinfo if gi and gi.gene_id in selectedIds] 
     421        selectedRows = self.treeWidget.selectedIndexes() 
     422        selectedRows = [mapToSource(index).row() for index in selectedRows] 
     423         
     424        selectedGeneids = [self.row2geneinfo[row] for row in selectedRows] 
     425        selectedIds = [self.geneinfo[i][0] for i in selectedGeneids] 
     426        selectedIds = set(selectedIds) 
     427         
    237428        if self.useAttr: 
    238             attrs = [attr for attr, (name, gi) in zip(self.data.domain.attributes, self.geneinfo) if gi in selected] 
     429            def is_selected(attr): 
     430                return attr.name in selectedIds 
     431            attrs = [attr for attr in self.data.domain.attributes if is_selected(attr)] 
    239432            domain = orange.Domain(attrs, self.data.domain.classVar) 
    240433            domain.addmetas(self.data.domain.getmetas()) 
    241434            newdata = orange.ExampleTable(domain, self.data) 
    242435            self.send("Selected Examples", newdata) 
    243         else: 
     436        elif self.attributes: 
    244437            attr = self.attributes[self.geneAttr] 
    245438            geneinfo = dict(self.geneinfo) 
    246             examples = [ex for ex in self.data if geneinfo.get(str(ex[attr])) in selected] 
     439            examples = [ex for ex in self.data if str(ex[attr]) in selectedIds] 
    247440            if examples: 
    248441                newdata = orange.ExampleTable(examples) 
     
    250443                newdata = None 
    251444            self.send("Selected Examples", newdata) 
     445        else: 
     446            self.send("Selected Examples", None) 
    252447             
    253448    def rowFiltered(self, row): 
     
    306501        else: 
    307502            self.dictyExpressBox.hide() 
     503             
     504    def onAltSourceChange(self): 
     505        self.setItems() 
    308506         
    309507def reportItemView(view): 
Note: See TracChangeset for help on using the changeset viewer.