In [1]:
import ninetysix as ns
import pandas as pd
import numpy as np
In [2]:
# Seed
np.random.seed(8675309)
# A1-H12 wells
wells = [row+str(col)
for row in list('ABCDEFGH')
for col in range(1, 13)]
# Create a list of five plates
pt_list = []
for i in range(1, 6):
# Generate random distribution of values and make Plate
values = np.random.normal(10+i, 2, size=len(wells))
pt_ = ns.Plate(zip(wells, values))
# Add the annotation `plate` = i
pt_['plate'] = i
# Set `plate` as a location (not necessary)
pt_ = pt_.set_as_location('plate', idx=0)
# Add control annotations
controls = {
'[A-D]10': 'standard',
'E10': 'empty',
'[F-H]10': 'negative',
'other': 'experiment',
}
pt_ = pt_.annotate_wells({'controls': controls})
# Append only the DataFrame attribute (Plate.df) to work with pd.concat
pt_list.append(pt_.df)
# Store the location and values info
locations = pt_.locations
values = pt_.values
# Create new Plate object
plates = ns.Plate(pd.concat(pt_list).reset_index(drop=True))
# Update attributes
plates.locations = locations
plates.values = values
# Check the Plate's MultiIndexed DataFrame to see attributes
plates.mi_df
Out[2]:
locations | annotations | values | |||
---|---|---|---|---|---|
plate | row | column | controls | value | |
well | |||||
A1 | 1 | A | 1 | experiment | 12.178047 |
A2 | 1 | A | 2 | experiment | 12.466237 |
A3 | 1 | A | 3 | experiment | 8.675622 |
A4 | 1 | A | 4 | experiment | 9.886368 |
A5 | 1 | A | 5 | experiment | 9.455023 |
... | ... | ... | ... | ... | ... |
H8 | 5 | H | 8 | experiment | 13.611073 |
H9 | 5 | H | 9 | experiment | 15.589042 |
H10 | 5 | H | 10 | negative | 11.537206 |
H11 | 5 | H | 11 | experiment | 15.018260 |
H12 | 5 | H | 12 | experiment | 15.634150 |
480 rows × 5 columns
In [3]:
# Normalize each plate on its own and change prefix
plates = plates.normalize(
to='controls=standard',
zero=True,
groupby='plate',
prefix='norm '
)
plates
Out[3]:
well | plate | row | column | controls | norm value | value | |
---|---|---|---|---|---|---|---|
0 | A1 | 1 | A | 1 | experiment | 1.084058 | 12.178047 |
1 | A2 | 1 | A | 2 | experiment | 1.136504 | 12.466237 |
2 | A3 | 1 | A | 3 | experiment | 0.446671 | 8.675622 |
3 | A4 | 1 | A | 4 | experiment | 0.667008 | 9.886368 |
4 | A5 | 1 | A | 5 | experiment | 0.588509 | 9.455023 |
... | ... | ... | ... | ... | ... | ... | ... |
475 | H8 | 5 | H | 8 | experiment | 0.611111 | 13.611073 |
476 | H9 | 5 | H | 9 | experiment | 0.927520 | 15.589042 |
477 | H10 | 5 | H | 10 | negative | 0.279361 | 11.537206 |
478 | H11 | 5 | H | 11 | experiment | 0.836214 | 15.018260 |
479 | H12 | 5 | H | 12 | experiment | 0.934736 | 15.634150 |
480 rows × 7 columns
In [4]:
# Show that the mean of `norm value` for `controls == standard` in each plate is now 1
plates[plates['controls']=='standard'].groupby(['plate']).mean()
Out[4]:
column | norm value | value | |
---|---|---|---|
plate | |||
1 | 10 | 1.0 | 11.716153 |
2 | 10 | 1.0 | 12.517763 |
3 | 10 | 1.0 | 14.852484 |
4 | 10 | 1.0 | 13.165019 |
5 | 10 | 1.0 | 16.042136 |
In [5]:
# Generate layout of unnormalized and normalized plots
p = plates.plot_rof(groupby='plate') +\
plates.plot_rof(value_name='norm value', groupby='plate')
# Set plot-specific axis scaling
p = p.opts({'Scatter': {'framewise': True}})
# The data is translated and scaled, but otherwise the same
p.cols(1)
Out[5]:
In [6]:
cmap = {
'standard': ns.Colors.green,
'negative': ns.Colors.orange,
'empty': ns.Colors.gray,
'experiment': ns.Colors.blue,
}
plates.plot_bar(
variable='controls',
color='controls',
cmap=cmap,
groupby='plate',
jitter=0.5,
)
Out[6]: