Using custom networks#

In addition to using the mantra database as a basis for enrichment analysis, it is also possible to use self-generated networks. The only restriction for these networks is that they need to have the same node- and edge-types annotated with attributes named ‘node_type’ and ‘edge_type’.

We recommend to also set the additional attributes for compatibility with the provided plotting functions:

  • reaction: Formula, Description

  • metabolite: Name

  • organism: nodeLabel

  • gene: nodeLabel

The following names are currently used:

  • nodes
    • reaction

    • metabolite

    • organism

    • gene

  • edges
    • SUBSTRATE (metabolite - reaction)

    • PRODUCT (reaction - metabolite)

    • REACTION_ORGANISM (reaction - organism)

    • REACTION_GENE (reaction - gene)

We start with a set of metabolite and reaction nodes (and optionally organism and gene nodes) and edges.

 1import networkx as nx
 2import matplotlib.pyplot as plt
 3
 4from pymantra.statics import EDGE_BY_NODE_TYPE
 5from pymantra.database import reduce_reaction_nodes
 6from pymantra.plotting import plot_directed_graph
 7
 8metabolite_nodes = {f"m{i}" for i in range(6)}
 9reaction_nodes = {f"r{i}" for i in range(3)}
10organism_nodes = {f"o{i}" for i in range(4)}
11
12edges = {
13    # metabolite - reaction/ reaction - metabolite edges
14    ("m0", "r0"), ("r0", "m1"), ("r0", "m2"),
15    ("m1", "r1"), ("r1", "m3"), ("r1", "m4"),
16    ("m2", "r2"), ("r2", "m5"),
17    # organism - reaction edges
18    ("o0", "r0"), ("o1", "r0"),
19    ("o0", "r1"), ("o2", "r1"), ("o3", "r1"),
20    ("o1", "r2"), ("o2", "r2"), ("o3", "r2")
21}

The first step is to add the nodes with the required ‘node_type’ attribute.

23graph = nx.DiGraph()
24
25for node in metabolite_nodes:
26    graph.add_node(node, node_type="metabolite")
27for node in reaction_nodes:
28    graph.add_node(node, node_type="reaction")
29for node in organism_nodes:
30    graph.add_node(node, node_type="organism")

Subsequently, the edges can be added and the edge type can directly be inferred using the static variable EDGE_BY_NODE_TYPE, which is a dictionary, where the keys are 2-tuples of source and target node types.

To avoid having multiple reactions with the same substrates and products (these will always get the same reaction activity change), we use the reduce_reaction_nodes function.

32for src, tgt in edges:
33    src_type = graph.nodes[src]["node_type"]
34    tgt_type = graph.nodes[tgt]["node_type"]
35    graph.add_edge(
36        src, tgt, edge_type=EDGE_BY_NODE_TYPE[(src_type, tgt_type)])
37
38graph = reduce_reaction_nodes(graph)

Finally, we can plot the generated graph. This is also a partial sanity check, if node colours and shapes need to match the match the ones in the legend.

31
32for src, tgt in edges:

The graph can then be used to compute reaction models and multi-omics associations and to run a local search as in Finding dysregulated metabolic reactions and Reaction-based Metabolome-Microbiome Integration. The only requirement is of course that the metabolite, organsim and gene names match between graph and data.

Full Example Code#

 1import networkx as nx
 2import matplotlib.pyplot as plt
 3
 4from pymantra.statics import EDGE_BY_NODE_TYPE
 5from pymantra.database import reduce_reaction_nodes
 6from pymantra.plotting import plot_directed_graph
 7
 8metabolite_nodes = {f"m{i}" for i in range(6)}
 9reaction_nodes = {f"r{i}" for i in range(3)}
10organism_nodes = {f"o{i}" for i in range(4)}
11
12edges = {
13    # metabolite - reaction/ reaction - metabolite edges
14    ("m0", "r0"), ("r0", "m1"), ("r0", "m2"),
15    ("m1", "r1"), ("r1", "m3"), ("r1", "m4"),
16    ("m2", "r2"), ("r2", "m5"),
17    # organism - reaction edges
18    ("o0", "r0"), ("o1", "r0"),
19    ("o0", "r1"), ("o2", "r1"), ("o3", "r1"),
20    ("o1", "r2"), ("o2", "r2"), ("o3", "r2")
21}
22
23graph = nx.DiGraph()
24
25for node in metabolite_nodes:
26    graph.add_node(node, node_type="metabolite")
27for node in reaction_nodes:
28    graph.add_node(node, node_type="reaction")
29for node in organism_nodes:
30    graph.add_node(node, node_type="organism")
31
32for src, tgt in edges:
33    src_type = graph.nodes[src]["node_type"]
34    tgt_type = graph.nodes[tgt]["node_type"]
35    graph.add_edge(
36        src, tgt, edge_type=EDGE_BY_NODE_TYPE[(src_type, tgt_type)])
37
38graph = reduce_reaction_nodes(graph)
39
40plot_directed_graph(graph)
41plt.show()