Skip to content
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

docs(api): runtime parameters in Python API 2.18 #14677

Merged
merged 33 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
9d0c811
stub landing page, defining, using
ecormany Mar 15, 2024
bd8c48d
fix sphinx warnings
ecormany Mar 15, 2024
0e54149
code snippets for defining each type
ecormany Mar 15, 2024
ebfc509
stub Choosing Good Parameters page
ecormany Mar 18, 2024
6ec7e6d
some more RTP advice
ecormany Mar 18, 2024
3bcccaf
full first draft of Good Params
ecormany Mar 19, 2024
934b6b7
intro and add_parameters() §§
ecormany Mar 21, 2024
1b4b2bd
full draft of Defining
ecormany Mar 22, 2024
2bd3153
starting sample count use case
ecormany Mar 27, 2024
5b35d5e
sample count - tip racks §
ecormany Mar 28, 2024
caebf66
sample count - liquids § thru reagents
ecormany Mar 29, 2024
c714ca0
sample count - label sample wells
ecormany Mar 29, 2024
50fb0e9
draft through proc samples - needs code check
ecormany Mar 29, 2024
ee64629
fix sample loop code
ecormany Mar 29, 2024
1b64af2
full draft of sample count
ecormany Apr 1, 2024
842c88d
sample count - light proofread
ecormany Apr 1, 2024
9e11cf4
no unit attribute for int w/choices
ecormany Apr 1, 2024
6a89b35
add max lengths for description, units
ecormany Apr 2, 2024
1006616
first draft of using parameters
ecormany Apr 2, 2024
447a037
fix sphinx warning
ecormany Apr 2, 2024
62c9d79
first draft of style guide
ecormany Apr 23, 2024
0f32358
touch up Style Guide
ecormany Apr 23, 2024
9802e44
formatting tweak
ecormany Apr 24, 2024
a03a74a
stub dry run use case
ecormany May 1, 2024
07c6357
intro and outline for dry run
ecormany May 1, 2024
c2a1321
full draft of dry run use case
ecormany May 1, 2024
b12942e
delay, not pause
ecormany May 1, 2024
f086614
logic is hard
ecormany May 1, 2024
65eb712
draft docstring for .params
ecormany May 2, 2024
99f069b
update toctree order to match landing page order
ecormany May 2, 2024
8634a83
implement review feedback
ecormany May 3, 2024
59c9815
typo fix and wording change
ecormany May 3, 2024
3b8926b
final proofread
ecormany May 14, 2024
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
1 change: 1 addition & 0 deletions api/docs/v2/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -444,5 +444,6 @@
("py:class", r".*protocol_api\.deck.*"),
("py:class", r".*protocol_api\.config.*"),
("py:class", r".*opentrons_shared_data.*"),
("py:class", r".*protocol_api._parameters.Parameters.*"),
("py:class", r'.*AbstractLabware|APIVersion|LabwareLike|LoadedCoreMap|ModuleTypes|NoneType|OffDeckType|ProtocolCore|WellCore'), # laundry list of not fully qualified things
]
1 change: 1 addition & 0 deletions api/docs/v2/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Welcome
new_atomic_commands
new_complex_commands
robot_position
runtime_parameters
new_advanced_running
new_examples
adapting_ot2_flex
Expand Down
4 changes: 4 additions & 0 deletions api/docs/v2/new_labware.rst
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,8 @@ To use these optional methods, first create a liquid object with :py:meth:`.Prot

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

.. _defining-liquids:

Defining Liquids
================

Expand All @@ -291,6 +293,8 @@ This example uses ``define_liquid`` to create two liquid objects and instantiate

The ``display_color`` parameter accepts a hex color code, which adds a color to that liquid's label when you import your protocol into the Opentrons App. The ``define_liquid`` method accepts standard 3-, 4-, 6-, and 8-character hex color codes.

.. _loading-liquids:

Labeling Wells and Reservoirs
=============================

Expand Down
2 changes: 1 addition & 1 deletion api/docs/v2/new_protocol_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Protocols

.. autoclass:: opentrons.protocol_api.ProtocolContext
:members:
:exclude-members: location_cache, cleanup, clear_commands, params
:exclude-members: location_cache, cleanup, clear_commands

Instruments
===========
Expand Down
53 changes: 53 additions & 0 deletions api/docs/v2/parameters/choosing.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
:og:description: Advice on choosing effective parameters in Opentrons Python protocols.

.. _good-rtps:

************************
Choosing Good Parameters
************************

The first decision you need to make when adding parameters to your protocol is "What should be parameterized?" Your goals in adding parameters should be the following:

1. **Add flexibility.** Accommodate changes from run to run or from lab to lab.
2. **Work efficiently.** Don't burden run setup with too many choices or confusing options.
3. **Avoid errors.** Ensure that every combination of parameters produces an analyzable, runnable protocol.

Build on a Task
===============

Consider what scientific task is at the heart of your protocol, and build parameters that contribute to, rather than diverge from it.

For example, it makes sense to add a parameter for number of samples to a protocol that uses a particular DNA prep reagent kit. But it wouldn't make sense to add a parameter for *which reagent kit* to use for DNA prep. That kind of parameter would affect so many aspects of the protocol that it would make more sense to maintain two protocols, one for each kit.
ecormany marked this conversation as resolved.
Show resolved Hide resolved

Also consider how a small number of parameters can combine to produce many useful outputs. Take the serial dilution task from the :ref:`tutorial` as an example. We could add just three parameters to it: number of dilutions, dilution factor, and number of rows. Now that single protocol can produce a whole plate that gradually dilutes, a 2×4 grid that rapidly dilutes, and *thousands* of other combinations.

The trick to choosing good parameters is reasoning through the choices the protocol's users may make. If any of them lead to nonsensical outcomes or errors, adjust the parameters — or how your protocol :ref:`uses parameter values <using-rtp>` — to avoid those situations.

Consider Contradictions
=======================

Here's a common time-saving use of parameters: your protocol requires a 1-channel pipette and an 8-channel pipette, but it doesn't matter which mount they're attached to. Without parameters, you would have to assign the mounts in your protocol. Then if the robot is set up in the reverse configuration, you'd have to either physically swap the pipettes or modify your protocol.

One way to get this information is to ask which mount the 1-channel pipette is on, and which pipette the 8-channel pipette is on. But if a user answers "left" to both questions — even by accident — the API will raise an error, because you can't load two pipettes on a single mount. It's no better to flip things around by asking which pipette is on the left mount, and which pipette is on the right mount. Now the user can say that both mounts have a 1-channel pipette. This is even more dangerous, because it *might not* raise any errors in analysis. The protocol could run "successfully" on a robot with two 1-channel pipettes, but produce completely unintended results.
ecormany marked this conversation as resolved.
Show resolved Hide resolved

The best way to avoid these contradictions is to collapse the two questions into one, with limited choices. Where are the pipettes mounted? Either the 1-channel is on the left and the 8-channel on the right, or the 8-channel is on the left and the 1-channel is on the right. This approach is best for several reasons:

- It avoids analysis errors.
- It avoids potentially dangerous execution errors.
- It only requires the user to answer one question instead of two.
- The :ref:`phrasing of the question and answer <rtp-style>` makes it clear that the protocol requires exactly one of each pipette type.

Set Boundaries
==============

Numerical parameters support minimum and maximum values, which you should set to avoid incorrect inputs that are outside of your protocol's possibile actions.

Consider our earlier example of parameterizing serial dilution. Each of the three numerical parameters have logical upper and lower bounds, which we need to enforce to get sensible results.

- *Number of dilutions* must be between 0 and 11 on a 96-well plate. And it may make sense to require at least 1 dilution.
- *Dilution factor* is a ratio, which we can express as a decimal number that must be between 0 and 1.
- *Number of rows* must be between 1 and 8 on a 96-well plate.

What if you wanted to perform a dilution with 20 repetitions? It's possible with two 96-well plates, or with a 384-well plate. You could set the maximum for the number of dilutions to 24 and allow for these possibilities — either switching the plate type or loading an additional plate based on the provided value.

But what if the user wanted to do just 8 repetitions on a 384-well plate? That would require an additional parameter, an additional choice by the user, and additional logic in your protocol code. It's up to you as the protocol author to decide if adding more parameters adds unnecessary complexity. It may well be better to have two or three protocols that each work simply and efficiently.
ecormany marked this conversation as resolved.
Show resolved Hide resolved
181 changes: 181 additions & 0 deletions api/docs/v2/parameters/defining.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
:og:description: Define and set possible values for parameters in Opentrons Python protocols.

.. _defining-rtp:

*******************
Defining Parameters
*******************

To use parameters, you need to define them in :ref:`a separate function <add-parameters>` within your protocol. Each parameter definition has two main purposes: to specify acceptable values, and to inform the protocol user what the parameter does.

Depending on the :ref:`type of parameter <rtp-types>`, you'll need to specify some or all of the following.

.. list-table::
ecormany marked this conversation as resolved.
Show resolved Hide resolved
:header-rows: 1

* - Attribute
- Details
* - ``variable_name``
-
- A unique name for :ref:`referencing the parameter value <using-rtp>` elsewhere in the protocol.
- Must meet the usual requirements for `naming objects in Python <https://docs.python.org/3/reference/lexical_analysis.html#identifiers>`__.
* - ``display_name``
-
- A label for the parameter shown in the Opentrons App or on the touchscreen.
- Maximum 30 characters.
* - ``description``
-
- An optional longer explanation of what the parameter does, or how its values will affect the execution of the protocol.
- Maximum 100 characters.
* - ``default``
- The value the parameter will have if the user makes no changes to it during run setup.
* - ``minimum`` and ``maximum``
-
- For numeric parameters only.
- Allows free entry of any value within the range (inclusive).
- Both values are required.
- Can't be used at the same time as ``choices``.
* - ``choices``
-
- For numeric or string parameters.
- Provides a fixed list of values to choose from.
- Each choice has its own display name and value.
- Can't be used at the same time as ``minimum`` and ``maximum``.
* - ``units``
-
- Optional, for numeric parameters only.
- Displays after the number during run setup.
- Does not affect the parameter's value or protocol execution.
- Maximum [10/TK] characters.
ecormany marked this conversation as resolved.
Show resolved Hide resolved



.. _add-parameters:

The ``add_parameters()`` Function
=================================

All parameter definitions are contained in a Python function, which must be named ``add_parameters`` and takes a single argument. You must define ``add_parameters`` before the ``run`` function that contains protocol commands.
ecormany marked this conversation as resolved.
Show resolved Hide resolved

The examples on this page assume the following definition, which uses the argument name ``parameters``. The type specification of the argument is optional.

.. code-block::

def add_parameters(parameters: protocol_api.ProtocolContext.Parameters):

Within this function definition, call methods on ``parameters`` to define parameters. The next section demonstrates how each type of parameter has its own method.

.. _rtp-types:

Types of Parameters
===================

The API supports four types of parameters: Boolean (:py:class:`bool`), integer (:py:class:`int`), floating point number (:py:class:`float`), and string (:py:class:`str`). It is not possible to mix types within a single parameter.

Boolean Parameters
------------------

Boolean parameters are ``True`` or ``False`` only.

.. code-block::

parameters.add_bool(
variable_name="dry_run",
display_name="Dry Run",
description="Skip incubation delays and shorten mix steps.",
default=False
)

During run setup, users can toggle between the two values. In the Opentrons App, Boolean parameters appear as a toggle switch. On the touchscreen, they appear as *On* or *Off*, for ``True`` and ``False`` respectively.

.. versionadded:: 2.18

Integer Parameters
------------------

Integer parameters either accept a range of numbers or a list of numbers. You must specify one or the other; you can't prompt for any integer.
ecormany marked this conversation as resolved.
Show resolved Hide resolved

To specify a range, include ``minimum`` and ``maximum``.

.. code-block::

parameters.add_int(
variable_name="sample_count",
display_name="Sample count",
description="How many samples to process.",
default=24,
minimum=8,
maximum=48
)

During run setup, the user can enter any integer value from the minimum up to the maximum. Entering a value outside of the range will show an error. At that point, they can correct their custom value or restore the default value.

To specify a list of numbers, include ``choices``. Each choice is a dictionary with entries for display name and value. The display names let you briefly explain the effect each choice will have.

.. code-block::

parameters.add_int(
variable_name="volume",
display_name="Aspirate volume",
description="How much to aspirate from each sample.",
default=20,
choices=[
{"display_name": "Low (10 µL)", "value": 10},
{"display_name": "Medium (20 µL)", "value": 20},
{"display_name": "High (50 µL)", "value": 50},
],
unit="µL"
ecormany marked this conversation as resolved.
Show resolved Hide resolved
)

During run setup, the user can choose from a menu of the provided choices.

.. versionadded:: 2.18

Float Parameters
----------------

Float parameters either accept a range of numbers or a list of numbers. You must specify one or the other; you can't prompt for any floating point number.

Specifying a range or list is done exactly the same as in the integer examples above. The only difference is that all values must be floating point numbers.

.. code-block::

parameters.add_float(
variable_name="volume",
display_name="Aspirate volume",
description="How much to aspirate from each sample.",
default=5.0,
choices=[
{"display_name": "Low (2.5 µL)", "value": 2.5},
{"display_name": "Medium (5 µL)", "value": 5.0},
{"display_name": "High (10 µL)", "value": 10.0},
],
unit="µL"
ecormany marked this conversation as resolved.
Show resolved Hide resolved
)

Remember, you can't mix types in a parameter. So values of ``2.5``, ``5.0``, and ``10.0`` are valid, but ``2.5``, ``5``, and ``10`` will raise an error.
ecormany marked this conversation as resolved.
Show resolved Hide resolved

.. versionadded:: 2.18

String Parameters
-----------------

String parameters only accept a list of values. You can't currently prompt for free text entry of a string value.

To specify a list of strings, include ``choices``. Each choice is a dictionary with entries for display name and value. In most cases, the display name and value *will not* match. A common use for string display names is to provide an easy-to-read version of an API load name. You can also use them to briefly explain the effect each choice will have.
ecormany marked this conversation as resolved.
Show resolved Hide resolved

.. code-block::

parameters.add_str(
variable_name="pipette",
display_name="Pipette type",
choices=[
{"display_name": "1-Channel 50 µL", "value": "flex_1channel_50"},
{"display_name": "8-Channel 50 µL", "value": "flex_8channel_50"},
],
default="flex_1channel_50",
)

y3rsh marked this conversation as resolved.
Show resolved Hide resolved
During run setup, the user can choose from a menu of the provided choices.

.. versionadded:: 2.18
Loading
Loading