{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Tutorial: Plate Quadrants\n", "\n", "
\n", " Note: This notebook can be downloaded and used directly.\n", "
\n", "\n", "In many automated protocols liquid transfers have to be performed between different plate formats, e.g.: between 96-wellplate to 24-wellplates, or between 384-wellplates to 96-wellplates.\n", "\n", "To facilitate these liquid transfers, PLR standardized the definition of `Plate` \"Quadrants\" and enables dynamically accessing these quadrants to generate complex transfer pipetting patterns with ease:\n", "\n", "```python\n", "Plate_instance.get_quadrant(\n", " quadrant: Literal[\n", " \"tl\", \"top_left\",\n", " \"tr\", \"top_right\",\n", " \"bl\", \"bottom_left\",\n", " \"br\", \"bottom_right\"\n", " ],\n", " quadrant_type: Literal[\"block\", \"checkerboard\"] = \"checkerboard\",\n", " quadrant_internal_fill_order: Literal[\"column-major\", \"row-major\"] = \"column-major\",\n", " ) -> List[\"Well\"]\n", "```\n", "\n", "\n", "---\n", "\n", "## Attribute Explanations\n", "### Quadrant Type\n", "Depending on 1) manual vs fully-automated processing, and 2) y-channel spacing ability, two common definitions for “quadrant types” are:\n", "\n", "- **“block”**\n", " - division of plate into 4 zones based on the plate’s 2 symmetric axes\n", "- **“checkerboard”**\n", " - division of plate into 4 zones based on using every other row + every other column\n", "\n", "\n", "```{image} ./img/250304_explainer_quadrants_96.jpg\n", ":width: 500px\n", ":align: center" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```{image} ./img/250304_explainer_quadrants_384.jpg\n", ":width: 500px\n", ":align: center" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Quadrant identifiers\n", "To extract a specific quadrant we simply call the relative position of the desired quadrant, relative to the `Plate` origin / front-left-bottom:\n", "\n", "```{image} ./img/250304_explainer_quadrant_identifiers.jpg\n", ":width: 500px\n", ":align: center" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Fill Order\n", "All matrices, including plates, can be filled in two different orders:\n", "\n", "- **\"row-major\" order** (row-wise filling)\n", " - Filling proceeds across a row before moving to the next row.\n", " - Mostly used by manual handling of plates.\n", "- **\"column-major\" order** (column-wise filling)\n", " - Filling proceeds down a column before moving to the next column.\n", " - Common standard in robotic handling of plates due to parallelization opportunity of liquid transfer actions in the same x-coordinate(–> massive temporal acceleration)\n", "\n", "```{image} ./img/250304_explainer_fill_order.jpg\n", ":width: 500px\n", ":align: center" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Examples\n", "\n", "\n", "Start by creating a minimal deck in simulation mode:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from pylabrobot.resources import (\n", " Cor_6_wellplate_16800ul_Fb,\n", " CellVis_24_wellplate_3600uL_Fb,\n", " Thermo_TS_96_wellplate_1200ul_Rb,\n", " Revvity_384_wellplate_28ul_Ub\n", ")\n", "\n", "example_6_wellplate = Cor_6_wellplate_16800ul_Fb(name=\"example_6_wellplate\")\n", "example_24_wellplate = CellVis_24_wellplate_3600uL_Fb(name=\"example_24_wellplate\")\n", "example_96_wellplate = Thermo_TS_96_wellplate_1200ul_Rb(name=\"example_96_wellplate\")\n", "example_384_wellplate = Revvity_384_wellplate_28ul_Ub(name=\"example_384_wellplate\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### \"checkerboard\" + \"column-major\" (default)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[Well(name=example_24_wellplate_well_0_0, location=Coordinate(009.280, 063.800, 000.750), size_x=15.54, size_y=15.54, size_z=19, category=well),\n", " Well(name=example_24_wellplate_well_0_2, location=Coordinate(009.280, 025.200, 000.750), size_x=15.54, size_y=15.54, size_z=19, category=well),\n", " Well(name=example_24_wellplate_well_2_0, location=Coordinate(047.880, 063.800, 000.750), size_x=15.54, size_y=15.54, size_z=19, category=well),\n", " Well(name=example_24_wellplate_well_2_2, location=Coordinate(047.880, 025.200, 000.750), size_x=15.54, size_y=15.54, size_z=19, category=well),\n", " Well(name=example_24_wellplate_well_4_0, location=Coordinate(086.480, 063.800, 000.750), size_x=15.54, size_y=15.54, size_z=19, category=well),\n", " Well(name=example_24_wellplate_well_4_2, location=Coordinate(086.480, 025.200, 000.750), size_x=15.54, size_y=15.54, size_z=19, category=well)]" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "example_24_wellplate.get_quadrant(\n", " quadrant=\"tl\",\n", " quadrant_type=\"checkerboard\", # default\n", " quadrant_internal_fill_order=\"column-major\" # default\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For simplified inspection, we can call `.get_identifier()` on each Well instance returned:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['A1', 'C1', 'E1', 'G1', 'A3', 'C3', 'E3', 'G3', 'A5', 'C5', 'E5', 'G5', 'A7', 'C7', 'E7', 'G7', 'A9', 'C9', 'E9', 'G9', 'A11', 'C11', 'E11', 'G11']\n" ] } ], "source": [ "print([well.get_identifier() for well in example_96_wellplate.get_quadrant(\n", " quadrant=\"tl\",\n", " quadrant_type = \"checkerboard\", # default\n", " quadrant_internal_fill_order = \"column-major\" # default\n", ")])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### \"checkerboard\" + \"row-major\"" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['A1', 'A3', 'A5', 'A7', 'A9', 'A11', 'C1', 'C3', 'C5', 'C7', 'C9', 'C11', 'E1', 'E3', 'E5', 'E7', 'E9', 'E11', 'G1', 'G3', 'G5', 'G7', 'G9', 'G11']\n" ] } ], "source": [ "print([well.get_identifier() for well in example_96_wellplate.get_quadrant(\n", " quadrant=\"tl\",\n", " quadrant_type = \"checkerboard\", # Literal[\"block\", \"checkerboard\"]\n", " quadrant_internal_fill_order = \"row-major\" # Literal[\"column-major\", \"row-major\"]\n", ")])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### \"block\" + \"column-major\"" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['A1', 'B1', 'C1', 'D1', 'A2', 'B2', 'C2', 'D2', 'A3', 'B3', 'C3', 'D3', 'A4', 'B4', 'C4', 'D4', 'A5', 'B5', 'C5', 'D5', 'A6', 'B6', 'C6', 'D6']\n" ] } ], "source": [ "print([well.get_identifier() for well in example_96_wellplate.get_quadrant(\n", " quadrant=\"tl\",\n", " quadrant_type = \"block\",\n", " quadrant_internal_fill_order = \"column-major\"\n", ")])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### \"block\" + \"row-major\"" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'D1', 'D2', 'D3', 'D4', 'D5', 'D6']\n" ] } ], "source": [ "print([well.get_identifier() for well in example_96_wellplate.get_quadrant(\n", " quadrant=\"tl\",\n", " quadrant_type = \"block\", # Literal[\"block\", \"checkerboard\"]\n", " quadrant_internal_fill_order = \"row-major\" # Literal[\"column-major\", \"row-major\"]\n", ")])" ] } ], "metadata": { "kernelspec": { "display_name": "env", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.15" } }, "nbformat": 4, "nbformat_minor": 2 }