Labware
Basics#
In robotools
there are two important types of objects: Labware
and worklists.
A Labware
represents an array of wells, such as a microtiter plate (MTP), one or more troughs or even an arrangement of eppis or falcon tubes.
The worklists help you to perform liquid handling operations on Labware
objects while automatically creating a Gemini worklist file (*.gwl
) with the corresponding pipetting instructions.
These files contain things like source/destination, volume and can be executed by a Tecan EVO or Fluent liquid handlers.
But before we’ll get creating worklists, this example introduces how robotools
generally deals with liquid handling.
import robotools
The Labware
object#
Each Labware
object describes a $R\times C$ grid (array) of wells.
It has a name
and min_volume
/max_volume
to prevent you from pipetting impossible volumes.
The following cell creates a Labware
with the name "24-well plate"
.
When creating worklists, this name should match the labware defined on the liquid handler worktable.
plate = robotools.Labware(
"24-well plate",
rows=4, columns=6,
min_volume=100, max_volume=1_000,
initial_volumes=300
)
print(plate)
24-well plate
[[300. 300. 300. 300. 300. 300.]
[300. 300. 300. 300. 300. 300.]
[300. 300. 300. 300. 300. 300.]
[300. 300. 300. 300. 300. 300.]]
The Labware
has a lot of useful properties.
Most importantly: wells
and volumes
# These are the well IDs as they are typically printed on the plastic:
plate.wells
array([['A01', 'A02', 'A03', 'A04', 'A05', 'A06'],
['B01', 'B02', 'B03', 'B04', 'B05', 'B06'],
['C01', 'C02', 'C03', 'C04', 'C05', 'C06'],
['D01', 'D02', 'D03', 'D04', 'D05', 'D06']], dtype='<U3')
# In the same orientation, these are the current filling volumes:
plate.volumes
array([[300., 300., 300., 300., 300., 300.],
[300., 300., 300., 300., 300., 300.],
[300., 300., 300., 300., 300., 300.],
[300., 300., 300., 300., 300., 300.]])
If you are familiar with Python already, you probably know how NumPy slicing works.
Because .wells
and .volumes
are NumPy ndarray
s, you can use NumPy slicing to select particular ranges:
# This slice selects all wells except the first/last column/row:
plate.wells[1:-1, 1:-1]
array([['B02', 'B03', 'B04', 'B05'],
['C02', 'C03', 'C04', 'C05']], dtype='<U3')
Labware
s have methods such as .add()
, .remove()
for performing virtual liquid handling operations.
You won’t typically work with .add()
or .remove()
directly, because most things you do with a worklist will call these methods under the hood.
One job of the .add()
and .remove()
methods is to raise VolumeOverflowError
or VolumeUnderflowError
when the minimum/maximum working volumes are violated:
try:
plate.add(['A01', 'B01', 'C01'], [200, 200, 2000])
except robotools.VolumeViolationException as ex:
print(ex)
Too much volume for "24-well plate".C01: 300.0 + 2000 > 1000
Another job is to record a history of all liquid handling operations performed over the labware’s lifetime:
plate.add(plate.wells[1:-1, 1:-1], volumes=55, label="Add 55 µL to the center wells")
print(plate.report)
24-well plate
initial
[[300. 300. 300. 300. 300. 300.]
[300. 300. 300. 300. 300. 300.]
[300. 300. 300. 300. 300. 300.]
[300. 300. 300. 300. 300. 300.]]
Add 55 µL to the center wells
[[500. 300. 300. 300. 300. 300.]
[500. 355. 355. 355. 355. 300.]
[300. 355. 355. 355. 355. 300.]
[300. 300. 300. 300. 300. 300.]]
Troughs#
Troughs are a little weird, because for the EVOware, they have multiple rows, even though it’s actually just one big well.
Nevertheless, a Trough
is just a special type of Labware
that has virtual_rows
.
For the Tecan Fluent, the virtual_rows
setting is irrelevant.
The following example emulates an arrangement of 4 troughs next to each other.
They have virtual_rows=8
, so there’s enough space for 8 tips (A01
through H01
), but in reality it’s just one well per column:
quadruple_trough = robotools.Trough(
"4xTrough", 8, 4,
min_volume=1000, max_volume=30_000,
initial_volumes=[20_000, 10_000, 10_000, 10_000]
)
print(quadruple_trough)
4xTrough
[[20000. 10000. 10000. 10000.]]
Let’s say we want to aspirate 11x 100 µL from the first trough, operating all 8 pipettes in parallel. So we need 8 different virtual well IDs (A01-H01), but 11 in total.
The robotools.get_trough_wells
helper function returns such a well list:
vwells = robotools.get_trough_wells(
n=11,
trough_wells=quadruple_trough.wells[:, 0] # select the wells from the first trough
)
quadruple_trough.remove(vwells, 100)
print(f"""
Virtual wells:
{vwells}
Result:
{quadruple_trough}
""")
Virtual wells:
['A01', 'B01', 'C01', 'D01', 'E01', 'F01', 'G01', 'H01', 'A01', 'B01', 'C01']
Result:
4xTrough
[[18900. 10000. 10000. 10000.]]
%load_ext watermark
%watermark -idu
Last updated: 2024-04-23T13:11:50.287028+02:00