2 Correct data
First, we define functions to 1) get background-corrected values of our samples, 2) compute the standard concentrations, and 3) to get tidy data frames of the standard and the biological samples.
# Gets samples, performs background correction
# Works only on single rows of the 96-well plate
# The number of columns is user defined (set n.cols)
#' @param data input data frame
#' @param row.idx row index in the input data frame of the sample
#' @param col.dix column index in the input data frame of the first cell of the sample
#' @param n.cols number of columns to get in the input data frame
#' @return a data frame with background-corrected values
<- function(data, row.idx, col.idx, n.cols) {
correct.sample <- row.idx + 1 # we select only two rows (450 nm and 620 nm measurements)
row.end <- col.idx + (n.cols - 1) # the number of columns is user defined
col.end <- data %>%
sample :row.end, col.idx:col.end]
.[row.idx# Subtract background OD value for each sample
# Note: in our example data, 450 nm OD results are always on top of 620 nm OD results.
<- sample[1, ] - sample[2, ]
corr.sample # Return background-corrected OD value
return(as.tibble(corr.sample))
}
# Compute dilution series
#' @param max.conc.std maximal concentration
#' @param n.dilutions number of dilutions performed
#' @param dilution.fact dilution factor
#' @return a vector with concentrations
<- function(
comp.conc max.conc.std = max.conc.std,
n.dilutions = n.dilutions,
dilution.fact = dilution.fact) {
<- sapply(
dilutions seq(0, (n.dilutions - 1)),
function(x) max.conc.std / (dilution.fact^x)
)return(dilutions)
}
# Get background-corrected standard
# TODO: add documentation
<- function(data = data,
get.standard row.idx = row.idx.std,
col.idx = col.idx.std,
n.dilutions = n.dilutions,
n.repl = n.repl,
dilution.fact = dilution.fact,
max.conc.std = max.conc.std,
concentration = concentrations) {
# Assumes that the standard dilutions were pipetted in vertical order
<- row.idx + (n.dilutions * 2) - 1
row.end <- col.idx + (n.repl - 1)
col.end <- data %>% .[row.idx:row.end, col.idx:col.end]
standard <- purrr::map_df(
corr.standard seq(1, row.end, by = 2),
~ correct.sample(data = standard, ., col.idx = 1, n.cols = n.repl)
%>%
) na.omit() %>%
setNames(seq(n.repl)) %>%
::mutate(concentration = concentrations) %>%
dplyr::gather(key = replicate, value = absorbance, -concentration)
tidyr
return(corr.standard)
}
# TODO: add documentation
<- function(row.idx = row.idx.donor.1,
get.donors col.idx = col.idx.donor.1,
n.cols = n.repl.donors * length(tpoints)) {
<- row.idx + 1 # 450 nm and 620 nm
row.end <- col.idx + (n.cols - 1)
col.end <- data %>% .[row.idx:row.end, col.idx:col.end]
sample <- correct.sample(
corr.donors data = sample, row.idx = 1, col.idx = 1, n.cols = n.cols
)return(corr.donors)
}
Now we can create a data frame with the corrected data of the standard:
<- comp.conc(
concentrations max.conc.std = max.conc.std,
n.dilutions = n.dilutions,
dilution.fact = dilution.fact
)
<- get.standard(
standard data = data,
row.idx = row.idx.std,
col.idx = col.idx.std,
n.dilutions = n.dilutions,
n.repl = n.repl.std,
dilution.fact = dilution.fact,
max.conc.std = max.conc.std,
concentration = concentrations
)# Inspect result
standard
## # A tibble: 16 x 3
## concentration replicate absorbance
## <dbl> <chr> <dbl>
## 1 1 1 1.69
## 2 0.5 1 1.29
## 3 0.25 1 0.865
## 4 0.125 1 0.689
## 5 0.0625 1 0.26
## 6 0.0312 1 0.128
## 7 0.0156 1 0.059
## 8 0.00781 1 0.033
## 9 1 2 1.70
## 10 0.5 2 1.32
## 11 0.25 2 0.884
## 12 0.125 2 0.671
## 13 0.0625 2 0.262
## 14 0.0312 2 0.121
## 15 0.0156 2 0.062
## 16 0.00781 2 0.032
Here we select the wells with the blanks:
# Get blanks
<- correct.sample(data, row.idx.blank, col.idx.blank, n.cols = 2) %>%
blanks setNames(seq(1, dim(.)[2])) %>%
::gather(key = replicate, value = blank)
tidyr# Inspect blanks
blanks
## # A tibble: 2 x 2
## replicate blank
## <chr> <dbl>
## 1 1 0.00400
## 2 2 0.0050
And finally we create a data frame with the corrected data of our biological samples. In our case, we have a time series with five data points for four donors:
<- purrr::map_df(
donors seq(row.idx.donor.1, (row.idx.donor.1 + 2 * (n.donors - 1)), by = 2),
~ get.donors(., col.idx = col.idx.donor.1, n.cols = 10)
%>%
) # Add names that indicate time point and replicate ID separated by a dot
setNames(c(0.1, 0.2, 7.1, 7.2, 30.1, 30.2, 60.1, 60.2, 180.1, 180.2)) %>%
::mutate(donor = seq(1, n.donors)) %>%
dplyr::mutate(donor = factor(donor, unique(donor))) %>%
dplyr::gather(key = "time", value = "absorbance", -donor) %>%
tidyr::separate(time, c("time", "replicate")) %>%
tidyr::mutate(time = as.integer(time)) %>%
dplyr::group_by(donor, time)
dplyr<- donors %>%
donors.av ::summarise(absorbance.av = mean(absorbance)) %>%
dplyr::ungroup()
dplyr
# Inspect data
donors.av
## # A tibble: 20 x 3
## donor time absorbance.av
## <fct> <int> <dbl>
## 1 1 0 0.336
## 2 1 7 0.596
## 3 1 30 0.710
## 4 1 60 0.804
## 5 1 180 0.482
## 6 2 0 0.534
## 7 2 7 0.729
## 8 2 30 0.825
## 9 2 60 0.790
## 10 2 180 0.660
## 11 3 0 0.347
## 12 3 7 1.25
## 13 3 30 0.837
## 14 3 60 0.768
## 15 3 180 0.563
## 16 4 0 0.932
## 17 4 7 1.17
## 18 4 30 1.01
## 19 4 60 0.845
## 20 4 180 0.950
Before we proceed with the analysis, let’s plot the data and see whether it looks reasonable.