-
Notifications
You must be signed in to change notification settings - Fork 1
pySBOL2 MapsTo object tutorial #46
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 3 commits
30342d6
4cc1c0c
7a2f6ad
35f8867
b0ddb30
26f07d3
7a9925d
5e11528
2523b19
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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", | ||
| "\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", | ||
|
||
| "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", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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)?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This
ModuleDefinitionis incomplete without theInteractionobjects that link the Promoter to the TF to the output gene.As such, you should either add the two
Interactionobjects (my preference) or should add a comment saying that they have been omitted for simplicity.Same for the other inverter
ModuleDefinitionThere was a problem hiding this comment.
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.