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

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

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

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
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        shutil.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-ALL.sqlite"))
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
448from .obiGeneMania import wget, copyfileobj
449
450def chainiter(iterable):
451    for sub_iter in iterable:
452        for obj in sub_iter:
453            yield obj
454
455def chunks(iter, chunk_size=1000):
456    chunk = []
457    i = 0
458    for obj in iter:
459        chunk.append(obj)
460        if len(chunk) == chunk_size:
461            yield chunk
462            chunk = []
463    if chunk:
464        # The remaining items if any
465        yield chunk
466   
467STRINGInteraction = namedtuple("STRINGInteraciton",
468        ["protein_id1", "protein_id2", "combined_score", "mode",
469         "action", "score"])
470
471class STRING(PPIDatabase):
472    """ Access `STRING <http://www.string-db.org/>`_ PPI database.
473    """
474   
475    DATABASE_SCHEMA = """\
476    Database schema
477    ---------------
478    table `links`:
479        - `protein_id1`: id (text)
480        - `protein_id2`: id (text)
481        - `score`: combined score (int)
482       
483    table `actions`:
484        - `protein_id1`: id (text)
485        - `protein_id2`: id (text)
486        - `mode`: mode (text)
487        - `action`: action type (text)
488        - `score`: action score (int)
489       
490    table `proteins`:
491        - `protein_id`: protein id in STRING (text) (in the form of {taxid}.{name})
492        - `taxid`: organism taxid (text)
493       
494    table `aliases`:
495        - `protein_id: id (text)
496        - `alias`: protein alias (text)
497        - `source`: protein alias source (text)
498       
499    """
500    DOMAIN = "PPI"
501    FILENAME = "string-protein.sqlite"
502    VERSION = "2.0"
503   
504    # Mapping from obiTaxonomy.common_taxids() to taxids in STRING.
505     
506    TAXID_MAP = {"352472": "44689", # Dictyostelium discoideum
507                 "562": None,
508                 "2104": "272634", # Mycoplasma pneumoniae M129
509                 "4530": "39947", # Oryza sativa Japonica Group
510                 "4754": None,
511                 "8355": None,
512                 "4577": None
513                 }
514   
515   
516    def __init__(self):
517        self.filename = orngServerFiles.localpath_download(self.DOMAIN, self.FILENAME)
518        self.db = sqlite3.connect(self.filename)
519       
520    @classmethod
521    def common_taxids(cls):
522        common = obiTaxonomy.common_taxids()
523        common = [cls.TAXID_MAP.get(id, id) for id in common]
524        return filter(None, common)
525   
526    def organisms(self):
527        """ Return all organism taxids contained in this database.
528        """
529        cur = self.db.execute("select distinct taxid from proteins")
530        return [r[0] for r in cur.fetchall()]
531   
532    def ids(self, taxid=None):
533        """ Return a list of all protein ids. If `taxid` is not None limit
534        the results to ids from this organism only.
535       
536        """
537        if taxid is not None:
538            cur = self.db.execute("""\
539                select protein_id
540                from proteins
541                where taxid=?
542                """, (taxid,))
543        else:
544            cur = self.db.execute("""\
545                select protein_id
546                from proteins
547                """)
548        return [r[0] for r in cur.fetchall()]
549   
550    def synonyms(self, id):
551        """ Return a list of synonyms for primary `id` as reported by STRING (proteins.aliases.{version}.txt file)
552        """
553        cur = self.db.execute("""\
554            select alias
555            from aliases
556            where protein_id=?
557            """, (id,))
558        res = cur.fetchall()
559        return [r[0] for r in res]
560   
561    def synonyms_with_source(self, id):
562        """ Return a list of synonyms for primary `id` along
563        with its source as reported by STRING
564        (proteins.aliases.{version}.txt file)
565       
566        """
567        cur = self.db.execute("""\
568            select alias, source
569            from aliases
570            where protein_id=?
571            """, (id,))
572        res = cur.fetchall()
573        return [(syn, set(source.split(" "))) \
574                for syn, source in res]
575   
576    def all_edges(self, taxid=None):
577        """ Return a list of all edges. If taxid is not None return the
578        edges for this organism only.
579       
580        .. note:: This may take some time (and memory).
581       
582        """
583        if taxid is not None:
584            cur = self.db.execute("""\
585                select links.protein_id1, links.protein_id2, score
586                from links join proteins on
587                    links.protein_id1=proteins.protein_id
588                where taxid=?
589                """, (taxid,))
590        else:
591            cur = self.db.execute("""\
592                select protein_id1, protein_id1, score
593                from links
594                """)
595        return cur.fetchall()
596       
597    def edges(self, id):
598        """ Return a list of all edges (a list of 3-tuples (id1, id2, score)).
599        """
600        cur = self.db.execute("""\
601            select protein_id1, protein_id2, score
602            from links
603            where protein_id1=?
604            """, (id,))
605        return cur.fetchall()
606   
607    def all_edges_annotated(self, taxid=None):
608        """ Return a list of all edges annotated. If taxid is not None
609        return the edges for this organism only.
610       
611        """
612        res = []
613        for id in self.ids(taxid):
614            res.extend(self.edges_annotated(id))
615        return res
616       
617    def edges_annotated(self, id):
618        """ Return a list of all edges annotated.
619        """
620        cur = self.db.execute("""\
621            select links.protein_id1, links.protein_id2, links.score,
622                   actions.action, actions.mode, actions.score
623            from links left join actions on
624                   links.protein_id1=actions.protein_id1 and
625                   links.protein_id2=actions.protein_id2
626            where links.protein_id1=?
627        """, (id,))
628        return map(partial(apply,STRINGInteraction), cur.fetchall())
629   
630    def search_id(self, name, taxid=None):
631        if taxid is None:
632            cur = self.db.execute("""\
633                select proteins.protein_id
634                from proteins natural join aliases
635                where aliases.alias=?
636            """, (name,))
637        else:
638            cur = self.db.execute("""\
639                select proteins.protein_id
640                from proteins natural join aliases
641                where aliases.alias=? and proteins.taxid=?
642            """, (name, taxid))
643        return map(itemgetter(0), cur)
644       
645    @classmethod
646    def download_data(cls, version, taxids=None):
647        """ Download the  PPI data for local work (this may take some time).
648        Pass the version of the  STRING release e.g. v8.3.
649        The resulting sqlite database will only contain the protein
650        interactions for `taxids` (if None obiTaxonomy.common_taxids() will
651        be used).
652       
653        """
654        dir = orngServerFiles.localpath("PPI")
655
656        base_url = "http://www.string-db.org/newstring_download/"
657        links = base_url + "protein.links.{version}.txt.gz"
658        actions = base_url + "protein.actions.{version}.txt.gz"
659        aliases = base_url + "protein.aliases.{version}.txt.gz"
660       
661        wget(links.format(version=version), dir, progress=True)
662        wget(actions.format(version=version), dir, progress=True)
663        wget(aliases.format(version=version), dir, progress=True)
664       
665        links_filename = os.path.join(dir, "protein.links.{version}.txt".format(version=version))
666        actions_filename = os.path.join(dir, "protein.actions.{version}.txt".format(version=version))
667        aliases_filename = os.path.join(dir, "protein.aliases.{version}.txt".format(version=version))
668       
669        progress = ConsoleProgressBar("Extracting files:")
670        progress(1.0)
671        links_file = gzip.GzipFile(links_filename + ".gz", "rb")
672        shutil.copyfileobj(links_file, open(links_filename, "wb"))
673       
674        progress(60.0)
675        actions_file = gzip.GzipFile(actions_filename + ".gz", "rb")
676        shutil.copyfileobj(actions_file, open(actions_filename, "wb"))
677       
678        progress(90.0)
679        aliases_file = gzip.GzipFile(aliases_filename + ".gz", "rb")
680        shutil.copyfileobj(aliases_file, open(aliases_filename, "wb"))
681        progress.finish()
682       
683        cls.init_db(version, taxids)
684       
685    @classmethod
686    def init_db(cls, version, taxids=None):
687        """ Initialize the sqlite3 data base. `version` must contain a
688        STRING release version e.g 'v8.3'. If `taxids` is not `None` it
689        must contain a list of tax-ids in the STRING database for which
690        to extract the interactions for.
691       
692        """
693        def counter():
694            i = 0
695            while True:
696                yield i
697                i += 1
698               
699        protein_ids = defaultdict(counter().next)
700        protein_taxid = {}
701
702        dir = orngServerFiles.localpath(cls.DOMAIN)
703       
704        links_filename = os.path.join(dir, "protein.links.{version}.txt".format(version=version))
705        actions_filename = os.path.join(dir, "protein.actions.{version}.txt".format(version=version))
706        aliases_filename = os.path.join(dir, "protein.aliases.{version}.txt".format(version=version))
707       
708        links_file = open(links_filename, "rb")
709        actions_file = open(actions_filename, "rb")
710        aliases_file = open(aliases_filename, "rb")
711       
712        progress = ConsoleProgressBar("Processing links:")
713        progress(0.0)
714        filesize = os.stat(links_filename).st_size
715       
716        if taxids:
717            taxids = set(taxids)
718        else:
719            taxids = set(cls.common_taxids())
720                       
721        con = sqlite3.connect(orngServerFiles.localpath(cls.DOMAIN, cls.FILENAME))
722       
723        with con:
724            con.execute("drop table if exists links")
725            con.execute("drop table if exists proteins")
726            con.execute("drop table if exists actions")
727            con.execute("drop table if exists aliases")
728           
729            con.execute("create table links (protein_id1 text, protein_id2 text, score int)")
730            con.execute("create table proteins (protein_id text, taxid text)")
731            con.execute("create table actions (protein_id1 text, protein_id2 text, mode text, action text, score int)")
732            con.execute("create table aliases (protein_id text, alias text, source text)")
733           
734            header = links_file.readline() # read the header
735           
736            import csv
737            reader = csv.reader(links_file, delimiter=" ")
738           
739            def read_links(reader, chunk_size=1000000):
740                links = []
741                i = 0
742                split = str.split
743                for p1, p2, score in reader:
744                    if split(p1, ".", 1)[0] in taxids and split(p2, ".", 1)[0] in taxids:
745                        links.append((intern(p1), intern(p2), int(score)))
746                        if len(links) == chunk_size:
747                            yield links
748                            links = []
749                    i += 1
750                    if i % 1000 == 0: # Update the progress every 1000 lines
751                        progress(100.0 * links_file.tell() / filesize)
752                if links:
753                    yield links
754           
755            for chunk in read_links(reader):
756                con.executemany("insert into links values (?, ?, ?)", chunk)
757           
758            progress.finish()
759           
760            proteins = [res[0] for res in con.execute("select distinct protein_id1 from links")]
761            progress = ConsoleProgressBar("Processing proteins:")
762           
763            def protein_taxids(proteins):
764                protein_taxids = []
765                for i, prot in enumerate(proteins):
766                    taxid = prot.split(".", 1)[0]
767                    protein_taxids.append((prot, taxid))
768                    if i % 1000 == 0:
769                        progress(100.0 * i / len(proteins))
770                protein_taxids.sort()
771                return protein_taxids
772           
773            con.executemany("insert into proteins values (?, ?)", protein_taxids(proteins))
774           
775            progress.finish()
776           
777            filesize = os.stat(actions_filename).st_size
778           
779            actions_file.readline() # read header
780           
781            progress = ConsoleProgressBar("Processing actions:")
782            reader = csv.reader(actions_file, delimiter="\t")
783            def read_actions(reader):
784                actions = []
785                i = 0
786                split = str.split
787                for p1, p2, mode, action, a_is_acting, score in reader:
788                    if split(p1, ".", 1)[0] in taxids and split(p2, ".", 1)[0] in taxids:
789                        actions.append((intern(p1), intern(p2), mode, action, int(score)))
790                    i += 1
791                    if i % 1000 == 0:
792                        progress(100.0 * actions_file.tell() / filesize)
793                actions.sort()
794                return actions
795           
796            con.executemany("insert into actions values (?, ?, ?, ?, ?)", read_actions(reader))
797           
798            progress.finish()
799           
800            filesize = os.stat(aliases_filename).st_size
801            aliases_file.readline() # read header
802           
803            progress = ConsoleProgressBar("Processing aliases:")
804                           
805            reader = csv.reader(aliases_file, delimiter="\t")
806            def read_aliases(reader):
807                i = 0
808                for taxid, name, alias, source in reader:
809                    if taxid in taxids:
810                        yield (".".join([taxid, name]), 
811                               alias.decode("utf-8", errors="ignore"), 
812                               source.decode("utf-8", errors="ignore"),
813                               )
814                    i += 1
815                    if i % 1000 == 0:
816                        progress(100.0 * aliases_file.tell() / filesize)
817                       
818            con.executemany("insert into aliases values (?, ?, ?)", read_aliases(reader))
819           
820            progress.finish()
821
822            print "Indexing the database"
823           
824            con.execute("""\
825            create index if not exists index_link_protein_id1
826                on links (protein_id1)""")
827       
828            con.execute("""\
829                create index if not exists index_action_protein_id1
830                    on actions (protein_id1)""")
831           
832            con.execute("""\
833                create index if not exists index_proteins_id
834                    on proteins (protein_id)""")
835           
836            con.execute("""\
837                create index if not exists index_taxids
838                    on proteins (taxid)""")
839           
840            con.execute("""\
841                create index if not exists index_aliases_id
842                    on aliases (protein_id)""")
843           
844            con.execute("""\
845                create index if not exists index_aliases_alias
846                    on aliases (alias)""")
847           
848            con.executescript("""
849                DROP TABLE IF EXISTS version;
850               
851                CREATE TABLE version (
852                     string_version text,
853                     api_version text
854                );""")
855           
856            con.execute("""
857                INSERT INTO version
858                VALUES (?, ?)""", (version, cls.VERSION))
859           
860        progress.finish()
861       
862
863STRINGDetailedInteraction = namedtuple("STRINGDetailedInteraction",
864        ["protein_id1", "protein_id2", "combined_score", "mode",
865         "action", "score", "neighborhood", "fusion", "cooccurence", 
866         "coexpression", "experimental", "database", "textmining"
867         ])
868
869class STRINGDetailed(STRING):
870    """  Access `STRING <http://www.string-db.org/>`_ PPI database.
871    This class also allows access to subscores per channel.
872   
873    .. note:: This data is released under a
874        `Creative Commons Attribution-Noncommercial-Share Alike 3.0 License <http://creativecommons.org/licenses/by-nc-sa/3.0/>`_.
875        If you want to use this data for commercial purpuses
876        you must get a license from STRING.
877   
878    """
879   
880    DATABASE_SCHEMA = """\
881    DATABASE SCHEMA
882    ===============
883   
884    table `evidence`:
885        - `protein_id1`: protein id (text)
886        - `protein_id2`: protein id (text)
887        - `neighborhood`: score (int)
888        - `fusion`: score (int)
889        - `cooccurence`: score (int)
890        - `coexpression`: score (int)
891        - `experimental`: score (int)
892        - `database`: score (int)
893        - `textmining`: score (int)
894       
895    """
896    FILENAME_DETAILED = "string-protein-detailed.sqlite"
897   
898    def __init__(self):
899        STRING.__init__(self)
900        db_file = orngServerFiles.localpath(self.DOMAIN, self.FILENAME)
901        db_detailed_file = orngServerFiles.localpath_download(self.DOMAIN, self.FILENAME_DETAILED)
902        self.db_detailed = sqlite3.connect(db_detailed_file)
903        self.db_detailed.execute("ATTACH DATABASE ? as string", (db_file,))
904       
905    def edges_annotated(self, id):
906        """ Return a list of all edges annotated.
907        """
908        edges = STRING.edges_annotated(self, id)
909        edges_nc = []
910        for edge in edges:
911            id1, id2 = edge.protein_id1, edge.protein_id2
912            cur = self.db_detailed.execute("""\
913                SELECT neighborhood, fusion, cooccurence, coexpression,
914                       experimental, database, textmining
915                FROM evidence
916                WHERE protein_id1=? AND protein_id2=?
917                """, (id1, id2))
918            res = cur.fetchone()
919            if res:
920                evidence = res
921            else:
922                evidence = [0] * 7
923            edges_nc.append(
924                STRINGDetailedInteraction(*(tuple(edge) + tuple(evidence)))
925            )
926        return edges_nc
927       
928    @classmethod
929    def download_data(cls, version, taxids=None):
930        import gzip, shutil, csv
931       
932        baseurl = "http://www.string-db.org/newstring_download/"
933        links_filename = "protein.links.detailed.{version}.txt.gz".format(version=version)
934       
935        dir = orngServerFiles.localpath(cls.DOMAIN)
936        local_filename = os.path.join(dir, links_filename)
937         
938        if not os.path.exists(local_filename):
939            wget(baseurl + links_filename, dir, progress=True)
940        else:
941            print "Already downloaded - skiping"
942           
943        gz = gzip.open(os.path.join(dir, links_filename), "rb")
944
945        # Strip .gz extension
946        links_filename = os.path.join(dir, os.path.splitext(links_filename)[0])
947        if not os.path.exists(links_filename):
948            shutil.copyfileobj(gz, open(links_filename))
949       
950        cls.init_db(version, taxids)
951           
952    @classmethod
953    def init_db(cls, version, taxids=None):
954        import csv
955        dir = orngServerFiles.localpath(cls.DOMAIN)
956       
957        links_filename = "protein.links.detailed.{version}.txt".format(version=version)
958        links_filename = os.path.join(dir, links_filename)
959       
960        if taxids:
961            taxids = set(taxids)
962        else:
963            taxids = set(cls.common_taxids())
964       
965        links_file = open(links_filename, "rb")
966       
967        con = sqlite3.connect(os.path.join(dir, cls.FILENAME_DETAILED))
968        with con:
969            con.execute("""\
970                DROP TABLE IF EXISTS evidence
971            """)
972           
973            con.execute("""\
974                CREATE TABLE evidence(
975                     protein_id1 TEXT,
976                     protein_id2 TEXT,
977                     neighborhood INTEGER,
978                     fusion INTEGER,
979                     cooccurence INTEGER,
980                     coexpression INTEGER,
981                     experimental INTEGER,
982                     database INTEGER,
983                     textmining INTEGER
984                    )
985                """)
986           
987            links = csv.reader(links_file, delimiter=" ")
988            links.next() # Read header
989            filesize = os.stat(links_filename).st_size
990           
991            progress = ConsoleProgressBar("Processing links file:")
992            progress(1.0)
993           
994            def read_links(reader, chunk_size=100000):
995                split = str.split
996                for links in chunks(reader, chunk_size):
997                    chunk = []
998                    for p1, p2, n, f, c, cx, ex, db, t, _ in links:
999                        if split(p1, ".", 1)[0] in taxids and split(p2, ".", 1)[0] in taxids:
1000                            chunk.append((intern(p1), intern(p2), n, f, c, cx, ex, db, t))
1001                       
1002                    progress(100.0 * links_file.tell() / filesize)
1003                    if chunk:
1004                        yield chunk
1005           
1006            # The links are read in chunks for better performace
1007            for chunk in read_links(links):
1008                con.executemany("""
1009                    INSERT INTO evidence
1010                    VALUES  (?, ?, ?, ?, ?, ?, ?, ?, ?)
1011                    """, chunk)
1012       
1013            progress.finish()
1014           
1015            print "Indexing"
1016            con.execute("""\
1017                CREATE INDEX IF NOT EXISTS index_evidence
1018                    ON evidence (protein_id1, protein_id2)
1019            """)
1020           
1021            con.executescript("""
1022                DROP TABLE IF EXISTS version;
1023               
1024                CREATE TABLE version (
1025                     string_version text,
1026                     api_version text
1027                );
1028                """)
1029           
1030            con.execute("""
1031                INSERT INTO version
1032                VALUES (?, ?)""", (version, cls.VERSION))
1033       
1034       
1035class Interaction(object):
1036    def __init__(self, protein1, protein2, ref1=None, ref2=None, conf1=None, conf2=None):
1037        self.protein1, self.protein2 = protein1, protein2
1038        self.ref1, self.ref2 = ref1, ref2
1039        self.conf1, self.conf2 = conf1, conf2
1040        self.org1, self.org2 = None, None
1041   
1042class MIPS(object):
1043    VERSION = 1
1044    def __init__(self):
1045        self.load()
1046       
1047    def load(self):
1048        self.protein_names = defaultdict(set)
1049        self.refs = {}
1050        self.confidance = {}
1051        def process(element):
1052            d = {}
1053            participants = element.getElementsByTagName("proteinParticipant")
1054            proteins = []
1055            for protein in participants:
1056                interactor = protein.getElementsByTagName("proteinInteractor")[0]
1057                names = []
1058                for name in interactor.getElementsByTagName("shortLabel") + \
1059                            interactor.getElementsByTagName("fullName"):
1060                    names.append((name.tagName, name.childNodes[0].data))
1061               
1062                refs = []
1063                for ref in interactor.getElementsByTagName("primaryRef"):
1064                    refs += [(ref.tagName, ref.attributes.items())]
1065                org = dict(interactor.getElementsByTagName("organism")[0].attributes.items()).get("ncbiTaxId")
1066                conf = protein.getElementsByTagName("confidence")[0].attributes.items()
1067                proteins.append((names, refs, conf, org))
1068            interaction = Interaction(proteins[0][0][1][1], proteins[1][0][1][1])
1069            interaction.ref1, interaction.ref2 = proteins[0][1], proteins[1][1]
1070            interaction.conf1, interaction.conf2 = proteins[0][2], proteins[1][2]
1071            interaction.org1, interaction.org2 = proteins[0][3], proteins[1][3]
1072           
1073            self.protein_names[interaction.protein1].add(proteins[0][0][0][1])
1074            self.protein_names[interaction.protein2].add(proteins[1][0][0][1])
1075           
1076            return interaction
1077           
1078        document = minidom.parse(orngServerFiles.localpath_download("PPI", "allppis.xml"))
1079        interactions = document.getElementsByTagName("interaction")
1080        self.interactions = [process(interaction) for interaction in interactions]
1081       
1082        self.protein_interactions = defaultdict(set)
1083       
1084        for inter in self.interactions:
1085            self.protein_names[inter.protein1] = dict(inter.ref1[0][1]).get("id")
1086            self.protein_names[inter.protein2] = dict(inter.ref2[0][1]).get("id")
1087            self.protein_interactions[inter.protein1].add(inter)
1088            self.protein_interactions[inter.protein2].add(inter) 
1089       
1090    def __iter__(self):
1091        return iter(self.interactions)
1092   
1093    @classmethod
1094    def download(cls):
1095        import urllib2, shutil
1096        src = urllib2.urlopen("http://mips.helmholtz-muenchen.de/proj/ppi/data/mppi.gz")
1097        dest = orngServerFiles.localpath("PPI", "mppi.gz")
1098        shutil.copyfileobj(src, open(dest, "wb"))
1099       
1100    @classmethod 
1101    @pickled_cache(None, [("PPI", "allppis.xml")], version=1)
1102    def _get_instance(cls):
1103        return MIPS()
1104   
1105    @classmethod
1106    def get_instance(cls):
1107        if not hasattr(cls, "_instance"):
1108            cls._instance= cls._get_instance()
1109        return cls._instance
1110   
1111def mips_interactions(protein = None):
1112    mips = MIPS.get_instance()
1113    if protein is None:
1114        return list(mips)
1115    else:
1116        return mips.protein_interactions.get(protein)
1117
1118def mips_proteins():
1119    return set(MIPS.get_instance().protein_names.keys())
1120
1121class BioGRIDInteraction(object):
1122    """ An object representing a BioGRID interaction. Each member of this object
1123    represents a data from a single column of BIOGRID-ALL.tab file.
1124    Attributes:
1125        - *interactor_a*    - BioGRID identifier
1126        - *interactor_b*    - BioGRID identifier
1127        - *official_symbol_a*    - An official symbol for *interactor_a*
1128        - *official_symbol_b*    - An official symbol for *interactor_b*
1129        - *aliases_for_a*    - Aliases separated by '|'
1130        - *aliases_for_b*    - Aliases separated by '|'
1131        - *experimental_system*     - Experimental system (see BioGRID documentation on www.thebiogrid.org for a list of valid entrys)
1132        - *source*    -
1133        - *organism_a_id*    - NCBI Taxonomy identifier for *interactor_a*'s organism
1134        - *organism_b_id*    - NCBI Taxonomy identifier for *interactor_b*'s organism
1135    """
1136    __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"]
1137    def __init__(self, line):
1138        for attr, val in zip(self.__slots__, line.split("\t")):
1139            setattr(self, attr, val)
1140
1141class _BioGRID_Old(object):
1142    """ A BioGRID database interface
1143    Example::
1144        >>> ## finding all interactions for Homo sapiens sapiens
1145        >>> grid = BioGRID(case_insensitive=True)
1146        >>> proteins = proteins = biogrid.proteins() ## All proteins
1147        >>> proteins = [p for p in proteins if any(["9606" in [int.organism_a_id, int.organism_b_id] for int in grid.get(p)])]
1148    """
1149    VERSION = 1
1150    def __init__(self, case_insensitive=True):
1151#        warnings.warn("obiPPi._BioGRID_Old class is deprecated. Use obiPPI.BioGRID")
1152        self.case_insensitive = case_insensitive
1153        self._case = (lambda name: name.lower()) if self.case_insensitive else (lambda name: name)
1154        self.load()
1155       
1156    def load(self):
1157        text = open(orngServerFiles.localpath_download("PPI", "BIOGRID-ALL.tab"), "rb").read()
1158        text = text.split("SOURCE\tPUBMED_ID\tORGANISM_A_ID\tORGANISM_B_ID\n", 1)[-1]
1159        self.interactions = [BioGRIDInteraction(line) for line in text.splitlines() if line.strip()]
1160       
1161        self.protein_interactions = defaultdict(set)
1162        self.protein_names = {}
1163       
1164        case = self._case
1165
1166        def update(keys, value, collection):
1167            for k in keys:
1168                collection.setdefault(k, set()).add(value)
1169               
1170        for inter in self.interactions:
1171            update(map(case, [inter.official_symbol_a] + inter.aliases_for_a.split("|")), case(inter.interactor_a), self.protein_names)
1172            update(map(case, [inter.official_symbol_b] + inter.aliases_for_b.split("|")), case(inter.interactor_b), self.protein_names)
1173           
1174            self.protein_interactions[case(inter.interactor_a)].add(inter)
1175            self.protein_interactions[case(inter.interactor_b)].add(inter)
1176           
1177        self.protein_interactions = dict(self.protein_interactions)
1178
1179        if case("N/A") in self.protein_names:
1180            del self.protein_names[case("N/A")]
1181       
1182    def proteins(self):
1183        """ Return all protein names in BioGRID (from INTERACTOR_A, and INTERACTOR_B columns)
1184        """
1185        return self.protein_interactions.keys()
1186           
1187    def __iter__(self):
1188        """ Iterate over all BioGRIDInteraction objects
1189        """
1190        return iter(self.interactions)
1191   
1192    def __getitem__(self, key):
1193        """ Return a list of protein interactions that a protein is a part of
1194        """
1195        key = self._case(key)
1196#        keys = self.protein_alias_matcher.match(key)
1197        if key not in self.protein_interactions:
1198            keys = self.protein_names.get(key, [])
1199        else:
1200            keys = [key]
1201        if keys:
1202            return list(reduce(set.union, [self.protein_interactions.get(k, []) for k in keys], set()))
1203        else:
1204            raise KeyError(key)
1205   
1206    def get(self, key, default=None):
1207        """ Return a list of protein interactions that a protein is a part of
1208        """
1209        key = self._case(key)
1210#        keys = self.protein_alias_matcher.match(key)
1211        if key not in self.protein_interactions:
1212            keys = self.protein_names.get(keys, [])
1213        else:
1214            keys = [key] 
1215        if keys:
1216            return list(reduce(set.union, [self.protein_interactions.get(k, []) for k in keys], set()))
1217        else:
1218            return default
1219       
1220    @classmethod
1221    def get_instance(cls):
1222        if getattr(cls, "_instance", None) is None:
1223            cls._instance = _BioGRID_Old()
1224        return cls._instance
1225   
1226def biogrid_interactions(name=None):
1227    """Return a list of protein interactions (BioGRIDInteraction objects) that a protein is a part of
1228    """ 
1229    if name:
1230        return list(_BioGRID_Old.get_instance().get(name, set()))
1231    else:
1232        return _BioGRID_Old.get_instance().interactions
1233   
1234def biogrid_proteins():
1235    """ Return all protein names in BioGRID (from INTERACTOR_A, and INTERACTOR_B columns)
1236    """
1237    return _BioGRID_Old.get_instance().proteins()
1238
1239
1240if __name__ == "__main__":
1241    for protein in mips_proteins():
1242        print "Protein", protein, "interacts with", 
1243        print ",".join(set(reduce(list.__add__, [[inter.protein1, inter.protein2] for inter in mips_interactions(protein)], [])) -set([protein]))
1244           
Note: See TracBrowser for help on using the repository browser.