source: orange-bioinformatics/obiGene.py @ 1583:2b90e7c95085

Revision 1583:2b90e7c95085, 32.1 KB checked in by markotoplak, 2 years ago (diff)

Fixed a bug in obiGene (umatch did not work in Match objects). Gene set signatures method now accept examples from different domains on the input.

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
548    def umatch(self, gene):
549        """Returns an unique (only one matching target) target or None"""
550        mat = self.match(gene)
551        return mat[0] if len(mat) == 1 else None
552 
553class MatchAliases(Match):
554
555    def __init__(self, to_targets, parent):
556        self.to_targets = to_targets
557        self.parent = parent
558
559    def match(self, gene):
560        """
561        Input gene is first mapped to ids of sets of aliases which contain
562        it. Target genes belonding to the same sets of aliases are returned
563        as input's match.
564        """
565        inputgeneids = self.parent.to_ids(gene)
566        #return target genes with same ids
567        return list(set( \
568            reduce(lambda x,y: x+y, 
569                [ self.to_targets[igid] for igid in inputgeneids ], [])))
570
571    def explain(self, gene):
572        inputgeneids = self.parent.to_ids(gene)
573        return [ (self.to_targets[igid], self.parent.aliases[igid]) for igid in inputgeneids ]
574
575class MatcherAliasesPickled(MatcherAliases):
576    """
577    Gene matchers based on sets of aliases supporting pickling should
578    extend this class. Subclasses must define functions "filename",
579    "create_aliases_version" and "create_aliases". Those are crucial for
580    pickling of gene aliases to work.
581
582    Loading of gene aliases is done lazily: they are loaded when they are
583    needed. Loading of aliases for components of joined matchers is often
584    unnecessary and is therefore avoided.
585    """
586   
587    def set_aliases(self, aliases):
588        self.saved_aliases = aliases
589
590    def get_aliases(self):
591        if not self.saved_aliases: #loads aliases if not loaded
592            self.aliases = self.load_aliases()
593        #print "size of aliases ", len(self.saved_aliases)
594        return self.saved_aliases
595
596    aliases = property(get_aliases, set_aliases)
597
598    def get_mdict(self):
599        """ Creates mdict. Aliases are loaded if needed. """
600        if not self.saved_mdict:
601            self.saved_mdict = create_mapping(self.aliases, self.ignore_case)
602        return self.saved_mdict
603
604    def set_mdict(self, mdict):
605        self.saved_mdict = mdict
606
607    mdict = property(get_mdict, set_mdict)
608
609    def set_targets(self, targets):
610        return MatcherAliases.set_targets(self, targets)
611
612    def filename(self):
613        """ Returns file name for saving aliases. """
614        notImplemented()
615       
616    def create_aliases_version(self):
617        """ Returns version of the source database state. """
618        notImplemented()
619
620    def create_aliases(self):
621        """ Returns gene aliases. """
622        notImplemented()
623
624    def load_aliases(self):
625        fn = self.filename()
626        ver = self.create_aliases_version() #if version == None ignore it
627        if fn != None:
628            if isinstance(fn, tuple): #if you pass tuple, look directly
629               filename = fn[0]
630            else:
631               filename = os.path.join(buffer_path(), fn)
632            return auto_pickle(filename, ver, self.create_aliases)
633        else:
634            #if either file version of version is None, do not pickle
635            return self.create_aliases()
636
637    def __init__(self, ignore_case=True):
638        self.aliases = []
639        self.mdict = {}
640        self.ignore_case = ignore_case
641        self.filename() # test if valid filename can be built
642
643class MatcherAliasesKEGG(MatcherAliasesPickled):
644
645    def _organism_name(self, organism):
646        import obiKEGG 
647        return obiKEGG.organism_name_search(organism)
648
649    def create_aliases(self):
650        organism = self._organism_name(self.organism)
651        import obiKEGG
652        org = obiKEGG.KEGGOrganism(self.organism, genematcher=GMDirect())
653        genes = org.genes
654        osets = [ set([name]) | set(b.alt_names) for 
655                name,b in genes.items() ]
656        return osets
657
658    def create_aliases_version(self):
659        import obiKEGG
660        return obiKEGG.KEGGOrganism.organism_version(self.organism) + ".1"
661
662    def filename(self):
663        return "kegg_" + 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        import obiGO
690        return obiGO.organism_name_search(self.organism)
691
692    def create_aliases(self):
693        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        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        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        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        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        for matcher in self.matchers:
868            ms.append(matcher.set_targets(targets))
869        om = MatchSequence(ms)
870        self.matcho = om
871        return om
872
873    #this two functions are solely for backward compatibility
874    def match(self, gene):
875        return self.matcho.match(gene)
876    def explain(self, gene):
877        return self.matcho.explain(gene)
878
879class MatchSequence(Match):
880
881    def __init__(self, ms):
882        self.ms = ms
883
884    def match(self, gene):
885        for match in self.ms:
886            m = match.match(gene)
887            if m: 
888                return m
889        return []
890
891    def explain(self, gene):
892        for match in self.ms:
893            m = match.match(gene)
894            if m: 
895                return match.explain(gene)
896        return []
897
898class MatcherDirect(Matcher):
899    """
900    Direct matching to targets.
901    """
902
903    def __init__(self, ignore_case=True):
904        self.ignore_case = ignore_case
905
906    def set_targets(self, targets):
907        aliases = [ set([a]) for a in targets]
908        self.am = MatcherAliases(aliases, ignore_case=self.ignore_case)
909        self.matcho = self.am.set_targets(targets)
910        return self.matcho
911
912    #this two functions are solely for backward compatibility
913    def match(self, gene):
914        return self.matcho.match(gene)
915    def explain(self, gene):
916        return self.matcho.explain(gene)
917
918               
919GMDirect = MatcherDirect
920GMKEGG = MatcherAliasesKEGG
921GMGO = MatcherAliasesGO
922GMNCBI = MatcherAliasesNCBI
923GMDicty = MatcherAliasesDictyBase
924GMAffy = MatcherAliasesAffy
925GMEnsembl = MatcherAliasesEnsembl
926
927def issequencens(x):
928    return hasattr(x, '__getitem__') and not isinstance(x, basestring)
929
930def matcher(matchers, direct=True, ignore_case=True):
931    """
932    Build a matcher from a sequence of matchers. If a sequence element is a
933    sequence, join matchers in the subsequence.
934
935    direct - if True, add a direct matcher to targets
936    ignore_case - if True, ignores case with optionally added direct matcher
937    """
938    seqmat = []
939    if direct:
940        seqmat.append(MatcherDirect(ignore_case=ignore_case))
941    for mat in matchers:
942        if issequencens(mat):
943            mat = MatcherAliasesPickledJoined(list(mat))
944            seqmat.append(mat)
945        else:
946            seqmat.append(mat)
947    return MatcherSequence(seqmat)
948
949if __name__ == '__main__':
950
951    #m1 = matcher([[GMNCBI('44689'), GMDicty()]])
952    #print m1.matchers[1].aliases[:100]
953
954    #m2 = GMNCBI('Dictyostelium discoideum')
955    #print m2.aliases
956
957
958
959    """
960    gi = info(list(info)[0])
961    print gi.tax_id, gi.synonyms, gi.dbXrefs, gi.symbol_from_nomenclature_authority, gi.full_name_from_nomenclature_authority
962    """
963
964    #dobim z joinom prave stvari?
965
966    import time
967    import obiGeneSets
968
969    def testsets():
970        return obiGeneSets.collections([":kegg:hsa", ":go:hsa"])
971
972    def names1():
973        import orange
974        data = orange.ExampleTable("DLBCL.tab")
975        return [ a.name for a in  data.domain.attributes ]
976
977    def namesd():
978        import orange
979        data = orange.ExampleTable("dd_ge_biorep1.tab")
980        names = [ ex["gene"].value for ex in data ]
981        return names
982
983    genesets = auto_pickle("testcol", "3", testsets)
984    names = auto_pickle("testnames", "4", names1)
985    names2 = auto_pickle("testnamesdicty", "4", namesd)
986
987    info = NCBIGeneInfo('Dictyostelium discoideum')
988    for a in names2:
989        print a
990        info.get_info(a)
991
992    t = time.time()
993    mat5 = matcher([[GMKEGG('human'),GMGO('human')]], direct=False, ignore_case=True)
994    mat7 = GMDicty()
995    mat8 = GMNCBI('Homo sapiens')
996    print "initialized all", time.time()-t
997
998    print "using targets"
999
1000    mat5.set_targets(names)
1001    mat7.set_targets(names)
1002    mat8.set_targets(names)
1003
1004    print "before genes"
1005    genes = reduce(set.union, genesets.values()[:1000], set())
1006    genes = list(genes)
1007    print genes[:20]
1008    print len(genes)
1009    print "after genes"
1010
1011    for g in sorted(genes):
1012        print "KGO ", g, mat5.match(g), mat5.explain(g)
1013        print "DICT", g, mat7.match(g)
1014        print "NCBI", g, mat8.match(g)
1015
1016
Note: See TracBrowser for help on using the repository browser.