source: orange-bioinformatics/Orange/bioinformatics/obiGeneMania.py @ 1625:cefeb35cbfc9

Revision 1625:cefeb35cbfc9, 32.8 KB checked in by mitar, 2 years ago (diff)

Moving files around.

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
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
447
448def copyfileobj(src, dst, buffer=2**10, content_len=None, progress=None):
449    count = 0
450    if content_len is None:
451        content_len = guess_size(src) or sys.maxint
452    while True:
453        data = src.read(buffer)
454        dst.write(data)
455        count += len(data)
456        if progress:
457            progress(100.0 * count / content_len)
458        if not data:
459            break
460           
461           
462def wget(url, directory=".", dst_obj=None, progress=None):
463    """
464    .. todo:: Move to Orange.misc
465   
466    """
467    stream = urllib2.urlopen(url)
468    length = stream.headers.get("content-length", None)
469    if length is None:
470        length = sys.maxint
471    else:
472        length = int(length)
473   
474    basename = posixpath.basename(url)
475       
476    if dst_obj is None:
477        dst_obj = open(os.path.join(directory, basename), "wb")
478   
479    if progress == True:
480        from Orange.utils import ConsoleProgressBar
481        progress = ConsoleProgressBar("Downloading %r." % basename)
482        with finishing(progress):
483            copyfileobj(stream, dst_obj, buffer=2**10, content_len=length,
484                        progress=progress)
485    else:
486        copyfileobj(stream, dst_obj, buffer=2**10, content_len=length,
487                    progress=progress)
488   
489import obiPPI
490import orngServerFiles
491
492import obiTaxonomy
493from collections import namedtuple
494from operator import itemgetter
495from Orange.utils import lru_cache
496
497GENE_MANIA_INTERACTION_FIELDS = \
498    ["gene_a", "gene_b", "weight", "network_name",
499     "network_group", "source", "pubmed_id"]
500     
501GeneManiaInteraction = namedtuple("GeneManiaInteraction",
502                                  field_names=GENE_MANIA_INTERACTION_FIELDS
503                                 )
504
505import weakref
506class Internalizer(object):
507    """ A class that acts as the python builtin function ``intern``,
508    for as long as it is alive.
509   
510    .. note:: This is for memory optimization only, it does not affect
511        dict lookup speed.
512   
513    """
514    def __init__(self):
515        self._intern_dict = {}
516       
517    def __call__(self, obj):
518        return self._intern_dict.setdefault(obj, obj)
519   
520class GeneManiaDatabase(obiPPI.PPIDatabase):
521    DOMAIN = "PPI"
522    SERVER_FILE = "gene-mania-{taxid}.sqlite"
523   
524    TAXID2NAME = ""
525   
526    # DB schema
527    SCHEMA = """
528    table: `genes`
529        - `internal_id`: int (pk)
530        - `gene_name`: text (preferred name)
531       
532    table: `synonyms`:
533        - `internal_id: int (foreign key `genes.internal_id`)
534        - `synonym`: text
535        - `source_id`: int
536       
537    table: `source`:
538        - `source_id`: int
539        - `source_name`: text
540       
541    table: `links`:
542        - `gene_a`: int (fk `genes.internal_key`)
543        - `gene_b`: int (fk `genes.internal_key`)
544        - `network_id`: (fk `networks.network_id`)
545        - `weight`: real
546       
547    table: `networks`:
548        - `network_id`: int
549        - `network_name`: text
550        - `network_group`: text
551        - `source`: text
552        - `pubmed_id`: text
553       
554    view: `links_annotated`:
555        - `gene_name_a`
556        - `gene_name_b`
557        - `network_name`
558        - `network_group`
559        - `weight`
560       
561    """
562   
563    def __init__(self, taxid):
564        self.taxid = taxid
565       
566    @classmethod
567    def common_taxids(self):
568        return ["3702", "6239", "7227", "9606", "10090", "10116", "4932"]
569   
570    def organisms(self):
571        """ Return all organism taxids contained in this database.
572       
573        .. note:: a single taxid is returned (the one used at
574            instance initialization)   
575       
576        """
577        return [self.taxid]
578   
579    def ids(self, taxid=None):
580        """ Return all primary ids for `taxid`.
581        """
582        if taxid is None:
583            taxids = self.organisms()
584            return reduce(list.__add__, map(self.ids, taxids), [])
585       
586        con = self._db(taxid)
587        cur = con.execute("""\
588            SELECT gene_name FROM genes
589            """)
590        return map(itemgetter(0), cur)
591       
592    def synonyms(self, id):
593        """ Return a list of synonyms for primary `id`.
594        """
595        con = self._db(self.taxid)
596        cur = con.execute("""\
597            SELECT synonyms.synonym
598            FROM synonyms NATURAL LEFT JOIN genes
599            WHERE genes.gene_name=?
600            """, (id,))
601        return map(itemgetter(0), cur)
602       
603    def all_edges(self, taxid=None):
604        """ Return a list of all edges.
605        """
606        con = self._db(self.taxid)
607        cur = con.execute("""
608            SELECT links.gene_a, links.gene_b, links.weight
609            FROM links""")
610        id_to_name = self._gene_id_to_name()
611        return [(id_to_name[r[0]], id_to_name[r[1]], r[2]) \
612                for r in cur]
613       
614    def all_edges_annotated(self, taxid=None):
615        """ Return a list of all edges with all available annotations
616        """
617        con = self._db(self.taxid)
618        cur = con.execute("""\
619            SELECT links.gene_a, links.gene_b, links.weight, links.network_id
620            FROM links""")
621        gene_to_name = self._gene_id_to_name()
622        network_to_description = self._network_id_to_description()
623        res = []
624        for gene_a, gene_b, w, n_id in cur:
625            n_desc = network_to_description[n_id]
626           
627            res.append(GeneManiaInteraction(gene_to_name[gene_a],
628                            gene_to_name[gene_b], w, *n_desc))
629        return res
630       
631    def edges(self, id1):
632        """ Return all edges for primary id `id1`.
633        """       
634        con = self._db(self.taxid)
635        cur = con.execute("""\
636            SELECT genes1.gene_name, genes2.gene_name, links.weight
637            FROM genes AS genes1 
638                JOIN links
639                    ON genes1.internal_id=links.gene_a
640                JOIN genes AS genes2
641                    ON genes2.internal_id=links.gene_b
642            WHERE genes1.gene_name=?
643            """, (id1,))
644        res = cur.fetchall()
645        cur = con.execute("""\
646            SELECT genes1.gene_name, genes2.gene_name, links.weight
647            FROM genes AS genes1 
648                JOIN  links
649                    ON genes1.internal_id=links.gene_a
650                JOIN genes AS genes2
651                    ON genes2.internal_id=links.gene_b
652            WHERE genes2.gene_name=?
653            """, (id1,))
654        res += cur.fetchall()
655       
656        return res
657   
658    def edges_annotated(self, id=None):
659        """ Return a list of annotated edges for primary `id`
660        """
661        con = self._db(self.taxid)
662        cur = con.execute("""\
663            SELECT genes1.gene_name, genes2.gene_name, links.weight,
664                   networks.network_name, networks.network_group,
665                   networks.source, networks.pubmed_id
666            FROM genes AS genes1
667                JOIN  links
668                    ON genes1.internal_id=links.gene_a
669                JOIN genes AS genes2
670                    ON genes2.internal_id=links.gene_b
671                NATURAL JOIN networks
672            WHERE genes1.gene_name=?
673            """, (id,))
674        res = cur.fetchall()
675        cur = con.execute("""\
676            SELECT genes1.gene_name, genes2.gene_name, links.weight,
677                   networks.network_name, networks.network_group,
678                   networks.source, networks.pubmed_id
679            FROM genes AS genes1
680                JOIN links
681                    ON genes1.internal_id=links.gene_a
682                JOIN genes AS genes2
683                    ON genes2.internal_id=links.gene_b
684                NATURAL JOIN networks
685            WHERE genes2.gene_name=?
686            """, (id,))
687        res += cur.fetchall()
688        return [GeneManiaInteraction(*r) for r in res]
689   
690    def search_id(self, name, taxid=None):
691        """ Search the database for gene name. Return a list of matching
692        primary ids. Use `taxid` to limit the results to a single organism.
693       
694        """
695        con = self._db(self.taxid)
696        cur = con.execute("""\
697            SELECT genes.gene_name
698            FROM genes NATURAL JOIN synonyms
699            WHERE synonyms.synonym=?
700            """, (name,))
701        return map(itemgetter(0), cur)
702       
703    def _db(self, taxid=None):
704        """ Return an open sqlite3.Connection object. 
705        """
706        taxid = taxid or self.taxid
707        filename = orngServerFiles.localpath_download("PPI",
708                            self.SERVER_FILE.format(taxid=taxid))
709        if not os.path.exists(filename):
710            raise ValueError("Database is missing.")
711       
712        return sqlite3.connect(filename)
713   
714    @lru_cache(maxsize=1)
715    def _gene_id_to_name(self):
716        """ Return a dictionary mapping internal gene ids to
717        primary gene identifiers.
718       
719        """
720        con = self._db(self.taxid)
721        cur = con.execute("SELECT * FROM genes")
722        return dict(cur)
723   
724    @lru_cache(maxsize=1)
725    def _network_id_to_description(self):
726        """ Return a dictionary mapping internal network ids
727        to (name, group, source, pubmed id).
728         
729        """
730        con = self._db(self.taxid)
731        cur = con.execute("SELECT * FROM networks")
732        return dict((t[0], t[1:]) for t in cur)
733   
734    #####################################
735    # Data download and DB initialization
736    #####################################
737     
738    @classmethod
739    def download_data(cls, taxid=None, progress_callback=None):
740        """ Download the data for ``taxid`` from the GeneMANIA
741        website and initialize the local database.
742       
743        """
744        import tarfile
745       
746        baseurl = "http://genemania.org/data/current/"
747        directory = orngServerFiles.localpath("PPI")
748        if taxid is None:
749            taxid = cls.common_taxids()
750       
751        if isinstance(taxid, (list, tuple)):
752            taxids = taxid
753        else:
754            taxids = [taxid]
755        for taxid in taxids:
756            name = obiTaxonomy.name(taxid)
757            name = name.replace(" ", "_")
758           
759            if progress_callback is None:
760                progress = True #orngServerFiles.ConsoleProgressBar("Downloading %r." % filename)
761            else:
762                progress = progress_callback
763           
764            filename = name + ".tgz"
765            url = baseurl + "networks/" + filename   
766            wget(url, directory=directory, progress=progress)
767           
768            tgz_filename = os.path.join(directory, filename)   
769            tgz = tarfile.open(tgz_filename)
770            tgz.extractall(directory)
771           
772            filename = name + ".COMBINED.tgz"
773            url = baseurl + "precombined/" + filename
774            wget(url, directory=directory, progress=progress)
775           
776            tgz_filename = os.path.join(directory, filename)
777            tgz = tarfile.open(tgz_filename)
778            tgz.extractall(directory)
779       
780            cls.init_db([taxid])
781       
782    @classmethod
783    def init_db(cls, taxid=None):
784        """ Init the local data base.
785        """
786        from functools import partial
787        directory = orngServerFiles.localpath("PPI")
788        pjoin = partial(os.path.join, directory)
789        if taxid is None:
790            taxid = cls.common_taxids()
791           
792        if isinstance(taxid, (list, tuple)):
793            for tid in taxid:
794                cls.init_db(tid)
795            return
796               
797        if not isinstance(taxid, basestring):
798            raise ValueError("wrong taxid")
799           
800#        taxid = taxids
801        name = obiTaxonomy.name(taxid).replace(" ", "_")
802        networks = csv.reader(open(pjoin(name, "networks.txt")), delimiter="\t")
803        networks.next() # Header
804        networks = list(networks)
805       
806        database = pjoin(cls.SERVER_FILE.format(taxid=taxid))
807        with sqlite3.connect(database) as con:
808            con.execute("""DROP TABLE IF EXISTS genes""")
809            con.execute("""DROP TABLE IF EXISTS synonyms""")
810            con.execute("""DROP TABLE IF EXISTS source""")
811            con.execute("""DROP TABLE IF EXISTS links""")
812            con.execute("""DROP TABLE IF EXISTS networks""")
813           
814            con.execute("""DROP INDEX IF EXISTS genes_index""")
815            con.execute("""DROP INDEX IF EXISTS links_index_a""")
816            con.execute("""DROP INDEX IF EXISTS links_index_b""")
817           
818            con.execute("""\
819                CREATE TABLE networks
820                    (network_id INTEGER PRIMARY KEY ASC AUTOINCREMENT,
821                     network_name TEXT,
822                     network_group TEXT,
823                     source TEXT,
824                     pubmed_id TEXT
825                    )""")
826           
827            con.executemany("""\
828                INSERT INTO networks
829                VALUES (?, ?, ?, ?, ?)""", [(i, r[2], r[1], r[3], r[4]) \
830                                        for i, r in enumerate(networks)])
831           
832            con.execute("""\
833                CREATE TABLE genes
834                    (internal_id INTEGER PRIMARY KEY ASC AUTOINCREMENT,
835                     gene_name TEXT
836                    )""")
837           
838            identifiers = csv.reader(open(pjoin(name, "identifier_mappings.txt"), "rb"),
839                                    delimiter="\t")
840            identifiers.next() # skip header
841            identifiers = list(identifiers)
842            genes = sorted(set(r[0] for r in identifiers))
843            sources = sorted(set(r[2] for r in identifiers))
844           
845            con.executemany("""\
846                INSERT INTO genes
847                VALUES (?, ?)""", enumerate(genes))
848           
849            con.execute("""\
850            CREATE TABLE source
851                (source_id INTEGER PRIMARY KEY ASC AUTOINCREMENT,
852                 source_name TEXT
853                )""")
854           
855            con.executemany("""\
856                INSERT INTO source
857                VALUES (?, ?)""", enumerate(sources))
858           
859            con.execute("""\
860                CREATE TABLE synonyms
861                    (internal_id INTEGER REFERENCES genes (internal_id),
862                     synonym TEXT,
863                     source_id INT REFERENCES source (source_id)
864                    )""")
865           
866            gene_to_id = dict((g, i) for i, g in enumerate(genes))
867            source_to_id = dict((s, i) for i, s in enumerate(sources))
868            con.executemany("""\
869                INSERT INTO synonyms
870                VALUES (?, ?, ?)""", [(gene_to_id[r[0]], r[1], source_to_id[r[2]])\
871                                       for r in identifiers])
872           
873            con.execute("""\
874                CREATE TABLE links
875                    (gene_a INTEGER REFERENCES genes (internal_id),
876                     gene_b INTEGER REFERENCES genes (internal_id),
877                     network_id INTEGER REFERENCES networks (network_id),
878                     weight REAL
879                     -- , PRIMARY KEY (gene_a, gene_b, network_id)
880                    )""")
881           
882            for i, (filename, group, _, _, _) in enumerate(networks):
883                nf  = open(pjoin(name, filename), "rb")
884                interactions = csv.reader(nf, delimiter="\t")
885                interactions.next() # skip header
886                con.executemany("""\
887                    INSERT INTO links
888                    VALUES (?, ?, ?, ?)""",
889                    [(gene_to_id[r[0]], gene_to_id[r[1]], i, float(r[2])) \
890                     for r in interactions]
891                )
892               
893            # Add special combined network entry
894            combined_id = len(networks)
895            con.execute("""\
896                INSERT INTO networks
897                VALUES (?, ?, ?, ?, ?)""", 
898                (combined_id, "BP_COMBINING", "COMBINED", "GeneMANIA", ""))
899           
900            # Add the combined network links.
901            combined = open(pjoin(name + ".COMBINED", "COMBINED.DEFAULT_NETWORKS.BP_COMBINING.txt"), "rb")
902            combined = csv.reader(combined, delimiter="\t")
903            combined.next()
904            con.executemany("""\
905                INSERT INTO links
906                VALUES (?, ?, ?, ?)""",
907                    ((gene_to_id[r[0]], gene_to_id[r[1]], combined_id, float(r[2])) \
908                     for r in combined))
909           
910           
911            con.execute("""
912                CREATE VIEW IF NOT EXISTS links_annotated
913                AS SELECT genes1.gene_name AS gene_name_a,
914                          genes2.gene_name AS gene_name_b,
915                          links.weight,
916                          networks.network_name,
917                          networks.network_group,
918                          networks.source,
919                          networks.pubmed_id
920                   FROM  genes AS genes1
921                        JOIN links
922                              ON genes1.internal_id=links.gene_a
923                        JOIN genes AS genes2
924                              ON links.gene_b=genes2.internal_id
925                        JOIN networks
926                              ON links.network_id=networks.network_id
927                    """)
928           
929           
930            con.execute("""\
931                CREATE INDEX IF NOT EXISTS genes_index ON genes (gene_name)
932                """)
933            con.execute("""\
934                CREATE INDEX IF NOT EXISTS links_index_a ON links (gene_a)
935                """)
936            con.execute("""\
937                 CREATE INDEX IF NOT EXISTS links_index_b ON links (gene_b)
938                """)
939       
940           
941if __name__ == "__main__":
942    retrieve("9606", [ 'MRE11A', 'RAD51', 'MLH1', 'MSH2', 'DMC1', 'RAD51AP1', 'RAD50', 'MSH6', 'XRCC3', 'PCNA', 'XRCC2' ])
Note: See TracBrowser for help on using the repository browser.