Source code for constrain.lab.robot_assembly

#!/usr/bin/env python
# MIT License
# Copyright (c) 2022, Technical University of Denmark (DTU)
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.

"A module to for automating biological assemblies with robots"

from constrain.lab.containers_wells_picklists import (
    Transfer,
    Plate96,
    Plate2x4,
    PickList,
)
import pandas as pd


[docs]class LiquidHandler(Transfer): """This class is a subclass of the synbiopython Transfer class and be used to make flowbot instructions. Parameters ---------- Returns ------- """ def __init__(self) -> None: super().__init__()
[docs] def to_flowbot_instructions(self): """Return Flowbot instructions: i.e source, destination, volume # 4:A3, 4:A6, 20 # 3:A1, 7, 50.7 # 2:A, 2:B-F, 100 .""" return ( "{self.source_well.plate.name}:" "{self.source_well.name}," " {self.destination_well.plate.name}:" "{self.destination_well.name}, {self.volume} " ).format(self=self)
# Helper functions
[docs]def well_keys_96(row=True): """ If true it generates keys for a 96 well plate by row. else it does it by column Parameters ---------- row : bool if true it will generate keys horisontally for a 96 well plate. Else vertically. Returns ------- keys : list list of keys i.e ['A1', 'A2', 'A3',..] """ key_list = "ABCDEFGH" if row == True: wells_keys = [] for i in range(0, len(key_list)): for j in range(1, 13): wells_keys.append(key_list[i] + str(j)) else: wells_keys = [] for i in range(1, 13): for j in range(0, len(key_list)): wells_keys.append(str(key_list[j]) + str(i)) return wells_keys
# initializing well_keys well_keys = well_keys_96(row=True)
[docs]def make_virtual_plates_fromDF( f_primers: list, r_primers: list, templates: list, Dataframe_with_PCR_contents ): """ This function can make virtual plates from lists of primers and templates.The Pandas DataFrame is used to calculate how much pcr and h2o is needed for the reactions. Parameters ---------- f_primers: list list of forward primers r_primers: list list of reverse primers templates: list list of templates Dataframe_with_PCR_contents : pandas.DataFrame dataframe with a PCR scheme. Returns ------- Virtual 96 plates as containers. """ # initializing source_plate1 = Plate96(name="1") # Forward primers source_plate2 = Plate96(name="2") # Reverse primers source_plate3 = Plate96(name="3") # Templates source_plate4 = Plate2x4(name="4") # PCR mix and H20 well_keys = well_keys_96() volume_needed = len(Dataframe_with_PCR_contents) + 1 # Adding each primer/template to the virtual plates here a volume of 5 is arbitrarily chosen for i in range(0, len(f_primers)): source_plate1[well_keys[i]].add_content({f_primers[i]: 1}, volume=5.0) for j in range(0, len(r_primers)): source_plate2[well_keys[j]].add_content({r_primers[j]: 1}, volume=5.0) for k in range(0, len(templates)): source_plate3[well_keys[k]].add_content({templates[k]: 1}, volume=5.0) # Adding MM and H2O to the final plate source_plate4["A1"].add_content({"PCR_2x_mix": 10}, volume=volume_needed * 10) source_plate4["A2"].add_content({"H2O_MQ": 10}, volume=volume_needed * 7) return source_plate1, source_plate2, source_plate3, source_plate4
[docs]def picklist_from_plates( F_primer_plate, R_primer_plate, Templates_plate, MM_H20_plate, PCR_dataframe ): """This function can generate picklist from virtual plates and pandas dataframe with PCR components Parameters ---------- Returns ------- """ FORWARD_PRIMERS = F_primer_plate.to_pandas_dataframe() REVERSE_PRIMERS = R_primer_plate.to_pandas_dataframe() TEMPLATES = Templates_plate.to_pandas_dataframe() MM_H2O = MM_H20_plate.to_pandas_dataframe() destination_plate = Plate96(name="5") picklist = PickList() counter = 0 # FIRST WE CHECK WICH COMPONENTS WE NEED FOR THE PCRs for index, row in PCR_dataframe.iterrows(): templates = row["Template"] f_primers = row["forward_primer"] r_primers = row["reverse_primer"] # FORWARD PRIMERS # we see if we can find the primer we need in the primer plate and if we find it we will add it to the picklist for index1, row1 in FORWARD_PRIMERS.iterrows(): for k, v in row1["content"]["quantities"].items(): if k == f_primers: transfer_forward_primers = Transfer( F_primer_plate.wells[index1], destination_plate.wells[well_keys[counter]], 1, ) picklist.add_transfer(transfer=transfer_forward_primers) # REVERSE PRIMERS # we see if we can find the primer we need in the primer plate for index2, row2 in REVERSE_PRIMERS.iterrows(): for k, v in row2["content"]["quantities"].items(): if k == r_primers: transfer_reverse_primers = Transfer( R_primer_plate.wells[index2], destination_plate.wells[well_keys[counter]], 1, ) picklist.add_transfer(transfer=transfer_reverse_primers) # TEMPLATE # we see if we can find the primer we need in the plate for index3, row3 in TEMPLATES.iterrows(): for k, v in row3["content"]["quantities"].items(): if k == templates: transfer_template = Transfer( Templates_plate.wells[index3], destination_plate.wells[well_keys[counter]], 1, ) picklist.add_transfer(transfer=transfer_template) # Master mix transfer_MM = Transfer( MM_H20_plate.wells["A1"], destination_plate.wells[well_keys[counter]], 10 ) picklist.add_transfer(transfer=transfer_MM) # H20 transfer_H20 = Transfer( MM_H20_plate.wells["A2"], destination_plate.wells[well_keys[counter]], 7 ) picklist.add_transfer(transfer=transfer_H20) # TO MAKE SURE WE ADD TO THE CORRECT WELL counter += 1 return picklist
[docs]class RobotAssembly: """Class to generate instructions for robots on demand. Parameters ---------- pandas.DataFrame Pandas_dataframe with a PCR scheme F_primers : list list of forward primers R_primers :list list of reverse primers Templates : list list of templates Returns ------- RobotAssembly object. Methods include printing robot- excecutable intructions. """ def __init__( self, Pandas_dataframe_PCR, F_primers: list, R_primers: list, Templates: list ): ### 1.INITIALIZING ## if ( Pandas_dataframe_PCR is not None and F_primers is not None and R_primers is not None and Templates is not None ): # Initializing instances self.pandas_PCR = Pandas_dataframe_PCR self.forward_primers = F_primers self.reverse_primers = R_primers self.templates = Templates # Virtual plates ( self.source_plateF_primers, self.source_plateR_primers, self.source_plateTemplates, self.source_platePCRmix, ) = make_virtual_plates_fromDF( self.forward_primers, self.reverse_primers, self.templates, self.pandas_PCR, ) # Generating Picklist from virtual plates self.picklist = picklist_from_plates( self.source_plateF_primers, self.source_plateR_primers, self.source_plateTemplates, self.source_platePCRmix, self.pandas_PCR, ) else: print("Remember to put in all the neccesarry components")
[docs] def PlatesToExcelFile(self): """Returns an excel file of the plate setup that needs to be made before the flowbot can operate""" df1 = self.source_plateF_primers.to_pandas_dataframe() df2 = self.source_plateR_primers.to_pandas_dataframe() df3 = self.source_plateTemplates.to_pandas_dataframe() df4 = self.source_platePCRmix.to_pandas_dataframe() with pd.ExcelWriter("Plate_instructions.xlsx") as writer: return ( df1.to_excel(writer, sheet_name="Forward_primer_wells"), df2.to_excel(writer, sheet_name="Reverse_primer_wells"), df3.to_excel(writer, sheet_name="Template_wells"), df4.to_excel(writer, sheet_name="PCR_MIX_H20"), )
[docs] def print_well_df_to_string(self): """Prints Pandas dataframe in string format""" df1 = self.source_plateF_primers.to_pandas_dataframe() df2 = self.source_plateR_primers.to_pandas_dataframe() df3 = self.source_plateTemplates.to_pandas_dataframe() df4 = self.source_platePCRmix.to_pandas_dataframe() return print( " ###Forward primers: ", df1.to_csv(sep=" ", index=False, header=True), "\n", "###Reverse primers: ", df2.to_csv(sep=" ", index=False, header=True), "\n", "###Templates: ", df3.to_csv(sep=" ", index=False, header=True), df4.to_csv(sep=" ", index=False, header=True), )
[docs] def FlowbotInstructionsToCSV(self): """Prints flowbot instructions to csv format""" with open("Flowbot_instructions.csv", "w") as outfile: return print( "source, target, volume", "\n", *self.picklist.to_flowbot_instructions_string(), sep="", end="\n", file=outfile )