source: orange-bioinformatics/obiGeneMania.py @ 1523:8d72a620e865

Revision 1523:8d72a620e865, 32.1 KB checked in by ales_erjavec <ales.erjavec@…>, 2 years ago (diff)

Moved obiPPI import down the module due to a cyclic import dependency.

Line 
1""" Interface to retrieve gene networks from GeneMANIA server
2
3Example::
4   
5    >>> conn = Connection("http://localhost:8080/genemania")
6    >>> net = conn.retrieve(org="3702", ["PHYB", "ELF3", 'COP1", "SPA1", "FUS9"])
7    >>> net.save("graph.net")
8    >>> net.retrieve(org="3702", genes=["CIP1"], m="bp", r=100).save("CIP1.net")
9
10   
11
12"""
13
14import urllib2
15import urllib
16import re
17import posixpath
18from xml.dom import minidom
19
20import orange
21import orngNetwork
22
23DEFAULT_SERVER = "http://193.2.72.57:8080/genemania"
24
25_TAX_ID_2_INDEX = {"3702": 1,
26                   "6239": 2,
27                   "7227": 3,
28                   "9606": 4,
29                   "10090": 5,
30                   "4932": 6
31                   }
32class Connection(object):
33    _RE_TOKEN = re.compile(r'<li\s+id\s*=\s*"menu_save"\s*token\s*=\s*"([0-9]+)"><label>Save</label>')
34    _RE_NETWORK_TAB = re.compile(r'^<div\s*id\s*=\s*"networks_tab"\s*class\s*=\s*"tab">*?^</div>', re.MULTILINE)
35    _RE_NETWORK_GROUP_NAMES = re.compile(r'<div\s*class\s*=\s*"network_name"\s*id\s*=\s*"networkGroupName([0-9]+)"\s*>\s*([a-zA-Z0-9_\- ]+)\s*</div>')
36    _RE_NETWORK_NAMES = re.compile(r'<div\s*class\s*=\s*"network_name"\s*id\s*=\s*"networkName([0-9]+)"\s*>\s*([a-zA-Z0-9_\- ]+)\s*</div>')
37
38    def __init__(self, address=DEFAULT_SERVER):
39        """ Construct a Connection instance for GeneMANIA server at `address`
40       
41        :param address: URL address of GeneMANIA server
42        :type address: str
43        """
44        self.address = address
45                 
46       
47    def retrieveXML(self, org="9606", genes=[], m="automatic", r=10, token=None):
48        """ Same as `retrieve` but return the network as an xml string
49        """
50        if token is None:
51            page = self.retrieveHtmlPage(org, genes, m, r)
52#            query = self._queryPage(org, genes, m, r)
53#            stream = urllib2.urlopen(query)
54#            page = stream.read()
55            match = self._RE_TOKEN.findall(page)
56       
57            if match:
58                token = match[0]
59            else:
60                raise ValueError("Invalid query. %s" % self._queryPage(org, genes, m, r))
61       
62        query = self._queryGraph(token)
63        stream = urllib2.urlopen(query)
64        graph = stream.read()
65        self._graph = graph
66        return graph
67   
68    def retrieveHtmlPage(self, org="9606", genes=[], m="automatic", r=10):
69        """ Retrieve the HTML page (contains token to retrieve the graph, network descriptions ...)"
70        """
71        query = self._queryPage(org, genes, m, r)
72        stream = urllib2.urlopen(query)
73        page = stream.read()
74        self._page = page
75        return page
76   
77    def validate(self, org, genes):
78        """ Validate gene names for organism. Return a two
79        tuple, one with known and one with unknown genes
80        """
81       
82        organism = _TAX_ID_2_INDEX.get(org, 1)
83        genes = "; ".join(genes)
84        data = urllib.urlencode([("organism", str(organism)), ("genes", genes)])
85        validatorUrl = posixpath.join(self.address, "validator")
86        stream = urllib2.urlopen(validatorUrl, data)
87        response = stream.read()
88        dom = minidom.parseString(response)
89        return parseValidationResponse(dom)
90       
91       
92       
93    def _queryPage(self, org, genes, m, r):
94        return posixpath.join(self.address, "link?o=%s&g=%s&m=%s&r=%i" % (org, "|".join(genes), m, r)) 
95   
96   
97    def _queryGraph(self, token):
98        return posixpath.join(self.address, "pages/graph.xhtml?token=%s" % token)
99   
100   
101    def retrieve(self, org, genes, m="automatic", r=10):
102        """ Retrieve orngNetwork.Network instance representing the network for
103        the query, (See
104        `http://193.2.72.57:8080/genemania/pages/help.jsf#section/link`_ for
105        more details)
106       
107        :param org: NCBI taxonomy identifier (A. thaliana=3702, C. elegans=6239,
108                    D. melanogaster=7227, H. sapiens=9606, M. musculus=10090
109                    S. cerevisiae=4932)
110        :type org: str
111       
112        :param genes: query genes
113        :type genes: list
114       
115        :param m: network combining method; must be one of the following:
116                    * "automatic_relevance": Assigned based on query genes
117                    * "automatic": Automatically selected weighting method
118                       (Default)
119                    * "bp": biological process based
120                    * "mf": molecular function based
121                    * "cc": cellular component based
122                    * "average": equal by data type
123                    * "average_category: equal by network
124        :type m: str
125       
126        :param r: the number of results generated by GeneMANIA (must be in
127                  range 1..100
128        :type r: int
129        """
130        xml = self.retrieveXML(org, genes, m, r)
131        dom = minidom.parseString(xml)
132        graph = parse(dom)
133        return graph
134   
135       
136   
137def parse(DOM):
138    """ Parse the graph DOM as returned from geneMANIA server and return
139    an orngNetwork.Network instance
140    """
141    nodes = DOM.getElementsByTagName("node")
142    edges = DOM.getElementsByTagName("edge")
143    from collections import defaultdict
144    graphNodes = {}
145    graphEdges = defaultdict(list)
146   
147    def parseAttributes(element):
148        return dict([(key, value) for key, value in element.attributes.items()])
149   
150    def parseText(element):
151        text = u""
152        for el in element.childNodes:
153            if isinstance(el, minidom.Text):
154                text += el.wholeText
155        return text
156               
157    def parseData(node):
158        data = node.getElementsByTagName("data")
159        parsed = {}
160        for el in data:
161            attrs = parseAttributes(el)
162            key = attrs["key"]
163            parsed[key] = parseText(el)
164        return parsed
165   
166    for node in nodes:
167        attrs = parseAttributes(node)
168        id = attrs["id"]
169        data = parseData(node)
170        graphNodes[id] = data
171   
172    for edge in edges:
173        attrs = parseAttributes(edge)
174        source, target = attrs["source"], attrs["target"]
175        data = parseData(edge)
176        graphEdges[source, target].append(data)
177       
178    allData = reduce(list.__add__, graphEdges.values(), [])
179    edgeTypes = set([int(data["networkGroupId"]) for data in allData])
180    groupId2int = dict(zip(edgeTypes, range(len(edgeTypes))))
181    groupId2groupCode = dict([(int(data["networkGroupId"]), str(data["networkGroupCode"])) for data in allData])
182   
183    graph = orngNetwork.Network(len(graphNodes), False, len(edgeTypes))
184    graph.objects = graphNodes.keys()
185   
186    edgeWeights = []
187    for (source, target), edge_data in graphEdges.items():
188        edgesDefined = [None] * len(edgeTypes)
189        for data in edge_data:
190            edgeType = int(data["networkGroupId"])
191            edgeInd = groupId2int[edgeType]
192            edgesDefined[edgeInd] = float(data["weight"])
193           
194        edgesDefined = [0 if w is None else w for w in edgesDefined]
195        graph[source, target] = edgesDefined
196        edgeWeights.append(edgesDefined)
197       
198       
199    nodedomain = orange.Domain([orange.StringVariable("label"),
200                                orange.StringVariable("id"),
201                                orange.FloatVariable("score"),
202                                orange.StringVariable("symbol"),
203                                orange.StringVariable("go"),
204                                orange.EnumVariable("source", values=["true", "false"])], None)
205   
206    edgedomain = orange.Domain([orange.FloatVariable("u"),
207                                orange.FloatVariable("v")] +\
208                               [orange.FloatVariable("weight_%s" % groupId2groupCode[id]) for id in edgeTypes],
209                               None)
210   
211    label_id = lambda id: graph.objects.index(id) + 1
212    nodeitems = orange.ExampleTable(nodedomain,
213                  [[str(node["symbol"]), str(id), float(node["score"]),
214                    str(node["symbol"]), str(node["go"]), str(node["source"])]\
215                     for id, node in graphNodes.items()])
216    edgeitems = orange.ExampleTable(edgedomain,
217                  [[str(label_id(source)), str(label_id(target))] + weights \
218                      for ((source, target), _), weights in zip(graphEdges.items(), edgeWeights)])
219   
220    graph.items = nodeitems
221    graph.links = edgeitems
222    graph.optimization = None
223    return graph
224
225def parseValidationResponse(dom):
226    def getData(node):
227        data = []
228        for c in node.childNodes:
229            if c.nodeType == node.TEXT_NODE:
230                data.append(c.data)
231               
232        return " ".join([d.strip() for d in data])
233       
234    def getStrings(node):
235        strings = []
236        for string in node.getElementsByTagName("string"):
237            strings.append(getData(string))
238        return strings
239    errorCode = dom.getElementsByTagName("errorCode")[0]
240    errorCode = getData(errorCode)
241    invalidSymbols = getStrings(dom.getElementsByTagName("invalidSymbols")[0])
242    geneIds = getStrings(dom.getElementsByTagName("geneIds")[0])
243   
244    return errorCode, invalidSymbols, geneIds
245   
246
247from HTMLParser import HTMLParser
248
249class NetworkGroup(object):
250    """ Network group descriptor
251    """
252    def __init__(self):
253        self.weight = ""
254        self.networks = []
255        self.name = ""
256        self.id = ""
257
258
259class Network(object):
260    """ Source network descriptor
261    """
262   
263    def __init__(self):
264        self.weight = ""
265        self.name = ""
266        self.id = ""
267        self.description = ""
268       
269       
270class _NetworkTabParser(HTMLParser):
271    """ Parses the "Network" tab from the GeneMANIA HTML pages
272    """
273    _RE_GROUP_ID = re.compile(r"networkGroup(\d+)")
274    _RE_GROUP_WEIGHT_ID = re.compile(r"networkGroupWeight(\d+)")
275    _RE_GROUP_NAME_ID = re.compile(r"networkGroupName(\d+)")
276   
277    _RE_NETWORK_ID = re.compile(r"network(\d+)")
278    _RE_NETWORK_WEIGHT_ID = re.compile(r"networkWeight(\d+)")
279    _RE_NETWORK_NAME_ID = re.compile(r"networkName(\d+)")
280    _RE_NETWORK_DESCRIPTION_ID = re.compile("networkDescription(\d+)")
281   
282   
283    def __init__(self, *args, **kwargs):
284        HTMLParser.__init__(self)
285        self.networkGroups = []
286        self.networks = {}
287       
288        self.currentGroup = None
289        self.currentNetwork = None
290       
291        self.data_handler = None
292       
293    def handle_start_group(self, tag, attrs):
294        """ Handle '<li class=... id="networkGroup%i">'
295        """
296        self.currentGroup = NetworkGroup()
297        self.currentGroup.id = attrs.get("id")
298       
299        self.networkGroups.append(self.currentGroup)
300       
301       
302    def handle_start_group_weight(self, tag, attrs):
303        """ Handle '<span tooltip="..." id="networkGroupWeight%i">'
304        """
305        self.data_handler = self.handle_group_weight_data
306       
307    def handle_group_weight_data(self, data):
308        self.currentGroup.weight += data
309       
310    def handle_end_group_weight(self, tag):
311        self.data_handler = None
312       
313    def handle_start_group_name(self, tag, attrs):
314        """ Handle '<div class="network_name" id="networkGroupName%i">'
315        """
316        self.data_handler = self.handle_group_name_data
317       
318    def handle_group_name_data(self, data):
319        self.currentGroup.name += data
320       
321    def handle_start_network(self, tag, attrs):
322        """ Handle '<li class="checktree_network" id="network%i">'
323        """
324        self.currentNetwork = Network()
325        self.currentNetwork.id = attrs.get("id")
326       
327        self.currentGroup.networks.append(self.currentNetwork)
328       
329    def handle_start_network_weight(self, tag, attrs):
330        """ Handle '<span tooltip="..." id="networkWeight%i">'
331        """
332        self.data_handler = self.handle_network_weight_data
333       
334    def handle_network_weight_data(self, data):
335        self.currentNetwork.weight += data
336       
337    def handle_start_network_name(self, tag, attrs):
338        """ Handle '<div class="network_name" id="networkName%i">'
339        """
340        self.data_handler = self.handle_network_name_data
341       
342    def handle_network_name_data(self, data):
343        self.currentNetwork.name += data
344       
345    def handle_start_network_description(self, tag, attrs):
346        """ Handle '<div class="text" id="networkDescription%i">'
347        """
348        self.data_handler = self.handle_network_description_data
349       
350    def handle_network_description_data(self, data):
351        self.currentNetwork.description += data
352       
353    def handle_data(self, data):
354        if self.data_handler:
355            self.data_handler(data)
356   
357    def handle_starttag(self, tag, attrs):
358        attrs = dict(attrs)
359        if tag == "li" and self._RE_GROUP_ID.search(attrs.get("id", "")):
360            self.handle_start_group(tag, attrs)
361        elif tag == "span" and self._RE_GROUP_WEIGHT_ID.search(attrs.get("id", "")):
362            self.handle_start_group_weight(tag, attrs)
363        elif tag == "div" and self._RE_GROUP_NAME_ID.search(attrs.get("id", "")):
364            self.handle_start_group_name(tag, attrs)
365        elif tag == "li" and self._RE_NETWORK_ID.search(attrs.get("id", "")):
366            self.handle_start_network(tag, attrs)
367        elif tag == "span" and self._RE_NETWORK_WEIGHT_ID.search(attrs.get("id", "")):
368            self.handle_start_network_weight(tag, attrs)
369        elif tag == "div" and self._RE_NETWORK_NAME_ID.search(attrs.get("id", "")):
370            self.handle_start_network_name(tag, attrs)
371        elif tag == "div" and self._RE_NETWORK_DESCRIPTION_ID.search(attrs.get("id", "")):
372            self.handle_start_network_description(tag, attrs)
373        else:
374            HTMLParser.handle_starttag(self, tag, attrs)
375           
376    def handle_endtag(self, tag):
377        self.data_handler = None
378           
379
380def parsePage(html):
381    parser = _NetworkTabParser()
382    parser.feed(html)
383    return parser.networkGroups
384   
385
386def retrieve(org=None, genes=[], m="automatic", r=10):
387    """ A helper function, same as Connection().retrive(*args, **kwargs)
388    """
389    return Connection().retrieve(org, genes, m, r)
390
391
392"""
393======================
394PPI Database interface
395======================
396
397"""
398
399
400import sqlite3
401import csv
402import os
403import posixpath
404
405from contextlib import contextmanager
406import StringIO
407
408@contextmanager
409def finishing(obj):
410    """ Calls obj.finish() on context exit.
411    """
412    yield obj
413    obj.finish()
414
415def guess_size(fileobj):
416    try:
417        if isinstance(fileobj, file):
418            return os.fstat(fileobj.fileno()).st_size
419        elif isinstance(fileobj, StringIO.StringIO):
420            pos = fileobj.tell()
421            fileobj.seek(0, 2)
422            length = fileobj.tell() - pos
423            fileobj.seek(pos, 0)
424            return length
425        elif isinstance(fileobj, urllib.addinfourl):
426            length = fileobj.headers.get("content-length", None)
427            return length
428    except Exception, ex:
429        pass
430
431
432def copyfileobj(src, dst, buffer=2**10, content_len=None, progress=None):
433    count = 0
434    if content_len is None:
435        content_len = guess_size(src) or sys.maxint
436    while True:
437        data = src.read(buffer)
438        dst.write(data)
439        count += len(data)
440        if progress:
441            progress(100.0 * count / content_len)
442        if not data:
443            break
444           
445           
446def wget(url, directory=".", dst_obj=None, progress=None):
447    """
448    .. todo:: Move to Orange.misc
449   
450    """
451    stream = urllib2.urlopen(url)
452    length = stream.headers.get("content-length", None)
453    if length is None:
454        length = sys.maxint
455    else:
456        length = int(length)
457   
458    basename = posixpath.basename(url)
459       
460    if dst_obj is None:
461        dst_obj = open(os.path.join(directory, basename), "wb")
462   
463    if progress == True:
464        from Orange.misc import ConsoleProgressBar
465        progress = ConsoleProgressBar("Downloading %r." % basename)
466        with finishing(progress):
467            copyfileobj(stream, dst_obj, buffer=2**10, content_len=length,
468                        progress=progress)
469    else:
470        copyfileobj(stream, dst_obj, buffer=2**10, content_len=length,
471                    progress=progress)
472   
473import obiPPI
474import orngServerFiles
475
476import obiTaxonomy
477from collections import namedtuple
478from operator import itemgetter
479from Orange.misc import lru_cache
480
481GENE_MANIA_INTERACTION_FIELDS = \
482    ["gene_a", "gene_b", "weight", "network_name",
483     "network_group", "source", "pubmed_id"]
484     
485GeneManiaInteraction = namedtuple("GeneManiaInteraction",
486                                  field_names=GENE_MANIA_INTERACTION_FIELDS
487                                 )
488
489import weakref
490class Internalizer(object):
491    """ A class that acts as the python builtin function ``intern``,
492    for as long as it is alive.
493   
494    .. note:: This is for memory optimization only, it does not affect
495        dict lookup speed.
496   
497    """
498    def __init__(self):
499        self._intern_dict = {}
500       
501    def __call__(self, obj):
502        return self._intern_dict.setdefault(obj, obj)
503   
504class GeneManiaDatabase(obiPPI.PPIDatabase):
505    DOMAIN = "PPI"
506    SERVER_FILE = "gene-mania-{taxid}.sqlite"
507   
508    TAXID2NAME = ""
509   
510    # DB schema
511    SCHEMA = """
512    table: `genes`
513        - `internal_id`: int (pk)
514        - `gene_name`: text (preferred name)
515       
516    table: `synonyms`:
517        - `internal_id: int (foreign key `genes.internal_id`)
518        - `synonym`: text
519        - `source_id`: int
520       
521    table: `source`:
522        - `source_id`: int
523        - `source_name`: text
524       
525    table: `links`:
526        - `gene_a`: int (fk `genes.internal_key`)
527        - `gene_b`: int (fk `genes.internal_key`)
528        - `network_id`: (fk `networks.network_id`)
529        - `weight`: real
530       
531    table: `networks`:
532        - `network_id`: int
533        - `network_name`: text
534        - `network_group`: text
535        - `source`: text
536        - `pubmed_id`: text
537       
538    view: `links_annotated`:
539        - `gene_name_a`
540        - `gene_name_b`
541        - `network_name`
542        - `network_group`
543        - `weight`
544       
545    """
546   
547    def __init__(self, taxid):
548        self.taxid = taxid
549       
550    @classmethod
551    def common_taxids(self):
552        return ["3702", "6239", "7227", "9606", "10090", "10116", "4932"]
553   
554    def organisms(self):
555        """ Return all organism taxids contained in this database.
556       
557        .. note:: a single taxid is returned (the one used at
558            instance initialization)   
559       
560        """
561        return [self.taxid]
562   
563    def ids(self, taxid=None):
564        """ Return all primary ids for `taxid`.
565        """
566        if taxid is None:
567            taxids = self.organisms()
568            return reduce(list.__add__, map(self.ids, taxids), [])
569       
570        con = self._db(taxid)
571        cur = con.execute("""\
572            SELECT gene_name FROM genes
573            """)
574        return map(itemgetter(0), cur)
575       
576    def synonyms(self, id):
577        """ Return a list of synonyms for primary `id`.
578        """
579        con = self._db(self.taxid)
580        cur = con.execute("""\
581            SELECT synonyms.synonym
582            FROM synonyms NATURAL LEFT JOIN genes
583            WHERE genes.gene_name=?
584            """, (id,))
585        return map(itemgetter(0), cur)
586       
587    def all_edges(self, taxid=None):
588        """ Return a list of all edges.
589        """
590        con = self._db(self.taxid)
591        cur = con.execute("""
592            SELECT links.gene_a, links.gene_b, links.weight
593            FROM links""")
594        id_to_name = self._gene_id_to_name()
595        return [(id_to_name[r[0]], id_to_name[r[1]], r[2]) \
596                for r in cur]
597       
598    def all_edges_annotated(self, taxid=None):
599        """ Return a list of all edges with all available annotations
600        """
601        con = self._db(self.taxid)
602        cur = con.execute("""\
603            SELECT links.gene_a, links.gene_b, links.weight, links.network_id
604            FROM links""")
605        gene_to_name = self._gene_id_to_name()
606        network_to_description = self._network_id_to_description()
607        res = []
608        for gene_a, gene_b, w, n_id in cur:
609            n_desc = network_to_description[n_id]
610           
611            res.append(GeneManiaInteraction(gene_to_name[gene_a],
612                            gene_to_name[gene_b], w, *n_desc))
613        return res
614       
615    def edges(self, id1):
616        """ Return all edges for primary id `id1`.
617        """       
618        con = self._db(self.taxid)
619        cur = con.execute("""\
620            SELECT genes1.gene_name, genes2.gene_name, links.weight
621            FROM genes AS genes1 
622                JOIN links
623                    ON genes1.internal_id=links.gene_a
624                JOIN genes AS genes2
625                    ON genes2.internal_id=links.gene_b
626            WHERE genes1.gene_name=?
627            """, (id1,))
628        res = cur.fetchall()
629        cur = con.execute("""\
630            SELECT genes1.gene_name, genes2.gene_name, links.weight
631            FROM genes AS genes1 
632                JOIN  links
633                    ON genes1.internal_id=links.gene_a
634                JOIN genes AS genes2
635                    ON genes2.internal_id=links.gene_b
636            WHERE genes2.gene_name=?
637            """, (id1,))
638        res += cur.fetchall()
639       
640        return res
641   
642    def edges_annotated(self, id=None):
643        """ Return a list of annotated edges for primary `id`
644        """
645        con = self._db(self.taxid)
646        cur = con.execute("""\
647            SELECT genes1.gene_name, genes2.gene_name, links.weight,
648                   networks.network_name, networks.network_group,
649                   networks.source, networks.pubmed_id
650            FROM genes AS genes1
651                JOIN  links
652                    ON genes1.internal_id=links.gene_a
653                JOIN genes AS genes2
654                    ON genes2.internal_id=links.gene_b
655                NATURAL JOIN networks
656            WHERE genes1.gene_name=?
657            """, (id,))
658        res = cur.fetchall()
659        cur = con.execute("""\
660            SELECT genes1.gene_name, genes2.gene_name, links.weight,
661                   networks.network_name, networks.network_group,
662                   networks.source, networks.pubmed_id
663            FROM genes AS genes1
664                JOIN links
665                    ON genes1.internal_id=links.gene_a
666                JOIN genes AS genes2
667                    ON genes2.internal_id=links.gene_b
668                NATURAL JOIN networks
669            WHERE genes2.gene_name=?
670            """, (id,))
671        res += cur.fetchall()
672        return [GeneManiaInteraction(*r) for r in res]
673   
674    def search_id(self, name, taxid=None):
675        """ Search the database for gene name. Return a list of matching
676        primary ids. Use `taxid` to limit the results to a single organism.
677       
678        """
679        con = self._db(self.taxid)
680        cur = con.execute("""\
681            SELECT genes.gene_name
682            FROM genes NATURAL JOIN synonyms
683            WHERE synonyms.synonym=?
684            """, (name,))
685        return map(itemgetter(0), cur)
686       
687    def _db(self, taxid=None):
688        """ Return an open sqlite3.Connection object. 
689        """
690        taxid = taxid or self.taxid
691        filename = orngServerFiles.localpath_download("PPI",
692                            self.SERVER_FILE.format(taxid=taxid))
693        if not os.path.exists(filename):
694            raise ValueError("Database is missing.")
695       
696        return sqlite3.connect(filename)
697   
698    @lru_cache(maxsize=1)
699    def _gene_id_to_name(self):
700        """ Return a dictionary mapping internal gene ids to
701        primary gene identifiers.
702       
703        """
704        con = self._db(self.taxid)
705        cur = con.execute("SELECT * FROM genes")
706        return dict(cur)
707   
708    @lru_cache(maxsize=1)
709    def _network_id_to_description(self):
710        """ Return a dictionary mapping internal network ids
711        to (name, group, source, pubmed id).
712         
713        """
714        con = self._db(self.taxid)
715        cur = con.execute("SELECT * FROM networks")
716        return dict((t[0], t[1:]) for t in cur)
717   
718    #####################################
719    # Data download and DB initialization
720    #####################################
721     
722    @classmethod
723    def download_data(cls, taxid=None, progress_callback=None):
724        """ Download the data for ``taxid`` from the GeneMANIA
725        website and initialize the local database.
726       
727        """
728        import tarfile
729       
730        baseurl = "http://genemania.org/data/current/"
731        directory = orngServerFiles.localpath("PPI")
732        if taxid is None:
733            taxid = cls.common_taxids()
734       
735        if isinstance(taxid, (list, tuple)):
736            taxids = taxid
737        else:
738            taxids = [taxid]
739        for taxid in taxids:
740            name = obiTaxonomy.name(taxid)
741            name = name.replace(" ", "_")
742           
743            if progress_callback is None:
744                progress = True #orngServerFiles.ConsoleProgressBar("Downloading %r." % filename)
745            else:
746                progress = progress_callback
747           
748            filename = name + ".tgz"
749            url = baseurl + "networks/" + filename   
750            wget(url, directory=directory, progress=progress)
751           
752            tgz_filename = os.path.join(directory, filename)   
753            tgz = tarfile.open(tgz_filename)
754            tgz.extractall(directory)
755           
756            filename = name + ".COMBINED.tgz"
757            url = baseurl + "precombined/" + filename
758            wget(url, directory=directory, progress=progress)
759           
760            tgz_filename = os.path.join(directory, filename)
761            tgz = tarfile.open(tgz_filename)
762            tgz.extractall(directory)
763       
764            cls.init_db([taxid])
765       
766    @classmethod
767    def init_db(cls, taxid=None):
768        """ Init the local data base.
769        """
770        from functools import partial
771        directory = orngServerFiles.localpath("PPI")
772        pjoin = partial(os.path.join, directory)
773        if taxid is None:
774            taxid = cls.common_taxids()
775           
776        if isinstance(taxid, (list, tuple)):
777            for tid in taxid:
778                cls.init_db(tid)
779            return
780               
781        if not isinstance(taxid, basestring):
782            raise ValueError("wrong taxid")
783           
784#        taxid = taxids
785        name = obiTaxonomy.name(taxid).replace(" ", "_")
786        networks = csv.reader(open(pjoin(name, "networks.txt")), delimiter="\t")
787        networks.next() # Header
788        networks = list(networks)
789       
790        database = pjoin(cls.SERVER_FILE.format(taxid=taxid))
791        with sqlite3.connect(database) as con:
792            con.execute("""DROP TABLE IF EXISTS genes""")
793            con.execute("""DROP TABLE IF EXISTS synonyms""")
794            con.execute("""DROP TABLE IF EXISTS source""")
795            con.execute("""DROP TABLE IF EXISTS links""")
796            con.execute("""DROP TABLE IF EXISTS networks""")
797           
798            con.execute("""DROP INDEX IF EXISTS genes_index""")
799            con.execute("""DROP INDEX IF EXISTS links_index_a""")
800            con.execute("""DROP INDEX IF EXISTS links_index_b""")
801           
802            con.execute("""\
803                CREATE TABLE networks
804                    (network_id INTEGER PRIMARY KEY ASC AUTOINCREMENT,
805                     network_name TEXT,
806                     network_group TEXT,
807                     source TEXT,
808                     pubmed_id TEXT
809                    )""")
810           
811            con.executemany("""\
812                INSERT INTO networks
813                VALUES (?, ?, ?, ?, ?)""", [(i, r[2], r[1], r[3], r[4]) \
814                                        for i, r in enumerate(networks)])
815           
816            con.execute("""\
817                CREATE TABLE genes
818                    (internal_id INTEGER PRIMARY KEY ASC AUTOINCREMENT,
819                     gene_name TEXT
820                    )""")
821           
822            identifiers = csv.reader(open(pjoin(name, "identifier_mappings.txt"), "rb"),
823                                    delimiter="\t")
824            identifiers.next() # skip header
825            identifiers = list(identifiers)
826            genes = sorted(set(r[0] for r in identifiers))
827            sources = sorted(set(r[2] for r in identifiers))
828           
829            con.executemany("""\
830                INSERT INTO genes
831                VALUES (?, ?)""", enumerate(genes))
832           
833            con.execute("""\
834            CREATE TABLE source
835                (source_id INTEGER PRIMARY KEY ASC AUTOINCREMENT,
836                 source_name TEXT
837                )""")
838           
839            con.executemany("""\
840                INSERT INTO source
841                VALUES (?, ?)""", enumerate(sources))
842           
843            con.execute("""\
844                CREATE TABLE synonyms
845                    (internal_id INTEGER REFERENCES genes (internal_id),
846                     synonym TEXT,
847                     source_id INT REFERENCES source (source_id)
848                    )""")
849           
850            gene_to_id = dict((g, i) for i, g in enumerate(genes))
851            source_to_id = dict((s, i) for i, s in enumerate(sources))
852            con.executemany("""\
853                INSERT INTO synonyms
854                VALUES (?, ?, ?)""", [(gene_to_id[r[0]], r[1], source_to_id[r[2]])\
855                                       for r in identifiers])
856           
857            con.execute("""\
858                CREATE TABLE links
859                    (gene_a INTEGER REFERENCES genes (internal_id),
860                     gene_b INTEGER REFERENCES genes (internal_id),
861                     network_id INTEGER REFERENCES networks (network_id),
862                     weight REAL
863                     -- , PRIMARY KEY (gene_a, gene_b, network_id)
864                    )""")
865           
866            for i, (filename, group, _, _, _) in enumerate(networks):
867                nf  = open(pjoin(name, filename), "rb")
868                interactions = csv.reader(nf, delimiter="\t")
869                interactions.next() # skip header
870                con.executemany("""\
871                    INSERT INTO links
872                    VALUES (?, ?, ?, ?)""",
873                    [(gene_to_id[r[0]], gene_to_id[r[1]], i, float(r[2])) \
874                     for r in interactions]
875                )
876               
877            # Add special combined network entry
878            combined_id = len(networks)
879            con.execute("""\
880                INSERT INTO networks
881                VALUES (?, ?, ?, ?, ?)""", 
882                (combined_id, "BP_COMBINING", "COMBINED", "GeneMANIA", ""))
883           
884            # Add the combined network links.
885            combined = open(pjoin(name + ".COMBINED", "COMBINED.DEFAULT_NETWORKS.BP_COMBINING.txt"), "rb")
886            combined = csv.reader(combined, delimiter="\t")
887            combined.next()
888            con.executemany("""\
889                INSERT INTO links
890                VALUES (?, ?, ?, ?)""",
891                    ((gene_to_id[r[0]], gene_to_id[r[1]], combined_id, float(r[2])) \
892                     for r in combined))
893           
894           
895            con.execute("""
896                CREATE VIEW IF NOT EXISTS links_annotated
897                AS SELECT genes1.gene_name AS gene_name_a,
898                          genes2.gene_name AS gene_name_b,
899                          links.weight,
900                          networks.network_name,
901                          networks.network_group,
902                          networks.source,
903                          networks.pubmed_id
904                   FROM  genes AS genes1
905                        JOIN links
906                              ON genes1.internal_id=links.gene_a
907                        JOIN genes AS genes2
908                              ON links.gene_b=genes2.internal_id
909                        JOIN networks
910                              ON links.network_id=networks.network_id
911                    """)
912           
913           
914            con.execute("""\
915                CREATE INDEX IF NOT EXISTS genes_index ON genes (gene_name)
916                """)
917            con.execute("""\
918                CREATE INDEX IF NOT EXISTS links_index_a ON links (gene_a)
919                """)
920            con.execute("""\
921                 CREATE INDEX IF NOT EXISTS links_index_b ON links (gene_b)
922                """)
923       
924           
925if __name__ == "__main__":
926    retrieve("9606", [ 'MRE11A', 'RAD51', 'MLH1', 'MSH2', 'DMC1', 'RAD51AP1', 'RAD50', 'MSH6', 'XRCC3', 'PCNA', 'XRCC2' ])
Note: See TracBrowser for help on using the repository browser.