Skip to content

Automation and REST API

cy3sbml can be driven from scripts and other programs. From Python (a script or a Jupyter notebook), R or any other language you can import SBML models, read the SBML behind the networks and map your data onto them.

cy3sbml registers Cytoscape commands in the namespace cy3sbml. Cytoscape offers every command in three places:

  • in the Command Line of Cytoscape (View → Show Command Panel), for example cy3sbml import biomodelsId=BIOMD0000000012;
  • in automation scripts (Tools → Execute Command File);
  • in CyREST, the REST API of Cytoscape, as POST http://localhost:1234/v1/commands/cy3sbml/<command> with the arguments as JSON body. Help → Automation → CyREST Command API opens the interactive documentation (Swagger) of all commands, including those of cy3sbml.

Every cy3sbml command returns JSON. In CyREST the result is data, and an error (a wrong argument, a network that is not an SBML network, a failed download) is a message in errors:

curl -X POST -H "Content-Type: application/json" \
    -d '{"biomodelsId": "BIOMD0000000012"}' \
    http://localhost:1234/v1/commands/cy3sbml/import
{
  "data": {
    "models": [{
      "rootNetwork": 52, "name": "BIOMD0000000012", "modelId": "BIOMD0000000012",
      "modelName": "Elowitz2000 - Repressilator",
      "networks": [
        {"suid": 1024, "name": "BIOMD0000000012", "type": "base"},
        {"suid": 1167, "name": "BIOMD0000000012__kinetic", "type": "kinetic"},
        {"suid": 1310, "name": "BIOMD0000000012__all", "type": "all"}
      ]
    }]
  },
  "errors": []
}

The cy3sbml commands cover what is specific to SBML. Styles, layouts, images, the selection and tables are handled by the commands of Cytoscape itself, for example vizmap apply, layout force-directed, view export, network select and table import file, or the corresponding functions of py4cytoscape and RCy3.

Python

The Python examples use py4cytoscape. cy3sbml_client.py sends the arguments of a command as JSON through CyREST and returns its result:

"""Call the automation commands of cy3sbml from Python.

The commands of cy3sbml are Cytoscape commands in the namespace `cy3sbml`, which
CyREST offers as `POST /v1/commands/cy3sbml/<command>` with the arguments as JSON
body. `command` calls them with py4cytoscape and returns the JSON result; the
arguments are sent as JSON, so any value works (e.g. an SBML string).

See https://matthiaskoenig.github.io/cy3sbml/guide/automation/ for the commands.
"""

import time
from pathlib import Path
from typing import Any

import py4cytoscape as p4c
from py4cytoscape.exceptions import CyError

# attempts and seconds between them of export_png
EXPORT_ATTEMPTS: int = 20
EXPORT_WAIT: float = 0.5

# the models of the cy3sbml repository, used by the examples
MODELS: Path = (
    Path(__file__).resolve().parents[2] / "src" / "test" / "resources" / "models"
)


def command(name: str, **arguments: str | int | float | bool) -> dict[str, Any]:
    """Runs a cy3sbml command and returns its result.

    >>> command("import", biomodelsId="BIOMD0000000012")
    {'models': [{'rootNetwork': 52, ...}]}

    Raises a `CyError` with the message of cy3sbml if the command fails.
    """
    result = p4c.cyrest_post(f"commands/cy3sbml/{name}", body=arguments)
    if result["errors"]:
        raise CyError(result["errors"][0]["message"])
    return result["data"]


def network(suid: int) -> str:
    """The network argument of a command for a network SUID."""
    return f"SUID:{suid}"


def network_of_type(model: dict[str, Any], network_type: str) -> int:
    """The SUID of the network of the model with the type base/kinetic/all/layout."""
    for net in model["networks"]:
        if net["type"] == network_type:
            return int(net["suid"])
    message = f"The model {model['name']} has no {network_type} network."
    raise ValueError(message)


def export_png(path: Path, network_suid: int) -> Path:
    """Exports a PNG image of the view of the network.

    Cytoscape renders a change of a view (style, layout, bypasses) asynchronously, so
    an image exported right after the change can show the view before it. The image
    is exported until two exports are identical. The path is a path of the computer
    Cytoscape runs on.
    """
    previous = None
    for _ in range(EXPORT_ATTEMPTS):
        p4c.export_image(
            str(path), type="PNG", network=network_suid, overwrite_file=True
        )
        content = path.read_bytes()
        if content == previous:
            break
        previous = content
        time.sleep(EXPORT_WAIT)
    return path


def check_cytoscape() -> None:
    """Fails if Cytoscape with CyREST and cy3sbml is not running."""
    p4c.cytoscape_ping()
    names = {app["appName"] for app in p4c.get_installed_apps()}
    if "cy3sbml" not in names:
        raise RuntimeError("cy3sbml is not installed in Cytoscape.")

For example, explore_model.py imports a model, reads the SBML, reads SBML elements and selects the nodes of SBML ids:

"""Read the SBML behind the networks.

- lists the SBML models open in Cytoscape (`cy3sbml networks`),
- gets the SBML document of a network (`cy3sbml document`),
- reads SBML elements by SBML id and of selected nodes (`cy3sbml element`),
- selects the nodes of SBML ids (`cy3sbml nodes` and core `network select`).

```bash
uv run explore_model.py
```
"""

from typing import Any

import py4cytoscape as p4c
from cy3sbml_client import MODELS, check_cytoscape, command, network, network_of_type


def print_element(element: dict[str, Any]) -> None:
    print(
        f"  {element['class']} {element['id']} ({element['name']}),"
        f" SBO {element['sboTerm']}"
    )
    for term in element["cvTerms"]:
        print(f"    {term['qualifier']}: {', '.join(term['resources'])}")


def main() -> None:
    check_cytoscape()
    model = command("import", file=str(MODELS / "unittests" / "core_01.xml"))["models"][
        0
    ]
    base = network_of_type(model, "base")

    for open_model in command("networks")["models"]:
        print(
            f"{open_model['modelId']}:"
            f" SBML L{open_model['level']}V{open_model['version']},"
            f" packages {open_model['packages']},"
            f" {len(open_model['networks'])} networks"
        )

    sbml = command("document", network=network(base))["sbml"]
    print(f"SBML of {model['modelId']}: {len(sbml)} characters")

    # the element of an SBML id
    print("element of the SBML id BLL:")
    for element in command("element", network=network(base), sbmlId="BLL")["elements"]:
        print_element(element)

    # select the nodes of SBML ids, then read the elements of the selected nodes
    nodes = command("nodes", network=network(base), sbmlIds="BLL,IL,AL")["nodes"]
    suids = [suid for node_suids in nodes.values() for suid in node_suids]
    p4c.clear_selection(network=base)
    p4c.select_nodes(suids, by_col="SUID", network=base)
    print("elements of the selected nodes:")
    elements = command("element", network=network(base), nodeList="selected")[
        "elements"
    ]
    for element in elements:
        print_element(element)


if __name__ == "__main__":
    main()

The other examples:

Script What it shows
import_and_style.py import a file and a BioModel, apply the style cy3sbml-dark, export PNG images
cofactors_and_layout.py split and merge cofactor nodes, save and restore the node positions
map_data.py map a flux distribution with SBML ids onto the reactions: a data column joined on sbml id with a style mapping, and colors on the node SUIDs of the SBML ids
biomodels_search.py search BioModels and import the first result

Run them with uv while Cytoscape with cy3sbml runs on the same computer (the files are read and written by Cytoscape):

cd examples/python
uv run map_data.py

Cytoscape draws a change of a view (a style, a layout, bypasses) asynchronously. An image exported right after the change can still show the view before the change; the helper export_png of the examples exports until two images are identical.

Arguments

  • network: a network of an SBML model imported by cy3sbml, the base, kinetic, all or a layout network. It is given as the network name, SUID:<SUID> or current (the default, the current network).
  • nodeList: nodes of the network: all, selected, unselected, a comma separated list of node names, or <column>:<value>, for example sbml id:PX or SUID:1047.
  • File paths are paths on the computer Cytoscape runs on.

The networks of a model in the results have a type: base, kinetic, all or layout, the value of the network column sbmlSubnetwork (see Network model). The types do not depend on the network names, which Cytoscape changes when a model is imported twice (for example BIOMD0000000012_1).

Commands

cy3sbml import

Imports an SBML model like an import in the GUI: the base, kinetic and all network and a network per layout, with views, the cy3sbml style and the layout. A COMBINE archive (OMEX) imports its SBML models.

Argument Description
file path of an SBML file or a COMBINE archive
url http or https URL of an SBML file or a COMBINE archive
sbml the SBML as a string
biomodelsId id of a BioModels model, which is downloaded and imported

Give exactly one of the arguments. The result has the imported models, each with its root network SUID, model id and name, and its networks (SUID, name, type), as in the example above. The command fails if nothing is imported, for example for a file that is no SBML. Other URLs than http and https (for example file: URLs) are rejected, give a local file with file. A COMBINE archive is imported only if it has at most 100000 entries and its unpacked files have at most 4 GiB in total.

Searches BioModels like the BioModels dialog.

Argument Description
query the search query, for example a model name, a species or a gene
{"matches": 2, "models": [
  {"id": "BIOMD0000000012", "name": "Elowitz2000 - Repressilator",
   "submissionDate": "2005-09-13T00:00:00Z", "lastModified": ""}, ...]}

At most 1000 models are returned; matches is the number of all matching models. Import a model with cy3sbml import biomodelsId=<id>.

cy3sbml networks

Lists the SBML models open in Cytoscape. No arguments. Per model: the root network, model id and name, the SBML level and version, the packages with their versions (for example {"fbc": 2}) and the networks.

cy3sbml document

The SBML document of the model of a network.

Argument Description
network the network, default: the current network
file optional path the SBML is written to

Without file the result is {"sbml": "<SBML>"}, with file {"file": "<path>"}.

cy3sbml element

The SBML elements of nodes, of an SBML id or of a metaid.

Argument Description
network the network, default: the current network
nodeList the nodes, for example selected
sbmlId the SBML id (SId) of an element
metaId the metaid of an element

Give one of nodeList, sbmlId and metaId. Per element: the JSBML class, id, name, metaId, sboTerm, the cvTerms of the annotation (qualifier and resources), the notes (XHTML) and the SUIDs of its nodes in the network:

{"elements": [{"class": "Species", "id": "PX", "name": "LacI protein",
  "metaId": "_000006", "sboTerm": "SBO:0000252",
  "cvTerms": [{"qualifier": "BQB_IS_VERSION_OF",
               "resources": ["http://identifiers.org/uniprot/P03023"]}],
  "notes": "", "nodes": [1047]}]}

cy3sbml nodes

The nodes of SBML ids in a network (the column sbml id), to map data with SBML ids onto the nodes.

Argument Description
network the network, default: the current network
sbmlIds comma separated SBML ids; default: all SBML ids of the network
{"nodes": {"PX": [1047], "PY": [1049], "missing": []}}

An id without node in the network has an empty list. An element can have several nodes, for example the clones of a split cofactor node or the aliases of a layout network.

cy3sbml cofactors split

Splits nodes into one node per edge, like Split cofactor nodes (see Cofactor nodes).

Argument Description
network the network, default: the current network
nodeList the nodes to split

The result has the SUIDs of the new nodes: {"clones": [2101, 2102, 2103]}.

cy3sbml cofactors merge

Merges split nodes back into their node, like Merge cofactor nodes.

Argument Description
network the network, default: the current network
nodeList the split nodes to merge; default: all split nodes of the network

The result has the SUIDs of the merged nodes: {"merged": [1047]}.

cy3sbml layout save

Saves the node positions of the view of a network in a layout file, like Save Layout (see Layouts).

Argument Description
network the network, default: the current network
file path of the layout file (XML)

The result has the file and the number of saved positions: {"file": "<path>", "nodes": 12}.

cy3sbml layout load

Moves the nodes of the view of a network to their positions in a layout file, like Load Layout.

Argument Description
network the network, default: the current network
file path of the layout file (XML)

The result has the file and the number of moved nodes: {"file": "<path>", "nodes": 12}.