source: orange-bioinformatics/obiGene.py @ 1578:9bc83a60db78

Revision 1578:9bc83a60db78, 31.9 KB checked in by markotoplak, 2 years ago (diff)

Gene matcher now have a call function and return a Match object, which is used for matching. Backward compatibility was retained.

Line 
1import os
2import obiTaxonomy
3import orngServerFiles
4
5import time
6
7default_database_path = orngServerFiles.localpath("NCBI_geneinfo")
8
9class GeneInfo(object):
10    """ An object representing the NCBI information for a gene.
11    """
12
13    NCBI_GENEINFO_TAGS = ("tax_id", "gene_id", "symbol", "locus_tag", "synonyms",
14                          "dbXrefs", "chromosome", "map_location", "description", "type",
15                          "symbol_from_nomenclature_authority", "full_name_from_nomenclature_authority",
16                          "nomenclature_status", "other_designations", "modification_date")
17    NCBI_MULTIPLE_CARDINALITY_TAGS = ("synonyms", "dbXrefs", "other_designations")
18   
19    __slots__ = NCBI_GENEINFO_TAGS
20    def __init__(self, line):
21        """ Construct the GeneInfo object from a line in the NCBI gene_info file
22        """
23        line = line.split("\t")
24        for attr, value in zip(self.__slots__, line):
25            if value == "-":
26                value = None
27            if attr in GeneInfo.NCBI_MULTIPLE_CARDINALITY_TAGS:
28                value = value.split("|") if value != None else []
29            setattr(self, attr, value)
30
31    def __repr__(self):
32        def format(value):
33            if not value:
34                return "-"
35            elif type(value) == list:
36                return "|".join(value)
37            else:
38                return value
39        return "\t".join(format(getattr(self, slot)) for slot in self.__slots__)
40
41    def __str__(self):
42        return repr(self)
43
44class GeneHistory(object):
45    NCBI_GENE_HISTORY_TAGS = ("tax_id", "gene_id", "discontinued_gene_id", "discontinued_symbol", "discontinue_date")
46    __slots__ = NCBI_GENE_HISTORY_TAGS
47    def __init__(self, line):
48        for attr, value in zip(self.__slots__, line.split("\t")):
49            setattr(self, attr, value)
50           
51           
52class NCBIGeneInfo(dict):
53    TAX_MAP = {
54            "2104": "272634",  # Mycoplasma pneumoniae
55            "4530": "39947",  # Oryza sativa
56            "5833": "36329",  # Plasmodium falciparum
57            "4932": "559292",  # Saccharomyces cerevisiae
58            }
59       
60    def __init__(self, organism, genematcher=None):
61        """ An dictionary like object for accessing NCBI gene info
62        Arguments::
63                - *organism*    Organism id
64
65        Example::
66            >>> info = NCBIGeneInfo("Homo sapiens")
67        """
68       
69        self.taxid = self.organism_name_search(organism)
70
71
72        fname = orngServerFiles.localpath_download("NCBI_geneinfo", "gene_info.%s.db" % self.taxid)
73        file = open(fname, "rb")
74        self.update(dict([(line.split("\t", 3)[1], line) for line in file.read().split("\n") if line.strip() and not line.startswith("#")]))
75
76        # NOTE orig init time for gene matcher: 2.5s, new 4s: investigate the slowdown
77        # NOTE matches are not the same because aliases are build a bit
78        # differently (main name versus old aliases conflict!)
79
80        self.matcher = genematcher
81        if self.matcher == None:
82            if self.taxid == '352472':
83                self.matcher = matcher([GMNCBI(self.taxid), GMDicty(), [GMNCBI(self.taxid), GMDicty()]])
84            else:
85                self.matcher = matcher([GMNCBI(self.taxid)])
86
87        #if this is done with a gene matcher, pool target names
88        self.matcher.set_targets(self.keys())
89       
90    def history(self):
91        if getattr(self, "_history", None) is None:
92            fname = orngServerFiles.localpath_download("NCBI_geneinfo", "gene_history.%s.db" % self.taxid)
93            try:
94                self._history = dict([(line.split("\t")[2], GeneHistory(line)) for line in open(fname, "rb").read().split("\n")])
95               
96            except Exception, ex:
97                print >> sys.srderr, "Loading NCBI gene history failed.", ex
98                self._history = {}
99        return self._history
100       
101    @classmethod
102    def organism_version(cls, name):
103        oname = cls.organism_name_search(name)
104        #FIXME, dirty hack to ensure file id downloaded
105        orngServerFiles.localpath_download("NCBI_geneinfo", "gene_info.%s.db" % oname) 
106        return orngServerFiles.info("NCBI_geneinfo", "gene_info.%s.db" % oname)["datetime"]
107
108    @classmethod
109    def organism_name_search(cls, org):
110        taxids = obiTaxonomy.to_taxid(org, mapTo=cls.common_taxids())
111        if not taxids:
112            taxids = obiTaxonomy.search(org, onlySpecies=False)
113            taxids = set(cls.common_taxids()).intersection(taxids) #onlySpecies=False needed to find correct dicty
114        if len(taxids) == 0:
115            raise obiTaxonomy.UnknownSpeciesIdentifier, org
116        elif len(taxids) > 1:
117            raise obiTaxonomy.MultipleSpeciesException, ", ".join(["%s: %s" % (id, obiTaxonomy.name(id)) for id in taxids])
118        taxid = taxids.pop()
119        return cls.TAX_MAP.get(taxid, taxid)
120
121    @classmethod   
122    def load(cls, file):
123        """ A class method that loads gene info from file
124        """
125        if type(file) in [str, unicode]:
126            file = open(file, "rb")
127        return cls((line.split("\t", 3)[1], line) for line in file.read().split("\n") if line.strip() and not line.startswith("#"))
128       
129    def get_info(self, gene_id, def_=None):
130        """ Search and return the GeneInfo object for gene_id
131        """
132        try:
133            return self(gene_id)
134        except KeyError:
135            return def_
136       
137    def __call__(self, name):
138        """ Search and return the GeneInfo object for gene_id
139        """
140        #id = self.translate.get(name, name)
141        #print self.matcher.umatch(name), self.matcher.match(name)
142        id = self.matcher.umatch(name)
143        return self[id]
144
145    def __getitem__(self, key):
146#        return self.get(gene_id, self.matcher[gene_id])
147        return GeneInfo(dict.__getitem__(self, key))
148
149    def __setitem__(self, key, value):
150        if type(value) == str:
151            dict.__setitem__(self, key, value)
152        else:
153            dict.__setitem__(self, key, repr(value))
154
155    def get(self, key, def_=None):
156        try:
157            return self[key]
158        except KeyError:
159            return def_
160
161    def itervalues(self):
162        for val in dict.itervalues(self):
163            yield GeneInfo(val)
164
165    def iteritems(self):
166        for key, val in zip(self.iterkeys(), self.itervalues()):
167            yield key, val
168
169    def values(self):
170        return list(self.itervalues())
171   
172    def items(self):
173        return list(self.iteritems())
174
175    @staticmethod
176    def get_geneinfo_from_ncbi(file, progressCallback=None):
177        import urllib2, gzip, shutil, tempfile
178        from cStringIO import StringIO
179        if isinstance(file, basestring):
180            file = open(file, "wb")
181       
182        stream = urllib2.urlopen("ftp://ftp.ncbi.nih.gov/gene/DATA/gene_info.gz")
183        tmpfile = tempfile.TemporaryFile()
184        shutil.copyfileobj(stream, tmpfile)
185        tmpfile.seek(0)
186        stream = gzip.GzipFile(None, "rb", fileobj=tmpfile)
187        shutil.copyfileobj(stream, file)
188       
189    @staticmethod
190    def get_gene_history_from_ncbi(file, progressCallback=None):
191        import urllib2, gzip, shutil, tempfile
192        from cStringIO import StringIO
193        if isinstance(file, basestring):
194            file = open(file, "wb")
195       
196        stream = urllib2.urlopen("ftp://ftp.ncbi.nih.gov/gene/DATA/gene_history.gz")
197        tmpfile = tempfile.TemporaryFile()
198        shutil.copyfileobj(stream, tmpfile)
199        tmpfile.seek(0)
200        stream = gzip.GzipFile(None, "rb", fileobj=tmpfile)
201        shutil.copyfileobj(stream, file)
202       
203    @classmethod
204    def common_taxids(cls):
205        taxids = obiTaxonomy.common_taxids()
206        return [cls.TAX_MAP.get(id, id) for id in taxids if cls.TAX_MAP.get(id, id)]
207   
208    @classmethod
209    def essential_taxids(cls):
210        taxids = obiTaxonomy.essential_taxids()
211        return [cls.TAX_MAP.get(id, id) for id in taxids if cls.TAX_MAP.get(id, id)]
212
213
214class EnsembleGeneInfo(object):
215#    BIO_MART_DATASETS = {"9606": "hsapiens"}
216    DEF_ATTRS = ["ensembl_gene_id", "external_gene_id", "entrezgene"]
217    BIOMART_CONF = {"9606": ("hsapiens_gene_ensembl", DEF_ATTRS) # + ["hgnc_symbol"])
218                    }
219    def __init__(self, organism, gene_matcher=None):
220        self.organism = self.organism_name_search(organism) 
221        self.load()
222        if gene_matcher is None:
223            self.gene_matcher = matcher([GMEnsembl(self.organism), GMNCBI(self.organism)])
224        else:
225            self.gene_matcher = gene_matcher
226       
227    @classmethod
228    def organism_name_search(cls, name):
229        taxids = obiTaxonomy.to_taxid(name, mapTo=cls.common_taxids())
230        if len(taxids) == 1:
231            return taxids[0]
232        else:
233            raise ValueError(name)
234       
235    @classmethod
236    def common_taxids(cls):
237        return ["3702", "9913", "6239", "7955", "9606", "7227",
238                "10090", "10116", "4932", "4896", "8355"]
239   
240    @classmethod
241    def version(cls):
242        return "v1.0"
243       
244    def filename(self):
245        return "ensembl_" + self.organism
246   
247    def create_info(self):
248        import obiBioMart
249        if self.organism in self.BIOMART_CONF:
250            dset_name, attrs = self.BIOMART_CONF[self.organism]
251        else:
252            dset_name, attrs = self.default_biomart_conf(self.organism)
253       
254        dataset = obiBioMart.BioMartDataset("ensembl", dset_name)
255        table = dataset.get_example_table(attributes=attrs, unique=True)
256        print len(table)
257        table.save(dset_name + ".tab")
258        from collections import defaultdict
259        names = defaultdict(set)
260        for ex in table:
261            row = [str(v) for v in ex if not v.isSpecial() and str(v)]
262            names[row[0]].update(row)
263        return names
264       
265    def default_biomart_conf(self, taxid):
266        name = obiTaxonomy.name(self.organism).lower()
267        name1, name2 = name.split(" ")[: 2]
268        dset_name = name1[0] + name2 + "_gene_ensembl"
269        return dset_name, self.DEF_ATTRS
270   
271    def load(self):
272        import cPickle
273        dir = orngServerFiles.localpath("EnsembleGeneInfo")
274        if not os.path.exists(dir):
275            os.makedirs(dir)
276       
277        try:
278            filename = orngServerFiles.localpath_download("EnsembleGeneInfo", self.filename())
279            info = cPickle.load(open(filename, "rb"))
280        except Exception, ex:   
281            filename = orngServerFiles.localpath("EnsembleGeneInfo", self.filename())
282            info = self.create_info()
283            cPickle.dump(info, open(filename, "wb"))
284           
285        self.info = info
286       
287    def __getitem__(self, key):
288        return self.info[key]
289    def __contains__(self, key):
290        return key in self.info
291    def __len__(self):
292        return len(self.info)
293    def __iter__(self):
294        return iter(self.info)
295    def keys(self):
296        return self.info.keys()
297    def values(self):
298        return self.info.values()
299    def items(self):
300        return self.info.items()
301    def get(self, key, default=None):
302        return self.info.get(key, default)
303   
304    def genes(self):
305        return self.info.keys()
306   
307    def aliases(self):
308        return [(key,) + tuple(value) for key, value in self.items()]
309   
310    def ensembl_id(self, name):
311        return self.gene_matcher.umatch(name)
312       
313"""
314Gene matcher.
315
316"Database" for each organism is a list of sets of gene aliases.
317"""
318
319from collections import defaultdict
320import os
321
322gene_matcher_path = None
323
324def ignore_case(gs):
325    """ Transform names in sets in list to lower case """
326    return [ set([a.lower() for a in g]) for g in gs ]
327
328def create_mapping(groups, lower=False):
329    """
330    Returns mapping of aliases to the group index. If lower
331    is True, lower case forms of gene aliases are mapped to indices.
332
333    Unpickling the results of this function (binary format)
334    is slower than running it.
335
336    TIMING NOTES:
337    - lower() costs are neglible (< 10%)
338    - building sets instead of lists also costs about 10 percent
339    """
340    togroup = defaultdict(set)
341
342    # code duplicated because running a function in relatively expensive here.
343    if lower: 
344        for i,group in enumerate(groups):
345            for alias in group:
346                togroup[alias.lower()].add(i)
347    else:
348        for i,group in enumerate(groups):
349            for alias in group:
350                togroup[alias].add(i)
351
352    return togroup
353
354def join_sets(set1, set2, lower=False):
355    """
356    Joins two sets of gene set mappings. If lower is True, lower case
357    forms of gene aliases are compared.
358
359    A group g1 from set1 is joined to a group of aliases g2 from set2,
360    if the groups share at least one gene.
361    Returns all joined groups and groups that were not matched, which
362    remain unchanged.
363
364    The operation both commutative and associative.
365    """
366
367    set1 = [ set(a) for a in set1 ]
368    set2 = [ set(a) for a in set2 ]
369
370    currentmap = create_mapping(set1, lower=lower)
371
372    new = [] #new groups
373
374    #remember used to find unused
375    set1used = set() 
376    set2used = set()
377
378    fn = lambda x: x
379    if lower:
380        fn = lambda x: x.lower()
381
382    for i, group in enumerate(set2):
383
384        #find groups of aliases (from set1)  intersecting with a current
385        #group from set2
386        cross = reduce(set.union, 
387            [ currentmap[fn(alias)] for alias in group if fn(alias) in currentmap], set())
388
389        for c in cross:
390            #print c, group & set1[c], group, set1[c]
391            set1used.add(c)
392            set2used.add(i)
393            new.append(group | set1[c]) #add a union
394
395    #add groups without matches (from both sets)
396    set1add = set(range(len(set1))) - set1used
397    set2add = set(range(len(set2))) - set2used
398
399    for a in set1add:
400        new.append(set1[a])
401    for a in set2add:
402        new.append(set2[a])
403
404    return new
405 
406def join_sets_l(lsets, lower=False):
407    """
408    Joins multiple gene set mappings using join_sets function.
409    """
410    current = lsets[0]
411    for b in lsets[1:]:
412        current = join_sets(current, b, lower=lower)
413    return current
414
415class Matcher(object):
416    """
417    Gene matcher tries to match an input gene to some target.
418    """
419
420    def copy(self):
421        return notImplemented()
422
423    def __call__(self, targets):
424        return self.set_targets(targets)
425
426    def set_targets(self, targets):
427        """
428        Set input list of gene names as targets.
429        Abstract function.
430        """
431        notImplemented()
432
433    def match(self, gene):
434        """Returns a list of matching target gene names."""
435        notImplemented()
436
437    def umatch(self, gene):
438        """Returns an unique (only one matching target) target or None"""
439        mat = self.match(gene)
440        return mat[0] if len(mat) == 1 else None
441
442    def explain(self, gene):
443        """
444        Returns an gene matches with explanations as lists of tuples.
445        Each tuple consists of a list of target genes in a set
446        of aliases matched to input gene, returned as a second part
447        of the tuple.
448        """
449        notImplemented()
450
451def buffer_path():
452    """ Returns buffer path from Orange's setting folder if not
453    defined differently (in gene_matcher_path). """
454    if  gene_matcher_path == None:
455        import orngEnviron
456        pth = os.path.join(orngEnviron.directoryNames["bufferDir"], 
457            "gene_matcher")
458        try:
459            os.makedirs(pth)
460        except:
461            pass
462        return pth
463    else:
464        return gene_matcher_path
465
466def auto_pickle(filename, version, func, *args, **kwargs):
467    """
468    Run function func with given arguments and save the results to
469    a file named filename. If results for a given filename AND
470    version were already saved, just read and return them.
471    """
472
473    import cPickle as pickle
474
475    output = None
476    outputOk = False
477
478    try:
479        f = open(filename,'rb')
480
481        try:
482            versionF = pickle.load(f)
483            if version == None or versionF == version:
484                outputOk = True
485                output = pickle.load(f)
486        except:
487            pass
488        finally:
489            f.close()
490
491    except:
492        pass
493
494    if not outputOk:
495        output = func(*args, **kwargs)
496
497        #save output before returning
498        f = open(filename,'wb')
499        pickle.dump(version, f, -1)
500        pickle.dump(output, f, -1)
501        f.close()
502
503    return output
504
505class MatcherAliases(Matcher):
506    """
507    Genes matcher based on a list of sets of given aliases.
508
509    Target genes belonging to same sets of aliases as the input gene are
510    returned as matching genes.
511
512    """
513    def __init__(self, aliases, ignore_case=True):
514        self.aliases = aliases
515        self.ignore_case = ignore_case
516        self.mdict = create_mapping(self.aliases, self.ignore_case)
517
518    def to_ids(self, gene):
519        """ Return ids of sets of aliases the gene belongs to. """
520        if self.ignore_case:
521            gene = gene.lower()
522        return self.mdict[gene]
523
524    def set_targets(self, targets):
525        """
526        A reverse dictionary is made according to each target's membership
527        in the sets of aliases.
528        """
529        d = defaultdict(list)
530        #d = id: [ targets ], where id is index of the set of aliases
531        for target in targets:
532            ids = self.to_ids(target)
533            if ids != None:
534                for id in ids:
535                    d[id].append(target)
536        mo = MatchAliases(d, self)
537        self.matcho = mo #backward compatibility - default match object
538        return mo
539
540    #this two functions are solely for backward compatibility
541    def match(self, gene):
542        return self.matcho.match(gene)
543    def explain(self, gene):
544        return self.matcho.explain(gene)
545
546class Match(object):
547    pass
548 
549class MatchAliases(Match):
550
551    def __init__(self, to_targets, parent):
552        self.to_targets = to_targets
553        self.parent = parent
554
555    def match(self, gene):
556        """
557        Input gene is first mapped to ids of sets of aliases which contain
558        it. Target genes belonding to the same sets of aliases are returned
559        as input's match.
560        """
561        inputgeneids = self.parent.to_ids(gene)
562        #return target genes with same ids
563        return list(set( \
564            reduce(lambda x,y: x+y, 
565                [ self.to_targets[igid] for igid in inputgeneids ], [])))
566
567    def explain(self, gene):
568        inputgeneids = self.parent.to_ids(gene)
569        return [ (self.to_targets[igid], self.parent.aliases[igid]) for igid in inputgeneids ]
570
571class MatcherAliasesPickled(MatcherAliases):
572    """
573    Gene matchers based on sets of aliases supporting pickling should
574    extend this class. Subclasses must define functions "filename",
575    "create_aliases_version" and "create_aliases". Those are crucial for
576    pickling of gene aliases to work.
577
578    Loading of gene aliases is done lazily: they are loaded when they are
579    needed. Loading of aliases for components of joined matchers is often
580    unnecessary and is therefore avoided.
581    """
582   
583    def set_aliases(self, aliases):
584        self.saved_aliases = aliases
585
586    def get_aliases(self):
587        if not self.saved_aliases: #loads aliases if not loaded
588            self.aliases = self.load_aliases()
589        #print "size of aliases ", len(self.saved_aliases)
590        return self.saved_aliases
591
592    aliases = property(get_aliases, set_aliases)
593
594    def get_mdict(self):
595        """ Creates mdict. Aliases are loaded if needed. """
596        if not self.saved_mdict:
597            self.saved_mdict = create_mapping(self.aliases, self.ignore_case)
598        return self.saved_mdict
599
600    def set_mdict(self, mdict):
601        self.saved_mdict = mdict
602
603    mdict = property(get_mdict, set_mdict)
604
605    def set_targets(self, targets):
606        return MatcherAliases.set_targets(self, targets)
607
608    def filename(self):
609        """ Returns file name for saving aliases. """
610        notImplemented()
611       
612    def create_aliases_version(self):
613        """ Returns version of the source database state. """
614        notImplemented()
615
616    def create_aliases(self):
617        """ Returns gene aliases. """
618        notImplemented()
619
620    def load_aliases(self):
621        fn = self.filename()
622        ver = self.create_aliases_version() #if version == None ignore it
623        if fn != None:
624            if isinstance(fn, tuple): #if you pass tuple, look directly
625               filename = fn[0]
626            else:
627               filename = os.path.join(buffer_path(), fn)
628            return auto_pickle(filename, ver, self.create_aliases)
629        else:
630            #if either file version of version is None, do not pickle
631            return self.create_aliases()
632
633    def __init__(self, ignore_case=True):
634        self.aliases = []
635        self.mdict = {}
636        self.ignore_case = ignore_case
637        self.filename() # test if valid filename can be built
638
639class MatcherAliasesKEGG(MatcherAliasesPickled):
640
641    def _organism_name(self, organism):
642        import obiKEGG 
643        return obiKEGG.organism_name_search(organism)
644
645    def create_aliases(self):
646        organism = self._organism_name(self.organism)
647        import obiKEGG
648        org = obiKEGG.KEGGOrganism(self.organism, genematcher=GMDirect())
649        genes = org.genes
650        osets = [ set([name]) | set(b.alt_names) for 
651                name,b in genes.items() ]
652        return osets
653
654    def create_aliases_version(self):
655        import obiKEGG
656        return obiKEGG.KEGGOrganism.organism_version(self.organism) + ".1"
657
658    def filename(self):
659        return "kegg_" + self._organism_name(self.organism) 
660
661    def __init__(self, organism, ignore_case=True):
662        self.organism = organism
663        MatcherAliasesPickled.__init__(self, ignore_case=ignore_case)
664
665class MatcherAliasesFile(MatcherAliasesPickled):
666
667    def create_aliases(self):
668        canNotCreateButCanOnlyOpen()
669
670    def create_aliases_version(self):
671        return None
672
673    def filename(self):
674        return (self.filename_,)
675
676    def __init__(self, filename, ignore_case=True):
677        self.filename_ = filename
678        MatcherAliasesPickled.__init__(self, ignore_case=ignore_case)
679
680
681class MatcherAliasesGO(MatcherAliasesPickled):
682
683    def _organism_name(self, organism):
684        """ Returns internal GO organism name. Used to define file name. """
685        import obiGO
686        return obiGO.organism_name_search(self.organism)
687
688    def create_aliases(self):
689        import obiGO
690        annotations = obiGO.Annotations(self.organism, genematcher=GMDirect())
691        names = annotations.geneNamesDict
692        return map(set, list(set([ \
693            tuple(sorted(set([name]) | set(genes))) \
694            for name,genes in names.items() ])))
695
696    def filename(self):
697        return "go_" + self._organism_name(self.organism)
698
699    def create_aliases_version(self):
700        import obiGO
701        return "v2." + obiGO.Annotations.organism_version(self.organism)
702
703    def __init__(self, organism, ignore_case=True):
704        self.organism = organism
705        MatcherAliasesPickled.__init__(self, ignore_case=ignore_case)
706
707class MatcherAliasesDictyBase(MatcherAliasesPickled):
708
709    def create_aliases(self):
710        import obiDicty
711        db = obiDicty.DictyBase()
712        #db.info, db.mappings
713        infoa = [ set([id,name]) | set(aliases) for id,(name,aliases,_) in db.info.items() ]
714        mappingsa = [ set(filter(None, a)) for a in db.mappings ]
715        joineda = join_sets(infoa, mappingsa, lower=True)
716        return joineda
717
718    def create_aliases_version(self):
719        import obiDicty
720        return "v1." + obiDicty.DictyBase.version()
721
722    def filename(self):
723        return "dictybase" 
724
725    def __init__(self, ignore_case=True):
726        MatcherAliasesPickled.__init__(self, ignore_case=ignore_case)
727
728class MatcherAliasesNCBI(MatcherAliasesPickled):
729
730    def _organism_name(self, organism):
731        return NCBIGeneInfo.organism_name_search(organism)
732
733    def create_aliases(self):
734        ncbi = NCBIGeneInfo(self.organism, genematcher=GMDirect())
735        out = []
736        for k in ncbi.keys():
737            out.append(set(filter(None, [k, ncbi[k].symbol, ncbi[k].locus_tag] + [ s for s in ncbi[k].synonyms ] )))
738        return out
739
740    def filename(self):
741        return "ncbi_" + self._organism_name(self.organism)
742
743    def create_aliases_version(self):
744        return "v2." + NCBIGeneInfo.organism_version(self.organism)
745
746    def __init__(self, organism, ignore_case=True):
747        self.organism = organism
748        MatcherAliasesPickled.__init__(self, ignore_case=ignore_case)
749       
750class MatcherAliasesAffy(MatcherAliasesPickled):
751    def create_aliases(self):
752        filename = orngServerFiles.localpath_download("Affy", self.organism + ".pickle")
753        import cPickle
754        return cPickle.load(open(filename, "rb"))
755   
756    def filename(self):
757        return "affy_" + self.organism
758   
759    def create_aliases_version(self):
760        orngServerFiles.localpath_download("Affy", self.organism + ".pickle")
761        return orngServerFiles.info("Affy", self.organism + ".pickle")["datetime"]
762       
763    def __init__(self, organism, **kwargs):
764        self.organism = organism
765        MatcherAliasesPickled.__init__(self, **kwargs)
766   
767       
768class MatcherAliasesEnsembl(MatcherAliasesPickled):
769    """ A matcher for Ensemble ids
770    """
771    DEF_ATTRS = ["ensembl_gene_id", "external_gene_id", "entrezgene"]
772    # taxid: (dataset_name, [name_attr1, name_attr2 ...])
773    BIOMART_CONF = {}
774    def __init__(self, organism, **kwargs):
775        self.organism = organism
776        MatcherAliasesPickled.__init__(self, **kwargs)
777       
778    def filename(self):
779        return "ensembl_" + self.organism
780   
781    def create_aliases_version(self):
782        return "v1"
783   
784    def create_aliases(self):
785        import obiBioMart
786        if self.organism in self.BIOMART_CONF:
787            dset_name, attrs = self.BIOMART_CONF[self.organism]
788        else:
789            dset_name, attrs = self.default_biomart_conf(self.organism)
790       
791        dataset = obiBioMart.BioMartDataset("ensembl", dset_name)
792        table = dataset.get_example_table(attributes=attrs)
793        from collections import defaultdict
794        names = defaultdict(set)
795        for ex in table:
796            row = [str(v) for v in ex if not v.isSpecial() and str(v)]
797            names[row[0]].update(row)
798        return names.values()
799       
800    def default_biomart_conf(self, taxid):
801        name = obiTaxonomy.name(self.organism).lower()
802        name1, name2 = name.split(" ")[: 2]
803        dset_name = name1[0] + name2 + "_gene_ensembl"
804        return dset_name, self.DEF_ATTRS
805       
806
807class MatcherAliasesPickledJoined(MatcherAliasesPickled):
808    """
809    Creates a new matcher by joining gene aliases from different data sets.
810    Sets of aliases are joined if they contain common genes.
811
812    The joined gene matcher can only be pickled if the source gene
813    matchers are picklable.
814    """
815
816    def filename(self):
817        # do not pickle if any is unpicklable
818        try:
819            filenames = [ mat.filename() for mat in self.matchers ]
820            if self.ignore_case:
821                filenames += [ "icj" ]
822            return "__".join(filenames)
823        except:
824            return None
825
826    def create_aliases(self):
827        return join_sets_l([ mat.aliases for mat in self.matchers ], lower=self.ignore_case)
828
829    def create_aliases_version(self):
830        try:
831            return "v4_" + "__".join([ mat.create_aliases_version() for mat in self.matchers ])
832        except:
833            return None
834
835    def __init__(self, matchers):
836        """
837        Join matchers together. Groups of aliases are joined if
838        they share a common name.
839
840        If ignore_case is True, ignores case when joining gene aliases.
841        """
842        #FIXME: sorting of matchers to avoid multipying pickled files for
843        #different orderings.
844        self.matchers = matchers
845        allic = set([ m.ignore_case for m in self.matchers ])
846        if len(allic) > 1:
847            notAllMatchersHaveEqualIgnoreCase()
848        ignore_case = list(allic)[0]
849
850        MatcherAliasesPickled.__init__(self, ignore_case=ignore_case)
851       
852class MatcherSequence(Matcher):
853    """
854    Each gene goes through sequence of gene matchers (in the same order
855    as in the matchers arguments) until a match is found.
856    """
857   
858    def __init__(self, matchers):
859        self.matchers = matchers
860
861    def set_targets(self, targets):
862        ms = []
863        for matcher in self.matchers:
864            ms.append(matcher.set_targets(targets))
865        om = MatchSequence(ms)
866        self.matcho = om
867        return om
868
869    #this two functions are solely for backward compatibility
870    def match(self, gene):
871        return self.matcho.match(gene)
872    def explain(self, gene):
873        return self.matcho.explain(gene)
874
875class MatchSequence(Match):
876
877    def __init__(self, ms):
878        self.ms = ms
879
880    def match(self, gene):
881        for match in self.ms:
882            m = match.match(gene)
883            if m: 
884                return m
885        return []
886
887    def explain(self, gene):
888        for match in self.ms:
889            m = match.match(gene)
890            if m: 
891                return match.explain(gene)
892        return []
893
894class MatcherDirect(Matcher):
895    """
896    Direct matching to targets.
897    """
898
899    def __init__(self, ignore_case=True):
900        self.ignore_case = ignore_case
901
902    def set_targets(self, targets):
903        aliases = [ set([a]) for a in targets]
904        self.am = MatcherAliases(aliases, ignore_case=self.ignore_case)
905        self.matcho = self.am.set_targets(targets)
906        return self.matcho
907
908    #this two functions are solely for backward compatibility
909    def match(self, gene):
910        return self.matcho.match(gene)
911    def explain(self, gene):
912        return self.matcho.explain(gene)
913
914               
915GMDirect = MatcherDirect
916GMKEGG = MatcherAliasesKEGG
917GMGO = MatcherAliasesGO
918GMNCBI = MatcherAliasesNCBI
919GMDicty = MatcherAliasesDictyBase
920GMAffy = MatcherAliasesAffy
921GMEnsembl = MatcherAliasesEnsembl
922
923def issequencens(x):
924    return hasattr(x, '__getitem__') and not isinstance(x, basestring)
925
926def matcher(matchers, direct=True, ignore_case=True):
927    """
928    Build a matcher from a sequence of matchers. If a sequence element is a
929    sequence, join matchers in the subsequence.
930
931    direct - if True, add a direct matcher to targets
932    ignore_case - if True, ignores case with optionally added direct matcher
933    """
934    seqmat = []
935    if direct:
936        seqmat.append(MatcherDirect(ignore_case=ignore_case))
937    for mat in matchers:
938        if issequencens(mat):
939            mat = MatcherAliasesPickledJoined(list(mat))
940            seqmat.append(mat)
941        else:
942            seqmat.append(mat)
943    return MatcherSequence(seqmat)
944
945if __name__ == '__main__':
946
947    #m1 = matcher([[GMNCBI('44689'), GMDicty()]])
948    #print m1.matchers[1].aliases[:100]
949
950    #m2 = GMNCBI('Dictyostelium discoideum')
951    #print m2.aliases
952
953
954
955    """
956    gi = info(list(info)[0])
957    print gi.tax_id, gi.synonyms, gi.dbXrefs, gi.symbol_from_nomenclature_authority, gi.full_name_from_nomenclature_authority
958    """
959
960    #dobim z joinom prave stvari?
961
962    import time
963    import obiGeneSets
964
965    def testsets():
966        return obiGeneSets.collections([":kegg:hsa", ":go:hsa"])
967
968    def names1():
969        import orange
970        data = orange.ExampleTable("DLBCL.tab")
971        return [ a.name for a in  data.domain.attributes ]
972
973    def namesd():
974        import orange
975        data = orange.ExampleTable("dd_ge_biorep1.tab")
976        names = [ ex["gene"].value for ex in data ]
977        return names
978
979    genesets = auto_pickle("testcol", "3", testsets)
980    names = auto_pickle("testnames", "4", names1)
981    names2 = auto_pickle("testnamesdicty", "4", namesd)
982
983    info = NCBIGeneInfo('Dictyostelium discoideum')
984    for a in names2:
985        print a
986        info.get_info(a)
987
988    t = time.time()
989    mat5 = matcher([[GMKEGG('human'),GMGO('human')]], direct=False, ignore_case=True)
990    mat7 = GMDicty()
991    mat8 = GMNCBI('Homo sapiens')
992    print "initialized all", time.time()-t
993
994    print "using targets"
995
996    mat5.set_targets(names)
997    mat7.set_targets(names)
998    mat8.set_targets(names)
999
1000    print "before genes"
1001    genes = reduce(set.union, genesets.values()[:1000], set())
1002    genes = list(genes)
1003    print genes[:20]
1004    print len(genes)
1005    print "after genes"
1006
1007    for g in sorted(genes):
1008        print "KGO ", g, mat5.match(g), mat5.explain(g)
1009        print "DICT", g, mat7.match(g)
1010        print "NCBI", g, mat8.match(g)
1011
1012
Note: See TracBrowser for help on using the repository browser.