source: orange-bioinformatics/Orange/bioinformatics/obiPPI.py @ 1625:cefeb35cbfc9

Revision 1625:cefeb35cbfc9, 45.2 KB checked in by mitar, 2 years ago (diff)

Moving files around.

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