Skip to content

Commit

Permalink
new strategy to recording plate reader results
Browse files Browse the repository at this point in the history
  • Loading branch information
rclarke0 committed Nov 21, 2024
1 parent c429df3 commit 21a4025
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 58 deletions.
7 changes: 6 additions & 1 deletion abr-testing/abr_testing/data_collection/abr_google_drive.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def create_data_dictionary(
headers: List[str] = []
headers_lpc: List[str] = []
list_of_heights: List[List[Any]] = [[], [], [], [], [], [], [], []]
hellma_plate_orientation = False # default hellma plate is not rotated.
for filename in os.listdir(storage_directory):
file_path = os.path.join(storage_directory, filename)
if file_path.endswith(".json"):
Expand All @@ -67,6 +68,10 @@ def create_data_dictionary(
if run_id in runs_to_save:
print(f"started reading run {run_id}.")
robot = file_results.get("robot_name")
parameters = file_results.get("runTimeParameters", "")
for parameter in parameters:
if parameter["displayName"] == "Hellma Plate Orientation":
hellma_plate_orientation = bool(parameter["value"])
protocol_name = file_results["protocol"]["metadata"].get("protocolName", "")
software_version = file_results.get("API_Version", "")
left_pipette = file_results.get("left", "")
Expand Down Expand Up @@ -123,7 +128,7 @@ def create_data_dictionary(
file_results, labware_name="opentrons_tough_pcr_auto_sealing_lid"
)
plate_reader_dict = read_robot_logs.plate_reader_commands(
file_results, hellma_plate_standards
file_results, hellma_plate_standards, hellma_plate_orientation
)
list_of_heights = read_robot_logs.liquid_height_commands(
file_results, list_of_heights
Expand Down
72 changes: 41 additions & 31 deletions abr-testing/abr_testing/data_collection/read_robot_logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,9 @@ def liquid_height_commands(


def plate_reader_commands(
file_results: Dict[str, Any], hellma_plate_standards: List[Dict[str, Any]]
file_results: Dict[str, Any],
hellma_plate_standards: List[Dict[str, Any]],
orientation: bool,
) -> Dict[str, object]:
"""Plate Reader Command Counts."""
commandData = file_results.get("commands", "")
Expand Down Expand Up @@ -279,38 +281,46 @@ def plate_reader_commands(
read = "yes"
elif read == "yes" and commandType == "comment":
result = command["params"].get("message", "")
formatted_result = result.split("result: ")[1]
result_dict = eval(formatted_result)
result_dict_keys = list(result_dict.keys())
if len(result_dict_keys) > 1:
read_type = "multi"
else:
read_type = "single"
for wavelength in result_dict_keys:
one_wavelength_dict = result_dict.get(wavelength)
result_ndarray = plate_reader.convert_read_dictionary_to_array(
one_wavelength_dict
)
for item in hellma_plate_standards:
wavelength_of_interest = item["wavelength"]
if str(wavelength) == str(wavelength_of_interest):
error_cells = plate_reader.check_byonoy_data_accuracy(
result_ndarray, item, False
if "result:" in result:
plate_name = result.split("result:")[0]
formatted_result = result.split("result: ")[1]
print(formatted_result)
result_dict = eval(formatted_result)
result_dict_keys = list(result_dict.keys())
if len(result_dict_keys) > 1:
read_type = "multi"
else:
read_type = "single"
if "hellma_plate" in plate_name:
for wavelength in result_dict_keys:
one_wavelength_dict = result_dict.get(wavelength)
result_ndarray = plate_reader.convert_read_dictionary_to_array(
one_wavelength_dict
)
if len(error_cells[0]) > 0:
percent = (96 - len(error_cells)) / 96 * 100
for cell in error_cells:
print(
"FAIL: Cell " + str(cell) + " out of accuracy spec."
for item in hellma_plate_standards:
wavelength_of_interest = item["wavelength"]
if str(wavelength) == str(wavelength_of_interest):
error_cells = plate_reader.check_byonoy_data_accuracy(
result_ndarray, item, orientation
)
else:
percent = 100
print(
f"PASS: {wavelength_of_interest} meet accuracy specification"
)
final_result[read_type, wavelength, read_num] = percent
read_num += 1
read = "no"
if len(error_cells[0]) > 0:
percent = (96 - len(error_cells)) / 96 * 100
for cell in error_cells:
print(
"FAIL: Cell "
+ str(cell)
+ " out of accuracy spec."
)
else:
percent = 100
print(
f"PASS: {wavelength_of_interest} meet accuracy spec."
)
final_result[read_type, wavelength, read_num] = percent
read_num += 1
else:
final_result = result_dict
read = "no"
plate_dict = {
"Plate Reader # of Reads": read_count,
"Plate Reader Avg Read Time (sec)": avg_read_time,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,11 @@ def parse_results_volume(
else:
print(f"Expected JSON object (dict) but got {type(json_data).__name__}.")
commands = {}

hellma_plate_orientation = False
parameters = json_data.get("runTimeParameters", "")
for parameter in parameters:
if parameter["displayName"] == "Hellma Plate Orientation":
hellma_plate_orientation = bool(parameter["value"])
start_time = datetime.fromisoformat(commands[0]["createdAt"])
end_time = datetime.fromisoformat(commands[len(commands) - 1]["completedAt"])
header = ["", "Protocol Name", "Date", "Time"]
Expand Down Expand Up @@ -283,7 +287,7 @@ def parse_results_volume(
temp_module_dict = read_robot_logs.temperature_module_commands(json_data)
thermo_cycler_dict = read_robot_logs.thermocycler_commands(json_data)
plate_reader_dict = read_robot_logs.plate_reader_commands(
json_data, hellma_plate_standards
json_data, hellma_plate_standards, hellma_plate_orientation
)
instrument_dict = read_robot_logs.instrument_commands(
json_data, labware_name=None
Expand Down Expand Up @@ -499,12 +503,12 @@ def check_params(protocol_path: str) -> str:
def get_extra_files(protocol_file_path: str) -> tuple[str, List[Path]]:
"""Get supporting files for protocol simulation if needed."""
params = check_params(protocol_file_path)
needs_files = input("Does your protocol utilize custom labware? (y/n): ")
needs_files = input("Does your protocol utilize custom labware? (Y/N): ")
labware_files = []
if needs_files == "y":
if needs_files == "Y":
num_labware = input("How many custom labware?: ")
for labware_num in range(int(num_labware)):
path = input("Enter custom labware definition: ")
path = input("Enter custom labware definition path: ")
labware_files.append(Path(path))
return (params, labware_files)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,12 @@ def add_parameters(parameters: ParameterContext) -> None:
def run(ctx: ProtocolContext) -> None:
"""Protocol."""
mount_pos_50ul = ctx.params.pipette_mount # type: ignore[attr-defined]
# TODO: Load plate reader
# Plate Reader
plate_reader: AbsorbanceReaderContext = ctx.load_module(
helpers.abs_mod_str, "A3"
) # type: ignore[assignment]
hs: HeaterShakerContext = ctx.load_module(helpers.hs_str, "A1") # type: ignore[assignment]
hs_adapter = hs.load_adapter("opentrons_96_pcr_adapter")
# TODO: load tube reservoir, 3 well plates, 3 50 ul tip racks, 1ch 50 ul pipette
tube_rack = ctx.load_labware(
"opentrons_10_tuberack_nest_4x50ml_6x15ml_conical", "C2", "Reagent Tube"
)
Expand Down Expand Up @@ -74,11 +72,11 @@ def run(ctx: ProtocolContext) -> None:
p50.aspirate(10, tartrazine_tube.bottom(z=height))
p50.air_gap(5)
p50.dispense(5, well.top())
p50.dispense(10, well.bottom(z=1))
p50.dispense(10, well.bottom(z=0.5))
p50.blow_out()
p50.return_tip()
helpers.move_labware_to_hs(ctx, sample_plate, hs, hs_adapter)
helpers.set_hs_speed(ctx, hs, 1500, 1.0, True)
helpers.set_hs_speed(ctx, hs, 1500, 2.0, True)
hs.open_labware_latch()
plate_reader.close_lid()
plate_reader.initialize("single", [450])
Expand All @@ -95,26 +93,32 @@ def run(ctx: ProtocolContext) -> None:
avg = statistics.mean(readings)
# Check if every average is within +/- 5% of 2.85
percent_error_dict = {}
percent_error_sum = 0.0
for reading in readings_and_wells:
well_name = str(reading[0])
measurement = reading[1]
percent_error = (measurement - 2.85) / 2.85 * 100
percent_error_dict[well_name] = percent_error
percent_error_sum += percent_error
avg_percent_error = percent_error_sum / 96.0
standard_deviation = statistics.stdev(readings)
try:
cv = standard_deviation / avg
except ZeroDivisionError:
cv = 0.0
cv_percent = cv * 100
cv_dict[sample_plate_name] = {"CV": cv_percent, "Mean": avg, "SD": standard_deviation}
msg = f"result: {result}"
cv_dict[sample_plate_name] = {
"CV": cv_percent,
"Mean": avg,
"SD": standard_deviation,
"Avg Percent Error": avg_percent_error,
}
all_percent_error_dict[sample_plate_name] = percent_error_dict
ctx.comment(msg=msg)
plate_reader.open_lid()
ctx.move_labware(sample_plate, deck_locations[i], use_gripper=True)
i += 1

# Print percent error dictionary
ctx.comment("Percent Error: " + str(all_percent_error_dict))
# Print cv dictionary
ctx.comment("Plate Reader Result: " + str(cv_dict))
ctx.comment("Plate Reader result: " + str(cv_dict))
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,7 @@
}


requirements = {
"robotType": "Flex",
"apiLevel": "2.21",
}
requirements = {"robotType": "Flex", "apiLevel": "2.21"}

HELLMA_PLATE_SLOT = "D4"
PLATE_READER_SLOT = "C3"
Expand Down Expand Up @@ -58,14 +55,11 @@ def add_parameters(parameters: ParameterContext) -> None:
"""Add Parameters."""
helpers.create_hs_speed_parameter(parameters)
helpers.create_dot_bottom_parameter(parameters)
parameters.add_str(
parameters.add_bool(
variable_name="plate_orientation",
display_name="Hellma Plate Orientation",
default="0_deg",
choices=[
{"display_name": "0 degree Rotation", "value": "0_deg"},
{"display_name": "180 degree Rotation", "value": "180_deg"},
],
default=True,
description="If hellma plate is rotated, set to True.",
)


Expand All @@ -85,7 +79,7 @@ def plate_reader_actions(
protocol.move_labware(hellma_plate, plate_reader, use_gripper=True)
plate_reader.close_lid()
result = plate_reader.read(str(datetime.now()))
msg = f"result: {result}"
msg = f"{hellma_plate_name} result: {result}"
protocol.comment(msg=msg)
plate_reader.open_lid()
protocol.move_labware(hellma_plate, HELLMA_PLATE_SLOT, use_gripper=True)
Expand All @@ -96,7 +90,7 @@ def plate_reader_actions(
protocol.move_labware(hellma_plate, plate_reader, use_gripper=True)
plate_reader.close_lid()
result = plate_reader.read(str(datetime.now()))
msg = f"result {hellma_plate_name}: {result}"
msg = f"{hellma_plate_name} result: {result}"
protocol.comment(msg=msg)
plate_reader.open_lid()
protocol.move_labware(hellma_plate, HELLMA_PLATE_SLOT, use_gripper=True)
Expand All @@ -108,7 +102,7 @@ def run(protocol: ProtocolContext) -> None:
# LOAD PARAMETERS
heater_shaker_speed = protocol.params.heater_shaker_speed # type: ignore[attr-defined]
dot_bottom = protocol.params.dot_bottom # type: ignore[attr-defined]
plate_orientation = protocol.params.plate_orientation # type: ignore[attr-defined]
plate_orientation = protocol.params.plate_orientation # type: ignore[attr-defined]
plate_name_str = "hellma_plate_" + str(plate_orientation)
global p200_tips
global p50_tips
Expand Down

0 comments on commit 21a4025

Please sign in to comment.