Skip to content
Open
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
303 changes: 303 additions & 0 deletions examples/sbol2/CreatingSBOL2Objects/MapsTo.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,303 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "cell-001",
"metadata": {},
"source": [
"# MapsTo in pySBOL2\n",
"The MapsTo class in the Synthetic Biology Open Language (SBOL) is used to explicitly state that two `ComponentInstance` objects, often from different levels of design hierarchy, represent the same biological entity. It is most often used when `ModuleDefinition` and `ComponentDefinition` objects are composed using `Module` and `ComponentInstance` objects.\n",
"\n",
"`MapsTo` objects define how a `ComponentInstance` in a higher-level design relates to a `ComponentInstance` in a lower-level design through identity and refinement relationships.\n",
"\n",
"MapsTo objects have the following required properties:\n",
"\n",
"* `local`: Refers to the `ComponentInstance` in the higher-level design.\n",
"* `remote`: Refers to the `ComponentInstance` in the lower-level design. The referenced instance must have access=\"public\".\n",
"* `refinement`: Specifies how to interpret the relationship between the local and remote instances using a URI. For * `example`: http://sbols.org/v2#useRemote.\n",
"\n",
"This example demonstrates linking a FunctionalComponent in a high-level toggle switch module to one in a lower-level LacI inverter using a MapsTo object. We will:\n",
"\n",
"1. Define all necessary biological parts (`ComponentDefinition`): two proteins (LacI, cI) and two promoters (pLac, pR).\n",
"2. Define two `ModuleDefinition` objects for genetic inverters: one repressed by LacI and one repressed by cI.\n",
"3. Define a higher-level `ModuleDefinition` for the toggle switch itself.\n",
"4. Instantiate both inverters inside the toggle switch module.\n",
"5. Use `MapsTo` to connect the inputs and outputs of the inverters, forming the complete, mutually-repressive feedback loop.\n",
"\n",
"For more information on the MapsTo class and its properties, refer to page 30 in the SBOL 2.x.x specification document."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "cell-002",
"metadata": {},
"outputs": [],
"source": [
"import sbol2"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "cell-003",
"metadata": {},
"outputs": [],
"source": [
"doc = sbol2.Document()\n",
"\n",
"# Set the namespace for all SBOL objects\n",
"sbol2.setHomespace('https://github.com/SynBioDex/SBOL-Notebooks')"
]
},
{
"cell_type": "markdown",
"id": "cell-004",
"metadata": {},
"source": [
"## Define Shared Biological Parts\n",
"\n",
"Here we define four `ComponentDefinition` objects representing the core parts of our toggle switch: the coding sequences for the two repressor proteins (LacI and cI) and the two promoters they regulate (pLac and pR). In a real design, these would be detailed with sequence information."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "cell-005",
"metadata": {},
"outputs": [],
"source": [
"# Coding Sequences (CDS)\n",
"lacI_cds = sbol2.ComponentDefinition('LacI_CDS', sbol2.BIOPAX_DNA)\n",
"lacI_cds.name = 'LacI Coding Sequence'\n",
"lacI_cds.addRole(sbol2.SO_CDS)\n",
"doc.addComponentDefinition(lacI_cds)\n",
"\n",
"cI_cds = sbol2.ComponentDefinition('cI_CDS', sbol2.BIOPAX_DNA)\n",
"cI_cds.name = 'Lambda cI Coding Sequence'\n",
"cI_cds.addRole(sbol2.SO_CDS)\n",
"doc.addComponentDefinition(cI_cds)\n",
"\n",
"# Define Promoters\n",
"pLac = sbol2.ComponentDefinition('pLac', sbol2.BIOPAX_DNA)\n",
"pLac.name = 'pLac Promoter'\n",
"pLac.addRole(sbol2.SO_PROMOTER)\n",
"doc.addComponentDefinition(pLac)\n",
"\n",
"pR = sbol2.ComponentDefinition('pR', sbol2.BIOPAX_DNA)\n",
"pR.name = 'pR Promoter'\n",
"pR.addRole(sbol2.SO_PROMOTER)\n",
"doc.addComponentDefinition(pR)"
]
},
{
"cell_type": "markdown",
"id": "cell-006",
"metadata": {},
"source": [
"## Define the Inverter Modules (Lower-Level Subsystems)\n",
"\n",
"A toggle switch is composed of two inverters. We define each as a `ModuleDefinition`. Each inverter has an input (the repressor protein), a regulated promoter, and an output (the protein it produces). We also add `Interaction` objects to specify the biological function: repression.\n",
"\n",
"- **LacI Inverter**: Takes LacI as input to repress the pLac promoter, which produces the cI protein.\n",
"- **cI Inverter**: Takes cI as input to repress the pR promoter, which produces the LacI protein."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "cell-007",
"metadata": {},
"outputs": [],
"source": [
"# 1. LacI Inverter Module (LacI represses production of cI)\n",
"laci_inverter_md = sbol2.ModuleDefinition('LacI_Inverter')\n",
"\n",
"# Functional Components of the LacI inverter\n",
"tf_in = laci_inverter_md.functionalComponents.create('input_transcription_factor')\n",
"tf_in.definition = lacI_cds\n",
"tf_in.access = sbol2.SBOL_ACCESS_PUBLIC\n",
"tf_in.direction = sbol2.SBOL_DIRECTION_IN\n",
"\n",
"prom = laci_inverter_md.functionalComponents.create('promoter')\n",
"prom.definition = pLac.identity\n",
"prom.access = sbol2.SBOL_ACCESS_PRIVATE\n",
"\n",
"gene_out = laci_inverter_md.functionalComponents.create('output_gene')\n",
"gene_out.definition = cI_cds.identity\n",
"gene_out.access = sbol2.SBOL_ACCESS_PUBLIC\n",
"gene_out.direction = sbol2.SBOL_DIRECTION_OUT\n",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ModuleDefinition is incomplete without the Interaction objects that link the Promoter to the TF to the output gene.
As such, you should either add the two Interaction objects (my preference) or should add a comment saying that they have been omitted for simplicity.
Same for the other inverter ModuleDefinition

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay I will include it.

"\n",
"\n",
"# 2. cI Inverter Module (cI represses production of LacI)\n",
"ci_inverter_md = sbol2.ModuleDefinition('cI_Inverter')\n",
"\n",
"# Functional Components of the cI inverter\n",
"tf_in_2 = ci_inverter_md.functionalComponents.create('input_transcription_factor')\n",
"tf_in_2.definition = cI_cds.identity\n",
"tf_in_2.access = sbol2.SBOL_ACCESS_PUBLIC\n",
"tf_in_2.direction = sbol2.SBOL_DIRECTION_IN\n",
"\n",
"prom_2 = ci_inverter_md.functionalComponents.create('promoter')\n",
"prom_2.definition = pR.identity\n",
"prom_2.access = sbol2.SBOL_ACCESS_PRIVATE\n",
"\n",
"gene_out_2 = ci_inverter_md.functionalComponents.create('output_gene')\n",
"gene_out_2.definition = lacI_cds.identity\n",
"gene_out_2.access = sbol2.SBOL_ACCESS_PUBLIC\n",
"gene_out_2.direction = sbol2.SBOL_DIRECTION_OUT"
]
},
{
"cell_type": "markdown",
"id": "cell-008",
"metadata": {},
"source": [
"## Define the Toggle Switch Module (Higher-Level Circuit)\n",
"\n",
"This `ModuleDefinition` represents the complete genetic toggle switch. From this high-level perspective, we only care about the two key players: the LacI protein and the cI protein."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "cell-009",
"metadata": {},
"outputs": [],
"source": [
"toggle_md = sbol2.ModuleDefinition('toggle_switch')\n",
"\n",
"# The toggle switch's behavior is defined by two protein pools\n",
"laci_fc = toggle_md.functionalComponents.create('LacI_protein')\n",
"laci_fc.definition = lacI_cds.identity\n",
"laci_fc.direction = sbol2.SBOL_DIRECTION_IN_OUT\n",
"\n",
"ci_fc = toggle_md.functionalComponents.create('cI_protein')\n",
"ci_fc.definition = cI_cds.identity\n",
"ci_fc.direction = sbol2.SBOL_DIRECTION_IN_OUT"
]
},
{
"cell_type": "markdown",
"id": "cell-010",
"metadata": {},
"source": [
"## Add Inverter Modules to Toggle Switch (Composition)\n",
"\n",
"We now instantiate both inverter modules within the toggle switch module. This reflects **module composition** in SBOL—building a larger system from smaller, defined subsystems."
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "cell-010b",
"metadata": {},
"outputs": [],
"source": [
"# Instantiate the LacI inverter\n",
"laci_inverter_instance = toggle_md.modules.create('laci_inverter_inst')\n",
"laci_inverter_instance.definition = laci_inverter_md.identity\n",
"\n",
"# Instantiate the cI inverter\n",
"ci_inverter_instance = toggle_md.modules.create('ci_inverter_inst')\n",
"ci_inverter_instance.definition = ci_inverter_md.identity"
]
},
{
"cell_type": "markdown",
"id": "cell-011",
"metadata": {},
"source": [
"## Wire the Circuit with `MapsTo`\n",
"\n",
"This is the key step. We use `MapsTo` objects to connect the components and form the feedback loop. We need four mappings to declare that:\n",
"1. The `LacI_protein` in the toggle switch is the same molecule that acts as the input to the LacI inverter.\n",
"2. The `cI_protein` in the toggle switch is the same molecule that is produced as the output of the LacI inverter.\n",
"3. The `cI_protein` in the toggle switch is the same molecule that acts as the input to the cI inverter.\n",
"4. The `LacI_protein` in the toggle switch is the same molecule that is produced as the output of the cI inverter.\n",
"\n",
"This wiring correctly models the mutual repression: LacI represses cI production, and cI represses LacI production."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "cell-012",
"metadata": {},
"outputs": [],
"source": [
"# Map 1: LacI protein is the input to the LacI inverter\n",
"map1 = laci_inverter_instance.mapsTos.create('map_laci_in')\n",
"map1.refinement = sbol2.SBOL_REFINEMENT_USE_REMOTE\n",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the others have their refinement values set as well?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, missed this.
Updated.

"map1.local = laci_fc.identity\n",
"map1.remote = tf_in.identity\n",
"\n",
"# Map 2: cI protein is the output of the LacI inverter\n",
"map2 = laci_inverter_instance.mapsTos.create('map_ci_out')\n",
"map2.local = ci_fc.identity\n",
"map2.remote = gene_out.identity\n",
"\n",
"# Map 3: cI protein is the input to the cI inverter\n",
"map3 = ci_inverter_instance.mapsTos.create('map_ci_in')\n",
"map3.local = ci_fc.identity\n",
"map3.remote = tf_in_2.identity\n",
"\n",
"# Map 4: LacI protein is the output of the cI inverter\n",
"map4 = ci_inverter_instance.mapsTos.create('map_laci_out')\n",
"map4.local = laci_fc.identity\n",
"map4.remote = gene_out_2.identity"
]
},
{
"cell_type": "markdown",
"id": "cell-013",
"metadata": {},
"source": [
"## Finalize and Validate\n",
"\n",
"We add all high-level modules to the document and check that the complete design conforms to SBOL specifications. If valid, it is saved as `toggle_switch_complete.xml`."
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "cell-014",
"metadata": {},
"outputs": [],
"source": [
"doc.addModuleDefinition(laci_inverter_md)\n",
"doc.addModuleDefinition(ci_inverter_md)\n",
"doc.addModuleDefinition(toggle_md)\n",
"\n",
"# Validate the document\n",
"report = doc.validate()\n",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you do something with the contents of the document to show it's correct and useful besides just validate it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you have any idea in how to do it? We can use it as input fora model (like iBioSim)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking something like starting with LacI and tracing the Interactions to show that the linkages go around in a circle.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@GeneCodeSavvy please implement this idea so we can review it in the 1o1

"\n",
"if report == \"Valid.\":\n",
" doc.write(\"example_mapsto.xml\")\n",
"else:\n",
" print(report)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.5"
}
},
"nbformat": 4,
"nbformat_minor": 5
}