# SBMLLayout

A clean Python API for reading and writing the [SBML Layout extension](https://sbml.org/documents/specifications/level-3/version-1/layout/).

## Installation

```bash
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 — you quickly hit undocumented requirements of the underlying
libsbml Layout package. SBMLLayout takes care of all of that bookkeeping for you.

## Quick start

```python
import tellurium as te
import SBMLLayout as sl

r = te.loada('''
    J1: S1 -> S2 + A; k1*S1
    J2: S2 + A -> S3; k2*S2*A
    k1 = 0.1; k2 = 0.2
''')

layout = sl.Layout(r.getSBML())

# Species nodes
layout.addNode('S1', x=160, y=100, w=50, h=45)
layout.addNode('S2', x=160, y=250, w=50, h=45)
layout.addNode('S3', x=160, y=390, w=50, h=45)
layout.addNode('A',  x=60,  y=200, w=50, h=40)            # prime copy
layout.addNode('A',  x=280, y=300, w=50, h=40, alias=True) # alias copy

# Reactions — use 'A:1' to route J2 to the alias copy
layout.addReaction('J1', center=(184, 205),
                   reactants=['S1'],
                   products=['S2', 'A'])

layout.addReaction('J2', center=(185, 346),
                   reactants=['S2', 'A:1'],
                   products=['S3'])

# Export SBML with layout embedded
sbml = layout.toSBML()

# Hand off to SBMLDiagrams for rendering
import SBMLDiagrams
df = SBMLDiagrams.load(sbml)
df.draw()
```

## API reference

### `Layout(sbml_string)`

Create a new layout for the given SBML model string.

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

Add a species node.  Call multiple times with the same `species_id` and
`alias=True` to create alias copies.  Copy indices are assigned in call order
(first call = copy 0, second call = copy 1, …).

### `addReaction(reaction_id, reactants, products, center=None, handles=None)`

Add a reaction.

- **reactants / products**: list of species references.  Plain `'S1'` refers to
  copy 0; `'A:1'` refers to copy 1 of species A.
- **center**: `(x, y)` junction point.  If omitted, no junction is set.
- **handles**: list of `(x, y)` bezier handles in the order
  `[center_handle, reactant_0, …, product_0, …]`.  If omitted, a straight line
  is produced.

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

Add a compartment bounding box.

### `toSBML()`

Return a valid SBML Level 3 string with the layout extension embedded.

## Method chaining

All `add*` methods return `self`, so you can chain calls:

```python
sbml = (sl.Layout(r.getSBML())
    .addNode('S1', x=160, y=100, w=50, h=45)
    .addNode('S2', x=160, y=250, w=50, h=45)
    .addReaction('J1', center=(184, 205),
                 reactants=['S1'], products=['S2'])
    .toSBML())
```

## Compatibility

The SBML produced by `toSBML()` is compatible with:
- [SBMLDiagrams](https://github.com/sys-bio/SBMLDiagrams)
- [SBMLNetwork](https://github.com/sys-bio/SBMLNetwork)
- Any tool that supports SBML Level 3 Layout package v1
