source: orange-bioinformatics/Orange/bioinformatics/obiGene.py @ 1632:9cf919d0f343

Revision 1632:9cf919d0f343, 32.3 KB checked in by mitar, 2 years ago (diff)

Fixing imports.

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