| name | bio-systems-biology-network-visualization |
| description | Visualize metabolic networks and overlay flux data onto pathway maps using Escher, Cytoscape, KEGG API, and NetworkX. Use when: user wants to draw a metabolic pathway, create a flux map from FBA results, visualize network topology, or generate publication-ready pathway figures. Triggers: visualize pathway, flux map, Escher, metabolic network diagram, Cytoscape metabolic, KEGG pathway coloring, network visualization, pathway drawing, metabolic map, overlay fluxes, reaction graph, publication figure pathway. |
| tool_type | python |
| primary_tool | escher |
Version Compatibility
Reference examples tested with: escher 1.7+, py4cytoscape 1.9+, networkx 3.1+
Before using code patterns, verify installed versions match. If versions differ:
- Python:
pip show <package> then help(module.function) to check signatures
If code throws ImportError, AttributeError, or TypeError, introspect the installed
package and adapt the example to match the actual API rather than retrying.
Metabolic Network Visualization
"Visualize metabolic fluxes on pathway maps" -> Render genome-scale flux distributions on interactive pathway maps with Escher, automate Cytoscape network layouts, color KEGG pathways by expression or flux, and build custom metabolic networks with NetworkX.
- Python:
escher.Builder() for pathway maps, py4cytoscape for Cytoscape automation, networkx for graph analysis
Installation
pip install escher py4cytoscape networkx matplotlib requests pandas
pip install jupyterlab
jupyter labextension install @jupyter-widgets/jupyterlab-manager
Escher: Interactive Pathway Maps with Flux Overlay
Goal: Display FBA flux results on a metabolic pathway map in Jupyter.
Approach: Load a COBRApy model, run FBA, then pass the flux dictionary to Escher's Builder to render an interactive SVG map with reaction arrows scaled by flux magnitude.
import escher
import cobra
model = cobra.io.load_model("textbook")
solution = model.optimize()
flux_data = {rxn.id: solution.fluxes[rxn.id] for rxn in model.reactions}
builder = escher.Builder(
map_name="e_coli_core.Core metabolism",
model=model,
reaction_data=flux_data,
reaction_scale=[
{"type": "min", "color": "#2166ac", "size": 4},
{"type": "value", "value": 0, "color": "#f7f7f7", "size": 8},
{"type": "max", "color": "#b2182b", "size": 20},
],
reaction_styles=["color", "size", "text"],
identifiers_on_map="bigg_id",
)
builder.display_in_notebook()
Escher: Metabolite Concentration Overlay
Goal: Map metabolomics measurements onto pathway nodes.
Approach: Provide a metabolite-level dictionary to Escher's Builder to color and size metabolite nodes by measured concentration.
import escher
metabolite_data = {
"glc__D_c": 5.2,
"g6p_c": 0.8,
"f6p_c": 0.3,
"fdp_c": 1.5,
"pyr_c": 0.9,
"lac__D_c": 2.1,
"atp_c": 4.8,
"adp_c": 1.2,
}
builder = escher.Builder(
map_name="e_coli_core.Core metabolism",
metabolite_data=metabolite_data,
metabolite_styles=["color", "size", "text"],
metabolite_scale=[
{"type": "min", "color": "#ffffcc", "size": 10},
{"type": "median", "color": "#fd8d3c", "size": 20},
{"type": "max", "color": "#800026", "size": 30},
],
)
builder.display_in_notebook()
Escher: Export Publication Figures
Goal: Save Escher maps as static images for manuscripts.
Approach: Escher is primarily a JavaScript visualization tool with a Python wrapper
for Jupyter. It can export to standalone HTML; for static SVG/PNG, use the browser-based
export menu or take a screenshot approach.
import escher
import cobra
model = cobra.io.load_model("textbook")
solution = model.optimize()
flux_data = {rxn.id: solution.fluxes[rxn.id] for rxn in model.reactions}
builder = escher.Builder(
map_name="e_coli_core.Core metabolism",
reaction_data=flux_data,
reaction_styles=["color", "size"],
)
builder.save_html("flux_map.html")
py4cytoscape: Automated Network Analysis
Goal: Build and style metabolic networks in Cytoscape programmatically.
Approach: Create a network from reaction-metabolite edges, apply layout algorithms, and map data to visual properties via py4cytoscape.
import py4cytoscape as p4c
import pandas as pd
p4c.cytoscape_version_info()
nodes = pd.DataFrame({
"id": ["Glucose", "G6P", "F6P", "FBP", "G3P", "Pyruvate",
"Acetyl-CoA", "Lactate", "Citrate"],
"type": ["substrate", "intermediate", "intermediate", "intermediate",
"intermediate", "hub", "hub", "product", "TCA"],
})
edges = pd.DataFrame([
{"source": "Glucose", "target": "G6P", "interaction": "HK", "flux": 8.2},
{"source": "G6P", "target": "F6P", "interaction": "PGI", "flux": 4.9},
{"source": "F6P", "target": "FBP", "interaction": "PFK", "flux": 7.5},
{"source": "FBP", "target": "G3P", "interaction": "FBA", "flux": 7.5},
{"source": "G3P", "target": "Pyruvate", "interaction": "Lower glycolysis", "flux": 15.0},
{"source": "Pyruvate", "target": "Acetyl-CoA", "interaction": "PDH", "flux": 9.3},
{"source": "Pyruvate", "target": "Lactate", "interaction": "LDH", "flux": 5.1},
{"source": "Acetyl-CoA", "target": "Citrate", "interaction": "CS", "flux": 6.0},
])
p4c.create_network_from_data_frames(
nodes=nodes,
edges=edges,
title="Glycolysis_TCA",
collection="Metabolic Networks",
)
p4c.layout_network("force-directed")
style_name = "MetabolicFlux"
p4c.create_visual_style(style_name)
p4c.set_visual_style(style_name)
p4c.set_edge_line_width_mapping(
table_column="flux",
table_column_values=[0, 5, 15],
widths=[1, 4, 10],
mapping_type="c",
style_name=style_name,
)
p4c.set_edge_color_mapping(
table_column="flux",
table_column_values=[0, 7.5, 15],
colors=["#2166ac", "#f7f7f7", "#b2182b"],
mapping_type="c",
style_name=style_name,
)
p4c.set_node_shape_default("ELLIPSE", style_name=style_name)
p4c.set_node_color_default("#66c2a5", style_name=style_name)
p4c.set_node_label_mapping(table_column="name", style_name=style_name)
p4c.export_image("metabolic_network.png", type="PNG", zoom=300)
p4c.export_image("metabolic_network.svg", type="SVG")
p4c.save_session("metabolic_network.cys")
KEGG Pathway Coloring
Goal: Color KEGG pathway diagrams by measured metabolite levels or gene expression.
Approach: Use the KEGG REST API to retrieve pathway images with user-specified coloring of enzymes and compounds.
import requests
from urllib.parse import urlencode
def color_kegg_pathway(pathway_id, gene_colors=None, compound_colors=None):
"""Color a KEGG pathway map via the KEGG API."""
color_entries = []
for src in [gene_colors, compound_colors]:
if src:
color_entries.extend(f"{k} {v}" for k, v in src.items())
params = {"map": pathway_id, "multi_query": "\n".join(color_entries)}
response = requests.get("https://www.kegg.jp/kegg-bin/show_pathway", params=params)
return response.url
gene_colors = {
"hsa:2645": "#ff0000",
"hsa:5213": "#ff6666",
"hsa:5315": "#6666ff",
}
compound_colors = {
"C00031": "#ff9900",
"C00022": "#0099ff",
}
colored_url = color_kegg_pathway("hsa00010", gene_colors, compound_colors)
print(f"Colored pathway: {colored_url}")
KEGG Pathway Retrieval
Goal: Programmatically fetch KEGG pathway membership for metabolites and genes.
Approach: Query the KEGG REST API to retrieve pathway-compound and pathway-gene linkages.
import requests
def get_kegg_pathways_for_compound(compound_id):
"""Get all pathways containing a KEGG compound."""
url = f"https://rest.kegg.jp/link/pathway/{compound_id}"
resp = requests.get(url)
pathways = []
for line in resp.text.strip().split("\n"):
if line:
parts = line.split("\t")
pathways.append(parts[1].replace("path:", ""))
return pathways
def get_pathway_compounds(pathway_id):
"""Get all compounds in a KEGG pathway."""
url = f"https://rest.kegg.jp/link/compound/{pathway_id}"
resp = requests.get(url)
compounds = []
for line in resp.text.strip().split("\n"):
if line:
parts = line.split("\t")
compounds.append(parts[1].replace("cpd:", ""))
return compounds
pyruvate_pathways = get_kegg_pathways_for_compound("cpd:C00022")
print(f"Pyruvate in {len(pyruvate_pathways)} pathways: {pyruvate_pathways[:5]}")
glycolysis_compounds = get_pathway_compounds("path:hsa00010")
print(f"Glycolysis compounds: {glycolysis_compounds}")
NetworkX: Custom Metabolic Networks
Goal: Build and analyze metabolic network topology (degree distribution, hubs, shortest paths).
Approach: Construct a bipartite graph of reactions and metabolites from a COBRA model, compute centrality metrics, and render with matplotlib.
import networkx as nx
import cobra
import matplotlib.pyplot as plt
import numpy as np
def build_metabolic_graph(model):
"""Build a metabolite-centric directed graph from a COBRA model."""
graph = nx.DiGraph()
for rxn in model.reactions:
substrates = [m.id for m in rxn.reactants]
products = [m.id for m in rxn.products]
for s in substrates:
for p in products:
graph.add_edge(s, p, reaction=rxn.id)
if rxn.reversibility:
for p in products:
graph.add_edge(p, s, reaction=rxn.id)
return graph
model = cobra.io.load_model("textbook")
graph = build_metabolic_graph(model)
currency = ["h_c", "h2o_c", "atp_c", "adp_c", "nad_c", "nadh_c",
"pi_c", "h_e", "h2o_e", "coa_c"]
graph.remove_nodes_from([n for n in currency if n in graph])
degree_cent = nx.degree_centrality(graph)
betweenness = nx.betweenness_centrality(graph)
top_hubs = sorted(degree_cent.items(), key=lambda x: x[1], reverse=True)[:10]
for met, score in top_hubs:
print(f" {met}: degree={score:.3f}, betweenness={betweenness.get(met, 0):.3f}")
solution = model.optimize()
flux_dict = {rxn.id: solution.fluxes[rxn.id] for rxn in model.reactions}
edge_colors = [flux_dict.get(d["reaction"], 0) for _, _, d in graph.edges(data=True)]
pos = nx.spring_layout(graph, k=2, seed=42)
node_sizes = [300 * degree_cent.get(n, 0.01) + 50 for n in graph.nodes()]
plt.rcParams.update({"font.family": "Arial", "font.size": 10})
fig, ax = plt.subplots(figsize=(16, 12))
nx.draw_networkx_nodes(graph, pos, node_size=node_sizes, node_color="#66c2a5",
alpha=0.8, ax=ax)
nx.draw_networkx_edges(graph, pos, edge_color=edge_colors,
edge_cmap=plt.cm.RdBu_r, width=1.5, alpha=0.6, ax=ax)
nx.draw_networkx_labels(graph, pos, font_size=8, ax=ax)
sm = plt.cm.ScalarMappable(cmap=plt.cm.RdBu_r,
norm=plt.Normalize(vmin=min(edge_colors),
vmax=max(edge_colors)))
sm.set_array([])
plt.colorbar(sm, ax=ax, label="Flux (mmol/gDW/h)")
ax.set_title("E. coli Core Metabolic Network with FBA Fluxes")
ax.axis("off")
plt.savefig("metabolic_network_flux.png", dpi=300, bbox_inches="tight")
plt.close()
Differential Flux Visualization
Goal: Compare flux distributions between two conditions and highlight changes on the pathway map.
Approach: Compute flux differences (condition B minus condition A), then pass the delta dictionary to Escher for diverging color scale visualization.
import escher
import cobra
model = cobra.io.load_model("textbook")
with model:
sol_aerobic = model.optimize()
flux_aerobic = {r.id: sol_aerobic.fluxes[r.id] for r in model.reactions}
with model:
model.reactions.get_by_id("EX_o2_e").lower_bound = 0
sol_anaerobic = model.optimize()
flux_anaerobic = {r.id: sol_anaerobic.fluxes[r.id] for r in model.reactions}
flux_diff = {rxn_id: flux_anaerobic.get(rxn_id, 0) - flux_aerobic.get(rxn_id, 0)
for rxn_id in flux_aerobic.keys() | flux_anaerobic.keys()}
builder = escher.Builder(
map_name="e_coli_core.Core metabolism",
model=model,
reaction_data=flux_diff,
reaction_scale=[
{"type": "min", "color": "#2166ac", "size": 15},
{"type": "value", "value": 0, "color": "#f7f7f7", "size": 5},
{"type": "max", "color": "#b2182b", "size": 15},
],
reaction_styles=["color", "size", "text"],
)
builder.save_html("flux_diff_aerobic_vs_anaerobic.html")
Best Practices
- Remove currency metabolites (H2O, H+, ATP, NAD+) from network graphs to reduce visual clutter
- Use diverging color scales (blue-white-red) for flux data centered on zero
- For large networks (>500 nodes), use Cytoscape instead of matplotlib for interactive exploration
- Always include a color scale legend in exported figures
- Use Escher's built-in maps (available at https://escher.github.io) before creating custom maps
- When overlaying multiple data types, use separate visual channels (color for flux, size for confidence)
- Publication figures: export as SVG then edit in Inkscape/Illustrator for final polish
- Use 300 DPI minimum for raster exports (600 DPI for line art)
- Font sizes: 8-12pt for labels, 10-14pt for axis titles
- Use colorblind-safe palettes (e.g., viridis, RdBu from ColorBrewer)
- Set
plt.rcParams["font.family"] = "Arial" for journal compatibility
- Avoid thin hairline strokes that disappear in print
Related Skills
- systems-biology/flux-balance-analysis - Generate flux data for overlay
- metabolomics-analysis/pathway-mapping - Map metabolites to pathways
- pathway-analysis/bioservices - Query pathway databases