Skip to main content

Clean API for reading and writing the SBML Layout extension

Project description

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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sbmllayout-0.5.1.tar.gz (26.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sbmllayout-0.5.1-py3-none-any.whl (23.8 kB view details)

Uploaded Python 3

File details

Details for the file sbmllayout-0.5.1.tar.gz.

File metadata

  • Download URL: sbmllayout-0.5.1.tar.gz
  • Upload date:
  • Size: 26.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for sbmllayout-0.5.1.tar.gz
Algorithm Hash digest
SHA256 ddb9dc8355fd6a6dab29f1f7dd4701913797cca0186a58f5307c8122b30525f4
MD5 32110700771ce054a200f1dbd9615e25
BLAKE2b-256 273d907da84befd3a5a00779dc6fc7bbae014999c027380a4d01e37f48da55df

See more details on using hashes here.

File details

Details for the file sbmllayout-0.5.1-py3-none-any.whl.

File metadata

  • Download URL: sbmllayout-0.5.1-py3-none-any.whl
  • Upload date:
  • Size: 23.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for sbmllayout-0.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 66fb35d9144d6869c0ff1f9ddd6df80d87ad6da93f1f2088cfab37d3526865f1
MD5 292f818f2bc2ea2b880be4f8b68f0e1e
BLAKE2b-256 4c3f1f4fe407b9547895b6647c3d97cc36ce2f8cb8934cd1ec34dedbe5ba6e07

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page