source: orange-bioinformatics/orangecontrib/bio/obiGeneMania.py @ 1873:0810c5708cc5

Revision 1873:0810c5708cc5, 31.7 KB checked in by Ales Erjavec <ales.erjavec@…>, 7 months ago (diff)

Moved '_bioinformatics' into orangecontrib namespace.

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