source: orange-bioinformatics/orangecontrib/bio/obiPPI.py @ 1873:0810c5708cc5

Revision 1873:0810c5708cc5, 44.3 KB checked in by Ales Erjavec <ales.erjavec@…>, 7 months ago (diff)

Moved '_bioinformatics' into orangecontrib namespace.

Line 
1"""\
2Protein-protein interactions
3============================
4
5This is python module for accessing PPI data. 
6"""
7
8from __future__ import absolute_import
9
10import collections, gzip, posixpath, os, shutil, sqlite3, sys, urllib2, warnings, xml.dom.minidom as minidom
11from collections import defaultdict
12from operator import itemgetter
13
14from Orange.orng import orngServerFiles
15from Orange.utils import ConsoleProgressBar, lru_cache, wget
16
17from . import obiTaxonomy
18
19from .obiTaxonomy import pickled_cache
20
21class PPIDatabase(object):
22    """ A general interface for protein-protein interaction database access.
23   
24    An example useage::
25        >>> ppidb = MySuperPPIDatabase()
26        >>> ppidb.organisms() # List all organisms (taxids)
27        ['...
28       
29        >>> ppidb.ids() # List all protein ids
30        ['...
31       
32        >>> ppidb.ids(taxid="9606") # List all human protein ids.
33        ['...
34       
35        >>> ppidb.links() # List all links
36        [('...
37    """
38    def __init__(self):
39        pass
40   
41    def organisms(self):
42        """ Return all organism taxids contained in this database.
43        """
44        raise NotImplementedError
45   
46    def ids(self, taxid=None):
47        """ Return a list of all protein ids. If `taxid` is not None limit
48        the results to ids from this organism only.
49       
50        """
51        raise NotImplementedError
52   
53    def synonyms(self, id):
54        """ Return a list of synonyms for primary `id`.
55        """
56        raise NotImplementedError
57   
58    def all_edges(self, taxid=None):
59        """ Return a list of all edges. If taxid is not None return the
60        edges for this organism only.
61       
62        """
63        raise NotImplementedError
64   
65    def edges(self, id1, id2=None):
66        """ Return a list of all edges (a list of 3-tuples (id1, id2, score)).
67        """
68        raise NotImplementedError
69   
70    def all_edges_annotated(self, taxid=None):
71        """ Return a list of all edges annotated. If taxid is not None
72        return the edges for this organism only.
73       
74        """
75        res = []
76        for id in self.ids(taxid):
77            res.extend(self.edges_annotated(id))
78        return res
79       
80    def edges_annotated(self, id=None):
81        """ Return a list of all edges annotated
82        """
83        raise NotImplementedError
84     
85    def search_id(self, name, taxid=None):
86        """ Search the database for protein name. Return a list of matching
87        primary ids. Use `taxid` to limit the results to a single organism.
88         
89        """
90        raise NotImplementedError
91   
92    def extract_network(self, ids):
93        """
94        """
95        from Orange import network
96       
97        graph = network.Graph()
98        for id in ids:
99            graph.add_node(id, synonyms=",".join(self.synonyms(id)))
100           
101        for id in ids:
102            edges = self.edges(id)
103           
104            for id1, id2, score in edges:
105                graph.add_edge(id1, id2, weight=score)
106               
107        return graph
108       
109   
110    @classmethod
111    def download_data(self):
112        """ Download the latest PPI data for local work.
113        """
114        raise NotImplementedError
115   
116class BioGRID(PPIDatabase):
117    """ Access `BioGRID <http://thebiogrid.org>`_ PPI data.
118   
119    Example ::
120   
121        >>> biogrid = BioGRID()
122        >>> print biogrid.organism() # Print a list of all organism ncbi taxis in BioGRID
123        [u'10090',...
124       
125        >>> print biogrid.ids(taxid="9606") # Print a set of all human protein ids
126        [u'110004'
127       
128        >>> print biogrid.synonyms("110004") # Print a list of all synonyms for protein id '110004' as reported by BioGRID
129        [u'3803', u'CU464060.2', u'CD158b', u'p58.2', u'CD158B1', u'NKAT6']
130       
131        >>>
132       
133    """
134   
135    SCHEMA = [("links", """\
136        biogrid_interaction_id text,
137        biogrid_id_interactor_a text,
138        biogrid_id_interactor_b text,
139        experimental_system text,
140        experimental_system_type text,
141        author text,
142        pubmed_id text,
143        throughput text,
144        score real,
145        modification text,
146        phenotypes text,
147        qualifications text,
148        tags text,
149        source_database text
150        """),
151            ("proteins", """\
152        biogrid_id_interactor text,
153        entrez_gene_interactor text,
154        systematic_name_interactor text,
155        official_symbol_interactor text,
156        synonyms_interactor text,
157        organism_interactor text,
158        """)]
159    VERSION = "2.0"
160   
161    # All column names in the tab2 table.
162    FIELDS = ['biogrid_interaction_id',
163              'entrez_gene_interactor_a',
164              'entrez_gene_interactor_b',
165              'biogrid_id_interactor_a',
166              'biogrid_id_interactor_b',
167              'systematic_name_interactor_a',
168              'systematic_name_interactor_b',
169              'official_symbol_interactor_a',
170              'official_symbol_interactor_b',
171              'synonyms_interactor_a',
172              'synonyms_interactor_b',
173              'experimental_system',
174              'experimental_system_type',
175              'author',
176              'pubmed_id',
177              'organism_interactor_a',
178              'organism_interactor_b',
179              'throughput',
180              'score',
181              'modification',
182              'phenotypes',
183              'qualifications',
184              'tags',
185              'source_database'
186              ]
187   
188#    BioGRIDInteraction = collections.namedtuple("BioGRIDInteraction", " ".join(SCHEMA[0][1]))
189#    BioGRIDInteractor = collections.namedtuple("BioGRIDInteractor", " ".join(SCHEMA[1][1]))
190   
191    DOMAIN = "PPI"
192    SERVER_FILE = "BIOGRID-ALL.sqlite"
193   
194    def __init__(self):
195        self.filename = orngServerFiles.localpath_download(self.DOMAIN, self.SERVER_FILE)
196#        info = orngServerFiles.info(self.DOMAIN, self.SERVER_FILE)
197        # assert version matches
198        self.db = sqlite3.connect(self.filename)
199        self.init_db_index()
200
201    @lru_cache(1)
202    def organisms(self):
203        cur = self.db.execute("select distinct organism_interactor from proteins")
204        return cur.fetchall()
205
206    @lru_cache(3)
207    def ids(self, taxid=None):
208        """ Return a list of all protein ids (biogrid_id_interactors).
209        If `taxid` is not None limit the results to ids from this organism
210        only.
211       
212        """
213        if taxid is None:
214            cur = self.db.execute("""\
215                select biogrid_id_interactor
216                from proteins""")
217        else:
218            cur = self.db.execute("""\
219                select biogrid_id_interactor
220                from proteins
221                where organism_interactor=?""", (taxid,))
222       
223        return [t[0] for t in cur.fetchall()]
224
225    def synonyms(self, id):
226        """ Return a list of synonyms for primary `id`.
227       
228        """
229        cur = self.db.execute("""\
230            select entrez_gene_interactor,
231                   systematic_name_interactor,
232                   official_symbol_interactor,
233                   synonyms_interactor
234            from proteins
235            where biogrid_id_interactor=?
236            """, (id,))
237        rec = cur.fetchone()
238        if rec:
239            synonyms = list(rec[:-1]) + (rec[-1].split("|") if rec[-1] is not None else [])
240            return [s for s in synonyms if s is not None]
241        else:
242            return []
243   
244    def all_edges(self, taxid=None):
245        """ Return a list of all edges. If taxid is not None return the
246        edges for this organism only.
247       
248        """
249        if taxid is not None:
250            cur = self.db.execute("""\
251                select biogrid_id_interactor_a, biogrid_id_interactor_a, score
252                from links left join proteins on
253                    biogrid_id_interactor_a=biogrid_id_interactor or
254                    biogrid_id_interactor_b=biogrid_id_interactor
255                where organism_interactor=?
256            """, (taxid,))
257        else:
258            cur = self.db.execute("""\
259                select biogrid_id_interactor_a, biogrid_id_interactor_a, score
260                from links
261            """)
262        edges = cur.fetchall()
263        return edges
264           
265    def edges(self, id):
266        """ Return a list of all interactions where id is a participant
267        (a list of 3-tuples (id_a, id_b, score)).
268       
269        """
270       
271        cur = self.db.execute("""\
272            select biogrid_id_interactor_a, biogrid_id_interactor_b, score
273            from links
274            where biogrid_id_interactor_a=? or biogrid_id_interactor_b=?
275        """, (id, id))
276        return cur.fetchall() 
277       
278    def all_edges_annotated(self, taxid=None):
279        """ Return a list of all edges annotated. If taxid is not None
280        return the edges for this organism only.
281       
282        """
283        if taxid is not None:
284            cur = self.db.execute("""\
285                select *
286                from links left join proteins on
287                    biogrid_id_interactor_a=biogrid_id_interactor or
288                    biogrid_id_interactor_b=biogrid_id_interactor
289                where organism_interactor=?
290            """, (taxid,))
291        else:
292            cur = self.db.execute("""\
293                select *
294                from links
295            """)
296        edges = cur.fetchall()
297        return edges
298       
299       
300    def edges_annotated(self, id):
301        """ Return a list of all links
302        """
303        cur = self.db.execute("""\
304            select *
305            from links
306            where biogrid_id_interactor_a=? or biogrid_id_interactor_b=?
307        """, (id, id))
308        return cur.fetchall()
309   
310    def search_id(self, name, taxid=None):
311        """ Search the database for protein name. Return a list of matching
312        primary ids. Use `taxid` to limit the results to a single organism.
313         
314        """
315            # TODO: synonyms_interactor can contain multiple synonyms
316            # (should create an indexed table of synonyms)
317        if taxid is None:
318            cur = self.db.execute("""\
319                select biogrid_id_interactor
320                from proteins
321                where (biogrid_id_interactor=? or
322                       entrez_gene_interactor=? or
323                       systematic_name_interactor=? or
324                       official_symbol_interactor=? or
325                       synonyms_interactor=?)
326            """, ((name,) * 5))
327        else:
328            cur = self.db.execute("""\
329                select biogrid_id_interactor
330                from proteins
331                where (biogrid_id_interactor=? or
332                       entrez_gene_interactor=? or
333                       systematic_name_interactor=? or
334                       official_symbol_interactor=? or
335                       synonyms_interactor=?)
336                      and organism_interactor=?
337            """, ((name,) * 5) + (taxid,))
338        res = map(itemgetter(0), cur)
339        return res
340   
341    @classmethod
342    def download_data(cls, address):
343        """ Pass the address of the latest release (the tab2 format).
344        """
345        import urllib2, shutil, zipfile
346        from StringIO import StringIO
347        stream = urllib2.urlopen(address)
348        stream = StringIO(stream.read())
349        file = zipfile.ZipFile(stream)
350        filename = file.namelist()[0]
351        ppi_dir = orngServerFiles.localpath("PPI")
352        file.extract(filename, ppi_dir)
353        shutil.move(orngServerFiles.localpath("PPI", filename),
354                    orngServerFiles.localpath("PPI", "BIOGRID-ALL.tab2"))
355        filepath = orngServerFiles.localpath("PPI", "BIOGRID-ALL.tab2")
356        cls.init_db(filepath)
357        os.remove(filepath)
358       
359    @classmethod
360    def init_db(cls, filepath):
361        """ Initialize the sqlite data base from a BIOGRID-ALL.*tab2.txt file
362        format.
363       
364        """
365        dirname = os.path.dirname(filepath)
366        lineiter = iter(open(filepath, "rb"))
367        headers = lineiter.next() # read the first line
368       
369        con = sqlite3.connect(os.path.join(dirname, BioGRID.SERVER_FILE))
370        con.execute("drop table if exists links") # Drop old table
371        con.execute("drop table if exists proteins") # Drop old table
372       
373        con.execute("""\
374            create table links (
375                biogrid_interaction_id text,
376                biogrid_id_interactor_a text,
377                biogrid_id_interactor_b text,
378                experimental_system text,
379                experimental_system_type text,
380                author text,
381                pubmed_id text,
382                throughput text,
383                score real,
384                modification text,
385                phenotypes text,
386                qualifications text,
387                tags text,
388                source_database text
389            )""")
390       
391        con.execute("""\
392            create table proteins (
393                biogrid_id_interactor text,
394                entrez_gene_interactor text,
395                systematic_name_interactor text,
396                official_symbol_interactor text,
397                synonyms_interactor text,
398                organism_interactor text
399            )""")
400       
401        proteins = {}
402        nulls = lambda values: [val if val != "-" else None for val in values]
403        link_indices = [0, 3, 4, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23] # Values that go in the links table
404        interactor_a_indices = [3, 1, 5, 7, 9, 15] # Values that go in the proteins table
405        interactor_b_indices = [4, 2, 6, 8, 10, 16] # Values that go in the proteins table
406       
407        def processlinks(file):
408            for line in file:
409                if line != "\n":
410                    fields = nulls(line.strip().split("\t"))
411                    yield [fields[i] for i in link_indices]
412                    interactor_a = [fields[i] for i in interactor_a_indices]
413                    interactor_b = [fields[i] for i in interactor_b_indices]
414                    proteins[interactor_a[0]] = interactor_a
415                    proteins[interactor_b[0]] = interactor_b
416       
417        con.executemany("""\
418            insert into links values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
419            """, processlinks(lineiter))
420       
421        con.executemany("""\
422            insert into proteins values (?, ?, ?, ?, ?, ?)
423            """, proteins.itervalues())
424        con.commit()
425        con.close()
426       
427    def init_db_index(self):
428        """ Will create an indexes (if not already pressent) in the database
429        for faster searching by primary ids.
430       
431        """
432        self.db.execute("""\
433        create index if not exists index_on_biogrid_id_interactor_a
434           on links (biogrid_id_interactor_a)
435        """)
436        self.db.execute("""\
437        create index if not exists index_on_biogrid_id_interactor_b
438           on links (biogrid_id_interactor_b)
439        """)
440        self.db.execute("""\
441        create index if not exists index_on_biogrid_id_interactor
442           on proteins (biogrid_id_interactor)
443        """)
444       
445from collections import namedtuple
446from functools import partial
447
448def chainiter(iterable):
449    for sub_iter in iterable:
450        for obj in sub_iter:
451            yield obj
452
453def chunks(iter, chunk_size=1000):
454    chunk = []
455    i = 0
456    for obj in iter:
457        chunk.append(obj)
458        if len(chunk) == chunk_size:
459            yield chunk
460            chunk = []
461    if chunk:
462        # The remaining items if any
463        yield chunk
464   
465STRINGInteraction = namedtuple("STRINGInteraciton",
466        ["protein_id1", "protein_id2", "combined_score", "mode",
467         "action", "score"])
468
469class STRING(PPIDatabase):
470    """ Access `STRING <http://www.string-db.org/>`_ PPI database.
471    """
472   
473    DATABASE_SCHEMA = """\
474    Database schema
475    ---------------
476    table `links`:
477        - `protein_id1`: id (text)
478        - `protein_id2`: id (text)
479        - `score`: combined score (int)
480       
481    table `actions`:
482        - `protein_id1`: id (text)
483        - `protein_id2`: id (text)
484        - `mode`: mode (text)
485        - `action`: action type (text)
486        - `score`: action score (int)
487       
488    table `proteins`:
489        - `protein_id`: protein id in STRING (text) (in the form of {taxid}.{name})
490        - `taxid`: organism taxid (text)
491       
492    table `aliases`:
493        - `protein_id: id (text)
494        - `alias`: protein alias (text)
495        - `source`: protein alias source (text)
496       
497    """
498    DOMAIN = "PPI"
499    FILENAME = "string-protein.sqlite"
500    VERSION = "2.0"
501   
502    # Mapping from obiTaxonomy.common_taxids() to taxids in STRING.
503     
504    TAXID_MAP = {"352472": "44689", # Dictyostelium discoideum
505                 "562": None,
506                 "2104": "272634", # Mycoplasma pneumoniae M129
507                 "4530": "39947", # Oryza sativa Japonica Group
508                 "4754": None,
509                 "8355": None,
510                 "4577": None
511                 }
512   
513   
514    def __init__(self):
515        self.filename = orngServerFiles.localpath_download(self.DOMAIN, self.FILENAME)
516        self.db = sqlite3.connect(self.filename)
517       
518    @classmethod
519    def common_taxids(cls):
520        common = obiTaxonomy.common_taxids()
521        common = [cls.TAXID_MAP.get(id, id) for id in common]
522        return filter(None, common)
523   
524    def organisms(self):
525        """ Return all organism taxids contained in this database.
526        """
527        cur = self.db.execute("select distinct taxid from proteins")
528        return [r[0] for r in cur.fetchall()]
529   
530    def ids(self, taxid=None):
531        """ Return a list of all protein ids. If `taxid` is not None limit
532        the results to ids from this organism only.
533       
534        """
535        if taxid is not None:
536            cur = self.db.execute("""\
537                select protein_id
538                from proteins
539                where taxid=?
540                """, (taxid,))
541        else:
542            cur = self.db.execute("""\
543                select protein_id
544                from proteins
545                """)
546        return [r[0] for r in cur.fetchall()]
547   
548    def synonyms(self, id):
549        """ Return a list of synonyms for primary `id` as reported by STRING (proteins.aliases.{version}.txt file)
550        """
551        cur = self.db.execute("""\
552            select alias
553            from aliases
554            where protein_id=?
555            """, (id,))
556        res = cur.fetchall()
557        return [r[0] for r in res]
558   
559    def synonyms_with_source(self, id):
560        """ Return a list of synonyms for primary `id` along
561        with its source as reported by STRING
562        (proteins.aliases.{version}.txt file)
563       
564        """
565        cur = self.db.execute("""\
566            select alias, source
567            from aliases
568            where protein_id=?
569            """, (id,))
570        res = cur.fetchall()
571        return [(syn, set(source.split(" "))) \
572                for syn, source in res]
573   
574    def all_edges(self, taxid=None):
575        """ Return a list of all edges. If taxid is not None return the
576        edges for this organism only.
577       
578        .. note:: This may take some time (and memory).
579       
580        """
581        if taxid is not None:
582            cur = self.db.execute("""\
583                select links.protein_id1, links.protein_id2, score
584                from links join proteins on
585                    links.protein_id1=proteins.protein_id
586                where taxid=?
587                """, (taxid,))
588        else:
589            cur = self.db.execute("""\
590                select protein_id1, protein_id1, score
591                from links
592                """)
593        return cur.fetchall()
594       
595    def edges(self, id):
596        """ Return a list of all edges (a list of 3-tuples (id1, id2, score)).
597        """
598        cur = self.db.execute("""\
599            select protein_id1, protein_id2, score
600            from links
601            where protein_id1=?
602            """, (id,))
603        return cur.fetchall()
604   
605    def all_edges_annotated(self, taxid=None):
606        """ Return a list of all edges annotated. If taxid is not None
607        return the edges for this organism only.
608       
609        """
610        res = []
611        for id in self.ids(taxid):
612            res.extend(self.edges_annotated(id))
613        return res
614       
615    def edges_annotated(self, id):
616        """ Return a list of all edges annotated.
617        """
618        cur = self.db.execute("""\
619            select links.protein_id1, links.protein_id2, links.score,
620                   actions.action, actions.mode, actions.score
621            from links left join actions on
622                   links.protein_id1=actions.protein_id1 and
623                   links.protein_id2=actions.protein_id2
624            where links.protein_id1=?
625        """, (id,))
626        return map(partial(apply,STRINGInteraction), cur.fetchall())
627   
628    def search_id(self, name, taxid=None):
629        if taxid is None:
630            cur = self.db.execute("""\
631                select proteins.protein_id
632                from proteins natural join aliases
633                where aliases.alias=?
634            """, (name,))
635        else:
636            cur = self.db.execute("""\
637                select proteins.protein_id
638                from proteins natural join aliases
639                where aliases.alias=? and proteins.taxid=?
640            """, (name, taxid))
641        return map(itemgetter(0), cur)
642       
643    @classmethod
644    def download_data(cls, version, taxids=None):
645        """ Download the  PPI data for local work (this may take some time).
646        Pass the version of the  STRING release e.g. v8.3.
647        The resulting sqlite database will only contain the protein
648        interactions for `taxids` (if None obiTaxonomy.common_taxids() will
649        be used).
650       
651        """
652        dir = orngServerFiles.localpath("PPI")
653
654        base_url = "http://www.string-db.org/newstring_download/"
655        links = "protein.links.{version}.txt.gz".format(version=version)
656        actions = "protein.actions.{version}.txt.gz".format(version=version)
657        aliases = "protein.aliases.{version}.txt.gz".format(version=version)
658
659        def wgeti(f, dir, progress):
660            if not os.path.exists(os.path.join(dir, f)):
661                print "Downloading:", f
662                wget(base_url + f, dir, progress=progress)
663            else:
664                print "Already downloaded - skiping:", f
665
666        wgeti(links, dir, progress=True)
667        wgeti(actions, dir, progress=True)
668        wgeti(aliases, dir, progress=True)
669       
670        cls.init_db(version, taxids)
671       
672    @classmethod
673    def init_db(cls, version, taxids=None):
674        """ Initialize the sqlite3 data base. `version` must contain a
675        STRING release version e.g 'v8.3'. If `taxids` is not `None` it
676        must contain a list of tax-ids in the STRING database for which
677        to extract the interactions for.
678       
679        """
680        def counter():
681            i = 0
682            while True:
683                yield i
684                i += 1
685               
686        protein_ids = defaultdict(counter().next)
687        protein_taxid = {}
688
689        dir = orngServerFiles.localpath(cls.DOMAIN)
690       
691        links_filename = os.path.join(dir, "protein.links.{version}.txt.gz".format(version=version))
692        actions_filename = os.path.join(dir, "protein.actions.{version}.txt.gz".format(version=version))
693        aliases_filename = os.path.join(dir, "protein.aliases.{version}.txt.gz".format(version=version))
694       
695        links_file = gzip.GzipFile(links_filename, "rb")
696        actions_file = gzip.GzipFile(actions_filename, "rb")
697        aliases_file = gzip.GzipFile(aliases_filename, "rb")
698       
699        progress = ConsoleProgressBar("Processing links:")
700        progress(0.0)
701        filesize = os.stat(links_filename).st_size*10 #not the correct size!
702       
703        if taxids:
704            taxids = set(taxids)
705        else:
706            taxids = set(cls.common_taxids())
707                       
708        con = sqlite3.connect(orngServerFiles.localpath(cls.DOMAIN, cls.FILENAME))
709       
710        with con:
711            con.execute("drop table if exists links")
712            con.execute("drop table if exists proteins")
713            con.execute("drop table if exists actions")
714            con.execute("drop table if exists aliases")
715           
716            con.execute("create table links (protein_id1 text, protein_id2 text, score int)")
717            con.execute("create table proteins (protein_id text, taxid text)")
718            con.execute("create table actions (protein_id1 text, protein_id2 text, mode text, action text, score int)")
719            con.execute("create table aliases (protein_id text, alias text, source text)")
720           
721            header = links_file.readline() # read the header
722           
723            import csv
724            reader = csv.reader(links_file, delimiter=" ")
725           
726            def read_links(reader, chunk_size=1000000):
727                links = []
728                i = 0
729                split = str.split
730                for p1, p2, score in reader:
731                    if split(p1, ".", 1)[0] in taxids and split(p2, ".", 1)[0] in taxids:
732                        links.append((intern(p1), intern(p2), int(score)))
733                        if len(links) == chunk_size:
734                            yield links
735                            links = []
736                    i += 1
737                    if i % 1000 == 0: # Update the progress every 1000 lines
738                        progress(100.0 * links_file.tell() / filesize)
739                if links:
740                    yield links
741           
742            for chunk in read_links(reader):
743                con.executemany("insert into links values (?, ?, ?)", chunk)
744           
745            progress.finish()
746           
747            proteins = [res[0] for res in con.execute("select distinct protein_id1 from links")]
748            progress = ConsoleProgressBar("Processing proteins:")
749           
750            def protein_taxids(proteins):
751                protein_taxids = []
752                for i, prot in enumerate(proteins):
753                    taxid = prot.split(".", 1)[0]
754                    protein_taxids.append((prot, taxid))
755                    if i % 1000 == 0:
756                        progress(100.0 * i / len(proteins))
757                protein_taxids.sort()
758                return protein_taxids
759           
760            con.executemany("insert into proteins values (?, ?)", protein_taxids(proteins))
761           
762            progress.finish()
763           
764            filesize = os.stat(actions_filename).st_size*10
765           
766            actions_file.readline() # read header
767           
768            progress = ConsoleProgressBar("Processing actions:")
769            reader = csv.reader(actions_file, delimiter="\t")
770            def read_actions(reader):
771                actions = []
772                i = 0
773                split = str.split
774                for p1, p2, mode, action, a_is_acting, score in reader:
775                    if split(p1, ".", 1)[0] in taxids and split(p2, ".", 1)[0] in taxids:
776                        actions.append((intern(p1), intern(p2), mode, action, int(score)))
777                    i += 1
778                    if i % 1000 == 0:
779                        progress(100.0 * actions_file.tell() / filesize)
780                actions.sort()
781                return actions
782           
783            con.executemany("insert into actions values (?, ?, ?, ?, ?)", read_actions(reader))
784           
785            progress.finish()
786           
787            filesize = os.stat(aliases_filename).st_size*10
788            aliases_file.readline() # read header
789           
790            progress = ConsoleProgressBar("Processing aliases:")
791                           
792            reader = csv.reader(aliases_file, delimiter="\t")
793            def read_aliases(reader):
794                i = 0
795                for taxid, name, alias, source in reader:
796                    if taxid in taxids:
797                        yield (".".join([taxid, name]), 
798                               alias.decode("utf-8", errors="ignore"), 
799                               source.decode("utf-8", errors="ignore"),
800                               )
801                    i += 1
802                    if i % 1000 == 0:
803                        progress(100.0 * aliases_file.tell() / filesize)
804                       
805            con.executemany("insert into aliases values (?, ?, ?)", read_aliases(reader))
806           
807            progress.finish()
808
809            print "Indexing the database"
810           
811            con.execute("""\
812            create index if not exists index_link_protein_id1
813                on links (protein_id1)""")
814       
815            con.execute("""\
816                create index if not exists index_action_protein_id1
817                    on actions (protein_id1)""")
818           
819            con.execute("""\
820                create index if not exists index_proteins_id
821                    on proteins (protein_id)""")
822           
823            con.execute("""\
824                create index if not exists index_taxids
825                    on proteins (taxid)""")
826           
827            con.execute("""\
828                create index if not exists index_aliases_id
829                    on aliases (protein_id)""")
830           
831            con.execute("""\
832                create index if not exists index_aliases_alias
833                    on aliases (alias)""")
834           
835            con.executescript("""
836                DROP TABLE IF EXISTS version;
837               
838                CREATE TABLE version (
839                     string_version text,
840                     api_version text
841                );""")
842           
843            con.execute("""
844                INSERT INTO version
845                VALUES (?, ?)""", (version, cls.VERSION))
846           
847        progress.finish()
848       
849
850STRINGDetailedInteraction = namedtuple("STRINGDetailedInteraction",
851        ["protein_id1", "protein_id2", "combined_score", "mode",
852         "action", "score", "neighborhood", "fusion", "cooccurence", 
853         "coexpression", "experimental", "database", "textmining"
854         ])
855
856class STRINGDetailed(STRING):
857    """  Access `STRING <http://www.string-db.org/>`_ PPI database.
858    This class also allows access to subscores per channel.
859   
860    .. note:: This data is released under a
861        `Creative Commons Attribution-Noncommercial-Share Alike 3.0 License <http://creativecommons.org/licenses/by-nc-sa/3.0/>`_.
862        If you want to use this data for commercial purpuses
863        you must get a license from STRING.
864   
865    """
866   
867    DATABASE_SCHEMA = """\
868    DATABASE SCHEMA
869    ===============
870   
871    table `evidence`:
872        - `protein_id1`: protein id (text)
873        - `protein_id2`: protein id (text)
874        - `neighborhood`: score (int)
875        - `fusion`: score (int)
876        - `cooccurence`: score (int)
877        - `coexpression`: score (int)
878        - `experimental`: score (int)
879        - `database`: score (int)
880        - `textmining`: score (int)
881       
882    """
883    FILENAME_DETAILED = "string-protein-detailed.sqlite"
884   
885    def __init__(self):
886        STRING.__init__(self)
887        db_file = orngServerFiles.localpath(self.DOMAIN, self.FILENAME)
888        db_detailed_file = orngServerFiles.localpath_download(self.DOMAIN, self.FILENAME_DETAILED)
889        self.db_detailed = sqlite3.connect(db_detailed_file)
890        self.db_detailed.execute("ATTACH DATABASE ? as string", (db_file,))
891       
892    def edges_annotated(self, id):
893        """ Return a list of all edges annotated.
894        """
895        edges = STRING.edges_annotated(self, id)
896        edges_nc = []
897        for edge in edges:
898            id1, id2 = edge.protein_id1, edge.protein_id2
899            cur = self.db_detailed.execute("""\
900                SELECT neighborhood, fusion, cooccurence, coexpression,
901                       experimental, database, textmining
902                FROM evidence
903                WHERE protein_id1=? AND protein_id2=?
904                """, (id1, id2))
905            res = cur.fetchone()
906            if res:
907                evidence = res
908            else:
909                evidence = [0] * 7
910            edges_nc.append(
911                STRINGDetailedInteraction(*(tuple(edge) + tuple(evidence)))
912            )
913        return edges_nc
914       
915    @classmethod
916    def download_data(cls, version, taxids=None):
917        import gzip, shutil, csv
918       
919        baseurl = "http://www.string-db.org/newstring_download/"
920        links_filename = "protein.links.detailed.{version}.txt.gz".format(version=version)
921       
922        dir = orngServerFiles.localpath(cls.DOMAIN)
923        local_filename = os.path.join(dir, links_filename)
924         
925        if not os.path.exists(local_filename):
926            wget(baseurl + links_filename, dir, progress=True)
927        else:
928            print "Already downloaded - skiping"
929           
930        cls.init_db(version, taxids)
931           
932    @classmethod
933    def init_db(cls, version, taxids=None):
934        import csv
935        dir = orngServerFiles.localpath(cls.DOMAIN)
936       
937        links_filename = "protein.links.detailed.{version}.txt.gz".format(version=version)
938        links_filename = os.path.join(dir, links_filename)
939       
940        if taxids:
941            taxids = set(taxids)
942        else:
943            taxids = set(cls.common_taxids())
944       
945        links_file = gzip.GzipFile(links_filename, "rb")
946       
947        con = sqlite3.connect(os.path.join(dir, cls.FILENAME_DETAILED))
948        with con:
949            con.execute("""\
950                DROP TABLE IF EXISTS evidence
951            """)
952           
953            con.execute("""\
954                CREATE TABLE evidence(
955                     protein_id1 TEXT,
956                     protein_id2 TEXT,
957                     neighborhood INTEGER,
958                     fusion INTEGER,
959                     cooccurence INTEGER,
960                     coexpression INTEGER,
961                     experimental INTEGER,
962                     database INTEGER,
963                     textmining INTEGER
964                    )
965                """)
966           
967            links = csv.reader(links_file, delimiter=" ")
968            links.next() # Read header
969            filesize = os.stat(links_filename).st_size*10 #not the correct size
970           
971            progress = ConsoleProgressBar("Processing links file:")
972            progress(1.0)
973           
974            def read_links(reader, chunk_size=100000):
975                split = str.split
976                for links in chunks(reader, chunk_size):
977                    chunk = []
978                    for p1, p2, n, f, c, cx, ex, db, t, _ in links:
979                        if split(p1, ".", 1)[0] in taxids and split(p2, ".", 1)[0] in taxids:
980                            chunk.append((intern(p1), intern(p2), n, f, c, cx, ex, db, t))
981                       
982                    progress(100.0 * links_file.tell() / filesize)
983                    if chunk:
984                        yield chunk
985           
986            # The links are read in chunks for better performace
987            for chunk in read_links(links):
988                con.executemany("""
989                    INSERT INTO evidence
990                    VALUES  (?, ?, ?, ?, ?, ?, ?, ?, ?)
991                    """, chunk)
992       
993            progress.finish()
994           
995            print "Indexing"
996            con.execute("""\
997                CREATE INDEX IF NOT EXISTS index_evidence
998                    ON evidence (protein_id1, protein_id2)
999            """)
1000           
1001            con.executescript("""
1002                DROP TABLE IF EXISTS version;
1003               
1004                CREATE TABLE version (
1005                     string_version text,
1006                     api_version text
1007                );
1008                """)
1009           
1010            con.execute("""
1011                INSERT INTO version
1012                VALUES (?, ?)""", (version, cls.VERSION))
1013       
1014       
1015class Interaction(object):
1016    def __init__(self, protein1, protein2, ref1=None, ref2=None, conf1=None, conf2=None):
1017        self.protein1, self.protein2 = protein1, protein2
1018        self.ref1, self.ref2 = ref1, ref2
1019        self.conf1, self.conf2 = conf1, conf2
1020        self.org1, self.org2 = None, None
1021   
1022class MIPS(object):
1023    VERSION = 1
1024    def __init__(self):
1025        self.load()
1026       
1027    def load(self):
1028        self.protein_names = defaultdict(set)
1029        self.refs = {}
1030        self.confidance = {}
1031        def process(element):
1032            d = {}
1033            participants = element.getElementsByTagName("proteinParticipant")
1034            proteins = []
1035            for protein in participants:
1036                interactor = protein.getElementsByTagName("proteinInteractor")[0]
1037                names = []
1038                for name in interactor.getElementsByTagName("shortLabel") + \
1039                            interactor.getElementsByTagName("fullName"):
1040                    names.append((name.tagName, name.childNodes[0].data))
1041               
1042                refs = []
1043                for ref in interactor.getElementsByTagName("primaryRef"):
1044                    refs += [(ref.tagName, ref.attributes.items())]
1045                org = dict(interactor.getElementsByTagName("organism")[0].attributes.items()).get("ncbiTaxId")
1046                conf = protein.getElementsByTagName("confidence")[0].attributes.items()
1047                proteins.append((names, refs, conf, org))
1048            interaction = Interaction(proteins[0][0][1][1], proteins[1][0][1][1])
1049            interaction.ref1, interaction.ref2 = proteins[0][1], proteins[1][1]
1050            interaction.conf1, interaction.conf2 = proteins[0][2], proteins[1][2]
1051            interaction.org1, interaction.org2 = proteins[0][3], proteins[1][3]
1052           
1053            self.protein_names[interaction.protein1].add(proteins[0][0][0][1])
1054            self.protein_names[interaction.protein2].add(proteins[1][0][0][1])
1055           
1056            return interaction
1057           
1058        document = minidom.parse(orngServerFiles.localpath_download("PPI", "allppis.xml"))
1059        interactions = document.getElementsByTagName("interaction")
1060        self.interactions = [process(interaction) for interaction in interactions]
1061       
1062        self.protein_interactions = defaultdict(set)
1063       
1064        for inter in self.interactions:
1065            self.protein_names[inter.protein1] = dict(inter.ref1[0][1]).get("id")
1066            self.protein_names[inter.protein2] = dict(inter.ref2[0][1]).get("id")
1067            self.protein_interactions[inter.protein1].add(inter)
1068            self.protein_interactions[inter.protein2].add(inter) 
1069       
1070    def __iter__(self):
1071        return iter(self.interactions)
1072   
1073    @classmethod
1074    def download(cls):
1075        import urllib2, shutil
1076        src = urllib2.urlopen("http://mips.helmholtz-muenchen.de/proj/ppi/data/mppi.gz")
1077        dest = orngServerFiles.localpath("PPI", "mppi.gz")
1078        shutil.copyfileobj(src, open(dest, "wb"))
1079       
1080    @classmethod 
1081    @pickled_cache(None, [("PPI", "allppis.xml")], version=1)
1082    def _get_instance(cls):
1083        return MIPS()
1084   
1085    @classmethod
1086    def get_instance(cls):
1087        if not hasattr(cls, "_instance"):
1088            cls._instance= cls._get_instance()
1089        return cls._instance
1090   
1091def mips_interactions(protein = None):
1092    mips = MIPS.get_instance()
1093    if protein is None:
1094        return list(mips)
1095    else:
1096        return mips.protein_interactions.get(protein)
1097
1098def mips_proteins():
1099    return set(MIPS.get_instance().protein_names.keys())
1100
1101class BioGRIDInteraction(object):
1102    """ An object representing a BioGRID interaction. Each member of this object
1103    represents a data from a single column of BIOGRID-ALL.tab file.
1104    Attributes:
1105        - *interactor_a*    - BioGRID identifier
1106        - *interactor_b*    - BioGRID identifier
1107        - *official_symbol_a*    - An official symbol for *interactor_a*
1108        - *official_symbol_b*    - An official symbol for *interactor_b*
1109        - *aliases_for_a*    - Aliases separated by '|'
1110        - *aliases_for_b*    - Aliases separated by '|'
1111        - *experimental_system*     - Experimental system (see BioGRID documentation on www.thebiogrid.org for a list of valid entrys)
1112        - *source*    -
1113        - *organism_a_id*    - NCBI Taxonomy identifier for *interactor_a*'s organism
1114        - *organism_b_id*    - NCBI Taxonomy identifier for *interactor_b*'s organism
1115    """
1116    __slots__ = ["interactor_a", "interactor_b", "official_symbol_a","official_symbol_b", "aliases_for_a", "aliases_for_b", "experimental_system", "source", "pubmed_id", "organism_a_id", "organism_b_id"]
1117    def __init__(self, line):
1118        for attr, val in zip(self.__slots__, line.split("\t")):
1119            setattr(self, attr, val)
1120
1121class _BioGRID_Old(object):
1122    """ A BioGRID database interface
1123    Example::
1124        >>> ## finding all interactions for Homo sapiens sapiens
1125        >>> grid = BioGRID(case_insensitive=True)
1126        >>> proteins = proteins = biogrid.proteins() ## All proteins
1127        >>> proteins = [p for p in proteins if any(["9606" in [int.organism_a_id, int.organism_b_id] for int in grid.get(p)])]
1128    """
1129    VERSION = 1
1130    def __init__(self, case_insensitive=True):
1131#        warnings.warn("obiPPi._BioGRID_Old class is deprecated. Use obiPPI.BioGRID")
1132        self.case_insensitive = case_insensitive
1133        self._case = (lambda name: name.lower()) if self.case_insensitive else (lambda name: name)
1134        self.load()
1135       
1136    def load(self):
1137        text = open(orngServerFiles.localpath_download("PPI", "BIOGRID-ALL.tab"), "rb").read()
1138        text = text.split("SOURCE\tPUBMED_ID\tORGANISM_A_ID\tORGANISM_B_ID\n", 1)[-1]
1139        self.interactions = [BioGRIDInteraction(line) for line in text.splitlines() if line.strip()]
1140       
1141        self.protein_interactions = defaultdict(set)
1142        self.protein_names = {}
1143       
1144        case = self._case
1145
1146        def update(keys, value, collection):
1147            for k in keys:
1148                collection.setdefault(k, set()).add(value)
1149               
1150        for inter in self.interactions:
1151            update(map(case, [inter.official_symbol_a] + inter.aliases_for_a.split("|")), case(inter.interactor_a), self.protein_names)
1152            update(map(case, [inter.official_symbol_b] + inter.aliases_for_b.split("|")), case(inter.interactor_b), self.protein_names)
1153           
1154            self.protein_interactions[case(inter.interactor_a)].add(inter)
1155            self.protein_interactions[case(inter.interactor_b)].add(inter)
1156           
1157        self.protein_interactions = dict(self.protein_interactions)
1158
1159        if case("N/A") in self.protein_names:
1160            del self.protein_names[case("N/A")]
1161       
1162    def proteins(self):
1163        """ Return all protein names in BioGRID (from INTERACTOR_A, and INTERACTOR_B columns)
1164        """
1165        return self.protein_interactions.keys()
1166           
1167    def __iter__(self):
1168        """ Iterate over all BioGRIDInteraction objects
1169        """
1170        return iter(self.interactions)
1171   
1172    def __getitem__(self, key):
1173        """ Return a list of protein interactions that a protein is a part of
1174        """
1175        key = self._case(key)
1176#        keys = self.protein_alias_matcher.match(key)
1177        if key not in self.protein_interactions:
1178            keys = self.protein_names.get(key, [])
1179        else:
1180            keys = [key]
1181        if keys:
1182            return list(reduce(set.union, [self.protein_interactions.get(k, []) for k in keys], set()))
1183        else:
1184            raise KeyError(key)
1185   
1186    def get(self, key, default=None):
1187        """ Return a list of protein interactions that a protein is a part of
1188        """
1189        key = self._case(key)
1190#        keys = self.protein_alias_matcher.match(key)
1191        if key not in self.protein_interactions:
1192            keys = self.protein_names.get(keys, [])
1193        else:
1194            keys = [key] 
1195        if keys:
1196            return list(reduce(set.union, [self.protein_interactions.get(k, []) for k in keys], set()))
1197        else:
1198            return default
1199       
1200    @classmethod
1201    def get_instance(cls):
1202        if getattr(cls, "_instance", None) is None:
1203            cls._instance = _BioGRID_Old()
1204        return cls._instance
1205   
1206def biogrid_interactions(name=None):
1207    """Return a list of protein interactions (BioGRIDInteraction objects) that a protein is a part of
1208    """ 
1209    if name:
1210        return list(_BioGRID_Old.get_instance().get(name, set()))
1211    else:
1212        return _BioGRID_Old.get_instance().interactions
1213   
1214def biogrid_proteins():
1215    """ Return all protein names in BioGRID (from INTERACTOR_A, and INTERACTOR_B columns)
1216    """
1217    return _BioGRID_Old.get_instance().proteins()
1218
1219
1220if __name__ == "__main__":
1221    for protein in mips_proteins():
1222        print "Protein", protein, "interacts with", 
1223        print ",".join(set(reduce(list.__add__, [[inter.protein1, inter.protein2] for inter in mips_interactions(protein)], [])) -set([protein]))
1224           
Note: See TracBrowser for help on using the repository browser.