9. Network Visualization

This notebook demonstrates how to view MASSpy models on network maps using the Escher visualization tool [KDragerE+15].

The Escher package must already be installed into the environment. To install Escher:

pip install escher>=1.7

9.1. Viewing Models with Escher

The MASSpy package also comes with some example maps.

[1]:
from os.path import join

import numpy as np

import mass
import mass.example_data

# Load the glycolysis and hemoglobin models, then merge them
glycolysis = mass.example_data.create_example_model("Glycolysis")
hemoglobin = mass.example_data.create_example_model("Hemoglobin")
model = glycolysis.merge(hemoglobin, inplace=False)

# Set the path to the map file
map_filepath = join(mass.example_data.MAPS_DIR, "RBC.glycolysis.map.json")

# To view the list of available maps, remove the semicolon
mass.example_data.view_example_maps();
Set parameter Username

The primary object for viewing Escher maps is the escher.Builder, a Jupyter widget that can be viewed in a Jupyter notebook.

[2]:
import escher
from escher import Builder

# Turns off the warning message when leaving or refreshing this page.
# The default setting is False to help avoid losing work.
escher.rc['never_ask_before_quit'] = True

To load an existing map, the path to the JSON file of the Escher map is provided to the map_json argument of the Builder. The MassModel can be loaded using the model argument.

[3]:
escher_builder = Builder(
    model=model,
    map_json=map_filepath)

escher_builder

9.2. Mapping Data onto Escher

9.2.1. Viewing Reaction Data

Reaction data can be displayed on the Escher map using a dictionary that contains reaction identifiers, and values to map onto reaction arrows. The dict can be provided to the reaction_data argument upon initialization of the builder.

For example, to display the steady state fluxes on the map:

[4]:
initial_flux_data = {
    reaction.id: flux
    for reaction, flux in model.steady_state_fluxes.items()}

# New instance to prevent modifications to the existing maps
escher_builder = Builder(
    model=model,
    map_json=map_filepath,
    reaction_data=initial_flux_data)

# Display map in notebook
escher_builder

The color and size of the data scale can be altered by providing a tuple of at least two dictionaries. Each dictionary is considered a “stop” that defines the color and size at or near that particular value in the data set. The type key defines the type for the stop, the color key defines the color of the arrow, and the size key defines the thickness of the arrow.

[5]:
# New instance to prevent modifications to the existing maps
escher_builder = Builder(
    model=model,
    map_json=map_filepath,
    reaction_data=initial_flux_data,
    reaction_scale=(
        {"type": 'min', "color": 'green', "size": 5 },
        {"type": 'value', "value": 1.12, "color": 'purple', "size": 10},
        {"type": 'max', "color": 'blue', "size": 15 }),
)

# Display map in notebook
escher_builder

9.2.2. Viewing Metabolite Data

Metabolite data also can be displayed on an Escher map by using a dictionary containing metabolite identifiers, and values to map onto metabolite nodes. In addition to setting the attributes to apply upon initializing the builder, the attributes also can be set for a map after initialization.

For example, to display metabolite concentrations on the map:

[6]:
initial_conc_data = {
    metabolite.id: round(conc, 8)
    for metabolite, conc in model.initial_conditions.items()}

# New instance to prevent modifications to the existing maps
escher_builder = Builder(
    model=model,
    map_json=map_filepath,
    metabolite_data=initial_conc_data)

# Display map in notebook
escher_builder

The secondary metabolites can be removed by setting hide_secondary_metabolites as True to provide a cleaner visualization of the primary metabolites in the network.

[7]:
escher_builder.hide_secondary_metabolites = True

Note that changes made affect the already displayed map. Here, a preset scale is applied to the metabolite concentrations.

[8]:
escher_builder.metabolite_scale_preset = "RdYlBu"

9.2.3. Visualizing SBML models with Escher in Python

Suppose that we would like to visualize our SBML model on a network map as follows: 1. We would like to create this map with the Escher web-based API. 2. We would like to view the model on the network map within in a Jupyter notebook using the Escher Python-based API. 3. We would like to display the value of forward rate constants for each reaction on the network map.

The JSON format is the preferred format for Escher to load models onto network maps (read more here). Therefore, we must convert models between SBML and JSON formats to achieve our goal.

Note: The models and maps used in the following example are also available in the example data.

[9]:
import mass.io

Fortunately, the mass.io submodule is capable of exporting such models.

First the SBML model is loaded using the mass.io.sbml submodule. The model is then exported to a JSON format using the mass.io.json submodule for use in the Escher web-based API.

[10]:
# Define path to SBML model
path_to_sbml_model = join(mass.example_data.MODELS_DIR, "Simple_Toy.xml")

# Load SBML model
model = mass.io.sbml.read_sbml_model(path_to_sbml_model)

# Export as JSON
path_to_json_model = "./Simple_Toy.json"
mass.io.json.save_json_model(model, filename=path_to_json_model)

Suppose that we have now created our map using the Escher web-based API and saved it as the file “simple_toy_map.json”. To display the map with the model:

[11]:
# Define path to Escher map
path_to_map = join(mass.example_data.MAPS_DIR, "simple_toy_map.json")
escher_builder = Builder(
    model_json=path_to_json_model,
    map_json=path_to_map)
escher_builder

Finally the forward rate constant data from the MassModel object is added to the map:

[12]:
escher_builder.reaction_data = dict(zip(
    model.reactions.list_attr("id"),
    model.reactions.list_attr("forward_rate_constant")
))

9.3. Additional Examples

For additional information and examples on how to visualize networks and MASSpy models using Escher, see the following:

Due to versioning compatibility issues, it is possible that Jinja2==3.1.2 must be installed. See issue