source: orange-bioinformatics/_bioinformatics/obiPPI.py @ 1720:354d91b1af9f

Revision 1720:354d91b1af9f, 45.1 KB checked in by markotoplak, 20 months ago (diff)

Fixed update scripts for STRING and Taxonomy.

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