Plotting#

This guide shows how to visualize CORNETO graphs, from basic plotting to configurable styling.

It covers:

  • plotting a graph directly

  • styling edges and vertices from numeric values

  • using presets for common workflows

  • customizing themes

  • exporting and interoperability (DOT, pydot, NetworkX)

  • browser-side rendering for notebook environments

import corneto as cn
from corneto.graph import Graph

cn.info()
Installed version:v1.0.0b7
Available backends:CVXPY v1.8.1, PICOS v2.6.2
Default backend (corneto.opt):CVXPY
Installed solvers:CVXOPT, GLPK, GLPK_MI, HIGHS, SCIP, SCIPY
Plot backend (default):auto -> graphviz
Available plot backends:graphviz v0.20.3; networkx v3.6.1+mpl v3.10.8; graphviz-wasm
Installed path:/home/runner/work/corneto/corneto/corneto
Repository:https://github.com/saezlab/corneto

1. Basic graph visualization#

Create a graph and visualize it directly.

G = Graph(name="toy")
G.add_edge("A", "B")
G.add_edge("B", "C")
G.add_edge("A", "C")

G.plot()
../../_images/a71025b976c1c752ee0a47efd73032cb7fbb263c0a57e58b823abfa6cf6ba41f.svg

2. Visual encoding from values#

Map signs and magnitudes to colors and line widths. This is useful for inspecting activities, scores, or inferred edge effects.

G.plot_values(
    edge_values=[-1, 2, 0],
    vertex_values=[1, -1, 0],
)
'digraph {\n  node [fixedsize="true"];\n  "A" [shape="circle", color="firebrick4", penwidth="2"];\n  "B" [shape="circle", color="dodgerblue4", penwidth="2"];\n  "B" [shape="circle", color="dodgerblue4", penwidth="2"];\n  "C" [shape="circle"];\n  "A" [shape="circle", color="firebrick4", penwidth="2"];\n  "C" [shape="circle"];\n  "A" -> "B" [arrowhead="normal", penwidth="5", color="dodgerblue4"];\n  "B" -> "C" [arrowhead="normal", penwidth="5", color="firebrick4"];\n  "A" -> "C" [arrowhead="normal", penwidth="0.25", color="black"];\n}'

You can also focus on a subset of edges.

G.plot_values(edge_values=[-1, 2, 0], edge_indexes=[0, 1])
'digraph {\n  node [fixedsize="true"];\n  "A" [shape="circle"];\n  "B" [shape="circle"];\n  "B" [shape="circle"];\n  "C" [shape="circle"];\n  "A" -> "B" [arrowhead="normal", penwidth="5", color="dodgerblue4"];\n  "B" -> "C" [arrowhead="normal", penwidth="5", color="firebrick4"];\n}'

3. Presets for common workflows#

Presets provide sensible styling defaults with minimal code.

G.plot(
    preset="default",
    data={
        "edge_values": [-1.5, 2.0, 0.1],
        "vertex_values": [1.0, -0.5, 0.0],
    },
)
../../_images/7ec406deaf637802f12450f7b2faf382fd95ba4c6537b69f0e05a2c43a8f03af.svg

Metabolic flux visualization#

For metabolic models, metabolism rescales flux values and highlights sign and magnitude.

G_flux = Graph(name="flux-demo")
G_flux.add_edge("Glucose", "Pyruvate")
G_flux.add_edge("Pyruvate", "Lactate")
G_flux.add_edge("Pyruvate", "Acetyl-CoA")

G_flux.plot(
    preset="metabolism",
    data={
        "edge_values": [20.0, -0.2, 3.0],
        "scale": "log",
        "clip_quantil": 0.05,
    },
)
../../_images/088bfb045c963e355755df8ebfe88beb54f0dc9919b889c63ddde47923a491d8.svg

Method-aware presets and role styling#

Some presets can apply role-aware node styling when role metadata is available (for example from feature_data). This keeps the plotting API generic while allowing method-specific defaults.

As one concrete case, preset="signaling" uses defaults such as:

  • input (e.g. receptors): triangle

  • output (e.g. TFs): diamond

  • internal nodes: circle

You can still override styles explicitly via role_styles or custom_vertex_attr.

# Example: signaling preset with role metadata + custom solution variable names
G_sig = Graph(name="signaling-demo")
G_sig.add_edge("TGFBR1", "AKT1")
G_sig.add_edge("AKT1", "STAT3")

D_sig = cn.Data.from_cdict(
    {
        "sample1": {
            "TGFBR1": {"mapping": "vertex", "role": "input", "value": 1.0},
            "STAT3": {"mapping": "vertex", "role": "output", "value": -1.0},
        }
    }
)

G_sig.plot(
    preset="signaling",
    feature_data=D_sig,
    solution={"v": [1.0, 0.0, -1.0], "e": [1.0, -1.0]},
    solution_map={"vertex": "v", "edge": "e"},
)
../../_images/d24b0e0637efc4a413e8b7b31d03c52fd49f3cf185185d7808935c5b79150536.svg

4. Theme customization#

Override theme values to adapt colors and widths to your preferred visual style.

G.plot(
    processor="sign_magnitude",
    theme={
        "positive_color": "darkgreen",
        "negative_color": "darkorange",
        "zero_color": "gray40",
        "min_edge_width": 0.5,
        "max_edge_width": 6.0,
    },
    data={"edge_values": [-1.5, 2.0, 0.0]},
)
../../_images/ad9366cee517e9a84d286ebfa74c221cb1a799c18c3ed012f542fa3007e54bce.svg

5. Export and interoperability#

Export DOT text or backend objects for integration with other tools.

dot_source = G.to_dot()
print(type(dot_source), dot_source.splitlines()[0])

G_pydot = G.to_dot(backend="pydot")
print(type(G_pydot))

G_graphviz = G.to_graphviz()
print(type(G_graphviz))
<class 'str'> digraph {
<class 'pydot.core.Dot'>
<class 'graphviz.graphs.Digraph'>
from IPython.display import SVG, display

display(SVG(G_pydot.create_svg()))
../../_images/9ba490fae7c423f1ccab81b75a297f8df8acd35150e95a3a13c78c51d5d4e018.svg
import matplotlib.pyplot as plt
import networkx as nx
from networkx.drawing.nx_pydot import from_pydot, graphviz_layout

G_nx = from_pydot(G.to_dot(backend="pydot"))
pos = graphviz_layout(G_nx, prog="neato")

plt.figure(figsize=(4, 3))
nx.draw(
    G_nx,
    pos,
    with_labels=True,
    arrows=True,
    node_color="lightblue",
    edge_color="gray",
    node_size=700,
    font_size=10,
)
plt.show()
../../_images/224a0951bf4415e20683a0f22b1b6d741c2f5f8a0dbb214d9ccf8a4fe4609c74.png

6. Browser/WASM rendering#

Use renderer="wasm" in browser-based notebook environments (e.g. marimo or Pyodide) where local Graphviz dot may be unavailable.

G.plot(renderer="wasm")

7. Custom processors#

A processor is a callable: processor(graph, data, theme) -> (edge_attrs, vertex_attrs).

Use a custom processor when styling needs to follow domain-specific rules.

def highlight_path_processor(graph, data, theme):
    path_edges = set(data.get("path_edges", []))
    edge_attrs = {}
    for i in range(graph.num_edges):
        if i in path_edges:
            edge_attrs[i] = {"color": "purple", "penwidth": "5"}
        else:
            edge_attrs[i] = {
                "color": theme.get("zero_color", "black"),
                "penwidth": "1",
            }
    return edge_attrs, {}


G.plot(
    processor=highlight_path_processor,
    theme={"zero_color": "lightgray"},
    data={"path_edges": [0, 1]},
)
../../_images/58fd68e564750d094b60fa51097c5666365c0fdcd7e17a20abb991d2e90e543a.svg