diff --git a/examples/sbol2/CreatingSBOL2Objects/MapsTo.ipynb b/examples/sbol2/CreatingSBOL2Objects/MapsTo.ipynb new file mode 100644 index 0000000..f731c85 --- /dev/null +++ b/examples/sbol2/CreatingSBOL2Objects/MapsTo.ipynb @@ -0,0 +1,461 @@ +{ + "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 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": "ae833529", + "metadata": {}, + "outputs": [], + "source": [ + "# RBS\n", + "B0032_rbs = sbol2.ComponentDefinition('B0032', sbol2.BIOPAX_DNA)\n", + "B0032_rbs.name = 'B0032_rbs'\n", + "B0032_rbs.addRole(sbol2.SO_RBS)\n", + "doc.addComponentDefinition(B0032_rbs)\n", + "\n", + "# Terminator\n", + "B0015_terminator = sbol2.ComponentDefinition('B0015', sbol2.BIOPAX_DNA)\n", + "B0015_terminator.name = 'B0015_terminator'\n", + "B0015_terminator.addRole(sbol2.SO_TERMINATOR)\n", + "doc.addComponentDefinition(B0015_terminator)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "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", + "\n", + "# 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": "code", + "execution_count": 5, + "id": "cedd52b6", + "metadata": {}, + "outputs": [], + "source": [ + "# The toggle switch's behavior is defined by two protein pools\n", + "LacI_protein = sbol2.ComponentDefinition('LacI_protein', sbol2.BIOPAX_PROTEIN)\n", + "LacI_protein.name = 'LacI Protein'\n", + "LacI_protein.addRole('http://identifiers.org/ncit/NCIT:C17207') # 'Transcriptional factor'\n", + "doc.addComponentDefinition(LacI_protein)\n", + "\n", + "cI_protein = sbol2.ComponentDefinition('cI_protein', sbol2.BIOPAX_PROTEIN)\n", + "cI_protein.name = 'Lambda cI Protein'\n", + "cI_protein.addRole('http://identifiers.org/ncit/NCIT:C17208') # 'Transcriptional factor'\n", + "doc.addComponentDefinition(cI_protein) " + ] + }, + { + "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": 6, + "id": "cell-009", + "metadata": {}, + "outputs": [], + "source": [ + "toggle_md = sbol2.ModuleDefinition('toggle_switch')\n", + "\n", + "# Create functional components by calling using protein ComponentDefinitions\n", + "lacI_prot_fc = toggle_md.functionalComponents.create('LacI_protein_toggle')\n", + "lacI_prot_fc.definition = LacI_protein\n", + "lacI_prot_fc.direction = sbol2.SBOL_DIRECTION_IN_OUT\n", + "\n", + "cI_prot_fc = toggle_md.functionalComponents.create('cI_protein_toggle')\n", + "cI_prot_fc.definition = cI_protein\n", + "cI_prot_fc.direction = sbol2.SBOL_DIRECTION_IN_OUT" + ] + }, + { + "cell_type": "markdown", + "id": "cell-006", + "metadata": {}, + "source": [ + "## Define the Inverter Module Definition(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": 7, + "id": "cell-007", + "metadata": {}, + "outputs": [], + "source": [ + "# 1. LacI Inverter Module Definition (LacI represses production of cI)\n", + "lacI_inverter_md = sbol2.ModuleDefinition('LacI_Inverter')\n", + "\n", + "lacI_inverter_plac_comp = sbol2.component.Component('pLac_promoter')\n", + "lacI_inverter_plac_comp.definition = pLac.identity\n", + "lacI_inverter_b0032_rbs = sbol2.component.Component('B0032_rbs')\n", + "lacI_inverter_b0032_rbs.definition = B0032_rbs.identity\n", + "lacI_inverter_cI_cds = sbol2.component.Component('cI_cds')\n", + "lacI_inverter_cI_cds.definition = cI_cds.identity\n", + "lacI_inverter_b0015_terminator = sbol2.component.Component('B0015_terminator')\n", + "lacI_inverter_b0015_terminator.definition = B0015_terminator.identity\n", + "\n", + "## LacI Inverter Transcriptional Unit Component Definition\n", + "lacI_engineered_region = sbol2.ComponentDefinition('LacI_Engineered_Region', sbol2.BIOPAX_DNA)\n", + "lacI_engineered_region.name = 'LacI Engineered Region'\n", + "lacI_engineered_region.addRole('http://identifiers.org/so/SO:0000804')\n", + "lacI_engineered_region.components.add(lacI_inverter_plac_comp)\n", + "lacI_engineered_region.components.add(lacI_inverter_b0032_rbs)\n", + "lacI_engineered_region.components.add(lacI_inverter_cI_cds)\n", + "lacI_engineered_region.components.add(lacI_inverter_b0015_terminator)\n", + "doc.addComponentDefinition(lacI_engineered_region)\n", + "\n", + "## pLac Promoter Functional Component\n", + "pLac_prom_fc_lacI_inverter = lacI_inverter_md.functionalComponents.create('pLac_promoter_LacI_inverter')\n", + "pLac_prom_fc_lacI_inverter.definition = lacI_inverter_plac_comp\n", + "pLac_prom_fc_lacI_inverter.direction = sbol2.SBOL_DIRECTION_NONE\n", + "\n", + "\n", + "## LacI Inverter Proteins Functional Component\n", + "lacI_prot_fc_lacI_inverter = lacI_inverter_md.functionalComponents.create('LacI_protein_LacI_inverter')\n", + "lacI_prot_fc_lacI_inverter.definition = LacI_protein\n", + "lacI_prot_fc_lacI_inverter.direction = sbol2.SBOL_DIRECTION_IN\n", + "\n", + "cI_prot_fc_lacI_inverter = lacI_inverter_md.functionalComponents.create('cI_protein_LacI_inverter')\n", + "cI_prot_fc_lacI_inverter.definition = cI_protein\n", + "cI_prot_fc_lacI_inverter.direction = sbol2.SBOL_DIRECTION_OUT\n", + "\n", + "\n", + "# 2. cI Inverter Module (cI represses production of LacI)\n", + "cI_inverter_md = sbol2.ModuleDefinition('cI_Inverter')\n", + "\n", + "cI_inverter_pR_comp = sbol2.component.Component('pR_promoter')\n", + "cI_inverter_pR_comp.definition = pR.identity\n", + "cI_inverter_b0032_rbs = sbol2.component.Component('B0032_rbs')\n", + "cI_inverter_b0032_rbs.definition = B0032_rbs.identity\n", + "cI_inverter_lacI_cds = sbol2.component.Component('lacI_cds')\n", + "cI_inverter_lacI_cds.definition = lacI_cds.identity\n", + "cI_inverter_b0015_terminator = sbol2.component.Component('B0015_terminator')\n", + "cI_inverter_b0015_terminator.definition = B0015_terminator.identity\n", + "\n", + "## cI Inverter Transcriptional Unit Component Definition\n", + "cI_engineered_region = sbol2.ComponentDefinition('cI_Engineered_Region', sbol2.BIOPAX_DNA)\n", + "cI_engineered_region.name = 'cI Engineered Region'\n", + "cI_engineered_region.addRole('http://identifiers.org/so/SO:0000804') \n", + "cI_engineered_region.components.add(cI_inverter_pR_comp)\n", + "cI_engineered_region.components.add(cI_inverter_b0032_rbs)\n", + "cI_engineered_region.components.add(cI_inverter_lacI_cds)\n", + "cI_engineered_region.components.add(cI_inverter_b0015_terminator)\n", + "doc.addComponentDefinition(cI_engineered_region)\n", + "\n", + "## pR promoter Unit Functional Component\n", + "pR_prom_fc_cI_inverter = cI_inverter_md.functionalComponents.create('pR_promoter_cI_inverter')\n", + "pR_prom_fc_cI_inverter.definition = cI_inverter_pR_comp\n", + "pR_prom_fc_cI_inverter.direction = sbol2.SBOL_DIRECTION_NONE\n", + "\n", + "## cI Inverter Proteins Functional Component\n", + "lacI_prot_fc_cI_inverter = cI_inverter_md.functionalComponents.create('LacI_protein_cI_inverter')\n", + "lacI_prot_fc_cI_inverter.definition = LacI_protein\n", + "lacI_prot_fc_cI_inverter.direction = sbol2.SBOL_DIRECTION_OUT\n", + "\n", + "cI_prot_fc_cI_inverter = cI_inverter_md.functionalComponents.create('cI_protein_cI_inverter')\n", + "cI_prot_fc_cI_inverter.definition = cI_protein\n", + "cI_prot_fc_cI_inverter.direction = sbol2.SBOL_DIRECTION_IN" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "9cdcd7c0-e419-4106-b7f3-7c8aba06fd7e", + "metadata": {}, + "outputs": [], + "source": [ + "# Interaction 1.1: LacI protein inhibiting cI production\n", + "interaction1_1 = sbol2.Interaction('LacI_represses_pLac')\n", + "interaction1_1.interaction_type = sbol2.SBO_INHIBITION\n", + "lacI_inverter_md.interactions.add(interaction1_1)\n", + "\n", + "# Creating participation objects\n", + "## LacI protein is the INHIBITOR\n", + "inhibitor1_1 = interaction1_1.participations.create('part_LacI_protein')\n", + "inhibitor1_1.participant = lacI_prot_fc_lacI_inverter\n", + "inhibitor1_1.roles = [sbol2.SBO_INHIBITOR]\n", + "\n", + "## pLac promoter is being INHIBITED\n", + "inhibited1_1 = interaction1_1.participations.create('part_pLac_promoter')\n", + "inhibited1_1.participant = pLac_prom_fc_lacI_inverter\n", + "inhibited1_1.roles = [sbol2.SBO_INHIBITED]\n", + "\n", + "# Interaction 1.2 : cI production\n", + "interaction1_2 = sbol2.Interaction('cI_production')\n", + "interaction1_2.interaction_type = sbol2.SBO_GENETIC_PRODUCTION\n", + "lacI_inverter_md.interactions.add(interaction1_2)\n", + "\n", + "# Creating participation objects\n", + "## pLac is the promoter\n", + "prom_1_2 = interaction1_2.participations.create('part_pLac_promoter')\n", + "prom_1_2.participant = pLac_prom_fc_lacI_inverter\n", + "prom_1_2.roles = [sbol2.SBO_PROMOTER]\n", + "\n", + "## cI is the product\n", + "product_1_2 = interaction1_2.participations.create('part_cI_protein')\n", + "product_1_2.participant = cI_prot_fc_lacI_inverter\n", + "product_1_2.roles = [sbol2.SBO_PRODUCT]\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "# Interaction 2.1: cI protein inhibiting LacI production\n", + "interaction2_1 = sbol2.Interaction('cI_represses_pR')\n", + "interaction2_1.interaction_type = sbol2.SBO_INHIBITION\n", + "cI_inverter_md.interactions.add(interaction2_1)\n", + "\n", + "## cI protein is the INHIBITOR\n", + "inhibitor2_1 = interaction2_1.participations.create('part_cI_protein')\n", + "inhibitor2_1.roles = [sbol2.SBO_INHIBITOR]\n", + "inhibitor2_1.participant = cI_prot_fc_cI_inverter\n", + "\n", + "## pR promoter is being INHIBITED\n", + "inhibited2_1 = interaction2_1.participations.create('part_transcriptional_unit')\n", + "inhibited2_1.roles = [sbol2.SBO_INHIBITED]\n", + "inhibited2_1.participant = pR_prom_fc_cI_inverter\n", + "\n", + "\n", + "# Interaction 2.2 : LacI production\n", + "interaction2_2 = sbol2.Interaction('lacI_production')\n", + "interaction2_2.interaction_type = sbol2.SBO_GENETIC_PRODUCTION\n", + "cI_inverter_md.interactions.add(interaction2_2)\n", + "\n", + "# Creating participation objects\n", + "## pLac is the promoter\n", + "prom_2_2 = interaction2_2.participations.create('part_pR_promoter')\n", + "prom_2_2.participant = pR_prom_fc_cI_inverter\n", + "prom_2_2.roles = [sbol2.SBO_PROMOTER]\n", + "\n", + "## cI is the product\n", + "product_2_2 = interaction2_2.participations.create('part_cI_protein')\n", + "product_2_2.participant = lacI_prot_fc_cI_inverter\n", + "product_2_2.roles = [sbol2.SBO_PRODUCT]" + ] + }, + { + "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": 9, + "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\n", + "laci_inverter_instance.displayId = 'laci_inverter_inst'\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\n", + "ci_inverter_instance.displayId = 'ci_inverter_inst'" + ] + }, + { + "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": 10, + "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_laci_protein')\n", + "map1.refinement = sbol2.SBOL_REFINEMENT_VERIFY_IDENTICAL\n", + "map1.local = lacI_prot_fc\n", + "map1.remote = lacI_prot_fc_lacI_inverter\n", + "\n", + "# Map 2: cI protein is the output of the LacI inverter\n", + "map2 = laci_inverter_instance.mapsTos.create('map_ci_out_cI_protein')\n", + "map2.refinement = sbol2.SBOL_REFINEMENT_VERIFY_IDENTICAL\n", + "map2.local = cI_prot_fc\n", + "map2.remote = cI_prot_fc_lacI_inverter\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.refinement = sbol2.SBOL_REFINEMENT_VERIFY_IDENTICAL\n", + "map3.local = cI_prot_fc\n", + "map3.remote = cI_prot_fc_cI_inverter\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.refinement = sbol2.SBOL_REFINEMENT_VERIFY_IDENTICAL\n", + "map4.local = lacI_prot_fc\n", + "map4.remote = lacI_prot_fc_cI_inverter" + ] + }, + { + "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": 11, + "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", + "\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 +}