Skip to main content

SBMLLayout

A clean Python API for attaching, editing, and rendering the SBML Layout extension.

Installation

pip install SBMLLayout

Why?

Existing tools (SBMLDiagrams, SBMLNetwork) are primarily visualisation tools that happen to expose a layout API as a side-effect. When you need to attach or manipulate layout geometry programmatically — especially with alias (repeated) species nodes or full bezier curves — you quickly hit undocumented requirements of the underlying libsbml Layout package. SBMLLayout takes care of all of that bookkeeping for you and includes its own skia-based renderer with full bezier support.

Quick start

import tellurium as te
from SBMLLayout import Layout

r = te.loada('''
    J1: S1 -> S2; k1*S1
    k1 = 0.1; S1 = 10; S2 = 0
''')

layout = Layout(r.getSBML())
layout.addNode('S1', x=100, y=150, w=60, h=40)
layout.addNode('S2', x=300, y=150, w=60, h=40)
layout.addReaction('J1', center=(200, 170),
                   reactants=['S1'], products=['S2'])

layout.draw()                        # display inline in Jupyter / IDE
layout.draw(output='network.png')    # save PNG  (scale=2 for high-DPI)
layout.draw(output='network.pdf')    # save PDF
layout.draw(output='network.svg')    # save SVG

Alias nodes

Species that appear more than once in a diagram (alias nodes) are supported as a first-class concept. Call addNode multiple times with the same species id and alias=True for each extra copy. Copy indices are assigned in call order (first call = copy 0, second = copy 1, …). Use 'A:1' syntax in reaction lists to route arms to a specific copy.

layout.addNode('A',  x=60,  y=200, w=50, h=40)             # prime  (copy 0)
layout.addNode('A',  x=280, y=300, w=50, h=40, alias=True)  # alias  (copy 1)

layout.addReaction('J1', center=(184, 205),
                   reactants=['S1'], products=['S2', 'A'])      # 'A' = copy 0
layout.addReaction('J2', center=(185, 346),
                   reactants=['S2', 'A:1'], products=['S3'])    # 'A:1' = copy 1

Bezier curves

Pass a handles list to addReaction to specify cubic bezier control points for each arm. Each entry is a pair of tuples ((BP1x, BP1y), (BP2x, BP2y)) where BP1 is near the species node and BP2 is near the junction. Use None for a straight-line arm.

# Bi-uni reaction: S1 + S2 -> S3 with curved reactant arms
layout.addReaction('J1',
    reactants=['S1', 'S2'],
    products=['S3'],
    center=(250, 203),
    handles=[
        ((210, 102), (240, 195)),  # S1 arm: (BP1, BP2)
        ((210, 302), (240, 211)),  # S2 arm: (BP1, BP2)
        None,                       # S3 arm: straight line
    ])

Direct reactions

For uni-uni reactions with no junction node, use direct=True. The line connects the reactant directly to the product with no junction circle.

# Straight direct line
layout.addReaction('J1', reactants=['S1'], products=['S2'], direct=True)

# Bezier direct curve
layout.addReaction('J1', reactants=['S1'], products=['S2'],
    direct=True,
    handles=[((160, 100), (240, 200))])  # single (BP1, BP2) pair

Compartments

layout.addCompartment('cell', x=10, y=10, w=500, h=400)

Method chaining

All add* and set* methods return self, so calls can be chained:

layout = (Layout(r.getSBML())
    .addNode('S1', x=100, y=150, w=60, h=40)
    .addNode('S2', x=300, y=150, w=60, h=40)
    .addReaction('J1', center=(200, 170),
                 reactants=['S1'], products=['S2'])
    .setReactionStyle('J1', color=(0, 100, 200, 255))
    .setNodeStyle('S1', fill=(220, 255, 220, 255)))
layout.draw()

Using the SBML with other tools

toSBML() returns a valid SBML Level 3 string that can be loaded into any tool supporting the SBML Layout package:

sbml = layout.toSBML()

# SBMLDiagrams
import SBMLDiagrams
df = SBMLDiagrams.load(sbml)
df.draw()

# Or save for use elsewhere
with open('model_with_layout.xml', 'w') as f:
    f.write(sbml)

Note that per-element style overrides set via setReactionStyle and setNodeStyle are stored on the Layout object and are used by layout.draw(). They are not written into the SBML and will not carry over if the SBML is loaded by another tool.

Global styling

Pass a Style instance to draw() to customise the appearance of the entire diagram. All colours are (R, G, B, A) tuples with values 0–255.

from SBMLLayout import Layout, Style

s = Style()
s.node_fill        = (200, 230, 255, 255)   # light blue fill
s.node_stroke      = (0,   80,  160, 255)   # dark blue border
s.reaction_stroke  = (50,  50,  50,  255)   # dark grey lines
s.node_gap         = 10.0                   # gap between node edge and line
s.junction_visible = False                  # hide junction circles

layout.draw(output='network.png', scale=2, style=s)

Full Style reference

Attribute Default Description
Canvas
background_color (255,255,255,255) Canvas background colour
margin 30.0 Padding around the network in pixels
Compartments
compartment_fill (240,240,255,180) Compartment fill colour
compartment_stroke (100,100,200,255) Compartment border colour
compartment_stroke_width 2.0 Compartment border width
compartment_corner_radius 8.0 Compartment rounded corner radius
Species nodes
node_fill (250,213,211,255) Node fill colour
node_stroke (130,37,31,255) Node border colour
node_stroke_width 2.0 Node border width
node_corner_radius 6.0 Node rounded corner radius
Labels
label_color (0,0,0,255) Text colour
label_font_size 14.0 Font size in points
label_font_family 'Arial' Font family name
Reaction lines
reaction_stroke (0,0,0,255) Reaction line colour
reaction_stroke_width 2.0 Reaction line width
node_gap 6.0 Gap between node edge and start/end of reaction arms. Set to 0.0 for lines that touch the node edge exactly. Applies uniformly to reactant and product ends on all reaction styles.
Junction circle
junction_fill (130,37,31,255) Junction circle fill colour
junction_radius 5.0 Junction circle radius
junction_visible True Whether to draw the junction circle
Arrowhead
arrow_fill (0,0,0,255) Arrowhead fill colour
arrow_length 12.0 Arrowhead length (tip to base) in pixels
arrow_width 7.0 Arrowhead width at base in pixels

Per-element styling

Individual reactions and nodes can be styled independently using setReactionStyle and setNodeStyle. These override the corresponding global Style values for the named element only.

# Highlight a specific reaction in red with a thicker line
layout.setReactionStyle('J4', color=(200, 0, 0, 255), stroke_width=3.0)

# Change just the colour of another reaction
layout.setReactionStyle('J1', color=(0, 100, 200, 255))

# Style a specific node
layout.setNodeStyle('E', fill=(255, 230, 200, 255), stroke=(180, 80, 0, 255))

# Style a node including its label colour
layout.setNodeStyle('A', fill=(220, 255, 220, 255), stroke=(0, 120, 0, 255),
                    label_color=(0, 80, 0, 255))

When a reaction colour is set via setReactionStyle, it applies to the reaction line, arrowhead, and junction circle together so everything stays visually consistent.

API reference

Layout(sbml_string)

Create a new layout for the given SBML Level 3 model string. Raises ValueError if the SBML is invalid or contains no model.

addNode(species_id, x, y, w=60, h=30, alias=False)

Add a species node. x, y are the top-left corner of the bounding box.

addReaction(reaction_id, reactants, products, center=None, handles=None, direct=False)

Add a reaction.

Parameter Description
reactants / products Lists of species refs. 'S1' = copy 0; 'A:1' = copy 1 of A.
center (x, y) junction point. Omit to let the renderer compute a default.
handles One ((BP1x,BP1y),(BP2x,BP2y)) pair per arm (reactants first, then products), or None for a straight arm. Omit entirely for all-straight lines.
direct If True, draw a single line/curve from reactant to product with no junction. For a direct bezier supply one handle pair.

addCompartment(compartment_id, x, y, w, h)

Add a compartment bounding box.

setReactionStyle(reaction_id, color=None, stroke_width=None)

Override the visual style for a single reaction. Returns self.

Parameter Description
reaction_id Must match a reaction id passed to addReaction.
color (R, G, B, A) tuple. Overrides the line, arrowhead, and junction circle colour for this reaction.
stroke_width Float. Overrides the line thickness for this reaction.

setNodeStyle(species_id, fill=None, stroke=None, stroke_width=None, label_color=None)

Override the visual style for a single species node. Applies to all copies (prime and aliases) of that species. Returns self.

Parameter Description
species_id Must match a species id passed to addNode.
fill (R, G, B, A) tuple. Overrides the node fill colour.
stroke (R, G, B, A) tuple. Overrides the node border colour.
stroke_width Float. Overrides the node border thickness.
label_color (R, G, B, A) tuple. Overrides the label text colour.

draw(output=None, scale=1.0, style=None)

Render the network. If output is omitted, displays inline (Jupyter / opens in default image viewer). Supported extensions: .png, .pdf, .svg. Per-element styles set via setReactionStyle and setNodeStyle are always applied regardless of whether a Style instance is passed.

toSBML()

Return a valid SBML Level 3 string with the Layout package embedded. Per-element styles are not included in the SBML output.

Compatibility

The SBML produced by toSBML() is compatible with:

Note on bezier curves and SBMLDiagrams

SBMLDiagrams does not read bezier curve data from the SBML Layout extension — it computes its own handle positions after loading. If you need bezier curves with SBMLDiagrams, use its setReactionBezierHandles API after SBMLDiagrams.load(). The SBMLLayout renderer reads and draws the full two-control-point cubic bezier data correctly.

Metadata

Release files for SBMLLayout 0.5.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for SBMLLayout 0.5.1
File Size Uploaded Provenance
sbmllayout-0.5.1.tar.gz 26.6 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for SBMLLayout 0.5.1
File Interpreter ABI Platform
sbmllayout-0.5.1-py3-none-any.whl Python 3 none any Details

Total release size: 50.4 kB

Release files / sbmllayout-0.5.1.tar.gz

Download URL sbmllayout-0.5.1.tar.gz
Size 26.6 kB
Tags Source
SHA-256 checksum
How to use checksums
ddb9dc8355fd6a6dab29f1f7dd4701913797cca0186a58f5307c8122b30525f4
BLAKE2b-256 checksum
How to use checksums
273d907da84befd3a5a00779dc6fc7bbae014999c027380a4d01e37f48da55df
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.10

Release files / sbmllayout-0.5.1-py3-none-any.whl

Download URL sbmllayout-0.5.1-py3-none-any.whl
Size 23.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
66fb35d9144d6869c0ff1f9ddd6df80d87ad6da93f1f2088cfab37d3526865f1
BLAKE2b-256 checksum
How to use checksums
4c3f1f4fe407b9547895b6647c3d97cc36ce2f8cb8934cd1ec34dedbe5ba6e07
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.10

Security for SBMLLayout 0.5.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page