Exemple #1
0
def convert(the_map,
            model,
            map_name=None,
            map_description=None,
            reaction_id_mapping=None,
            metabolite_id_mapping=None,
            gene_id_mapping=None,
            debug=False):
    """Convert an Escher map to the latest format using the COBRA model to update
    content. Returns a new map.

    Arguments
    ---------

    the_map: An Escher map loaded as a Python object (e.g. json.load('my_map.json')).

    model: A COBRA model.

    map_name: A name for the map. If a name is already present, this name
    overrides it.

    map_description: A description for the map. If a name is already present,
    this name overrides it.

    reaction_id_mapping: A dictionary with existing reaction IDs as keys and the
    new reaction IDs as values.

    metabolite_id_mapping: A dictionary with existing metabolite IDs as keys and the
    new metabolite IDs as values.

    gene_id_mapping: A dictionary with existing gene IDs as keys and the new
    gene IDs as values.

    debug: Check the map against the schema at some intermediate steps.

    """

    # make sure everything is up-to-date
    new_map = old_map_to_new_schema(the_map,
                                    map_name=map_name,
                                    map_description=map_description)
    if debug:
        validate_map(new_map)

    # apply the ids mappings
    apply_id_mappings(new_map, reaction_id_mapping, metabolite_id_mapping,
                      gene_id_mapping)
    if debug:
        validate_map(new_map)

    # apply the new model
    apply_cobra_model_to_map(new_map, model)

    validate_map(new_map)
    return new_map
def convert(the_map, model, map_name=None, map_description=None,
            reaction_id_mapping=None, metabolite_id_mapping=None,
            gene_id_mapping=None, debug=False):
    """Convert an Escher map to the latest format using the COBRA model to update
    content. Returns a new map.

    Arguments
    ---------

    the_map: An Escher map loaded as a Python object (e.g. json.load('my_map.json')).

    model: A COBRA model.

    map_name: A name for the map. If a name is already present, this name
    overrides it.

    map_description: A description for the map. If a name is already present,
    this name overrides it.

    reaction_id_mapping: A dictionary with existing reaction IDs as keys and the
    new reaction IDs as values.

    metabolite_id_mapping: A dictionary with existing metabolite IDs as keys and the
    new metabolite IDs as values.

    gene_id_mapping: A dictionary with existing gene IDs as keys and the new
    gene IDs as values.

    debug: Check the map against the schema at some intermediate steps.

    """

    # make sure everything is up-to-date
    new_map = old_map_to_new_schema(the_map, map_name=map_name,
                                    map_description=map_description)
    if debug:
        validate_map(new_map)

    # apply the ids mappings
    apply_id_mappings(new_map, reaction_id_mapping, metabolite_id_mapping,
                      gene_id_mapping)
    if debug:
        validate_map(new_map)

    # apply the new model
    apply_cobra_model_to_map(new_map, model)

    validate_map(new_map)
    return new_map
Exemple #3
0
def test_validate_map():
    the_map = [{ 'map_name': 'carbohydrate metabolism',
                 'map_id': 'h_sapiens_carb',
                 'map_description': 'A map of central carbon→ metabolism',
                 'homepage': 'https://escher.github.io',
                 'schema': 'https://escher.github.io/escher/jsonschema/1-0-0#'
             },
               { 'reactions': { '1': {'name': 'glyceraldehyde-3-phosphate dehydrogenase',
                                      'bigg_id': 'GAPD',
                                      'reversibility': True,
                                      'label_x': 0,
                                      'label_y': 0,
                                      'gene_reaction_rule': 'b1779',
                                      'genes': [{ 'bigg_id': 'b1779', 'name': 'gapA' }],
                                      'metabolites': [{ 'bigg_id': 'g3p_c', 'coefficient': -1 }],
                                      'segments': { '2': { 'from_node_id': '0',
                                                           'to_node_id': '1',
                                                           'b1': None,
                                                           'b2': None } } } },
                 'nodes': { '0': { 'node_type': 'metabolite',
                                   'x': 1,
                                   'y': 2,
                                   'bigg_id': 'g3p_c',
                                   'name': 'glyceraldehyde-3-phosphate cytosolic',
                                   'label_x': 3,
                                   'label_y': 3,
                                   'node_is_primary': True },
                            '1': { 'node_type': 'multimarker',
                                   'x': 10,
                                   'y': 12.3 } },
                 'text_labels': {},
                 'canvas': {'x': 1208.24,
                            'y':794.55,
                            'width':10402.35,
                            'height':13224.91}
             }] 
    validate_map(the_map)

    # missing node
    new_map = deepcopy(the_map)
    del new_map[1]['nodes']['1']
    with raises(Exception) as e:
        validate_map(new_map)
    print(e)
    assert 'No nodes for segments' in str(e.value)

    # zero coefficient
    new_map = deepcopy(the_map)
    new_map[1]['reactions']['1']['metabolites'][0]['coefficient'] = 0
    with raises(Exception) as e:
        validate_map(new_map)
    print(e)
    assert 'No non-zero stoichiometry for a connected metabolite node' in str(e.value)

    # # midmarker connected to metabolite
    # new_map = deepcopy(the_map)
    # new_map[1]['nodes']['1']['node_type'] = 'midmarker'
    # with raises(Exception) as e:
    #     validate_map(new_map)
    # print(e)
    # assert 'Segments connect midmarkers to metabolites' in str(e.value)

    # No gene name for gene in gene_reaction_rule
    new_map = deepcopy(the_map)
    del new_map[1]['reactions']['1']['genes'][0]['name']
    with raises(Exception) as e:
        validate_map(new_map)
    print(e)
    assert 'No gene name for gene in gene_reaction_rule' in str(e.value)
def convert(map, model):
    # check for new, 2-level maps
    has_head = isinstance(map, list) and len(map) == 2
    if has_head:
        map_body = map[1]
    else:
        map_body = map

    # add missing elements
    for k in ['nodes', 'reactions', 'text_labels']:
        if k not in map_body or len(map_body[k]) == 0:
            map_body[k] = {}
    # default canvas
    if 'canvas' not in map_body:
        map_body['canvas'] = { 'x': -1440,
                               'y': -775,
                               'width': 4320,
                               'height': 2325 }        
    
    # keep track of deleted nodes and reactions
    nodes_to_delete = set()
    reactions_to_delete = set()
    nodes_with_segments = set()

    # nodes
    for id, node in map_body['nodes'].items():
        # follow rules for type
        # metabolites
        if node['node_type'] == 'metabolite':
            # no bigg_id
            if not 'bigg_id' in node:
                print('No bigg_id for node %s. Deleting.' % id)
                nodes_to_delete.add(id)
                
            # unsupported attributes
            for key in list(node.keys()):
                if not key in ["node_type", "x", "y", "bigg_id", "name",
                               "label_x", "label_y", "node_is_primary"]:
                    del node[key]
                    
            # find the metabolite
            try:
                cobra_metabolite = model.metabolites.get_by_id(node['bigg_id'])
            except KeyError:
                print('Could not find metabolite %s in model. Deleting.' % node['bigg_id'])
                nodes_to_delete.add(id)
                continue
            # apply new display names
            node['name'] = cobra_metabolite.name

            # node_is_primary defaults to False
            if not 'node_is_primary' in node or node['node_is_primary'] not in [True, False]:
                node['node_is_primary'] = False
        # markers
        elif node['node_type'] in ['multimarker', 'midmarker']:
            # unsupported attributes
            for key in list(node.keys()):
                if not key in ["node_type", "x", "y"]:
                    del node[key]
        # invalid node_type
        else:
            nodes_to_delete.add(id)
        
    # update reactions
    for id, reaction in map_body['reactions'].items():
        # missing attributes
        will_delete = False
        for k in ["bigg_id", "segments", "label_x", "label_y"]:
            if not k in reaction:
                print('No %s for reaction %s. Deleting.' % (k, id))
                reactions_to_delete.add(id)
                will_delete = True
        if will_delete:
            continue

        # unsupported attributes
        for key in list(reaction.keys()):
            if not key in ["name", "bigg_id","reversibility",
                           "label_x", "label_y", "gene_reaction_rule",
                           "genes", "metabolites", "segments"]:
                del reaction[key]

        # cast attributes
        for k in ['label_x', 'label_y']:
            reaction[k] = float(reaction[k])

        # unsupported attributes in segments
        for s_id, segment in reaction['segments'].items():
            for key in list(segment.keys()):
                if not key in ["from_node_id", "to_node_id", "b1", "b2"]:
                    del segment[key]

            # cast attributes
            for k in ['b1', 'b2']:
                if segment[k] is not None and (segment[k]['x'] is None or segment[k]['y'] is None):
                    segment[k] = None

            # keep track of nodes that have appeared here
            for key in ['from_node_id', 'to_node_id']:
                try:
                    nodes_with_segments.add(segment[key])
                except KeyError:
                    pass

        # get reaction
        try:
            cobra_reaction = model.reactions.get_by_id(reaction['bigg_id'])
        except KeyError:
            print('Could not find reaction %s in model. Deleting.' % reaction['bigg_id'])
            reactions_to_delete.add(id)
            continue
        reaction['gene_reaction_rule'] = cobra_reaction.gene_reaction_rule
        reaction['reversibility'] = (cobra_reaction.lower_bound < 0 and cobra_reaction.upper_bound > 0)
        # reverse metabolites if reaction runs in reverse
        rev_mult = (-1 if
                    (cobra_reaction.lower_bound < 0 and cobra_reaction.upper_bound <= 0)
                    else 1)
        # use metabolites from reaction
        reaction['metabolites'] = [{'bigg_id': met.id, 'coefficient': coeff * rev_mult}
                                   for met, coeff in
                                   cobra_reaction.metabolites.items()]
            
        reaction['name'] = cobra_reaction.name

        reaction['genes'] = []
        for gene in genes_for_gene_reaction_rule(reaction['gene_reaction_rule']):
            try:
                cobra_gene = model.genes.get_by_id(gene)
            except KeyError:
                print('Could not find gene %s in model. Setting name to ID.')
                reaction['genes'].append({'bigg_id': gene, 'name': gene})
                continue
            reaction['genes'].append({'bigg_id': gene, 'name': cobra_gene.name})
        
        # remove any lost segments
        reaction['segments'] = {id: seg for id, seg in reaction['segments'].items()
                                if ((seg['to_node_id'] in map_body['nodes'] and seg['to_node_id'] not in nodes_to_delete) and
                                    (seg['from_node_id'] in map_body['nodes'] and seg['from_node_id'] not in nodes_to_delete))}

    # delete those reactions
    for reaction_id in reactions_to_delete:
        del map_body['reactions'][reaction_id]

    # delete those nodes
    for node_id in nodes_to_delete:
        del map_body['nodes'][node_id]

    # delete any nodes with no segment
    for node_id in list(map_body['nodes'].keys()):
        if node_id not in nodes_with_segments:
            # may not be there, if previously deleted
            try:
                del map_body['nodes'][node_id]
                print('No segments for node %s. Deleting' % node_id)
            except KeyError:
                pass
        
    # text labels
    for id, text_label in map_body['text_labels'].items():
        # unsupported attributes
        for key in list(text_label.keys()):
            if not key in ["x", "y", "text"]:
                del text_label[key]

    # canvas
    # unsupported attributes
    for key in list(map_body['canvas'].keys()):
        if not key in ["x", "y", "width", "height"]:
            del map_body['canvas'][key]

    # delete unsupported elements
    for key in list(map_body.keys()):
        if not key in ["nodes", "reactions", "text_labels", "canvas"]:
            del map_body[key]

    header = {
        "schema": "https://escher.github.io/escher/jsonschema/1-0-0#",
        "homepage": "https://escher.github.io",
        "map_name": "",
        "map_id": "",
        "map_description": ""
        }
    if has_head:
        for key, value in map[0].items():
            if key in ['schema', 'homepage']: continue
            header[key] = value
    
    the_map = [header, map_body]

    validate_map(the_map) 
    return the_map
def test_validate_map():
    the_map = [{ 'map_name': 'carbohydrate metabolism',
                 'map_id': 'h_sapiens_carb',
                 'map_description': 'A map of central carbon→ metabolism',
                 'homepage': 'https://escher.github.io',
                 'schema': 'https://escher.github.io/escher/jsonschema/1-0-0#'
             },
               { 'reactions': { '1': {'name': 'glyceraldehyde-3-phosphate dehydrogenase',
                                      'bigg_id': 'GAPD',
                                      'reversibility': True,
                                      'label_x': 0,
                                      'label_y': 0,
                                      'gene_reaction_rule': 'b1779',
                                      'genes': [{ 'bigg_id': 'b1779', 'name': 'gapA' }],
                                      'metabolites': [{ 'bigg_id': 'g3p_c', 'coefficient': -1 }],
                                      'segments': { '2': { 'from_node_id': '0',
                                                           'to_node_id': '1',
                                                           'b1': None,
                                                           'b2': None } } } },
                 'nodes': { '0': { 'node_type': 'metabolite',
                                   'x': 1,
                                   'y': 2,
                                   'bigg_id': 'g3p_c',
                                   'name': 'glyceraldehyde-3-phosphate cytosolic',
                                   'label_x': 3,
                                   'label_y': 3,
                                   'node_is_primary': True },
                            '1': { 'node_type': 'multimarker',
                                   'x': 10,
                                   'y': 12.3 } },
                 'text_labels': {},
                 'canvas': {'x': 1208.24,
                            'y':794.55,
                            'width':10402.35,
                            'height':13224.91}
             }]
    validate_map(the_map)

    # missing node
    new_map = deepcopy(the_map)
    del new_map[1]['nodes']['1']
    with raises(Exception) as e:
        validate_map(new_map)
    print(e)
    assert 'No nodes for segments' in str(e.value)

    # zero coefficient
    new_map = deepcopy(the_map)
    new_map[1]['reactions']['1']['metabolites'][0]['coefficient'] = 0
    with raises(Exception) as e:
        validate_map(new_map)
    print(e)
    assert 'No non-zero stoichiometry for a connected metabolite node' in str(e.value)

    # # midmarker connected to metabolite
    # new_map = deepcopy(the_map)
    # new_map[1]['nodes']['1']['node_type'] = 'midmarker'
    # with raises(Exception) as e:
    #     validate_map(new_map)
    # print(e)
    # assert 'Segments connect midmarkers to metabolites' in str(e.value)

    # No gene name for gene in gene_reaction_rule
    new_map = deepcopy(the_map)
    del new_map[1]['reactions']['1']['genes'][0]['name']
    with raises(Exception) as e:
        validate_map(new_map)
    print(e)
    assert 'No gene name for gene in gene_reaction_rule' in str(e.value)
Exemple #6
0
def convert(map, model):
    # check for new, 2-level maps
    has_head = isinstance(map, list) and len(map) == 2
    if has_head:
        map_body = map[1]
    else:
        map_body = map

    # add missing elements
    for k in ['nodes', 'reactions', 'text_labels']:
        if k not in map_body or len(map_body[k]) == 0:
            map_body[k] = {}
    # default canvas
    if 'canvas' not in map_body:
        map_body['canvas'] = {
            'x': -1440,
            'y': -775,
            'width': 4320,
            'height': 2325
        }

    # keep track of deleted nodes and reactions
    nodes_to_delete = set()
    reactions_to_delete = set()
    nodes_with_segments = set()

    # nodes
    for id, node in map_body['nodes'].items():
        # follow rules for type
        # metabolites
        if node['node_type'] == 'metabolite':
            # no bigg_id
            if not 'bigg_id' in node:
                print('No bigg_id for node %s. Deleting.' % id)
                nodes_to_delete.add(id)

            # unsupported attributes
            for key in list(node.keys()):
                if not key in [
                        "node_type", "x", "y", "bigg_id", "name", "label_x",
                        "label_y", "node_is_primary"
                ]:
                    del node[key]

            # find the metabolite
            try:
                cobra_metabolite = model.metabolites.get_by_id(node['bigg_id'])
            except KeyError:
                print('Could not find metabolite %s in model. Deleting.' %
                      node['bigg_id'])
                nodes_to_delete.add(id)
                continue
            # apply new display names
            node['name'] = cobra_metabolite.name

            # node_is_primary defaults to False
            if not 'node_is_primary' in node or node[
                    'node_is_primary'] not in [True, False]:
                node['node_is_primary'] = False
        # markers
        elif node['node_type'] in ['multimarker', 'midmarker']:
            # unsupported attributes
            for key in list(node.keys()):
                if not key in ["node_type", "x", "y"]:
                    del node[key]
        # invalid node_type
        else:
            nodes_to_delete.add(id)

    # update reactions
    for id, reaction in map_body['reactions'].items():
        # missing attributes
        will_delete = False
        for k in ["bigg_id", "segments", "label_x", "label_y"]:
            if not k in reaction:
                print('No %s for reaction %s. Deleting.' % (k, id))
                reactions_to_delete.add(id)
                will_delete = True
        if will_delete:
            continue

        # unsupported attributes
        for key in list(reaction.keys()):
            if not key in [
                    "name", "bigg_id", "reversibility", "label_x", "label_y",
                    "gene_reaction_rule", "genes", "metabolites", "segments"
            ]:
                del reaction[key]

        # cast attributes
        for k in ['label_x', 'label_y']:
            reaction[k] = float(reaction[k])

        # unsupported attributes in segments
        for s_id, segment in reaction['segments'].items():
            for key in list(segment.keys()):
                if not key in ["from_node_id", "to_node_id", "b1", "b2"]:
                    del segment[key]

            # cast attributes
            for k in ['b1', 'b2']:
                if segment[k] is not None and (segment[k]['x'] is None
                                               or segment[k]['y'] is None):
                    segment[k] = None

            # keep track of nodes that have appeared here
            for key in ['from_node_id', 'to_node_id']:
                try:
                    nodes_with_segments.add(segment[key])
                except KeyError:
                    pass

        # get reaction
        try:
            cobra_reaction = model.reactions.get_by_id(reaction['bigg_id'])
        except KeyError:
            print('Could not find reaction %s in model. Deleting.' %
                  reaction['bigg_id'])
            reactions_to_delete.add(id)
            continue
        reaction['gene_reaction_rule'] = cobra_reaction.gene_reaction_rule
        reaction['reversibility'] = (cobra_reaction.lower_bound < 0
                                     and cobra_reaction.upper_bound > 0)
        # reverse metabolites if reaction runs in reverse
        rev_mult = (-1 if (cobra_reaction.lower_bound < 0
                           and cobra_reaction.upper_bound <= 0) else 1)
        # use metabolites from reaction
        reaction['metabolites'] = [{
            'bigg_id': met.id,
            'coefficient': coeff * rev_mult
        } for met, coeff in cobra_reaction.metabolites.items()]

        reaction['name'] = cobra_reaction.name

        reaction['genes'] = []
        for gene in genes_for_gene_reaction_rule(
                reaction['gene_reaction_rule']):
            try:
                cobra_gene = model.genes.get_by_id(gene)
            except KeyError:
                print('Could not find gene %s in model. Setting name to ID.')
                reaction['genes'].append({'bigg_id': gene, 'name': gene})
                continue
            reaction['genes'].append({
                'bigg_id': gene,
                'name': cobra_gene.name
            })

        # remove any lost segments
        reaction['segments'] = {
            id: seg
            for id, seg in reaction['segments'].items()
            if ((seg['to_node_id'] in map_body['nodes']
                 and seg['to_node_id'] not in nodes_to_delete) and (
                     seg['from_node_id'] in map_body['nodes']
                     and seg['from_node_id'] not in nodes_to_delete))
        }

    # delete those reactions
    for reaction_id in reactions_to_delete:
        del map_body['reactions'][reaction_id]

    # delete those nodes
    for node_id in nodes_to_delete:
        del map_body['nodes'][node_id]

    # delete any nodes with no segment
    for node_id in list(map_body['nodes'].keys()):
        if node_id not in nodes_with_segments:
            # may not be there, if previously deleted
            try:
                del map_body['nodes'][node_id]
                print('No segments for node %s. Deleting' % node_id)
            except KeyError:
                pass

    # text labels
    for id, text_label in map_body['text_labels'].items():
        # unsupported attributes
        for key in list(text_label.keys()):
            if not key in ["x", "y", "text"]:
                del text_label[key]

    # canvas
    # unsupported attributes
    for key in list(map_body['canvas'].keys()):
        if not key in ["x", "y", "width", "height"]:
            del map_body['canvas'][key]

    # delete unsupported elements
    for key in list(map_body.keys()):
        if not key in ["nodes", "reactions", "text_labels", "canvas"]:
            del map_body[key]

    header = {
        "schema": "https://escher.github.io/escher/jsonschema/1-0-0#",
        "homepage": "https://escher.github.io",
        "map_name": "",
        "map_id": "",
        "map_description": ""
    }
    if has_head:
        for key, value in map[0].items():
            if key in ['schema', 'homepage']: continue
            header[key] = value

    the_map = [header, map_body]

    validate_map(the_map)
    return the_map