Développement de protéines dans le cloud en utilisant Python et Transcriptic ou Comment créer une protéine pour 360 $

Et si vous avez une idée d'une protéine fraîche et saine, et que vous voulez l'obtenir en réalité? Par exemple, aimeriez-vous créer un vaccin contre H. pylori (comme l' équipe slovène à iGEM 2008 ) en créant une protéine hybride qui combine des fragments de flagelline d' E. Coli qui stimulent la réponse immunitaire avec la flagelline H. pylori habituelle?

H. pylori Hybrid Flagellin Design Présenté par l'équipe slovène à iGEM 2008

Étonnamment, nous sommes très près de créer toutes les protéines que nous voulons sans quitter le cahier de Jupyter, grâce aux derniers développements en génomique, en biologie synthétique et plus récemment dans les laboratoires de cloud computing.

Dans cet article, je vais montrer le code Python de l'idée d'une protéine à son expression dans une cellule bactérienne, sans toucher à une pipette ni parler à personne. Le coût total ne sera que de quelques centaines de dollars! En utilisant la terminologie de Vijaya Pande de A16Z , il s'agit de Biologie 2.0.

Plus précisément, dans l'article, le code Python du laboratoire cloud effectue les opérations suivantes:

  • Synthèse d' une séquence d'ADN qui code pour n'importe quelle protéine que je veux.
  • Clonage de cet ADN synthétique dans un vecteur pouvant l'exprimer.
  • Transformation des bactéries avec ce vecteur et confirmation de l'expression.

Configuration de Python


Tout d'abord, les paramètres généraux de Python qui sont nécessaires pour tout bloc-notes Jupyter. Nous importons des modules Python utiles et créons des fonctions utilitaires, principalement pour la visualisation des données.

Code
import re import json import logging import requests import itertools import numpy as np import seaborn as sns import pandas as pd import matplotlib as mpl import matplotlib.pyplot as plt from io import StringIO from pprint import pprint from Bio.Seq import Seq from Bio.Alphabet import generic_dna from IPython.display import display, Image, HTML, SVG def uprint(astr): print(astr + "\n" + "-"*len(astr)) def show_html(astr): return display(HTML('{}'.format(astr))) def show_svg(astr, w=1000, h=1000): SVG_HEAD = '''<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">''' SVG_START = '''<svg viewBox="0 0 {w:} {h:}" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink= "http://www.w3.org/1999/xlink">''' return display(SVG(SVG_HEAD + SVG_START.format(w=w, h=h) + astr + '</svg>')) def table_print(rows, header=True): html = ["<table>"] html_row = "</td><td>".join(k for k in rows[0]) html.append("<tr style='font-weight:{}'><td>{}</td></tr>".format('bold' if header is True else 'normal', html_row)) for row in rows[1:]: html_row = "</td><td>".join(row) html.append("<tr style='font-family:monospace;'><td>{:}</td></tr>".format(html_row)) html.append("</table>") show_html(''.join(html)) def clean_seq(dna): dna = re.sub("\s","",dna) assert all(nt in "ACGTN" for nt in dna) return Seq(dna, generic_dna) def clean_aas(aas): aas = re.sub("\s","",aas) assert all(aa in "ACDEFGHIKLMNPQRSTVWY*" for aa in aas) return aas def Images(images, header=None, width="100%"): # to match Image syntax if type(width)==type(1): width = "{}px".format(width) html = ["<table style='width:{}'><tr>".format(width)] if header is not None: html += ["<th>{}</th>".format(h) for h in header] + ["</tr><tr>"] for image in images: html.append("<td><img src='{}' /></td>".format(image)) html.append("</tr></table>") show_html(''.join(html)) def new_section(title, color="#66aa33", padding="120px"): style = "text-align:center;background:{};padding:{} 10px {} 10px;".format(color,padding,padding) style += "color:#ffffff;font-size:2.55em;line-height:1.2em;" return HTML('<div style="{}">{}</div>'.format(style, title)) # Show or hide text HTML(""" <style> .section { display:flex;align-items:center;justify-content:center;width:100%; height:400px; background:#6a3;color:#eee;font-size:275%; } .showhide_label { display:block; cursor:pointer; } .showhide { position: absolute; left: -999em; } .showhide + div { display: none; } .showhide:checked + div { display: block; } .shown_or_hidden { font-size:85%; } </style> """) # Plotting style plt.rc("axes", titlesize=20, labelsize=15, linewidth=.25, edgecolor='#444444') sns.set_context("notebook", font_scale=1.2, rc={}) %matplotlib inline %config InlineBackend.figure_format = 'retina' # or 'svg' 

Laboratoires cloud


Comme AWS ou tout autre cloud informatique, le laboratoire de cloud possède des équipements de biologie moléculaire, ainsi que des robots qu'il loue sur Internet. Vous pouvez envoyer des instructions à vos robots en cliquant sur quelques boutons de l'interface ou en écrivant du code qui les programme vous-même. Il n'est pas nécessaire d'écrire vos propres protocoles, comme je le ferai ici, une partie importante de la biologie moléculaire est des tâches de routine standard, il est donc généralement préférable de s'appuyer sur un protocole étranger fiable qui a montré une bonne interaction avec les robots.

Récemment, un certain nombre d'entreprises dotées de laboratoires cloud sont apparues: Transcriptic , Autodesk Wet Lab Accelerator (bêta et construit sur la base de Transcriptic), Arcturus BioCloud (bêta), Emerald Cloud Lab (bêta), Synthego (n'a pas encore commencé). Il existe même des entreprises construites au-dessus de laboratoires cloud tels que Desktop Genetics , spécialisé dans CRISPR. Des articles scientifiques sur l'utilisation des laboratoires cloud dans la vraie science commencent à paraître.

Au moment d'écrire ces lignes, seul Transcriptic est dans le domaine public, nous allons donc l'utiliser. Si je comprends bien, la plupart des activités de transcription reposent sur l'automatisation de protocoles courants, et l'écriture de vos propres protocoles en Python (comme je le ferai dans cet article) est moins courante.


«Cellule de travail» transcriptique avec réfrigérateurs en bas et divers équipements de laboratoire sur le stand

Je donnerai aux robots Transcriptic des instructions sur l' auto-protocole . Autoprotocol est un langage basé sur JSON pour écrire des protocoles pour les robots de laboratoire (et les humains, pour ainsi dire). Le protocole automatique est principalement réalisé sur cette bibliothèque Python . Le langage a été créé à l'origine et est toujours pris en charge par Transcriptic, mais, si je comprends bien, il est complètement ouvert. Il y a une bonne documentation .

Une idée intéressante est que vous pouvez écrire des instructions pour les personnes dans des laboratoires distants, par exemple en Chine ou en Inde, sur l'auto-protocole et potentiellement obtenir des avantages en utilisant à la fois des personnes (leur jugement) et des robots (manque de jugement). Nous devons mentionner ici protocoles.io , il s'agit d'une tentative de normalisation des protocoles pour améliorer la reproductibilité, mais pour les humains, pas pour les robots.

 "instructions": [ { "to": [ { "well": "water/0", "volume": "500.0:microliter" } ], "op": "provision", "resource_id": "rs17gmh5wafm5p" }, ... ] 

Exemple de fragment autoprotocole

Paramètres Python pour la biologie moléculaire


En plus d'importer des bibliothèques standard, j'aurai besoin de certains utilitaires biologiques moléculaires spécifiques. Ce code est principalement destiné aux protocoles automatiques et transcriptiques.

Le concept de «volume mort» se retrouve souvent dans le code. Cela signifie la dernière goutte de liquide que les robots Transcriptic ne peuvent pas prendre avec une pipette des tubes (car ils ne peuvent pas la voir!). Vous devez passer beaucoup de temps pour vous assurer que les flacons contiennent suffisamment de matière.

Code
 import autoprotocol from autoprotocol import Unit from autoprotocol.container import Container from autoprotocol.protocol import Protocol from autoprotocol.protocol import Ref # "Link a ref name (string) to a Container instance." import requests import logging # Transcriptic authorization org_name = 'hgbrian' tsc_headers = {k:v for k,v in json.load(open("auth.json")).items() if k in ["X_User_Email","X_User_Token"]} # Transcriptic-specific dead volumes _dead_volume = [("96-pcr",3), ("96-flat",25), ("96-flat-uv",25), ("96-deep",15), ("384-pcr",2), ("384-flat",5), ("384-echo",15), ("micro-1.5",15), ("micro-2.0",15)] dead_volume = {k:Unit(v,"microliter") for k,v in _dead_volume} def init_inventory_well(well, headers=tsc_headers, org_name=org_name): """Initialize well (set volume etc) for Transcriptic""" def _container_url(container_id): return 'https://secure.transcriptic.com/{}/samples/{}.json'.format(org_name, container_id) response = requests.get(_container_url(well.container.id), headers=headers) response.raise_for_status() container = response.json() well_data = container['aliquots'][well.index] well.name = "{}/{}".format(container["label"], well_data['name']) if well_data['name'] is not None else container["label"] well.properties = well_data['properties'] well.volume = Unit(well_data['volume_ul'], 'microliter') if 'ERROR' in well.properties: raise ValueError("Well {} has ERROR property: {}".format(well, well.properties["ERROR"])) if well.volume < Unit(20, "microliter"): logging.warn("Low volume for well {} : {}".format(well.name, well.volume)) return True def touchdown(fromC, toC, durations, stepsize=2, meltC=98, extC=72): """Touchdown PCR protocol generator""" assert 0 < stepsize < toC < fromC def td(temp, dur): return {"temperature":"{:2g}:celsius".format(temp), "duration":"{:d}:second".format(dur)} return [{"cycles": 1, "steps": [td(meltC, durations[0]), td(C, durations[1]), td(extC, durations[2])]} for C in np.arange(fromC, toC-stepsize, -stepsize)] def convert_ug_to_pmol(ug_dsDNA, num_nts): """Convert ug dsDNA to pmol""" return float(ug_dsDNA)/num_nts * (1e6 / 660.0) def expid(val): """Generate a unique ID per experiment""" return "{}_{}".format(experiment_name, val) def µl(microliters): """Unicode function name for creating microliter volumes""" return Unit(microliters,"microliter") 

Synthèse d'ADN et biologie synthétique


Malgré sa connexion avec la biologie synthétique moderne, la synthèse d'ADN est une technologie assez ancienne. Pendant des décennies, nous avons pu fabriquer des oligonucléotides (c'est-à-dire des séquences d'ADN jusqu'à 200 bases). Cependant, c'était toujours cher, et la chimie n'a jamais permis de longues séquences d'ADN. Récemment, il est devenu possible à un prix raisonnable de synthétiser des gènes entiers (jusqu'à des milliers de bases). Cette réalisation ouvre véritablement l'ère de la «biologie synthétique».

La génomique synthétique de Craig Venter a poussé la biologie synthétique le plus loin en synthétisant un organisme entier - plus d'un million de bases de long. À mesure que la longueur de l'ADN augmente, le problème n'est plus la synthèse, mais l'assemblage (c'est-à-dire l'assemblage de séquences d'ADN synthétisées). Avec chaque assemblage, vous pouvez doubler la longueur d'ADN (ou plus), donc après une dizaine d'itérations, vous obtenez une molécule assez longue ! La distinction entre synthèse et assemblage devrait bientôt devenir claire pour l'utilisateur final.

La loi de Moore?


Le prix de la synthèse d'ADN baisse assez rapidement, passant de plus de 0,30 $ il y a deux ans à environ 0,10 $ aujourd'hui, mais elle se développe plus comme des bactéries que comme des processeurs. En revanche, les prix du séquençage de l'ADN baissent plus rapidement que la loi de Moore. Un objectif de 0,02 $ par base est défini comme un point d'inflexion où vous pouvez remplacer de nombreuses manipulations d'ADN chronophages par une simple synthèse. Par exemple, à ce prix, vous pouvez synthétiser un plasmide entier de 3 ko pour 60 $ et sauter un tas de biologie moléculaire. J'espère que nous y parviendrons dans quelques années.


Prix ​​de synthèse d'ADN comparés aux prix de séquençage d'ADN, prix pour 1 base (Carlson, 2014)

Entreprises de synthèse d'ADN


Il existe plusieurs grandes entreprises dans le domaine de la synthèse d'ADN: IDT est le plus grand producteur d'oligonucléotides et peut également produire des «fragments de gènes» ( gBlocks ) plus longs (jusqu'à 2 kb ). Gen9 , Twist et DNA 2.0 se spécialisent généralement dans les séquences d'ADN plus longues - ce sont des sociétés de synthèse de gènes. Il existe également de nouvelles sociétés intéressantes, telles que Cambrian Genomics et Genesis DNA , qui travaillent sur des méthodes de synthèse de nouvelle génération.

D'autres sociétés, comme Amyris , Zymergen et Ginkgo Bioworks , utilisent l'ADN synthétisé par ces sociétés pour travailler au niveau du corps. La génomique synthétique le fait aussi, mais elle synthétise l'ADN lui-même.

Ginkgo a récemment conclu un accord avec Twist pour faire 100 millions de bases: le plus gros accord que j'ai vu. Cela prouve que nous vivons dans le futur, Twist a même annoncé un code promotionnel sur Twitter: lorsque vous achetez 10 millions de bases d'ADN (presque tout le génome de la levure!), Vous obtenez 10 millions supplémentaires gratuitement.


Offre Twitter Twist Niche

Première partie: Conception de l'expérience


Protéine fluorescente verte


Dans cette expérience, nous synthétisons une séquence d'ADN pour une simple protéine fluorescente verte (GFP). La protéine GFP a été découverte pour la première fois dans une méduse fluorescente sous lumière ultraviolette. Il s'agit d'une protéine extrêmement utile car il est facile de détecter son expression simplement en mesurant la fluorescence. Il existe des options GFP qui produisent du jaune, du rouge, de l'orange et d'autres couleurs.

Il est intéressant de voir comment diverses mutations affectent la couleur d'une protéine, et c'est un problème d'apprentissage automatique potentiellement intéressant. Plus récemment, il faudrait passer beaucoup de temps en laboratoire pour cela, mais maintenant je vais vous montrer que c'est (presque) aussi simple que d'éditer un fichier texte!

Techniquement, mon GFP est une option Super Folder (sfGFP) avec quelques mutations pour améliorer la qualité.


Dans superfolder-GFP (sfGFP), certaines mutations lui confèrent certaines propriétés utiles.


Structure GFP (visualisée à l'aide de PV )

Synthèse de GFP dans Twist


J'ai eu la chance de participer au programme de test alpha de Twist, j'ai donc utilisé leur service de synthèse d'ADN (ils ont gentiment passé ma petite commande - merci, Twist!). Il s'agit d'une nouvelle entreprise dans notre domaine, avec un nouveau processus de synthèse simplifié. Leurs prix sont d'environ 0,10 $ par base ou moins , mais ils sont toujours en version bêta , et le programme alpha auquel j'ai participé a été fermé. Twist a recueilli environ 150 millions de dollars, de sorte que leur technologie est vivante.

J'ai envoyé ma séquence d'ADN à Twist sous forme de feuille de calcul Excel (il n'y a pas encore d'API, mais je suppose que ce sera bientôt), et ils ont envoyé l'ADN synthétisé directement dans ma boîte dans le laboratoire de transcription (j'ai également utilisé IDT pour la synthèse, mais ils n'ont pas envoyé ADN en transcriptic, ce qui gâche un peu le plaisir).

De toute évidence, ce processus n'est pas encore devenu un cas d'utilisation typique et nécessite un certain support, mais il a fonctionné, de sorte que l'ensemble du pipeline reste virtuel. Sans cela, j'aurais probablement besoin d'avoir accès au laboratoire - de nombreuses entreprises n'enverront pas d'ADN ou de réactifs à leur domicile.


GFP est inoffensif, donc tout type est mis en évidence

Vecteur plasmidique


Pour exprimer cette protéine dans des bactéries, le gène doit vivre quelque part, sinon l'ADN synthétique codant pour le gène se dégrade simplement instantanément. En règle générale, en biologie moléculaire, nous utilisons un plasmide, un morceau d'ADN rond qui vit en dehors du génome bactérien et exprime des protéines. Les plasmides sont un moyen pratique pour les bactéries de partager des modules fonctionnels utiles et autonomes, tels que la résistance aux antibiotiques. Il peut y avoir des centaines de plasmides dans une cellule.

La terminologie largement utilisée est qu'un plasmide est un vecteur et que l'ADN synthétique est une insertion (insertion). Donc, ici, nous essayons de cloner l'insertion dans un vecteur, puis de transformer les bactéries à l'aide du vecteur.


Génome bactérien et plasmide (pas à l'échelle!) ( Wikipedia )

pUC19


J'ai choisi un plasmide assez standard dans la série pUC19 . Ce plasmide est très souvent utilisé, et puisqu'il est disponible dans le cadre de l'inventaire transcriptique standard, nous n'avons pas besoin de leur envoyer quoi que ce soit.


Structure de pUC19: les principaux composants sont le gène de résistance à l'ampicilline, lacZα, MCS / polylinker et l'origine de la réplication (Wikipedia)

Le PUC19 a une fonction intéressante: puisqu'il contient le gène lacZα, vous pouvez utiliser la méthode de sélection bleu-blanc dessus et voir dans quelles colonies l'insertion a réussi. Deux produits chimiques sont nécessaires: IPTG et X-gal , et le circuit fonctionne comme suit:

  • L'IPTG induit l'expression de lacZα.
  • Si lacZα est désactivé via l'ADN inséré au site de clonage multiple ( MCS / polylinker ) dans lacZα, alors le plasmide ne peut pas hydrolyser X-gal et ces colonies seront blanches au lieu de bleu.
  • Par conséquent, une insertion réussie produit des colonies blanches et une insertion échouée produit des colonies bleues.


La sélection en bleu et blanc montre où l'expression lacZα a été désactivée ( Wikipedia )

La documentation openwetware indique:

E. coli DH5α ne nécessite pas d'IPTG pour induire l'expression du promoteur lac, même si un répresseur Lac est exprimé dans la souche. Le nombre de copies de la plupart des plasmides dépasse le nombre de répresseurs dans les cellules. Si vous avez besoin d'une expression maximale, ajoutez IPTG à une concentration finale de 1 mM.

Séquences d'ADN synthétique


Séquence d'ADN SfGFP


Il est facile d'obtenir la séquence d'ADN de sfGFP en prenant la séquence protéique et en la codant avec des codons appropriés pour l'organisme hôte (ici, E. coli ). Il s'agit d'une protéine de taille moyenne avec 236 acides aminés, donc à 10 cents la synthèse d'ADN coûte environ 70 $ par base.


Wolfram Alpha, calcul des coûts de synthèse

Les 12 premières bases de notre sfGFP sont la séquence Shine-Delgarno , que j'ai ajoutée moi-même, qui devrait théoriquement augmenter l'expression (AGGAGGACAGCT, puis ATG ( start codon ) démarre la protéine). Selon un outil de calcul développé par Salis Lab ( diapositives de cours ), on peut s'attendre à une expression moyenne à élevée de notre protéine (taux d'initiation de la traduction de 10 000 «unités arbitraires»).

 sfGFP_plus_SD = clean_seq(""" AGGAGGACAGCTATGTCGAAAGGAGAAGAACTGTTTACCGGTGTGGTTCCGATTCTGGTAGAACTGGA TGGGGACGTGAACGGCCATAAATTTAGCGTCCGTGGTGAGGGTGAAGGGGATGCCACAAATGGCAAAC TTACCCTTAAATTCATTTGCACTACCGGCAAGCTGCCGGTCCCTTGGCCGACCTTGGTCACCACACTG ACGTACGGGGTTCAGTGTTTTTCGCGTTATCCAGATCACATGAAACGCCATGACTTCTTCAAAAGCGC CATGCCCGAGGGCTATGTGCAGGAACGTACGATTAGCTTTAAAGATGACGGGACCTACAAAACCCGGG CAGAAGTGAAATTCGAGGGTGATACCCTGGTTAATCGCATTGAACTGAAGGGTATTGATTTCAAGGAA GATGGTAACATTCTCGGTCACAAATTAGAATACAACTTTAACAGTCATAACGTTTATATCACCGCCGA CAAACAGAAAAACGGTATCAAGGCGAATTTCAAAATCCGGCACAACGTGGAGGACGGGAGTGTACAAC TGGCCGACCATTACCAGCAGAACACACCGATCGGCGACGGCCCGGTGCTGCTCCCGGATAATCACTAT TTAAGCACCCAGTCAGTGCTGAGCAAAGATCCGAACGAAAAACGTGACCATATGGTGCTGCTGGAGTT CGTGACCGCCGCGGGCATTACCCATGGAATGGATGAACTGTATAAA""") print("Read in sfGFP plus Shine-Dalgarno: {} bases long".format(len(sfGFP_plus_SD))) sfGFP_aas = clean_aas("""MSKGEELFTGVVPILVELDGDVNGHKFSVRGEGEGDATNGKLTLKFICTTGKLPVPWPTLVTTLTYG VQCFSRYPDHMKRHDFFKSAMPEGYVQERTISFKDDGTYKTRAEVKFEGDTLVNRIELKGIDFKEDGNILGHKLEYNFNSHNVYITADKQKN GIKANFKIRHNVEDGSVQLADHYQQNTPIGDGPVLLPDNHYLSTQSVLSKDPNEKRDHMVLLEFVTAAGITHGMDELYK""") assert sfGFP_plus_SD[12:].translate() == sfGFP_aas print("Translation matches protein with accession 532528641") 

  Lire dans sfGFP plus Shine-Dalgarno: 726 bases de long
 La traduction correspond à la protéine avec l'accession 532528641 

Séquence d'ADN PUC19


Tout d'abord, je vérifie que la séquence pUC19 que j'ai téléchargée de l'ONÉ a la bonne longueur et qu'elle inclut le polylinker attendu.

 pUC19_fasta = !cat puc19fsa.txt pUC19_fwd = clean_seq(''.join(pUC19_fasta[1:])) pUC19_rev = pUC19_fwd.reverse_complement() assert all(nt in "ACGT" for nt in pUC19_fwd) assert len(pUC19_fwd) == 2686 pUC19_MCS = clean_seq("GAATTCGAGCTCGGTACCCGGGGATCCTCTAGAGTCGACCTGCAGGCATGCAAGCTT") print("Read in pUC19: {} bases long".format(len(pUC19_fwd))) assert pUC19_MCS in pUC19_fwd print("Found MCS/polylinker") 

  Lire en pUC19: 2686 bases de long
 Trouvé MCS / polylinker 

Nous faisons quelques QC de base pour nous assurer que EcoRI et BamHI ne sont présents dans pUC19 qu'une seule fois (les enzymes de restriction suivantes sont disponibles dans l'inventaire transcriptique par défaut: PstI , PvuII , EcoRI , BamHI , BbsI , BsmBI ).

 REs = {"EcoRI":"GAATTC", "BamHI":"GGATTC"} for rename, res in REs.items(): assert (pUC19_fwd.find(res) == pUC19_fwd.rfind(res) and pUC19_rev.find(res) == pUC19_rev.rfind(res)) assert (pUC19_fwd.find(res) == -1 or pUC19_rev.find(res) == -1 or pUC19_fwd.find(res) == len(pUC19_fwd) - pUC19_rev.find(res) - len(res)) print("Asserted restriction enzyme sites present only once: {}".format(REs.keys())) 

Maintenant, nous regardons la séquence lacZα et vérifions qu'il n'y a rien d'inattendu. Par exemple, il doit commencer par Met et se terminer par un codon stop. Il est également facile de confirmer qu'il s'agit de l'ORF lacZα complet de 324 pb en chargeant la séquence pUC19 dans le visualiseur Snapgene gratuit.

 lacZ = pUC19_rev[2217:2541] print("lacZα sequence:\t{}".format(lacZ)) print("r_MCS sequence:\t{}".format(pUC19_MCS.reverse_complement())) lacZ_p = lacZ.translate() assert lacZ_p[0] == "M" and not "*" in lacZ_p[:-1] and lacZ_p[-1] == "*" assert pUC19_MCS.reverse_complement() in lacZ assert pUC19_MCS.reverse_complement() == pUC19_rev[2234:2291] print("Found MCS once in lacZ sequence") 

  séquence lacZ: ATGACCATGATTACGCCAAGCTTGCATGCCTGCAGGTCGACTCTAGAGGATCCCCGGGTACCGAGCTCGAATTCACTGGCCGTCGTTTTACAACGTCGTGACTGGGAAAACCCTGGCGTTACCCAACTTAATCGCCTTGCAGCACATCCCCCTTTCGCCAGCTGGCGTAATAGCGAAGAGGCCCGCACCGATCGCCCTTCCCAACAGTTGCGCAGCCTGAATGGCGAATGGCGCCTGATGCGGTATTTTCTCCTTACGCATCTGTGCGGTATTTCACACCGCATATGGTGCACTCTCAGTACAATCTGCTCTGATGCCGCATAG
 séquence r_MCS: AAGCTTGCATGCCTGCAGGTCGACTCTAGAGGATCCCCGGGTACCGAGCTCGAATTC
 MCS trouvé une fois dans la séquence lacZ 

Assemblage Gibson


L'assemblage d'ADN signifie simplement des fragments de réticulation. Habituellement, vous collectez plusieurs fragments d'ADN dans un segment plus long, puis vous les clonez dans un plasmide ou un génome. Dans cette expérience, je veux cloner un segment d'ADN dans le plasmide pUC19 sous le promoteur lac pour l'expression dans E. coli .

Il existe de nombreuses méthodes de clonage (par exemple NEB , openwetware , addgene ). Ici, je vais utiliser l'assemblage Gibson ( développé par Daniel Gibson dans Synthetic Genomics en 2009), qui n'est pas nécessairement la méthode la moins chère, mais simple et flexible. Il vous suffit de mettre l'ADN que vous souhaitez collecter (avec le chevauchement approprié) dans un tube à essai avec le Gibson Assembly Master Mix, et il s'assemblera!


Revue de l'Assemblée Gibson ( ONÉ )

Matériel d'origine


On commence avec 100 ng d'ADN synthétique dans 10 µl de liquide. Cela équivaut à 0,21 picomole d'ADN ou à une concentration de 10 ng / μl.

 pmol_sfgfp = convert_ug_to_pmol(0.1, len(sfGFP_plus_SD)) print("Insert: 100ng of DNA of length {:4d} equals {:.2f} pmol".format(len(sfGFP_plus_SD), pmol_sfgfp)) 

  Insert: 100ng d'ADN de longueur 726 est égal à 0,21 pmol 

Selon le protocole d'assemblage de l'ONÉ , c'est assez de matériel source:

L'ONÉ recommande un total de 0,02 à 0,5 picomole de fragments d'ADN lorsque 1 ou 2 fragments sont assemblés dans le vecteur, ou 0,2 à 1,0 picomole de fragments d'ADN lorsque 4 à 6 fragments sont collectés.

0,02-0,5 pmoles * X μl
* L'efficacité de clonage optimisée est de 50 à 100 ng de vecteurs avec 2-3 fois plus d'insertions. Utilisez 5 fois plus d'insertions si la taille est inférieure à 200 bps. Le volume total de fragments de PCR non filtrés dans la réaction d'assemblage de Gibson ne doit pas dépasser 20%.

NEBuilder pour l'assemblage Gibson


NEBuilder de Biolab est un très bon outil pour créer un protocole de construction Gibson. Il vous génère même un PDF complet de quatre pages avec toutes les informations. En utilisant cet outil, nous développons un protocole pour couper pUC19 avec EcoRI, puis utilisons la PCR [PCR, la réaction en chaîne par polymérase permet d'obtenir une augmentation significative des petites concentrations de certains fragments d'ADN dans le matériel biologique - env. par.] pour ajouter des fragments de la taille appropriée à l'insertion.



Deuxième partie: expérimenter


L'expérience comprend quatre étapes:

  1. Réaction d'insertion de chaîne de polymérase pour ajouter du matériel avec une séquence flanquante.
  2. Couper un plasmide pour permettre l'insertion.
  3. Assemblage par insertion de Gibson et plasmides.
  4. Transformation de bactéries à l'aide du plasmide assemblé.

Étape 1. Insertion PCR


L'assemblage Gibson dépend de la séquence d'ADN que vous collectez, ayant une séquence qui se chevauchent (voir le protocole NEB avec les instructions détaillées ci-dessus). En plus d'une simple amplification, la PCR vous permet également d'ajouter une séquence d'ADN flanquante en incluant simplement une séquence supplémentaire dans les amorces (peut également être clonée en utilisant uniquement OE-PCR ).

Nous synthétisons les amorces selon le protocole NEB ci-dessus. J'ai essayé le protocole Quickstart sur le site Transcriptic, mais il y a toujours une commande auto- protocol . Le transcriptic lui-même ne synthétise pas les oligonucléotides, donc après 1-2 jours d'attente, ces amorces apparaissent comme par magie dans mon inventaire (notez que la partie spécifique au gène des amorces est indiquée en majuscule ci-dessous, mais ce ne sont que des choses cosmétiques).

 insert_primers = ["aaacgacggccagtgTTTATACAGTTCATCCATTCCATG", "cgggtaccgagctcgAGGAGGACAGCTATGTCG"] 

Analyse d'amorce


Vous pouvez analyser les propriétés de ces amorces à l'aide de l' IDT OligoAnalyzer . PCR primer dimer , NEB .

 Gene-specific portion of flank (uppercase)
  Melt temperature: 51C, 53.5C
Full sequence
  Melt temperature: 64.5C, 68.5C
  Hairpin: -.4dG, -5dG
  Self-dimer: -9dG, -16dG
  Heterodimer: -6dG 

PCR, , PCR. ( ), : . . , — .

Code
 """ PCR overlap extension of sfGFP according to NEB protocol. v5: Use 3/10ths as much primer as the v4 protocol. v6: more complex touchdown pcr procedure. The Q5 temperature was probably too hot v7: more time at low temperature to allow gene-specific part to anneal v8: correct dNTP concentration, real touchdown """ p = Protocol() # --------------------------------------------------- # Set up experiment # experiment_name = "sfgfp_pcroe_v8" template_length = 740 _options = {'dilute_primers' : False, # if working stock has not been made 'dilute_template': False, # if working stock has not been made 'dilute_dNTP' : False, # if working stock has not been made 'run_gel' : True, # run a gel to see the plasmid size 'run_absorbance' : False, # check absorbance at 260/280/320 'run_sanger' : False} # sanger sequence the new sequence options = {k for k,v in _options.items() if v is True} # --------------------------------------------------- # Inventory and provisioning # https://developers.transcriptic.com/v1.0/docs/containers # # 'sfgfp2': 'ct17yx8h77tkme', # inventory; sfGFP tube #2, micro-1.5, cold_20 # 'sfgfp_puc19_primer1': 'ct17z9542mrcfv', # inventory; micro-2.0, cold_4 # 'sfgfp_puc19_primer2': 'ct17z9542m5ntb', # inventory; micro-2.0, cold_4 # 'sfgfp_idt_1ngul': 'ct184nnd3rbxfr', # inventory; micro-1.5, cold_4, (ERROR: no template) # inv = { 'Q5 Polymerase': 'rs16pcce8rdytv', # catalog; Q5 High-Fidelity DNA Polymerase 'Q5 Buffer': 'rs16pcce8rmke3', # catalog; Q5 Reaction Buffer 'dNTP Mixture': 'rs16pcb542c5rd', # catalog; dNTP Mixture (25mM?) 'water': 'rs17gmh5wafm5p', # catalog; Autoclaved MilliQ H2O 'sfgfp_pcroe_v5_puc19_primer1_10uM': 'ct186cj5cqzjmr', # inventory; micro-1.5, cold_4 'sfgfp_pcroe_v5_puc19_primer2_10uM': 'ct186cj5cq536x', # inventory; micro-1.5, cold_4 'sfgfp1': 'ct17yx8h759dk4', # inventory; sfGFP tube #1, micro-1.5, cold_20 } # Existing inventory template_tube = p.ref("sfgfp1", id=inv['sfgfp1'], cont_type="micro-1.5", storage="cold_4").well(0) dilute_primer_tubes = [p.ref('sfgfp_pcroe_v5_puc19_primer1_10uM', id=inv['sfgfp_pcroe_v5_puc19_primer1_10uM'], cont_type="micro-1.5", storage="cold_4").well(0), p.ref('sfgfp_pcroe_v5_puc19_primer2_10uM', id=inv['sfgfp_pcroe_v5_puc19_primer2_10uM'], cont_type="micro-1.5", storage="cold_4").well(0)] # New inventory resulting from this experiment dilute_template_tube = p.ref("sfgfp1_0.25ngul", cont_type="micro-1.5", storage="cold_4").well(0) dNTP_10uM_tube = p.ref("dNTP_10uM", cont_type="micro-1.5", storage="cold_4").well(0) sfgfp_pcroe_out_tube = p.ref(expid("amplified"), cont_type="micro-1.5", storage="cold_4").well(0) # Temporary tubes for use, then discarded mastermix_tube = p.ref("mastermix", cont_type="micro-1.5", storage="cold_4", discard=True).well(0) water_tube = p.ref("water", cont_type="micro-1.5", storage="ambient", discard=True).well(0) pcr_plate = p.ref("pcr_plate", cont_type="96-pcr", storage="cold_4", discard=True) if 'run_absorbance' in options: abs_plate = p.ref("abs_plate", cont_type="96-flat", storage="cold_4", discard=True) # Initialize all existing inventory all_inventory_wells = [template_tube] + dilute_primer_tubes for well in all_inventory_wells: init_inventory_well(well) print(well.name, well.volume, well.properties) # ----------------------------------------------------- # Provision water once, for general use # p.provision(inv["water"], water_tube, µl(500)) # ----------------------------------------------------- # Dilute primers 1/10 (100uM->10uM) and keep at 4C # if 'dilute_primers' in options: for primer_num in (0,1): p.transfer(water_tube, dilute_primer_tubes[primer_num], µl(90)) p.transfer(primer_tubes[primer_num], dilute_primer_tubes[primer_num], µl(10), mix_before=True, mix_vol=µl(50)) p.mix(dilute_primer_tubes[primer_num], volume=µl(50), repetitions=10) # ----------------------------------------------------- # Dilute template 1/10 (10ng/ul->1ng/ul) and keep at 4C # OR # Dilute template 1/40 (10ng/ul->0.25ng/ul) and keep at 4C # if 'dilute_template' in options: p.transfer(water_tube, dilute_template_tube, µl(195)) p.mix(dilute_template_tube, volume=µl(100), repetitions=10) # Dilute dNTP to exactly 10uM if 'dilute_DNTP' in options: p.transfer(water_tube, dNTP_10uM_tube, µl(6)) p.provision(inv["dNTP Mixture"], dNTP_10uM_tube, µl(4)) # ----------------------------------------------------- # Q5 PCR protocol # www.neb.com/protocols/2013/12/13/pcr-using-q5-high-fidelity-dna-polymerase-m0491 # # 25ul reaction # ------------- # Q5 reaction buffer 5 µl # Q5 polymerase 0.25 µl # 10mM dNTP 0.5 µl -- 1µl = 4x12.5mM # 10uM primer 1 1.25 µl # 10uM primer 2 1.25 µl # 1pg-1ng Template 1 µl -- 0.5 or 1ng/ul concentration # ------------------------------- # Sum 9.25 µl # # # Mastermix tube will have 96ul of stuff, leaving space for 4x1ul aliquots of template p.transfer(water_tube, mastermix_tube, µl(64)) p.provision(inv["Q5 Buffer"], mastermix_tube, µl(20)) p.provision(inv['Q5 Polymerase'], mastermix_tube, µl(1)) p.transfer(dNTP_10uM_tube, mastermix_tube, µl(1), mix_before=True, mix_vol=µl(2)) p.transfer(dilute_primer_tubes[0], mastermix_tube, µl(5), mix_before=True, mix_vol=µl(10)) p.transfer(dilute_primer_tubes[1], mastermix_tube, µl(5), mix_before=True, mix_vol=µl(10)) p.mix(mastermix_tube, volume="48:microliter", repetitions=10) # Transfer mastermix to pcr_plate without template p.transfer(mastermix_tube, pcr_plate.wells(["A1","B1","C1"]), µl(24)) p.transfer(mastermix_tube, pcr_plate.wells(["A2"]), µl(24)) # acknowledged dead volume problems p.mix(pcr_plate.wells(["A1","B1","C1","A2"]), volume=µl(12), repetitions=10) # Finally add template p.transfer(template_tube, pcr_plate.wells(["A1","B1","C1"]), µl(1)) p.mix(pcr_plate.wells(["A1","B1","C1"]), volume=µl(12.5), repetitions=10) # --------------------------------------------------------- # Thermocycle with Q5 and hot start # 61.1 annealing temperature is recommended by NEB protocol # p.seal is enforced by transcriptic # extension_time = int(max(2, np.ceil(template_length * (11.0/1000)))) assert 0 < extension_time < 60, "extension time should be reasonable for PCR" cycles = [{"cycles": 1, "steps": [{"temperature": "98:celsius", "duration": "30:second"}]}] + \ touchdown(70, 61, [8, 25, extension_time], stepsize=0.5) + \ [{"cycles": 16, "steps": [{"temperature": "98:celsius", "duration": "8:second"}, {"temperature": "61.1:celsius", "duration": "25:second"}, {"temperature": "72:celsius", "duration": "{:d}:second".format(extension_time)}]}, {"cycles": 1, "steps": [{"temperature": "72:celsius", "duration": "2:minute"}]}] p.seal(pcr_plate) p.thermocycle(pcr_plate, cycles, volume=µl(25)) # -------------------------------------------------------- # Run a gel to hopefully see a 740bp fragment # if 'run_gel' in options: p.unseal(pcr_plate) p.mix(pcr_plate.wells(["A1","B1","C1","A2"]), volume=µl(12.5), repetitions=10) p.transfer(pcr_plate.wells(["A1","B1","C1","A2"]), pcr_plate.wells(["D1","E1","F1","D2"]), [µl(2), µl(4), µl(8), µl(8)]) p.transfer(water_tube, pcr_plate.wells(["D1","E1","F1","D2"]), [µl(18),µl(16),µl(12),µl(12)], mix_after=True, mix_vol=µl(10)) p.gel_separate(pcr_plate.wells(["D1","E1","F1","D2"]), µl(20), "agarose(10,2%)", "ladder1", "10:minute", expid("gel")) #--------------------------------------------------------- # Absorbance dilution series. Take 1ul out of the 25ul pcr plate wells # if 'run_absorbance' in options: p.unseal(pcr_plate) abs_wells = ["A1","B1","C1","A2","B2","C2","A3","B3","C3"] p.transfer(water_tube, abs_plate.wells(abs_wells[0:6]), µl(10)) p.transfer(water_tube, abs_plate.wells(abs_wells[6:9]), µl(9)) p.transfer(pcr_plate.wells(["A1","B1","C1"]), abs_plate.wells(["A1","B1","C1"]), µl(1), mix_after=True, mix_vol=µl(5)) p.transfer(abs_plate.wells(["A1","B1","C1"]), abs_plate.wells(["A2","B2","C2"]), µl(1), mix_after=True, mix_vol=µl(5)) p.transfer(abs_plate.wells(["A2","B2","C2"]), abs_plate.wells(["A3","B3","C3"]), µl(1), mix_after=True, mix_vol=µl(5)) for wavelength in [260, 280, 320]: p.absorbance(abs_plate, abs_plate.wells(abs_wells), "{}:nanometer".format(wavelength), exp_id("abs_{}".format(wavelength)), flashes=25) # ----------------------------------------------------------------------------- # Sanger sequencing: https://developers.transcriptic.com/docs/sanger-sequencing # "Each reaction should have a total volume of 15 µl and we recommend the following composition of DNA and primer: # PCR product (40 ng), primer (1 µl of a 10 µM stock)" # # By comparing to the gel ladder concentration (175ng/lane), it looks like 5ul of PCR product has approximately 30ng of DNA # if 'run_sanger' in options: p.unseal(pcr_plate) seq_wells = ["G1","G2"] for primer_num, seq_well in [(0, seq_wells[0]),(1, seq_wells[1])]: p.transfer(dilute_primer_tubes[primer_num], pcr_plate.wells([seq_well]), µl(1), mix_before=True, mix_vol=µl(50)) p.transfer(pcr_plate.wells(["A1"]), pcr_plate.wells([seq_well]), µl(5), mix_before=True, mix_vol=µl(10)) p.transfer(water_tube, pcr_plate.wells([seq_well]), µl(9)) p.mix(pcr_plate.wells(seq_wells), volume=µl(7.5), repetitions=10) p.sangerseq(pcr_plate, pcr_plate.wells(seq_wells[0]).indices(), expid("seq1")) p.sangerseq(pcr_plate, pcr_plate.wells(seq_wells[1]).indices(), expid("seq2")) # ------------------------------------------------------------------------- # Then consolidate to one tube. Leave at least 3ul dead volume in each tube # remaining_volumes = [well.volume - dead_volume['96-pcr'] for well in pcr_plate.wells(["A1","B1","C1"])] print("Consolidated volume", sum(remaining_volumes, µl(0))) p.consolidate(pcr_plate.wells(["A1","B1","C1"]), sfgfp_pcroe_out_tube, remaining_volumes, allow_carryover=True) uprint("\nProtocol 1. Amplify the insert (oligos previously synthesized)") jprotocol = json.dumps(p.as_dict(), indent=2) !echo '{jprotocol}' | transcriptic analyze open("protocol_{}.json".format(experiment_name),'w').write(jprotocol) 

 WARNING:root:Low volume for well sfGFP 1 /sfGFP 1 : 2.0:microliter 

 sfGFP 1 /sfGFP 1 2.0:microliter {'dilution': '0.25ng/ul'}
sfgfp_pcroe_v5_puc19_primer1_10uM 75.0:microliter {}
sfgfp_pcroe_v5_puc19_primer2_10uM 75.0:microliter {}
Consolidated volume 52.0:microliter

Protocol 1. Amplify the insert (oligos previously synthesized)
---------------------------------------------------------------

  
✓ Protocol analyzed
  11 instructions
  8 containers
  Total Cost: $32.18
  Workcell Time: $4.32
  Reagents & Consumables: $27.86 

: PCR



( ) ( ). , , .

D1, E1, F1 2 , 4 8 . (50 ). , .

GelEval , , , , . . GelEval 40 /.

, , dNTP , , 12,5 , 6 740bp 25 . GelEval 40 x 25 (1 2 ), , .


- EcoRI- pUC19, (D1, E1, F1), (D2)

PCR


Transcriptic . , .

, . 35 PCR, PCR . — ! — , PCR , .


PCR: , 35 42

2.


sfGFP pUC19, . NEB, EcoRI . Transcriptic , : NEB EcoRI 10x CutSmart , NEB pUC19 .

, . , Transcriptic :

 Item ID Amount Concentration Price
------------ ------ ------------- ----------------- ------
CutSmart 10x B7204S 5 ml 10 X $19.00
EcoRI R3101L 50,000 units 20,000 units/ml $225.00
pUC19 N3041L 250 µg 1,000 µg/ml $268.00 

NEB:

. 10X dH2O 1X. , , , , . 50 5 10x NEBuffer , dH2O.

, 1 λ 1 37°C 50 . , 5-10 10-20 1- .

1 50 .

Code
 """Protocol for cutting pUC19 with EcoRI.""" p = Protocol() experiment_name = "puc19_ecori_v3" options = {} inv = { 'water': "rs17gmh5wafm5p", # catalog; Autoclaved MilliQ H2O; ambient "pUC19": "rs17tcqmncjfsh", # catalog; pUC19; cold_20 "EcoRI": "rs17ta8xftpdk6", # catalog; EcoRI-HF; cold_20 "CutSmart": "rs17ta93g3y85t", # catalog; CutSmart Buffer 10x; cold_20 "ecori_p10x": "ct187v4ea85k2h", # inventory; EcoRI diluted 10x } # Tubes and plates I use then discard re_tube = p.ref("re_tube", cont_type="micro-1.5", storage="cold_4", discard=True).well(0) water_tube = p.ref("water_tube", cont_type="micro-1.5", storage="cold_4", discard=True).well(0) pcr_plate = p.ref("pcr_plate", cont_type="96-pcr", storage="cold_4", discard=True) # The result of the experiment, a pUC19 cut by EcoRI, goes in this tube for storage puc19_cut_tube = p.ref(expid("puc19_cut"), cont_type="micro-1.5", storage="cold_20").well(0) # ------------------------------------------------------------- # Provisioning and diluting. # Diluted EcoRI can be used more than once # p.provision(inv["water"], water_tube, µl(500)) if 'dilute_ecori' in options: ecori_p10x_tube = p.ref("ecori_p10x", cont_type="micro-1.5", storage="cold_20").well(0) p.transfer(water_tube, ecori_p10x_tube, µl(45)) p.provision(inv["EcoRI"], ecori_p10x_tube, µl(5)) else: # All "inventory" (stuff I own at transcriptic) must be initialized ecori_p10x_tube = p.ref("ecori_p10x", id=inv["ecori_p10x"], cont_type="micro-1.5", storage="cold_20").well(0) init_inventory_well(ecori_p10x_tube) # ------------------------------------------------------------- # Restriction enzyme cutting pUC19 # # 50ul total reaction volume for cutting 1ug of DNA: # 5ul CutSmart 10x # 1ul pUC19 (1ug of DNA) # 1ul EcoRI (or 10ul diluted EcoRI, 20 units, >10 units per ug DNA) # p.transfer(water_tube, re_tube, µl(117)) p.provision(inv["CutSmart"], re_tube, µl(15)) p.provision(inv["pUC19"], re_tube, µl(3)) p.mix(re_tube, volume=µl(60), repetitions=10) assert re_tube.volume == µl(120) + dead_volume["micro-1.5"] print("Volumes: re_tube:{} water_tube:{} EcoRI:{}".format(re_tube.volume, water_tube.volume, ecori_p10x_tube.volume)) p.distribute(re_tube, pcr_plate.wells(["A1","B1","A2"]), µl(40)) p.distribute(water_tube, pcr_plate.wells(["A2"]), µl(10)) p.distribute(ecori_p10x_tube, pcr_plate.wells(["A1","B1"]), µl(10)) assert all(well.volume == µl(50) for well in pcr_plate.wells(["A1","B1","A2"])) p.mix(pcr_plate.wells(["A1","B1","A2"]), volume=µl(25), repetitions=10) # Incubation to induce cut, then heat inactivation of EcoRI p.seal(pcr_plate) p.incubate(pcr_plate, "warm_37", "60:minute", shaking=False) p.thermocycle(pcr_plate, [{"cycles": 1, "steps": [{"temperature": "65:celsius", "duration": "21:minute"}]}], volume=µl(50)) # -------------------------------------------------------------- # Gel electrophoresis, to ensure the cutting worked # p.unseal(pcr_plate) p.mix(pcr_plate.wells(["A1","B1","A2"]), volume=µl(25), repetitions=5) p.transfer(pcr_plate.wells(["A1","B1","A2"]), pcr_plate.wells(["D1","E1","D2"]), µl(8)) p.transfer(water_tube, pcr_plate.wells(["D1","E1","D2"]), µl(15), mix_after=True, mix_vol=µl(10)) assert all(well.volume == µl(20) + dead_volume["96-pcr"] for well in pcr_plate.wells(["D1","E1","D2"])) p.gel_separate(pcr_plate.wells(["D1","E1","D2"]), µl(20), "agarose(10,2%)", "ladder2", "15:minute", expid("gel")) # ---------------------------------------------------------------------------- # Then consolidate all cut plasmid to one tube (puc19_cut_tube). # remaining_volumes = [well.volume - dead_volume['96-pcr'] for well in pcr_plate.wells(["A1","B1"])] print("Consolidated volume: {}".format(sum(remaining_volumes, µl(0)))) p.consolidate(pcr_plate.wells(["A1","B1"]), puc19_cut_tube, remaining_volumes, allow_carryover=True) assert all(tube.volume >= dead_volume['micro-1.5'] for tube in [water_tube, re_tube, puc19_cut_tube, ecori_p10x_tube]) # --------------------------------------------------------------- # Test protocol # jprotocol = json.dumps(p.as_dict(), indent=2) !echo '{jprotocol}' | transcriptic analyze #print("Protocol {}\n\n{}".format(experiment_name, jprotocol)) open("protocol_{}.json".format(experiment_name),'w').write(jprotocol) 

 Volumes: re_tube:135.0:microliter water_tube:383.0:microliter EcoRI:30.0:microliter
Consolidated volume: 78.0:microliter

  
✓ Protocol analyzed
  12 instructions
  5 containers
  Total Cost: $30.72
  Workcell Time: $3.38
  Reagents & Consumables: $27.34 

:


, . .

«» ( 1,5 15 !). , D1 E1 ( ). , EcoRI .

, D1 E1 2,6kb. D2 : , .

Deux photos sur gel sont très différentes. Cela est dû en partie au fait que cette étape Transcriptic n'a pas encore été automatisée.


Deux gels montrant pUC19 coupé (2.6kb) dans les bandes D1 et E1, et pUC19 non coupé en D2

Étape 3. Assemblage Gibson


, — , M13 ( ) qPCR , , . , , , .

, M13 , M13.

Code
 """Debugging transformation protocol: Gibson assembly followed by qPCR and a gel v2: include v3 Gibson assembly""" p = Protocol() options = {} experiment_name = "debug_sfgfp_puc19_gibson_seq_v2" inv = { "water" : "rs17gmh5wafm5p", # catalog; Autoclaved MilliQ H2O; ambient "M13_F" : "rs17tcpqwqcaxe", # catalog; M13 Forward (-41); cold_20 (1ul = 100pmol) "M13_R" : "rs17tcph6e2qzh", # catalog; M13 Reverse (-48); cold_20 (1ul = 100pmol) "SensiFAST_SYBR_No-ROX" : "rs17knkh7526ha", # catalog; SensiFAST SYBR for qPCR "sfgfp_puc19_gibson_v1_clone" : "ct187rzdq9kd7q", # inventory; assembled sfGFP; cold_4 "sfgfp_puc19_gibson_v3_clone" : "ct188ejywa8jcv", # inventory; assembled sfGFP; cold_4 } # --------------------------------------------------------------- # First get my sfGFP pUC19 clones, assembled with Gibson assembly # clone_plate1 = p.ref("sfgfp_puc19_gibson_v1_clone", id=inv["sfgfp_puc19_gibson_v1_clone"], cont_type="96-pcr", storage="cold_4", discard=False) clone_plate2 = p.ref("sfgfp_puc19_gibson_v3_clone", id=inv["sfgfp_puc19_gibson_v3_clone"], cont_type="96-pcr", storage="cold_4", discard=False) water_tube = p.ref("water", cont_type="micro-1.5", storage="cold_4", discard=True).well(0) master_tube = p.ref("master", cont_type="micro-1.5", storage="cold_4", discard=True).well(0) primer_tube = p.ref("primer", cont_type="micro-1.5", storage="cold_4", discard=True).well(0) pcr_plate = p.ref(expid("pcr_plate"), cont_type="96-pcr", storage="cold_4", discard=False) init_inventory_well(clone_plate1.well("A1")) init_inventory_well(clone_plate2.well("A1")) seq_wells = ["B2","B4","B6", # clone_plate1 "D2","D4","D6", # clone_plate2 "F2","F4"] # control # clone_plate2 was diluted 4X (20ul->80ul), according to NEB instructions assert clone_plate1.well("A1").volume == µl(18), clone_plate1.well("A1").volume assert clone_plate2.well("A1").volume == µl(78), clone_plate2.well("A1").volume # -------------------------------------------------------------- # Provisioning # p.provision(inv["water"], water_tube, µl(500)) # primers, diluted 2X, discarded at the end p.provision(inv["M13_F"], primer_tube, µl(13)) p.provision(inv["M13_R"], primer_tube, µl(13)) p.transfer(water_tube, primer_tube, µl(26), mix_after=True, mix_vol=µl(20), repetitions=10) # ------------------------------------------------------------------- # PCR Master mix -- 10ul SYBR mix, plus 1ul each undiluted primer DNA (100pmol) # Also add 15ul of dead volume # p.provision(inv['SensiFAST_SYBR_No-ROX'], master_tube, µl(11+len(seq_wells)*10)) p.transfer(primer_tube, master_tube, µl(4+len(seq_wells)*4)) p.mix(master_tube, volume=µl(63), repetitions=10) assert master_tube.volume == µl(127) # 15ul dead volume p.distribute(master_tube, pcr_plate.wells(seq_wells), µl(14), allow_carryover=True) p.distribute(water_tube, pcr_plate.wells(seq_wells), [µl(ul) for ul in [5,4,2, 4,2,0, 6,6]], allow_carryover=True) # Template -- starting with some small, unknown amount of DNA produced by Gibson p.transfer(clone_plate1.well("A1"), pcr_plate.wells(seq_wells[0:3]), [µl(1),µl(2),µl(4)], one_tip=True) p.transfer(clone_plate2.well("A1"), pcr_plate.wells(seq_wells[3:6]), [µl(2),µl(4),µl(6)], one_tip=True) assert all(pcr_plate.well(w).volume == µl(20) for w in seq_wells) assert clone_plate1.well("A1").volume == µl(11) assert clone_plate2.well("A1").volume == µl(66) # -------------------------------------------------------------- # qPCR # standard melting curve parameters # p.seal(pcr_plate) p.thermocycle(pcr_plate, [{"cycles": 1, "steps": [{"temperature": "95:celsius","duration": "2:minute"}]}, {"cycles": 40, "steps": [{"temperature": "95:celsius","duration": "5:second"}, {"temperature": "60:celsius","duration": "20:second"}, {"temperature": "72:celsius","duration": "15:second", "read": True}]}], volume=µl(20), # volume is optional dataref=expid("qpcr"), dyes={"SYBR": seq_wells}, # dye must be specified (tells transcriptic what aborbance to use?) melting_start="65:celsius", melting_end="95:celsius", melting_increment="0.5:celsius", melting_rate="5:second") # -------------------------------------------------------------- # Gel -- 20ul required # Dilute such that I have 11ul for sequencing # p.unseal(pcr_plate) p.distribute(water_tube, pcr_plate.wells(seq_wells), µl(11)) p.gel_separate(pcr_plate.wells(seq_wells), µl(20), "agarose(8,0.8%)", "ladder1", "10:minute", expid("gel")) # This appears to be a bug in Transcriptic. The actual volume should be 11ul # but it is not updating after running a gel with 20ul. # Primer tube should be equal to dead volume, or it's a waste assert all(pcr_plate.well(w).volume==µl(31) for w in seq_wells) assert primer_tube.volume == µl(16) == dead_volume['micro-1.5'] + µl(1) assert water_tube.volume > µl(25) # --------------------------------------------------------------- # Test and run protocol # jprotocol = json.dumps(p.as_dict(), indent=2) !echo '{jprotocol}' | transcriptic analyze open("protocol_{}.json".format(experiment_name),'w').write(jprotocol) 

 WARNING:root:Low volume for well sfgfp_puc19_gibson_v1_clone/sfgfp_puc19_gibson_v1_clone : 11.0:microliter 

 ✓ Protocol analyzed
  11 instructions
  6 containers
  Total Cost: $32.09
  Workcell Time: $6.98
  Reagents & Consumables: $25.11 

: qPCR


qPCR JSON Transcriptic API. , . API , .

-, :

 project_id, run_id = "p16x6gna8f5e9", "r18mj3cz3fku7" api_url = "https://secure.transcriptic.com/hgbrian/{}/runs/{}/data.json".format(project_id, run_id) data_response = requests.get(api_url, headers=tsc_headers) data = data_response.json() 

id, «» qPCR:

 qpcr_id = data['debug_sfgfp_puc19_gibson_seq_v1_qpcr']['id'] pp_api_url = "https://secure.transcriptic.com/data/{}.json?key=postprocessed_data".format(qpcr_id) data_response = requests.get(pp_api_url, headers=tsc_headers) pp_data = data_response.json() 

Ct ( ) . Ct — , . , (, , , ).

 # Simple util to convert wellnum to wellname n_w = {str(wellnum):'ABCDEFGH'[wellnum//12]+str(1+wellnum%12) for wellnum in range(96)} w_n = {v: k for k, v in n_w.items()} ct_vals = {n_w[k]:v for k,v in pp_data["amp0"]["SYBR"]["cts"].items()} ct_df = pd.DataFrame(ct_vals, index=["Ct"]).T ct_df["well"] = ct_df.index f, ax = plt.subplots(figsize=(16,6)) _ = sns.barplot(y="well", x="Ct", data=ct_df) 



, D2/4/6 ( «v3»), B2/4/6 ( «v1»). v1 v3 , v3 4X NEB, . 30 (F2, F4), -, , .

qPCR, .

 f, ax = plt.subplots(figsize=(16,6)) ax.set_color_cycle(['#fb6a4a', '#de2d26', '#a50f15', '#74c476', '#31a354', '#006d2c', '#08519c', '#6baed6']) amp0 = pp_data['amp0']['SYBR']['baseline_subtracted'] _ = [plt.plot(amp0[w_n[well]], label=well) for well in ['B2', 'B4', 'B6', 'D2', 'D4', 'D6', 'F2', 'F4']] _ = ax.set_ylim(0,) _ = plt.title("qPCR (reds=Gibson v1, greens=Gibson v3, blues=control)") _ = plt.legend(bbox_to_anchor=(1, .75), bbox_transform=plt.gcf().transFigure) 



, qPCR , . v3 , v1, .

:


, 1kb B2, B4, B6, D2, D4, D6: ( 740bp, M13 — 40bp ). . , F2 F4 .


: v3 (D2, D4, D6), qPCR

4.


— . E. coli sfGFP- pUC19.

Zymo DH5α Mix&Go . — Transcriptic. , , , , . , , .


Zymo Mix & Go


— , . (« »), , («, »). , .

. , 37°C. , , , , Transcriptic — , . , , - , . . .

: (, , Mix&Go ); (, ); (, PCR ).

, , , , . , , !


, , , pUC19 (. . sfGFP) . pUC19 , , .

(«6-flat» Transcriptic), , . , , , . .

Code
 """Simple transformation protocol: transformation with unaltered pUC19""" p = Protocol() experiment_name = "debug_sfgfp_puc19_gibson_v1" inv = { "water" : "rs17gmh5wafm5p", # catalog; Autoclaved MilliQ H2O; ambient "DH5a" : "rs16pbj944fnny", # catalog; Zymo DH5α; cold_80 "LB Miller" : "rs17bafcbmyrmh", # catalog; LB Broth Miller; cold_4 "Amp 100mgml" : "rs17msfk8ujkca", # catalog; Ampicillin 100mg/ml; cold_20 "pUC19" : "rs17tcqmncjfsh", # catalog; pUC19; cold_20 } # Catalog transform_plate = p.ref("transform_plate", cont_type="96-pcr", storage="ambient", discard=True) transform_tube = transform_plate.well(0) # ------------------------------------------------------------------------------------ # Plating transformed bacteria according to Tali's protocol (requires different code!) # http://learn.transcriptic.com/blog/2015/9/9/provisioning-commercial-reagents # Add 1-5ul plasmid and pre-warm culture plates to 37C before starting. # # # Extra inventory for plating # inv["lb-broth-100ug-ml-amp_6-flat"] = "ki17sbb845ssx9" # (kit, not normal ref) from blogpost inv["noAB-amp_6-flat"] = "ki17reefwqq3sq" # kit id inv["LB Miller"] = "rs17bafcbmyrmh" # # Ampicillin and no ampicillin plates # amp_6_flat = Container(None, p.container_type('6-flat')) p.refs["amp_6_flat"] = Ref('amp_6_flat', {"reserve": inv['lb-broth-100ug-ml-amp_6-flat'], "store": {"where": 'cold_4'}}, amp_6_flat) noAB_6_flat = Container(None, p.container_type('6-flat')) p.refs["noAB_6_flat"] = Ref('noAB_6_flat', {"reserve": inv['noAB-amp_6-flat'], "store": {"where": 'cold_4'}}, noAB_6_flat) # # Provision competent bacteria # p.provision(inv["DH5a"], transform_tube, µl(50)) p.provision(inv["pUC19"], transform_tube, µl(2)) # # Heatshock the bacteria to transform using a PCR machine # p.seal(transform_plate) p.thermocycle(transform_plate, [{"cycles": 1, "steps": [{"temperature": "4:celsius", "duration": "5:minute"}]}, {"cycles": 1, "steps": [{"temperature": "37:celsius", "duration": "30:minute"}]}], volume=µl(50)) p.unseal(transform_plate) # # Then dilute bacteria and spread onto 6-flat plates # Put more on ampicillin plates for more opportunities to get a colony # p.provision(inv["LB Miller"], transform_tube, µl(355)) p.mix(transform_tube, µl(150), repetitions=5) for i in range(6): p.spread(transform_tube, amp_6_flat.well(i), µl(55)) p.spread(transform_tube, noAB_6_flat.well(i), µl(10)) assert transform_tube.volume >= µl(15), transform_tube.volume # # Incubate and image 6-flat plates over 18 hours # for flat_name, flat in [("amp_6_flat", amp_6_flat), ("noAB_6_flat", noAB_6_flat)]: for timepoint in [6,12,18]: p.cover(flat) p.incubate(flat, "warm_37", "6:hour") p.uncover(flat) p.image_plate(flat, mode="top", dataref=expid("{}_t{}".format(flat_name, timepoint))) # --------------------------------------------------------------- # Analyze protocol # jprotocol = json.dumps(p.as_dict(), indent=2) !echo '{jprotocol}' | transcriptic analyze #print("Protocol {}\n\n{}".format(experiment_name, protocol)) open("protocol_{}.json".format(experiment_name),'w').write(jprotocol) 

 ✓ Protocol analyzed
  43 instructions
  3 containers
  $45.43 

:


, ( ) , , . , Transcriptic , .

( ) , . , , , , 55 10 . . , . , , .

( , , , E. coli . La croissance est beaucoup plus faible sur les plaques d'ampicilline, bien qu'il y ait beaucoup plus de bactéries, comme prévu).

Dans l'ensemble, la transformation a assez bien fonctionné pour se poursuivre, bien qu'il y ait quelques défauts.


Plaques de cellules transformées avec pUC19 après 18 heures: sans antibiotique (à gauche) et avec antibiotique (à droite)

Transformation du produit après assemblage


pUC19, , , , sfGFP.

, IPTG X-gal, - . , pUC19, sfGFP, .


, sfGFP 485 / 510 . , Transcriptic 485/535. , 485 510 . 600 ( OD600 ).


GFP ( biotek )

IPTG X-gal


IPTG 1M 1:1000. , X-gal 20 / 1:1000 (20 /). , 2000µl LB 2 .

40 X-gal 20 / 40 IPTG 0,1 mM ( 4 IPTG 1M), 30 . , IPTG, X-gal .

Code
 """Full Gibson assembly and transformation protocol for sfGFP and pUC19 v1: Spread IPTG and X-gal onto plates, then spread cells v2: Mix IPTG, X-gal and cells; spread the mixture v3: exclude X-gal so I can do colony picking better v4: repeat v3 to try other excitation/emission wavelengths""" p = Protocol() options = { "gibson" : False, # do a new gibson assembly "sanger" : False, # sanger sequence product "control_pUC19" : True, # unassembled pUC19 "XGal" : False # excluding X-gal should make the colony picking easier } for k, v in list(options.items()): if v is False: del options[k] experiment_name = "sfgfp_puc19_gibson_plates_v4" # ----------------------------------------------------------------------- # Inventory # inv = { # catalog "water" : "rs17gmh5wafm5p", # catalog; Autoclaved MilliQ H2O; ambient "DH5a" : "rs16pbj944fnny", # catalog; Zymo DH5α; cold_80 "Gibson Mix" : "rs16pfatkggmk5", # catalog; Gibson Mix (2X); cold_20 "LB Miller" : "rs17bafcbmyrmh", # catalog; LB Broth Miller; cold_4 "Amp 100mgml" : "rs17msfk8ujkca", # catalog; Ampicillin 100mg/ml; cold_20 "pUC19" : "rs17tcqmncjfsh", # catalog; pUC19; cold_20 # my inventory "puc19_cut_v2": "ct187v4ea7vvca", # inventory; pUC19 cut with EcoRI; cold_20 "IPTG" : "ct18a2r5wn6tqz", # inventory; IPTG at 1M (conc semi-documented); cold_20 "XGal" : "ct18a2r5wp5hcv", # inventory; XGal at 0.1M (conc not documented); cold_20 "sfgfp_pcroe_v8_amplified" : "ct1874zqh22pab", # inventory; sfGFP amplified to 40ng/ul; cold_4 "sfgfp_puc19_gibson_v3_clone" : "ct188ejywa8jcv", # inventory; assembled sfGFP; cold_4 # kits (must be used differently) "lb-broth-100ug-ml-amp_6-flat" : "ki17sbb845ssx9", # catalog; ampicillin plates "noAB-amp_6-flat" : "ki17reefwqq3sq" # catalog; no antibiotic plates } # # Catalog (all to be discarded afterward) # water_tube = p.ref("water", cont_type="micro-1.5", storage="ambient", discard=True).well(0) transform_plate = p.ref("trn_plate", cont_type="96-pcr", storage="ambient", discard=True) transform_tube = transform_plate.well(39) # experiment transform_tube_L = p.ref("trn_tubeL", cont_type="micro-1.5", storage="ambient", discard=True).well(0) transctrl_tube = transform_plate.well(56) # control transctrl_tube_L = p.ref("trc_tubeL", cont_type="micro-1.5", storage="ambient", discard=True).well(0) # # Plating according to Tali's protocol # http://learn.transcriptic.com/blog/2015/9/9/provisioning-commercial-reagents # amp_6_flat = Container(None, p.container_type('6-flat')) p.refs[expid("amp_6_flat")] = Ref(expid("amp_6_flat"), {"reserve": inv['lb-broth-100ug-ml-amp_6-flat'], "store": {"where": 'cold_4'}}, amp_6_flat) noAB_6_flat = Container(None, p.container_type('6-flat')) p.refs[expid("noAB_6_flat")] = Ref(expid("noAB_6_flat"), {"reserve": inv['noAB-amp_6-flat'], "store": {"where": 'cold_4'}}, noAB_6_flat) # # My inventory: EcoRI-cut pUC19, oePCR'd sfGFP, Gibson-assembled pUC19, IPTG and X-Gal # if "gibson" in options: puc19_cut_tube = p.ref("puc19_ecori_v2_puc19_cut", id=inv["puc19_cut_v2"], cont_type="micro-1.5", storage="cold_20").well(0) sfgfp_pcroe_amp_tube = p.ref("sfgfp_pcroe_v8_amplified", id=inv["sfgfp_pcroe_v8_amplified"], cont_type="micro-1.5", storage="cold_4").well(0) clone_plate = p.ref(expid("clone"), cont_type="96-pcr", storage="cold_4", discard=False) else: clone_plate = p.ref("sfgfp_puc19_gibson_v3_clone", id=inv["sfgfp_puc19_gibson_v3_clone"], cont_type="96-pcr", storage="cold_4", discard=False) IPTG_tube = p.ref("IPTG", id=inv["IPTG"], cont_type="micro-1.5", storage="cold_20").well(0) if "XGal" in options: XGal_tube = p.ref("XGal", id=inv["XGal"], cont_type="micro-1.5", storage="cold_20").well(0) # # Initialize inventory # if "gibson" in options: all_inventory_wells = [puc19_cut_tube, sfgfp_pcroe_amp_tube, IPTG_tube] assert puc19_cut_tube.volume == µl(66), puc19_cut_tube.volume assert sfgfp_pcroe_amp_tube.volume == µl(36), sfgfp_pcroe_amp_tube.volume else: all_inventory_wells = [IPTG_tube, clone_plate.well(0)] if "XGal" in options: all_inventory_wells.append(XGal_tube) for well in all_inventory_wells: init_inventory_well(well) print("Inventory: {} {} {}".format(well.name, well.volume, well.properties)) # # Provisioning. Water is used all over the protocol. Provision an excess since it's cheap # p.provision(inv["water"], water_tube, µl(500)) # ----------------------------------------------------------------------------- # Cloning/assembly (see NEBuilder protocol above) # # "Optimized efficiency is 50–100 ng of vectors with 2 fold excess of inserts." # pUC19 is 20ng/ul (78ul total). # sfGFP is ~40ng/ul (48ul total) # Therefore 4ul of each gives 80ng and 160ng of vector and insert respectively # def do_gibson_assembly(): # # Combine all the Gibson reagents in one tube and thermocycle # p.provision(inv["Gibson Mix"], clone_plate.well(0), µl(10)) p.transfer(water_tube, clone_plate.well(0), µl(2)) p.transfer(puc19_cut_tube, clone_plate.well(0), µl(4)) p.transfer(sfgfp_pcroe_amp_tube, clone_plate.well(0), µl(4), mix_after=True, mix_vol=µl(10), repetitions=10) p.seal(clone_plate) p.thermocycle(clone_plate, [{"cycles": 1, "steps": [{"temperature": "50:celsius", "duration": "16:minute"}]}], volume=µl(50)) # # Dilute assembled plasmid 4X according to the NEB Gibson assembly protocol (20ul->80ul) # p.unseal(clone_plate) p.transfer(water_tube, clone_plate.well(0), µl(60), mix_after=True, mix_vol=µl(40), repetitions=5) return # -------------------------------------------------------------------------------------------------- # Transformation # "Transform NEB 5-alpha Competent E. coli cells with 2 μl of the # assembled product, following the appropriate transformation protocol." # # Mix & Go http://www.zymoresearch.com/downloads/dl/file/id/173/t3015i.pdf # "[After mixing] Immediately place on ice and incubate for 2-5 minutes" # "The highest transformation efficiencies can be obtained by incubating Mix & Go cells with DNA on # ice for 2-5 minutes (60 minutes maximum) prior to plating." # "It is recommended that culture plates be pre-warmed to >20°C (preferably 37°C) prior to plating." # "Avoid exposing the cells to room temperature for more than a few seconds at a time." # # "If competent cells are purchased from other manufacture, dilute assembled products 4-fold # with H2O prior transformation. This can be achieved by mixing 5 μl of assembled products with # 15 μl of H2O. Add 2 μl of the diluted assembled product to competent cells." # def _do_transformation(): # # Combine plasmid and competent bacteria in a pcr_plate and shock # p.provision(inv["DH5a"], transform_tube, µl(50)) p.transfer(clone_plate.well(0), transform_tube, µl(3), dispense_speed="10:microliter/second") assert clone_plate.well(0).volume == µl(54), clone_plate.well(0).volume if 'control_pUC19' in options: p.provision(inv["DH5a"], transctrl_tube, µl(50)) p.provision(inv["pUC19"], transctrl_tube, µl(1)) # # Heatshock the bacteria to transform using a PCR machine # p.seal(transform_plate) p.thermocycle(transform_plate, [{"cycles": 1, "steps": [{"temperature": "4:celsius", "duration": "5:minute"}]}, {"cycles": 1, "steps": [{"temperature": "37:celsius", "duration": "30:minute"}]}], volume=µl(50)) return def _transfer_transformed_to_plates(): assert transform_tube.volume == µl(53), transform_tube.volume p.unseal(transform_plate) num_ab_plates = 4 # antibiotic places # # Transfer bacteria to a bigger tube for diluting # Then spread onto 6-flat plates # Generally you would spread 50-100ul of diluted bacteria # Put more on ampicillin plates for more opportunities to get a colony # I use a dilution series since it's unclear how much to plate # p.provision(inv["LB Miller"], transform_tube_L, µl(429)) # # Add all IPTG and XGal to the master tube # 4ul (1M) IPTG on each plate; 40ul XGal on each plate # p.transfer(IPTG_tube, transform_tube_L, µl(4*num_ab_plates)) if 'XGal' in options: p.transfer(XGal_tube, transform_tube_L, µl(40*num_ab_plates)) # # Add the transformed cells and mix (use new mix op in case of different pipette) # p.transfer(transform_tube, transform_tube_L, µl(50)) p.mix(transform_tube_L, volume=transform_tube_L.volume/2, repetitions=10) assert transform_tube.volume == dead_volume['96-pcr'] == µl(3), transform_tube.volume assert transform_tube_L.volume == µl(495), transform_tube_L.volume # # Spread an average of 60ul on each plate == 480ul total # for i in range(num_ab_plates): p.spread(transform_tube_L, amp_6_flat.well(i), µl(51+i*6)) p.spread(transform_tube_L, noAB_6_flat.well(i), µl(51+i*6)) assert transform_tube_L.volume == dead_volume["micro-1.5"], transform_tube_L.volume # # Controls: include 2 ordinary pUC19-transformed plates as a control # if 'control_pUC19' in options: num_ctrl = 2 assert num_ab_plates + num_ctrl <= 6 p.provision(inv["LB Miller"], transctrl_tube_L, µl(184)+dead_volume["micro-1.5"]) p.transfer(IPTG_tube, transctrl_tube_L, µl(4*num_ctrl)) if "XGal" in options: p.transfer(XGal_tube, transctrl_tube_L, µl(40*num_ctrl)) p.transfer(transctrl_tube, transctrl_tube_L, µl(48)) p.mix(transctrl_tube_L, volume=transctrl_tube_L.volume/2, repetitions=10) for i in range(num_ctrl): p.spread(transctrl_tube_L, amp_6_flat.well(num_ab_plates+i), µl(55+i*10)) p.spread(transctrl_tube_L, noAB_6_flat.well(num_ab_plates+i), µl(55+i*10)) assert transctrl_tube_L.volume == dead_volume["micro-1.5"], transctrl_tube_L.volume assert IPTG_tube.volume == µl(808), IPTG_tube.volume if "XGal" in options: assert XGal_tube.volume == µl(516), XGal_tube.volume return def do_transformation(): _do_transformation() _transfer_transformed_to_plates() # ------------------------------------------------------ # Measure growth in plates (photograph) # def measure_growth(): # # Incubate and photograph 6-flat plates over 18 hours # to see blue or white colonies # for flat_name, flat in [(expid("amp_6_flat"), amp_6_flat), (expid("noAB_6_flat"), noAB_6_flat)]: for timepoint in [9,18]: p.cover(flat) p.incubate(flat, "warm_37", "9:hour") p.uncover(flat) p.image_plate(flat, mode="top", dataref=expid("{}_t{}".format(flat_name, timepoint))) return # --------------------------------------------------------------- # Sanger sequencing, TURNED OFF # Sequence to make sure assembly worked # 500ng plasmid, 1 µl of a 10 µM stock primer # "M13_F" : "rs17tcpqwqcaxe", # catalog; M13 Forward (-41); cold_20 (1ul = 100pmol) # "M13_R" : "rs17tcph6e2qzh", # catalog; M13 Reverse (-48); cold_20 (1ul = 100pmol) # def do_sanger_seq(): seq_primers = [inv["M13_F"], inv["M13_R"]] seq_wells = ["G1","G2"] p.unseal(pcr_plate) for primer_num, seq_well in [(0, seq_wells[0]),(1, seq_wells[1])]: p.provision(seq_primers[primer_num], pcr_plate.wells([seq_well]), µl(1)) p.transfer(pcr_plate.wells(["A1"]), pcr_plate.wells(seq_wells), µl(5), mix_before=True, mix_vol=µl(10)) p.transfer(water_tube, pcr_plate.wells(seq_wells), µl(9)) p.mix(pcr_plate.wells(seq_wells), volume=µl(7.5), repetitions=10) p.sangerseq(pcr_plate, pcr_plate.wells(seq_wells[0]).indices(), expid("seq1")) p.sangerseq(pcr_plate, pcr_plate.wells(seq_wells[1]).indices(), expid("seq2")) return # --------------------------------------------------------------- # Generate protocol # # Skip Gibson since I already did it if 'gibson' in options: do_gibson_assembly() do_transformation() measure_growth() if 'sanger' in options: do_sanger_seq() # --------------------------------------------------------------- # Output protocol # jprotocol = json.dumps(p.as_dict(), indent=2) !echo '{jprotocol}' | transcriptic analyze #print("\nProtocol {}\n\n{}".format(experiment_name, jprotocol)) open("protocol_{}.json".format(experiment_name),'w').write(jprotocol) 

 Inventory: IPTG/IPTG/IPTG/IPTG/IPTG/IPTG 832.0:microliter {}
Inventory: sfgfp_puc19_gibson_v3_clone/sfgfp_puc19_gibson_v3_clone/sfgfp_puc19_gibson_v3_clone/sfgfp_puc19_gibson_v3_clone/sfgfp_puc19_gibson_v3_clone 57.0:microliter {}

  
✓ Protocol analyzed
  40 instructions
  8 containers
  Total Cost: $53.20
  Workcell Time: $17.35
  Reagents & Consumables: $35.86 


, «» 96- . ( autopick ).

Code
 """Pick colonies from plates and grow in amp media and check for fluorescence. v2: try again with a new plate (no blue colonies) v3: repeat with different emission and excitation wavelengths""" p = Protocol() options = {} for k, v in list(options.items()): if v is False: del options[k] experiment_name = "sfgfp_puc19_gibson_pick_v3" def plate_expid(val): """refer to the previous plating experiment's outputs""" plate_exp = "sfgfp_puc19_gibson_plates_v4" return "{}_{}".format(plate_exp, val) # ----------------------------------------------------------------------- # Inventory # inv = { # catalog "water" : "rs17gmh5wafm5p", # catalog; Autoclaved MilliQ H2O; ambient "LB Miller" : "rs17bafcbmyrmh", # catalog; LB Broth Miller; cold_4 "Amp 100mgml" : "rs17msfk8ujkca", # catalog; Ampicillin 100mg/ml; cold_20 "IPTG" : "ct18a2r5wn6tqz", # inventory; IPTG at 1M (conc semi-documented); cold_20 # plates from previous experiment, must be changed every new experiment plate_expid("amp_6_flat") : "ct18snmr9avvg9", # inventory; Ampicillin plates with blue-white screening of pUC19 plate_expid("noAB_6_flat") : "ct18snmr9dxfw2", # inventory; no AB plates with blue-white screening of pUC19 } # Tubes and plates lb_amp_tubes = [p.ref("lb_amp_{}".format(i+1), cont_type="micro-2.0", storage="ambient", discard=True).well(0) for i in range(4)] lb_xab_tube = p.ref("lb_xab", cont_type="micro-2.0", storage="ambient", discard=True).well(0) growth_plate = p.ref(expid("growth"), cont_type="96-flat", storage="cold_4", discard=False) # My inventory IPTG_tube = p.ref("IPTG", id=inv["IPTG"], cont_type="micro-1.5", storage="cold_20").well(0) # ampicillin plate amp_6_flat = Container(None, p.container_type('6-flat')) p.refs[plate_expid("amp_6_flat")] = Ref(plate_expid("amp_6_flat"), {"id":inv[plate_expid("amp_6_flat")], "store": {"where": 'cold_4'}}, amp_6_flat) # Use a total of 50 wells abs_wells = ["{}{}".format(row,col) for row in "BCDEF" for col in range(1,11)] abs_wells_T = ["{}{}".format(row,col) for col in range(1,11) for row in "BCDEF"] assert abs_wells[:3] == ["B1","B2","B3"] and abs_wells_T[:3] == ["B1","C1","D1"] def prepare_growth_wells(): # # To LB, add ampicillin at ~1/1000 concentration # Mix slowly in case of overflow # p.provision(inv["LB Miller"], lb_xab_tube, µl(1913)) for lb_amp_tube in lb_amp_tubes: p.provision(inv["Amp 100mgml"], lb_amp_tube, µl(2)) p.provision(inv["LB Miller"], lb_amp_tube, µl(1911)) p.mix(lb_amp_tube, volume=µl(800), repetitions=10) # # Add IPTG but save on X-Gal # http://openwetware.org/images/f/f1/Dh5a_sub.pdf # "If you are concerned about obtaining maximal levels of expression, add IPTG to a final concentration of 1 mM." # 2ul of IPTG in 2000ul equals 1mM # p.transfer(IPTG_tube, [lb_xab_tube] + lb_amp_tubes, µl(2), one_tip=True) # # Distribute LB among wells, row D is control (no ampicillin) # cols = range(1,11) row = "D" # control, no AB cwells = ["{}{}".format(row,col) for col in cols] assert set(cwells).issubset(set(abs_wells)) p.distribute(lb_xab_tube, growth_plate.wells(cwells), µl(190), allow_carryover=True) rows = "BCEF" for row, lb_amp_tube in zip(rows, lb_amp_tubes): cwells = ["{}{}".format(row,col) for col in cols] assert set(cwells).issubset(set(abs_wells)) p.distribute(lb_amp_tube, growth_plate.wells(cwells), µl(190), allow_carryover=True) assert all(lb_amp_tube.volume == lb_xab_tube.volume == dead_volume['micro-2.0'] for lb_amp_tube in lb_amp_tubes) return def measure_growth_wells(): # # Growth: absorbance and fluorescence over 24 hours # Absorbance at 600nm: cell growth # Absorbance at 615nm: X-gal, in theory # Fluorescence at 485nm/510nm: sfGFP # or 450nm/508nm (http://www.ncbi.nlm.nih.gov/pmc/articles/PMC2695656/) # hr = 4 for t in range(0,24,hr): if t > 0: p.cover(growth_plate) p.incubate(growth_plate, "warm_37", "{}:hour".format(hr), shaking=True) p.uncover(growth_plate) p.fluorescence(growth_plate, growth_plate.wells(abs_wells).indices(), excitation="485:nanometer", emission="535:nanometer", dataref=expid("fl2_{}".format(t)), flashes=25) p.fluorescence(growth_plate, growth_plate.wells(abs_wells).indices(), excitation="450:nanometer", emission="508:nanometer", dataref=expid("fl1_{}".format(t)), flashes=25) p.fluorescence(growth_plate, growth_plate.wells(abs_wells).indices(), excitation="395:nanometer", emission="508:nanometer", dataref=expid("fl0_{}".format(t)), flashes=25) p.absorbance(growth_plate, growth_plate.wells(abs_wells).indices(), wavelength="600:nanometer", dataref=expid("abs_{}".format(t)), flashes=25) return # --------------------------------------------------------------- # Protocol steps # prepare_growth_wells() batch = 10 for i in range(5): p.autopick(amp_6_flat.well(i), growth_plate.wells(abs_wells_T[i*batch:i*batch+batch]), dataref=expid("autopick_{}".format(i))) p.image_plate(amp_6_flat, mode="top", dataref=expid("autopicked_{}".format(i))) measure_growth_wells() # --------------------------------------------------------------- # Output protocol # jprotocol = json.dumps(p.as_dict(), indent=2) !echo '{jprotocol}' | transcriptic analyze open("protocol_{}.json".format(experiment_name),'w').write(jprotocol) 

 ✓ Protocol analyzed
  62 instructions
  8 containers
  Total Cost: $66.38
  Workcell Time: $57.59
  Reagents & Consumables: $8.78 

:


– , , (1-4) (5-6). , , , , IPTG X-gal, Transcriptic.


- (1-4) (5-6)

- - . ( GraphicsMagick ). , , ( , ).

, Transcriptic. , 10 . , , . . , , , , .


- (1-4) (5-6),

– . , . , . X-gal.

- . , .


, (1-4) (5-6)

:


50 96- 20 , sfGFP. ( , ) Transcriptic Tecan Infinite .

, , , sfGFP. , , - , sfGFP . , sfGFP, , , , .

(OD600) 20 ( 60 ).

 for t in [0,4,8,12,16,20]: abs_data = pd.read_csv("glow/sfgfp_puc19_gibson_pick_v3_abs_{}.csv".format(t), index_col="Well") flr_data = pd.read_csv("glow/sfgfp_puc19_gibson_pick_v3_fl2_{}.csv".format(t), index_col="Well") if t == 0: new_data = abs_data.join(flr_data) else: new_data = new_data.join(abs_data, rsuffix='_{}'.format(t)) new_data = new_data.join(flr_data, rsuffix='_{}'.format(t)) new_data.columns = ["OD 600:nanometer_0", "Fluorescence_0"] + list(new_data.columns[2:]) 

Nous plaçons sur la carte les données de la 20ème heure et les traces des mesures précédentes. En fait, je ne suis intéressé que par les dernières données, car c'est alors qu'il faut observer un pic de fluorescence.

 svg = [] W, H = 800, 500 min_x, max_x = 0, 0.8 min_y, max_y = 0, 50000 def _toxy(x, y): return W*(x-min_x)/(max_x-min_x), HH*(y-min_y)/(max_y-min_y) def _topt(x, y): return ','.join(map(str,_toxy(x,y))) ab_fls = [[row[0]] + [list(row[1])] for row in new_data.iterrows()] # axes svg.append('<g fill="#888" font-size="18" transform="translate(20,0),scale(.95)">') svg.append('<text x="0" y="{}">OD600 →</text>'.format(H+20)) svg.append('<text x="0" y="0" transform="rotate(-90),translate(-{},-8)">Fluorescence →</text>'.format(H)) svg.append('<line x1="0" y1="{}" x2="{}" y2="{}" style="stroke:#888;stroke-width:2" />'.format(H,W,H)) svg.append('<line x1="0" y1="0" x2="0" y2="{}" style="stroke:#888;stroke-width:2" />'.format(H)) # glow filter svg.append("""<filter id="glow" x="-200%" y="-200%" height="400%" width="400%"> <feColorMatrix type="matrix" values="0 0 0 0 0 255 0 0 0 0 0 0 0 0 0 0 0 0 1 0"/> <feGaussianBlur stdDeviation="10" result="coloredBlur"/> <feMerge><feMergeNode in="coloredBlur"/><feMergeNode in="SourceGraphic"/></feMerge> </filter>""") for n, (well, vals) in enumerate(ab_fls): fill = "#444" if not well.startswith("D") else "#aaa" gfilter = 'filter="url(#glow)"' if well in ["C3", "D1", "D3"] else "" cx, cy = _toxy(*vals[-2:]) svg.append('''<g id="point{n:d}"><circle {gfilter:s} r="12" cx="{cx:f}" cy="{cy:f}" fill="{fill:s}" /> <text x="{cx:f}" y="{cy:f}" font-size="10" text-anchor="middle" fill="#fff" alignment-baseline="middle">{txt:s}</text></g> '''.format(n=n, cx=cx, cy=cy, fill=fill, txt=well, gfilter=gfilter)) pathd = 'M{} '.format(_topt(*vals[:2])) pathd += ' '.join("L{}".format(_topt(*vals[i:i+2])) for i in range(2,len(vals),2)) svg.append('''<path d="{pathd:}" stroke="#ccc" stroke-width=".2" fill="none" id="path{n:d}"/>'''.format(pathd=pathd, n=n)) svg.append("</g>") # entire chart group show_svg(''.join(svg), w=W, h=H) 



OD600: , . , sfGFP

miniprep , , 13. , - miniprep - Transcriptic, . (C1, D1, D3) (B1, B3, E1), sfGFP muscle .

C1, D3 D3 sfGFP, B1, B3 E1 .


, . , 0 (40 000 ). 20- OD600 (, - ), . , , , , 11-15 .

(. . , ), , , ).

, , 50 sfGFP . , . , ( , , miniprep), 200 , .

, . , GFP, Python!

:


Prix


, , $360, :

  • $70
  • $32 PCR
  • $31
  • $32
  • $53
  • $67
  • $75 3 miniprep'

, $250-300 . , 50 , , .

, ( ) ( IT). Transcriptic , . , , . , , , , .

, . , - , . , : , , IDT .

:


, . , :

  • ! , . autoprotocol, .
  • . 100 , .
  • , , PCR. , , ? / ? , , , « 2-3 ». ?
  • . . , .
  • . .
  • . . , 1 96 (96−x) 96- , .
  • . csv , .
  • . - , .

, , , . , 1994 :

  • Transcriptic — . , , , . , , .
  • — Transcriptic.
  • , . Transcriptic ( , , ).
  • , ( : ~$0). , .
  • Transcriptic . , , .


, , - , , .

, :

  • Twist/IDT/Gen9 Transcriptic (, - ).
  • , , , , . .
  • ( NEB, IDT) (, primer3 ).

( ) , , . , in vivo (. . ).

, , : RBS , ; ; .

Pourquoi tout ça?


, . :

  • - //, .
  • , , .
  • in vivo split-GFP .
  • scFv . scFvs - .
  • BiTE , ( , ).
  • , ( ).
  • , . 1000 10 000 ? , GFP?

, , iGEM .

Transcriptic .

Source: https://habr.com/ru/post/fr451124/


All Articles