Created
August 9, 2026 14:39
-
-
Save JustABiologist/35762069350e47ca4351397be07e5896 to your computer and use it in GitHub Desktop.
GRASP Library Designer (Colab / PyPI)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "nbformat": 4, | |
| "nbformat_minor": 5, | |
| "metadata": { | |
| "kernelspec": { | |
| "display_name": "Python 3", | |
| "language": "python", | |
| "name": "python3" | |
| }, | |
| "language_info": { | |
| "name": "python", | |
| "pygments_lexer": "ipython3" | |
| }, | |
| "colab": { | |
| "provenance": [], | |
| "toc_visible": true | |
| } | |
| }, | |
| "cells": [ | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "# GRASP Library Designer\n", | |
| "\n", | |
| "Redesign and anneal the **42-module combinatorial GRASP library** (Farley et al., *NAR* 2025), then compile a target RNA with GAP.\n", | |
| "\n", | |
| "1. Run **0 · Install** once \n", | |
| "2. Fill the forms and run cells top → bottom \n", | |
| "\n", | |
| "Code is hidden by default (Colab Forms).\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "#@title 0 · Install (PyPI) { display-mode: \"form\" }\n", | |
| "#@markdown Installs everything from PyPI. No GitHub token needed. Re-run if imports fail after a runtime restart.\n", | |
| "\n", | |
| "%pip install -q -U \"grasp-library-designer>=0.1.0\"\n", | |
| "\n", | |
| "import importlib\n", | |
| "import grasp_library\n", | |
| "from importlib.metadata import version\n", | |
| "\n", | |
| "print(\"grasp-library-designer\", version(\"grasp-library-designer\"))\n", | |
| "print(\"import ok:\", grasp_library.__name__)\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "#@title 1 · Settings { display-mode: \"form\" }\n", | |
| "#@markdown Organism, synthesis, ligation, architecture, and anneal depth — then run this cell.\n", | |
| "\n", | |
| "target_rna = \"UUACACGUG\" #@param {type:\"string\"}\n", | |
| "organism = \"Escherichia coli (Kazusa)\" #@param [\"Escherichia coli (Kazusa)\", \"Saccharomyces cerevisiae (Kazusa)\", \"Homo sapiens (Kazusa)\", \"Euglena gracilis nuclear (Kazusa)\", \"Chlamydomonas reinhardtii nuclear (Kazusa)\", \"Chlamydomonas reinhardtii chloroplast (Kazusa)\"]\n", | |
| "genetic_code = 1 #@param {type:\"integer\"}\n", | |
| "nterm_overhang = \"AGGT\" #@param [\"AGGT\", \"AATG\"]\n", | |
| "architecture = \"9S\" #@param [\"9S\", \"14S\", \"19S\"]\n", | |
| "synthesis_vendor = \"Twist · Standard gene guidelines\" #@param [\"Twist · Express / Low complexity\", \"Twist · Standard gene guidelines\", \"Twist · Complex Genes tolerant\", \"IDT · gBlocks / eBlocks conservative\", \"Generic · conservative (default)\"]\n", | |
| "assembly_enzyme = \"GRASP default · BsaI + BpiI + BsmBI\" #@param [\"GRASP default · BsaI + BpiI + BsmBI\", \"BsaI (GGTCTC)\", \"BpiI / BbsI (GAAGAC)\", \"BsmBI / Esp3I (CGTCTC)\", \"None (no enzyme filter)\"]\n", | |
| "ligation_table = \"T4 · 18 h · 25 °C (Potapov)\" #@param [\"T4 · 18 h · 25 °C (Potapov)\", \"T4 · 18 h · 37 °C (Potapov)\", \"T4 · 1 h · 25 °C (Potapov)\", \"BsaI-HFv2 · constant 37 °C\", \"BsmBI-v2 · constant 42 °C\"]\n", | |
| "overhang_redesign = True #@param {type:\"boolean\"}\n", | |
| "redesign_selection = \"knee\" #@param [\"knee\", \"max_fidelity\"]\n", | |
| "optimize_depth = 2000 #@param {type:\"integer\"}\n", | |
| "\n", | |
| "from grasp_library import build_default_config, materialize_project\n", | |
| "from grasp_library.colab_forms import apply_form_settings\n", | |
| "from grasp_library import notebook_ui as ui\n", | |
| "\n", | |
| "PROJECT_DIR = materialize_project()\n", | |
| "INPUT_DIR = PROJECT_DIR / \"input\"\n", | |
| "OUTPUT_DIR = PROJECT_DIR / \"output\"\n", | |
| "PROFILE_GB = PROJECT_DIR / \"profiles\" / \"grasp_nar2025\" / \"genbank\"\n", | |
| "\n", | |
| "CONFIG = build_default_config(INPUT_DIR)\n", | |
| "CONFIG[\"project_name\"] = \"GRASP_library_colab\"\n", | |
| "\n", | |
| "applied = apply_form_settings(\n", | |
| " CONFIG,\n", | |
| " organism=organism,\n", | |
| " genetic_code=int(genetic_code),\n", | |
| " target_rna=target_rna,\n", | |
| " nterm_overhang=nterm_overhang,\n", | |
| " architecture=architecture,\n", | |
| " synthesis_vendor=synthesis_vendor,\n", | |
| " assembly_enzyme=assembly_enzyme,\n", | |
| " ligation_table=ligation_table,\n", | |
| " overhang_redesign=bool(overhang_redesign),\n", | |
| " redesign_selection=redesign_selection,\n", | |
| " optimize_depth=int(optimize_depth),\n", | |
| ")\n", | |
| "CONFIG = applied[\"config\"]\n", | |
| "CODON_DATA = applied[\"codon_data\"]\n", | |
| "CODON_TABLE = applied[\"codon_table\"]\n", | |
| "SELECTED_ORGANISM = organism\n", | |
| "\n", | |
| "parts = None\n", | |
| "target_map = None\n", | |
| "PARETO_FRONT = None\n", | |
| "SELECTED_OVERHANGS = None\n", | |
| "parts_with_redesigned_junctions = None\n", | |
| "optimized_library = None\n", | |
| "PARETO_PLOT = None\n", | |
| "ASSEMBLY = None\n", | |
| "FIDELITY = None\n", | |
| "\n", | |
| "ui.status(\n", | |
| " f\"Target <b>{CONFIG['target_rna']}</b> · <b>{organism}</b> · \"\n", | |
| " f\"arch <b>{architecture}</b> · N-term <code>{nterm_overhang}</code> · \"\n", | |
| " f\"redesign <b>{CONFIG['overhang_redesign']['enabled']}</b> ({redesign_selection}) · \"\n", | |
| " f\"depth <b>{CONFIG['optimizer']['iterations_per_part']:,}</b><br/>\"\n", | |
| " f\"Project → <code>{PROJECT_DIR}</code>\"\n", | |
| ")\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "#@title 2 · Import GRASP modules { display-mode: \"form\" }\n", | |
| "#@markdown Copies bundled Farley et al. GenBank into the project and builds parts tables.\n", | |
| "\n", | |
| "FORCE_REIMPORT = False #@param {type:\"boolean\"}\n", | |
| "\n", | |
| "from IPython.display import display\n", | |
| "from grasp_library import ensure_grasp_imported\n", | |
| "from grasp_library import notebook_ui as ui\n", | |
| "\n", | |
| "if not CODON_DATA:\n", | |
| " ui.note(\"Run Settings first.\")\n", | |
| "else:\n", | |
| " imported = ensure_grasp_imported(\n", | |
| " profile_genbank_dir=PROFILE_GB,\n", | |
| " input_dir=INPUT_DIR,\n", | |
| " force=bool(FORCE_REIMPORT),\n", | |
| " log=print,\n", | |
| " )\n", | |
| " parts = imported[\"parts\"]\n", | |
| " target_map = imported.get(\"target_map\")\n", | |
| " display(parts.head())\n", | |
| " jm = imported[\"junction_map\"]\n", | |
| " display(\n", | |
| " jm.groupby(\"junction\", as_index=False)\n", | |
| " .first()[[\"junction\", \"native_overhang\"]]\n", | |
| " )\n", | |
| " ui.status(\n", | |
| " f\"<b>{len(parts)}</b> modules · \"\n", | |
| " f\"<b>{jm['junction'].nunique()}</b> junctions · \"\n", | |
| " f\"<b>{len(imported['overhang_candidates'])}</b> overhang candidates\"\n", | |
| " )\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "#@title 3 · Redesign overhangs { display-mode: \"form\" }\n", | |
| "#@markdown Pareto search over synonym overhangs at fixed GRASP cut indices.\n", | |
| "\n", | |
| "RUN_OVERHANG_REDESIGN = True #@param {type:\"boolean\"}\n", | |
| "SEED = 42 #@param {type:\"integer\"}\n", | |
| "\n", | |
| "import random\n", | |
| "import numpy as np\n", | |
| "import pandas as pd\n", | |
| "from IPython.display import display\n", | |
| "from grasp_library import (\n", | |
| " LigationFidelityCalculator,\n", | |
| " load_and_validate_parts,\n", | |
| " optimize_coding_sequence,\n", | |
| " run_overhang_redesign,\n", | |
| ")\n", | |
| "from grasp_library import notebook_ui as ui\n", | |
| "\n", | |
| "random.seed(int(SEED))\n", | |
| "np.random.seed(int(SEED))\n", | |
| "\n", | |
| "PARETO_FRONT = None\n", | |
| "SELECTED_OVERHANGS = None\n", | |
| "parts_with_redesigned_junctions = None\n", | |
| "\n", | |
| "if not RUN_OVERHANG_REDESIGN:\n", | |
| " ui.note(\"RUN_OVERHANG_REDESIGN is off.\")\n", | |
| "elif not CODON_DATA:\n", | |
| " ui.note(\"Run Settings first.\")\n", | |
| "else:\n", | |
| " if parts is None and CONFIG[\"parts_file\"].exists():\n", | |
| " parts = load_and_validate_parts(CONFIG[\"parts_file\"])\n", | |
| " lig = CONFIG[\"ligation\"]\n", | |
| " FIDELITY = LigationFidelityCalculator(\n", | |
| " temperature=lig[\"temperature\"],\n", | |
| " hours=lig[\"hours\"],\n", | |
| " ligation_table=lig.get(\"ligation_table\"),\n", | |
| " min_efficiency=lig.get(\"min_efficiency\", 0.25),\n", | |
| " min_fidelity=lig.get(\"min_fidelity\", 0.9),\n", | |
| " )\n", | |
| " if not CONFIG.get(\"overhang_redesign\", {}).get(\"enabled\", True):\n", | |
| " ui.note(\"Overhang redesign disabled in Settings — keeping native overhangs.\")\n", | |
| " parts_with_redesigned_junctions = parts\n", | |
| " else:\n", | |
| " PARETO_FRONT, SELECTED_OVERHANGS, parts_with_redesigned_junctions = run_overhang_redesign(\n", | |
| " parts=parts,\n", | |
| " codon_data=CODON_DATA,\n", | |
| " config=CONFIG,\n", | |
| " optimize_coding_sequence=optimize_coding_sequence,\n", | |
| " input_dir=INPUT_DIR,\n", | |
| " output_dir=OUTPUT_DIR,\n", | |
| " seed=int(SEED),\n", | |
| " fidelity=FIDELITY,\n", | |
| " log=print,\n", | |
| " )\n", | |
| " display(PARETO_FRONT)\n", | |
| " display(\n", | |
| " pd.DataFrame([SELECTED_OVERHANGS], index=[\"overhang\"])\n", | |
| " .T.rename(columns={\"overhang\": \"selected\"})\n", | |
| " )\n", | |
| " ui.status(\"Overhang redesign done — next: anneal library.\")\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "#@title 4 · Anneal library { display-mode: \"form\" }\n", | |
| "#@markdown Full CDS simulated annealing for every module.\n", | |
| "\n", | |
| "RUN_LIBRARY_OPTIMIZE = True #@param {type:\"boolean\"}\n", | |
| "\n", | |
| "from IPython.display import display\n", | |
| "from grasp_library import (\n", | |
| " load_and_validate_parts,\n", | |
| " optimize_library,\n", | |
| " run_library_optimize,\n", | |
| ")\n", | |
| "from grasp_library import notebook_ui as ui\n", | |
| "\n", | |
| "optimized_library = None\n", | |
| "\n", | |
| "if not RUN_LIBRARY_OPTIMIZE:\n", | |
| " ui.note(\"RUN_LIBRARY_OPTIMIZE is off.\")\n", | |
| "elif not CODON_DATA:\n", | |
| " ui.note(\"Run Settings first.\")\n", | |
| "else:\n", | |
| " source_parts = (\n", | |
| " parts_with_redesigned_junctions\n", | |
| " if parts_with_redesigned_junctions is not None\n", | |
| " else parts\n", | |
| " )\n", | |
| " if source_parts is None and CONFIG[\"parts_file\"].exists():\n", | |
| " source_parts = load_and_validate_parts(CONFIG[\"parts_file\"])\n", | |
| " optimized_library = run_library_optimize(\n", | |
| " parts=source_parts,\n", | |
| " codon_data=CODON_DATA,\n", | |
| " config=CONFIG,\n", | |
| " optimize_library=optimize_library,\n", | |
| " output_dir=OUTPUT_DIR,\n", | |
| " log=print,\n", | |
| " )\n", | |
| " if SELECTED_OVERHANGS:\n", | |
| " tag = \";\".join(f\"{k}={v}\" for k, v in sorted(SELECTED_OVERHANGS.items()))\n", | |
| " optimized_library = optimized_library.copy()\n", | |
| " optimized_library[\"selected_overhangs\"] = tag\n", | |
| " optimized_library.to_csv(OUTPUT_DIR / \"optimized_library.csv\", index=False)\n", | |
| " display(optimized_library.head())\n", | |
| " ui.status(\n", | |
| " f\"Annealed <b>{len(optimized_library)}</b> sequences → \"\n", | |
| " f\"<code>{OUTPUT_DIR / 'optimized_library.csv'}</code>\"\n", | |
| " )\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "#@title 5 · Pareto plot { display-mode: \"form\" }\n", | |
| "#@markdown Rescores the front after redesign + anneal.\n", | |
| "\n", | |
| "RUN_PARETO_PLOT = True #@param {type:\"boolean\"}\n", | |
| "DEEP_RESCORE_ALL = False #@param {type:\"boolean\"}\n", | |
| "\n", | |
| "import pandas as pd\n", | |
| "from IPython.display import display\n", | |
| "from grasp_library import load_and_validate_parts, plot_library_pareto_after_anneal\n", | |
| "from grasp_library.workflows import parse_overhang_selection\n", | |
| "from grasp_library import notebook_ui as ui\n", | |
| "\n", | |
| "PARETO_PLOT = None\n", | |
| "\n", | |
| "if not RUN_PARETO_PLOT:\n", | |
| " ui.note(\"RUN_PARETO_PLOT is off.\")\n", | |
| "elif optimized_library is None or getattr(optimized_library, \"empty\", False):\n", | |
| " ui.note(\"Run Anneal library first.\")\n", | |
| "else:\n", | |
| " front = PARETO_FRONT\n", | |
| " selected = SELECTED_OVERHANGS\n", | |
| " src_parts = parts\n", | |
| "\n", | |
| " if front is None or getattr(front, \"empty\", True):\n", | |
| " path = OUTPUT_DIR / \"pareto_front.csv\"\n", | |
| " if path.exists():\n", | |
| " front = pd.read_csv(path)\n", | |
| " PARETO_FRONT = front\n", | |
| " else:\n", | |
| " ui.note(\"No Pareto front — run Redesign overhangs first (or enable redesign).\")\n", | |
| " front = None\n", | |
| "\n", | |
| " if front is not None and not front.empty:\n", | |
| " if selected is None and (OUTPUT_DIR / \"selected_overhangs.csv\").exists():\n", | |
| " sel = pd.read_csv(OUTPUT_DIR / \"selected_overhangs.csv\")\n", | |
| " if \"overhangs\" in sel.columns:\n", | |
| " selected = parse_overhang_selection(sel.iloc[0][\"overhangs\"])\n", | |
| " SELECTED_OVERHANGS = selected\n", | |
| " if src_parts is None and CONFIG[\"parts_file\"].exists():\n", | |
| " src_parts = load_and_validate_parts(CONFIG[\"parts_file\"])\n", | |
| " parts = src_parts\n", | |
| "\n", | |
| " junction_map = pd.read_csv(INPUT_DIR / \"junction_map.csv\")\n", | |
| " PARETO_PLOT = plot_library_pareto_after_anneal(\n", | |
| " front=front,\n", | |
| " parts=src_parts,\n", | |
| " junction_map=junction_map,\n", | |
| " codon_data=CODON_DATA,\n", | |
| " config=CONFIG,\n", | |
| " optimized_library=optimized_library,\n", | |
| " selected_overhangs=selected,\n", | |
| " fidelity=FIDELITY,\n", | |
| " deep_all=bool(DEEP_RESCORE_ALL),\n", | |
| " output_dir=OUTPUT_DIR,\n", | |
| " log=print,\n", | |
| " )\n", | |
| " display(PARETO_PLOT[\"front\"])\n", | |
| " display(PARETO_PLOT[\"figure\"])\n", | |
| " chosen = PARETO_PLOT[\"chosen\"]\n", | |
| " ui.status(\n", | |
| " f\"Selected · synthesis <b>{float(chosen['synthesis']):.3f}</b> · \"\n", | |
| " f\"codon <b>{float(chosen['codon_optimality']):.3f}</b> · \"\n", | |
| " f\"fidelity <b>{float(chosen['ligation_fidelity']):.6f}</b><br>\"\n", | |
| " f\"Plot → <code>{OUTPUT_DIR / 'pareto_front.png'}</code>\"\n", | |
| " )\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "#@title 6 · Export library { display-mode: \"form\" }\n", | |
| "#@markdown Writes CSV / FASTA / Excel and downloads the Excel in Colab.\n", | |
| "\n", | |
| "from grasp_library import export_optimized_library\n", | |
| "from grasp_library import notebook_ui as ui\n", | |
| "\n", | |
| "if optimized_library is None:\n", | |
| " ui.note(\"Run Anneal library first.\")\n", | |
| "else:\n", | |
| " paths = export_optimized_library(\n", | |
| " optimized_library,\n", | |
| " OUTPUT_DIR,\n", | |
| " selected_overhangs=SELECTED_OVERHANGS,\n", | |
| " )\n", | |
| " ui.status(\n", | |
| " \"Exported:<br/>\"\n", | |
| " f\"• <code>{paths['csv']}</code><br/>\"\n", | |
| " f\"• <code>{paths['fasta']}</code><br/>\"\n", | |
| " f\"• <code>{paths['xlsx']}</code>\"\n", | |
| " )\n", | |
| " if \"google.colab\" in __import__(\"sys\").modules:\n", | |
| " from google.colab import files\n", | |
| " files.download(str(paths[\"xlsx\"]))\n", | |
| " for p in sorted(OUTPUT_DIR.glob(\"optimized_grasp_*\")):\n", | |
| " if p.is_file():\n", | |
| " print(p.name)\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "#@title 7 · Compile target RNA { display-mode: \"form\" }\n", | |
| "#@markdown GAP-compile the Settings target against the annealed library and stitch the CDS.\n", | |
| "\n", | |
| "RUN_COMPILE = True #@param {type:\"boolean\"}\n", | |
| "\n", | |
| "from IPython.display import display\n", | |
| "from grasp_library import compile_and_assemble_target\n", | |
| "from grasp_library import notebook_ui as ui\n", | |
| "\n", | |
| "ASSEMBLY = None\n", | |
| "\n", | |
| "if not RUN_COMPILE:\n", | |
| " ui.note(\"RUN_COMPILE is off.\")\n", | |
| "elif optimized_library is None:\n", | |
| " ui.note(\"Run Anneal library first.\")\n", | |
| "else:\n", | |
| " ASSEMBLY = compile_and_assemble_target(\n", | |
| " target_rna=CONFIG[\"target_rna\"],\n", | |
| " optimized_library=optimized_library,\n", | |
| " config=CONFIG,\n", | |
| " input_dir=INPUT_DIR,\n", | |
| " output_dir=OUTPUT_DIR,\n", | |
| " architecture=CONFIG.get(\"architecture\", \"9S\"),\n", | |
| " nterm_overhang=CONFIG.get(\"nterm_overhang\", \"AGGT\"),\n", | |
| " )\n", | |
| " display(ASSEMBLY[\"assembly_plan\"])\n", | |
| " asm = ASSEMBLY[\"assembled\"]\n", | |
| " warn = asm.get(\"stitch_warning\") or \"\"\n", | |
| " ui.status(\n", | |
| " f\"Target <b>{ASSEMBLY['target_rna']}</b> · \"\n", | |
| " f\"translation verified <b>{asm.get('translation_verified')}</b>\"\n", | |
| " + (f\"<br/>{warn}\" if warn else \"\")\n", | |
| " + f\"<br/>Plan → <code>{ASSEMBLY['plan_csv']}</code>\"\n", | |
| " + f\"<br/>FASTA → <code>{ASSEMBLY['assembled_fasta']}</code>\"\n", | |
| " )\n", | |
| " for key, value in asm.items():\n", | |
| " if key not in {\"assembled_cds\", \"expected_protein\", \"observed_protein\"}:\n", | |
| " print(f\"{key}: {value}\")\n" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "metadata": {}, | |
| "source": [ | |
| "## Notes\n", | |
| "\n", | |
| "| Step | What happens |\n", | |
| "|---|---|\n", | |
| "| Install | `pip install grasp-library-designer` from PyPI |\n", | |
| "| Import | Bundled GenBank → parts / junctions / candidates |\n", | |
| "| Redesign | Synonym overhangs at fixed cut indices |\n", | |
| "| Anneal | Masked SA for every module |\n", | |
| "| Compile | GAP part order + CDS stitch |\n", | |
| "\n", | |
| "For a **single binder without the combinatorial library**, open `grasp_oneshot_designer.ipynb`.\n", | |
| "\n", | |
| "Package: https://pypi.org/project/grasp-library-designer/\n" | |
| ] | |
| } | |
| ] | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment