source: orange-bioinformatics/_bioinformatics/obiGene.py @ 1716:4c4266f7c5a5

Revision 1716:4c4266f7c5a5, 32.4 KB checked in by markotoplak, 20 months ago (diff)

Removed the old version of obiKEGG. Renamed obiKEGG2 -> obiKEGG.

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