Implements the deconvolution algorithm developed in Mauri, Vecchione, and Fritz (2019) which enables deconvolution of luminscence readings for experimental culture plates. {reluxr} provides functions for calculating the ‘best’ deconvolution matrix from a calibration plate, and enables usage of this calibration matrix (or one calculated previously) to adjust luminescent experimental values from a plate reader. This is an R-based implementation of the MatLab workflow from the original paper paper titled 1Deconvolution of Luminescence Cross-Talk in High-Throughput Gene Expression Profiling’ (Mauri, Vecchione, and Fritz 2019)
The package is not currently available on CRAN. Install the released
version from r-universe
with the following code:
install.package("reluxr", repos = "https://bradyajohnston.r-universe.dev")
This is a basic example which shows you how to solve a common problem:
library(reluxr)
fl <- system.file(
"extdata",
"calibrate_tecan",
"calTecan1.xlsx",
package = "reluxr"
)
The deconvolution matrix is created from a calibration plate, which contains a single well with luminescent bacteria, with all other wells being empty. The cross-talk when the plate-reader measures the wells can then be calculated and used to create a deconvolution matrix which will remove the crosstalk from the measured values.
dat <- plate_read_tecan(fl)
dat
#> # A tibble: 23,040 × 5
#> cycle_nr time_s signal well value
#> <dbl> <dbl> <chr> <chr> <dbl>
#> 1 1 0 OD600 A01 0.0450
#> 2 1 0 OD600 A02 0.0452
#> 3 1 0 OD600 A03 0.0453
#> 4 1 0 OD600 A04 0.0453
#> 5 1 0 OD600 A05 0.0453
#> 6 1 0 OD600 A06 0.0452
#> 7 1 0 OD600 A07 0.0458
#> 8 1 0 OD600 A08 0.0456
#> 9 1 0 OD600 A09 0.0455
#> 10 1 0 OD600 A10 0.0451
#> # … with 23,030 more rows
Regardless of how you read in the required data, it needs to be (and
should be regardless) in a tidy format, with each row being an
observation and each column a variable. In the case above we have
columns for the cycle_nr
, time_s
, signal
, well
and value
.
While it would be better to have a column for the OD600 and for the LUMI
data, the time points do not match and aren’t currently pivotable.
To have a look at the final data, we can plot the plate based on log-transformed luminescence values. We can see the very bright single well than contains the bacteria, and the bleed-through signal that is around it.
dat_fil <- dat |>
dplyr::filter(signal == "LUMI", time_s > 500)
dat_fil |>
dplyr::group_by(well) |>
dplyr::summarise(value = mean(value)) |>
rl_plot_plate(value)
We can use the rl_calc_decon_matrix()
function which will calculate a
deconvolution matrix, reducing the background bleed-through from the
plate to below a noise threshold. The noise threshold should be the
instrument’s background noise, which is defined as three times the
standard deviation of a blank well. The lower the noise threshold, the
harder it will be to calculate a deconvolution matrix which works with
the data.
We can also quickly look at the resulting deconvolution matrix
(mat_d_best
) itself.
mat_d_best <- rl_calc_decon_matrix(
data = dat_fil,
value = value,
time = time_s,
ref_well = "E05",
b_noise = 20
)
image(log10(mat_d_best))
Now that we have the matrix, we can use it to adjust the data.
We do so using the rl_adjust_plate()
funciton, which takes a
dataframe, the name of the column you which to adjust, the deconvolution
matrix (in this case mat_d_best
, and the name ofthe column which
stores the time data).
The returned dataframe will have the value column adjusted and deconvoluted using the deconvolution matrix supplied.
In the examples below we first plot all of the values without deconvolution, then apply the deconvolution matrix and plot the values again.
rl_plot_time <- function(data, time, value, group = "well") {
data <- dplyr::mutate(
data,
time = {{ time }},
value = {{ value }},
group = {{ group }}
)
plt <- ggplot2::ggplot(
data,
mapping = ggplot2::aes(
x = time,
y = value,
group = group
)
) +
ggplot2::geom_line() +
ggplot2::scale_y_log10() +
ggplot2::theme_bw()
plt
}
dat |>
dplyr::filter(signal == "LUMI") |>
rl_plot_time(time_s, value, well) +
ggplot2::labs(
x = "Time (s)",
y = "LUM"
)
#> Warning in self$trans$transform(x): NaNs produced
#> Warning: Transformation introduced infinite values in continuous y-axis
#> Warning: Removed 25 row(s) containing missing values (geom_path).
dat |>
dplyr::filter(signal == "LUMI") |>
rl_adjust_plate(value, mat_d_best, time = time_s) |> # deconvolute the values
rl_plot_time(time_s, value, well) +
ggplot2::labs(
x = "Time (s)",
y = "LUM"
)
#> Warning in self$trans$transform(x): NaNs produced
#> Warning: Transformation introduced infinite values in continuous y-axis
#> Warning: Removed 657 row(s) containing missing values (geom_path).
We can also replot the plate from earlier, with the newly deconvoluted values.
dat_fil |>
rl_adjust_plate(value, mat_d_best, time = time_s) |> # deconvolute the values
dplyr::group_by(well) |>
dplyr::summarise(value = mean(value)) |>
rl_plot_plate(value) +
ggplot2::scale_fill_viridis_c(
"log10(LUMI)",
breaks = 1:5,
limits = c(1, NA)
)
#> Scale for 'fill' is already present. Adding another scale for 'fill', which
#> will replace the existing scale.
#> Warning in FUN(X[[i]], ...): NaNs produced
Mauri, Marco, Stefano Vecchione, and Georg Fritz. 2019. “Deconvolution of Luminescence Cross-Talk in High-Throughput Gene Expression Profiling.” ACS Synthetic Biology 8 (6): 1361–70. https://doi.org/10.1021/acssynbio.9b00032.