source: orange-bioinformatics/obiPPI.py @ 1517:eeebac5bf699

Revision 1517:eeebac5bf699, 45.1 KB checked in by ales_erjavec <ales.erjavec@…>, 2 years ago (diff)

Split the source string.

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