Skip to content

docs(api): load liquids in API 2.23 #18025

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: chore_release-8.4.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 32 additions & 13 deletions api/docs/v2/new_labware.rst
Original file line number Diff line number Diff line change
Expand Up @@ -256,16 +256,16 @@ Equivalently, using ``rows_by_name``::

.. _labeling-liquids:

*************************
Labeling Liquids in Wells
*************************
****************************
Labeling Liquids in Labware
****************************

Optionally, you can specify the liquids that should be in various wells at the beginning of your protocol. Doing so helps you identify well contents by name and volume, and adds corresponding labels to a single well, or group of wells, in well plates and reservoirs. You can view the initial liquid setup:
Optionally, you can specify the liquids that should be in labware at the beginning of your protocol. Doing so helps you identify well contents by name and volume, and adds corresponding labels to a single well, group of wells, or an entire labware. You can view the initial liquid setup:

- For Flex protocols, on the touchscreen.
- For Flex or OT-2 protocols, in the Opentrons App (v6.3.0 or higher).

To use these optional methods, first create a liquid object with :py:meth:`.ProtocolContext.define_liquid` and then label individual wells by calling :py:meth:`.Well.load_liquid`.
To use these optional methods, first create a liquid object with :py:meth:`.ProtocolContext.define_liquid` and then label individual wells by calling :py:meth:`.Labware.load_liquid`.

Let's examine how these two methods work. The following examples demonstrate how to define colored water samples for a well plate and reservoir.

Expand Down Expand Up @@ -298,18 +298,35 @@ The ``display_color`` parameter accepts a hex color code, which adds a color to
Labeling Wells and Reservoirs
=============================

This example uses ``load_liquid`` to label the initial well location, contents, and volume (in µL) for the liquid objects created by ``define_liquid``. Notice how values of the ``liquid`` argument use the variable names ``greenWater`` and ``blueWater`` (defined above) to associate each well with a particular liquid:
This example uses ``load_liquid`` to label the initial well location, contents, and volume (in µL) for the liquid objects created by ``define_liquid``. Notice how values of the ``liquid`` argument use the variable names ``greenWater`` and ``blueWater`` (defined above) to associate each labware with a particular liquid:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's important to note that the new Labware method still makes reference to individual wells — it's not all or nothing.

Suggested change
This example uses ``load_liquid`` to label the initial well location, contents, and volume (in µL) for the liquid objects created by ``define_liquid``. Notice how values of the ``liquid`` argument use the variable names ``greenWater`` and ``blueWater`` (defined above) to associate each labware with a particular liquid:
This example uses ``load_liquid`` to label the initial well location, contents, and volume (in µL) for the liquid objects created by ``define_liquid``. Notice how values of the ``liquid`` argument use the variable names ``greenWater`` and ``blueWater`` (defined above) to associate wells in each labware with a particular liquid:


.. code-block:: python

well_plate["A1"].load_liquid(liquid=greenWater, volume=50)
well_plate["A2"].load_liquid(liquid=greenWater, volume=50)
well_plate["B1"].load_liquid(liquid=blueWater, volume=50)
well_plate["B2"].load_liquid(liquid=blueWater, volume=50)
reservoir["A1"].load_liquid(liquid=greenWater, volume=200)
reservoir["A2"].load_liquid(liquid=blueWater, volume=200)
## load entire well plate with greenWater
well_plate.load_liquid(
wells=()[0],
volume=50,
liquid="greenWater"
)

## load entire reservoir with blueWater
reservoir.load_liquid(
wells=[A1],
volume=50,
liquid="blueWater"
)
Comment on lines +305 to +317
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix up this code so it simulates and has proper comment formatting.

Suggested change
## load entire well plate with greenWater
well_plate.load_liquid(
wells=()[0],
volume=50,
liquid="greenWater"
)
## load entire reservoir with blueWater
reservoir.load_liquid(
wells=[A1],
volume=50,
liquid="blueWater"
)
# load entire well plate with greenWater
plate.load_liquid(
wells=plate.wells(), # using accessor
volume=50,
liquid=greenWater
)
# load entire reservoir with blueWater
reservoir.load_liquid(
wells=["A1"], # using list of well names
volume=50,
liquid=blueWater
)


``load_liquid`` makes it easy to load an entire well plate with a single command. Let's say you only need to load liquid in a few wells, or want to load multiple liquids or volumes in the same labware.

.. code-block:: python

well_plate.load_liquid_by_well({'A1': 200, 'A2': 100, 'A3': 50}, greenWater)
well_plate.load_liquid_by_well({'B1': 200, 'B2': 100, 'B3': 50}, blueWater)
Comment on lines +323 to +324
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use plate as the labware name here too. Not sure why we had well_plate before — it doesn't match our docs template protocol.



You can also use :py:meth:`.Labware.load_empty`to label individual wells or an entire labware as empty at the beginning of your protocol.

.. versionadded:: 2.14
.. versionadded:: 2.23
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double checked and these were added in 2.22.


This information is available after you import your protocol to the app or send it to Flex. A summary of liquids appears on the protocol detail page, and well-by-well detail is available on the run setup page (under Initial Liquid Setup in the app, or under Liquids on Flex).

Expand All @@ -321,6 +338,8 @@ Labeling vs Handling Liquids

The ``load_liquid`` arguments include a volume amount (``volume=n`` in µL). This amount is just a label. It isn't a command or function that manipulates liquids. It only tells you how much liquid should be in a well at the start of the protocol. You need to use a method like :py:meth:`.transfer` to physically move liquids from a source to a destination.

Although it's optional to define and load liquids in your protocol, you can use a starting liquid volume to specify pipette movements relative to a liquid location, like the :ref:`meniscus <well-meniscus>`, in your protocol.


.. _v2-location-within-wells:
.. _new-labware-well-properties:
Expand Down
43 changes: 13 additions & 30 deletions api/src/opentrons/protocol_api/labware.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,9 +326,11 @@ def load_liquid(self, liquid: Liquid, volume: float) -> None:
:param Liquid liquid: The liquid to load into the well.
:param float volume: The volume of liquid to load, in µL.

.. TODO: flag as deprecated in 2.22 docs
In API version 2.22 and later, use :py:meth:`~Labware.load_liquid`, :py:meth:`~Labware.load_liquid_by_well`,
or :py:meth:`~Labware.load_empty` to load liquid into a well.
.. deprecated:: 2.23

In API version 2.22 and later, use :py:meth:`~.Labware.load_liquid`, :py:meth:`~.Labware.load_liquid_by_well`,
or :py:meth:`~.Labware.load_empty` to load liquid into a well.

"""
self._core.load_liquid(
liquid=liquid,
Expand Down Expand Up @@ -1274,17 +1276,10 @@ def load_liquid(
has not been named in a call to :py:meth:`~Labware.load_empty`, :py:meth:`~Labware.load_liquid`, or
:py:meth:`~Labware.load_liquid_by_well`, the volume it contains is unknown and the well's liquid will not be tracked.

For example, to load 10µL of a liquid named ``water`` (defined with :py:meth:`~ProtocolContext.define_liquid`)
into all the wells of a labware, you could call ``labware.load_liquid(labware.wells(), 10, water)``.

If you want to load different volumes of liquid into different wells, use :py:meth:`~Labware.load_liquid_by_well`.

If you want to mark the well as containing no liquid, use :py:meth:`~Labware.load_empty`.

:param wells: The wells to load the liquid into.
:type wells: List of well names or list of Well objects, for instance from :py:meth:`~Labware.wells`.
:type wells: List of well names or list of Well objects- for instance, from :py:meth:`~Labware.wells`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A little clearer on the types. And sewing up the clauses more neatly.

Suggested change
:type wells: List of well names or list of Well objects- for instance, from :py:meth:`~Labware.wells`.
:type wells: List of string well names or list of :py:class:`.Well` objects (e.g., from :py:meth:`~Labware.wells`).


:param volume: The volume of liquid to load into each well, in 10µL.
:param volume: The volume of liquid to load into each well. Must be a multiple of 10.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making an assumption here that this meant the volume must be a multiple of 10... but I could be wrong.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No thats definitely just a typo. Should be a multiple of 1.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!!

:type volume: float

:param liquid: The liquid to load into each well, previously defined by :py:meth:`~ProtocolContext.define_liquid`
Expand Down Expand Up @@ -1320,18 +1315,9 @@ def load_liquid_by_well(
) -> None:
"""Mark several wells as containing unique volumes of liquid.

This method should be called at the beginning of a protocol, soon after loading the labware and before
liquid handling operations begin. It is a base of information for liquid tracking functionality. If a well in a labware
has not been named in a call to :py:meth:`~Labware.load_empty`, :py:meth:`~Labware.load_liquid`, or
:py:meth:`~Labware.load_liquid_by_well`, the volume it contains is unknown and the well's liquid will not be tracked.

For example, to load a decreasing amount of of a liquid named ``water`` (defined with :py:meth:`~ProtocolContext.define_liquid`)
into each successive well of a row, you could call
``labware.load_liquid_by_well({'A1': 1000, 'A2': 950, 'A3': 900, ..., 'A12': 600}, water)``

If you want to load the same volume of a liquid into multiple wells, it is often easier to use :py:meth:`~Labware.load_liquid`.

If you want to mark the well as containing no liquid, use :py:meth:`~Labware.load_empty`.
This method should be called at the beginning of a protocol, soon after loading labware and before
liquid handling begins. Loading liquids is required for liquid tracking functionality- if a well hasn't been assigned a starting volume with :py:meth:`~Labware.load_empty`, :py:meth:`~Labware.load_liquid`, or
:py:meth:`~Labware.load_liquid_by_well`, the volume it contains is unknown and the well's liquid will not be tracked throughout the protocol.

:param volumes: A dictionary of well names (or :py:class:`Well` objects, for instance from ``labware['A1']``)
:type wells: Dict[Union[str, Well], float]
Expand Down Expand Up @@ -1367,12 +1353,9 @@ def load_liquid_by_well(
def load_empty(self, wells: Sequence[Union[Well, str]]) -> None:
"""Mark several wells as empty.

This method should be called at the beginning of a protocol, soon after loading the labware and before liquid handling
operations begin. It is a base of information for liquid tracking functionality. If a well in a labware has not been named
in a call to :py:meth:`Labware.load_empty`, :py:meth:`Labware.load_liquid`, or :py:meth:`Labware.load_liquid_by_well`, the
volume it contains is unknown and the well's liquid will not be tracked.

For instance, to mark all wells in the labware as empty, you can call ``labware.load_empty(labware.wells())``.
This method should be called at the beginning of a protocol, after loading the labware and before liquid handling
begins. Loading liquids is required for liquid tracking functionality- if a well in a labware hasn't been assigned a starting volume with :py:meth:`Labware.load_empty`, :py:meth:`Labware.load_liquid`, or :py:meth:`Labware.load_liquid_by_well`, the
volume it contains is unknown and the well's liquid will not be tracked throughout the protocol.

:param wells: The list of wells to mark empty. To mark all wells as empty, pass ``labware.wells()``. You can also specify
wells by their names (for instance, ``labware.load_empty(['A1', 'A2'])``).
Expand Down
Loading