Skip to content

Plates

Generate random assay plates.

plates(options)

Main driver for snailz plate creation.

one with the design and one with the results.

Plate generation re-uses assay parameters: see assays.py for details. Plates are saved in the specified output directory with auto-generated names.

  • options.assays: path to assay parameter files.
  • options.designs: output directory for plate design files.
  • options.readings: output directory for plate reading files.

Parameters:

Name Type Description Default
options Namespace

see above.

required
Source code in snailz/plates.py
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
def plates(options: Namespace) -> None:
    '''Main driver for snailz plate creation.

    Each plate is represented by two files: one with the design and one with the results.
      Plate generation re-uses assay parameters: see `assays.py` for details.
      Plates are saved in the specified output directory with auto-generated names.

    -   options.assays: path to assay parameter files.
    -   options.designs: output directory for plate design files.
    -   options.readings: output directory for plate reading files.

    Args:
        options: see above.
    '''
    options.params = load_params(AssayParams, options.params)
    random.seed(options.params.seed)
    for filename, sample_id, kind in _join_assay_data(options):
        _make_plate(
            options.params,
            sample_id,
            kind,
            Path(options.designs, filename),
            Path(options.readings, filename),
        )

_generate(params, sample_locs, func)

Make body of plate design or results.

  • Each result is represented as a rectangular list of lists.
  • The first row of each result is lettered started with 'A' like a spreadsheet.
  • Each subsequent row starts with a row number from '1' like a spreadsheet.

Parameters:

Name Type Description Default
params AssayParams

assay parameters.

required
sample_locs list

location of sample in each row of plate

required
func callable

function used to generate interior table value

required

Returns:

Type Description
list

Rectangular list-of-lists.

Source code in snailz/plates.py
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
def _generate(params: AssayParams, sample_locs: list, func: callable) -> list:
    '''Make body of plate design or results.

    -   Each result is represented as a rectangular list of lists.
    -   The first row of each result is lettered started with 'A' like a spreadsheet.
    -   Each subsequent row starts with a row number from '1' like a spreadsheet.

    Args:
        params: assay parameters.
        sample_locs: location of sample in each row of plate
        func: function used to generate interior table value

    Returns:
        Rectangular list-of-lists.
    '''
    title_row = ['', *[chr(ord('A') + col) for col in range(PLATE_WIDTH)]]
    values = [
        [func(params, col == sample_locs[row]) for col in range(PLATE_WIDTH)]
        for row in range(PLATE_HEIGHT)
    ]
    labeled = [[str(i + 1), *r] for (i, r) in enumerate(values)]
    return [title_row, *labeled]

_join_assay_data(options)

Get experiment type and plate filename from data.

Parameters:

Name Type Description Default
options Namespace

see above.

required

Returns:

Type Description
callable

Generator that produces tuples of plate filename, plate, and experiment.

Source code in snailz/plates.py
68
69
70
71
72
73
74
75
76
77
78
79
80
def _join_assay_data(options: Namespace) -> callable:
    '''Get experiment type and plate filename from data.

    Args:
        options: see above.

    Returns:
        Generator that produces tuples of plate filename, plate, and experiment.
    '''
    assays = json.load(open(options.assays, 'r'))
    experiments = {x['sample_id']: x['kind'] for x in assays['experiment']}
    plates = {p['filename']: p['sample_id'] for p in assays['plate']}
    return ((f, plates[f], experiments[plates[f]]) for f in plates)

_make_head(kind, sample_id)

Make head of plate.

Parameters:

Name Type Description Default
kind str

kind of experiment ('calibration' or other).

required
sample_id int

which sample this experiment is for.

required

Returns:

Type Description
list

List-of-lists representation of head of plate.

Source code in snailz/plates.py
83
84
85
86
87
88
89
90
91
92
93
94
95
96
def _make_head(kind: str, sample_id: int) -> list:
    '''Make head of plate.

    Args:
        kind: kind of experiment ('calibration' or other).
        sample_id: which sample this experiment is for.

    Returns:
        List-of-lists representation of head of plate.
    '''
    return [
        [MODEL, kind, sample_id],
        [],
    ]

_make_placement(kind)

Generate random arrangement of sample locations in plate.

Parameters:

Name Type Description Default
kind str

kind of experiment ('calibration' or other).

required

Returns:

Type Description
tuple

Tuple of sample placements and column orders.

Source code in snailz/plates.py
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
def _make_placement(kind: str) -> tuple:
    '''Generate random arrangement of sample locations in plate.

    Args:
        kind: kind of experiment ('calibration' or other).

    Returns:
        Tuple of sample placements and column orders.
    '''
    placement = [[False for col in range(PLATE_WIDTH)] for row in range(PLATE_HEIGHT)]
    if kind == 'calibration':
        return placement, []
    columns = list(c for c in range(PLATE_WIDTH))
    random.shuffle(columns)
    columns = columns[:PLATE_HEIGHT]
    for r, row in enumerate(placement):
        row[columns[r]] = True
    return placement, columns

_make_plate(params, sample_id, kind, design_file, readings_file)

Generate an entire experimental plate.

  1. Build overall placement grid and sample locations.
  2. Make head and body of design file and save it.
  3. Make random readings for plate cells and save.
  4. Save plate and design in respective output directories.

Parameters:

Name Type Description Default
params AssayParams

assay parameters.

required
sample_id str

which sample this plate is for.

required
kind str

'calibration' or something else.

required
design_file str

where to write design.

required
readings_file str

where to write readings.

required
Source code in snailz/plates.py
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
def _make_plate(params: AssayParams, sample_id: str, kind: str, design_file: str, readings_file: str) -> None:
    '''Generate an entire experimental plate.

    1.  Build overall placement grid and sample locations.
    2.  Make head and body of design file and save it.
    3.  Make random readings for plate cells and save.
    4.  Save plate and design in respective output directories.

    Args:
        params: assay parameters.
        sample_id: which sample this plate is for.
        kind: 'calibration' or something else.
        design_file: where to write design.
        readings_file: where to write readings.
    '''
    placement, sample_locs = _make_placement(kind)

    design = [*_make_head('design', sample_id), *_generate(params, sample_locs, _make_treatment)]
    _save(design_file, _normalize_csv(design))

    readings = [*_make_head('readings', sample_id), *_generate(params, sample_locs, _make_reading)]
    _save(readings_file, _normalize_csv(readings))

_make_reading(params, treated)

Generate a single plate reading.

The reading is a random value whose mean depends on whether it is treated or a control.

Parameters:

Name Type Description Default
params AssayParams

assay parameters.

required
treated bool

is this location treated (versus a control)?

required

Returns:

Type Description
float

Randomly-generated reading value.

Source code in snailz/plates.py
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
def _make_reading(params: AssayParams, treated: bool) -> float:
    '''Generate a single plate reading.

    The reading is a random value whose mean depends on whether it is treated or a control.

    Args:
        params: assay parameters.
        treated: is this location treated (versus a control)?

    Returns:
        Randomly-generated reading value.
    '''
    mean = params.treated_val if treated else params.control_val
    value = max(0.0, random.gauss(mean, params.stdev))
    return f'{value:.02f}'

_make_treatment(params, treated)

Select a single plate treatment.

Parameters:

Name Type Description Default
params AssayParams

assay parameters.

required
treated bool

is this location treated (versus a control)?

required

Returns:

Type Description
str

Treatment if this is a treated cell or a randomly-selected control if it is not.

Source code in snailz/plates.py
160
161
162
163
164
165
166
167
168
169
170
171
def _make_treatment(params: AssayParams, treated: bool) -> str:
    '''Select a single plate treatment.

    Args:
        params: assay parameters.
        treated: is this location treated (versus a control)?

    Returns:
        Treatment if this is a treated cell or a randomly-selected control if it is not.
    '''
    result = params.treatment if treated else random.choice(params.controls)
    return result

_normalize_csv(rows)

Make sure all rows in list-of-lists table are the same length.

Short rows are extended with empty string values to match the length of the longest row.

Parameters:

Name Type Description Default
rows list

input list of lists.

required

Returns:

Type Description
list

Adjusted list of lists.

Source code in snailz/plates.py
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
def _normalize_csv(rows: list) -> list:
    '''Make sure all rows in list-of-lists table are the same length.

    Short rows are extended with empty string values to match the length of the longest row.

    Args:
        rows: input list of lists.

    Returns:
        Adjusted list of lists.
    '''
    required = max(len(r) for r in rows)
    for row in rows:
        row.extend([''] * (required - len(row)))
    return rows

_save(filename, rows)

Save results to file or show on standard output.

Parameters:

Name Type Description Default
filename str | None

output file (or None to write to standard output)

required
rows list

data to write.

required
Source code in snailz/plates.py
191
192
193
194
195
196
197
198
199
200
201
def _save(filename: str|None, rows: list) -> None:
    '''Save results to file or show on standard output.

    Args:
        filename: output file (or None to write to standard output)
        rows: data to write.
    '''
    if not filename:
        csv.writer(sys.stdout).writerows(rows)
    else:
        csv.writer(open(filename, 'w'), lineterminator='\n').writerows(rows)