R/fret_correct_signal.R

Defines functions fret_correct_signal

Documented in fret_correct_signal

#' @title Correct FRET signal
#'
#' @description This function corrects the raw FRET signal by applying
#'     corrections for donor bleedthrough and acceptor direct excitation. See
#'     \href{https://doi.org/10.1093/nar/gkr1045}{Hieb AR \emph{et al} (2012)}
#'     and \href{https://doi.org/10.1016/B978-0-12-391940-3.00011-1}{Winkler DD
#'     \emph{et al} (2012)} for details.
#'
#' @param data A dataframe containing the FRET data after avergaing over
#'     technical replicates. This dataframe must contain the following columns:
#'     \describe{
#'     \item{Experiment}{A unique name identifying each experiment.}
#'     \item{Type}{Either "acceptor_only" (no donor control), "donor_only" (no
#'     acceptor control), or "titration" (experiment with both donor and
#'     acceptor).}
#'     \item{Observation}{A number identifying each observation in a titration
#'     series (corresponds to the plate column numbers, if experiments are set
#'     up as rows in a 384-well plate). The number of observations for an
#'     experiment and its blanks must match, and a given observation number must
#'     associate data points at the same concentration in the titration series.}
#'     \item{concentration}{The ligand concentration in the titration series.}
#'     \item{fret_channel}{Fluorescence intensity in the FRET channel.}
#'     \item{acceptor_channel}{Fluorescence intensity in the acceptor channel.}
#'     \item{donor_channel}{Fluorescence intensity in the donor channel.}
#'     }
#'     The output of \code{\link{fret_average_replicates}} can be used
#'     directly as input for this function.
#' @param output_directory An optional output directory name where to write
#'     corrected data in CSV files. This directory will be created if it does
#'     not already exist.
#'
#' @return A dataframe containing the corrected FRET signal. It contains three
#'     columns:
#'     \describe{
#'     \item{Experiment}{A unique name identifying each experiment (same as in
#'     the input data).}
#'     \item{concentration}{The ligand concentration in the titration series
#'     (same as in the input data).}
#'     \item{signal}{The corrected FRET signal.}
#'     }
#'
#' @seealso \code{\link{fret_average_replicates}} to prepare a dataset for
#'     use with \code{fret_correct_signal}.
#'
#'     For details on the signal correction applied by \code{fret_correct_signal},
#'     see:
#'     \itemize{
#'     \item Hieb AR \emph{et al} (2012) Fluorescence Strategies for High-Throughput
#'     Quantification of Protein Interactions. \emph{Nucleic Acids Research}
#'     40 (5): e33 (\href{https://doi.org/10.1093/nar/gkr1045}{doi:10.1093/nar/gkr1045}) and
#'     \item Winkler DD \emph{et al} (2012) Quantifying Chromatin-Associated
#'     Interactions: The HI-FI System. In \emph{Methods in Enzymology} pp
#'     243–274. Elsevier
#'     (\href{https://doi.org/10.1016/B978-0-12-391940-3.00011-1}{doi:10.1016/B978-0-12-391940-3.00011-1}).
#'     }
#'
#' @importFrom magrittr %>%
#'
#' @export

fret_correct_signal <- function(data,
                                output_directory = NULL) {
    # Apply correction to each experiment in the large dataframe
    corrected_data <- data %>%
        dplyr::group_by(Experiment) %>%
        dplyr::do(fret_correct_one_dataset(.))

    # Optionally, write output to CSV files in the specified directory
    if (!is.null(output_directory)) {
        # Sanity check
        if (length(output_directory) > 1) {
            stop("Please provide a single directory name.")
        }
        # Create output directory, if it does not already exist
        if (!dir.exists(output_directory)) {
            message("Creating directory: ", output_directory)
            dir.create(output_directory)
        }
        # Split single dataframe by experiment name, then write each result to a CSV
        # file in the output directory
        corrected_data %>%
            split(corrected_data$Experiment) %>%
            mapply(readr::write_csv,
                   .,
                   path = paste(output_directory,
                                "/",
                                names(.),
                                "_corrected.csv",
                                sep = ""))
    }

    # Return corrected data
    corrected_data
}

#' @title Correct FRET signal for one experiment
#'
#' @description This internal function corrects the raw FRET signal of a single
#'     experiment by applying corrections for donor bleedthrough and acceptor
#'     direct excitation. See
#'     \href{https://doi.org/10.1093/nar/gkr1045}{Hieb AR \emph{et al} (2012)}
#'     and \href{https://doi.org/10.1016/B978-0-12-391940-3.00011-1}{Winkler DD
#'     \emph{et al} (2012)} for details.
#'
#' @param one_dataset A dataframe containing the FRET data after avergaing over
#'     technical replicates. This dataframe must contain the following columns:
#'     \describe{
#'     \item{Experiment}{A unique name identifying each experiment.}
#'     \item{Type}{Either "acceptor_only" (no donor control), "donor_only" (no
#'     acceptor control), or "titration" (experiment with both donor and
#'     acceptor).}
#'     \item{Observation}{A number identifying each observation in a titration
#'     series (corresponds to the plate column numbers, if experiments are set
#'     up as rows in a 384-well plate). The number of observations for an
#'     experiment and its blanks must match, and a given observation number must
#'     associate data points at the same concentration in the titration series.}
#'     \item{concentration}{The ligand concentration in the titration series.}
#'     \item{fret_channel}{Fluorescence intensity in the FRET channel.}
#'     \item{acceptor_channel}{Fluorescence intensity in the acceptor channel.}
#'     \item{donor_channel}{Fluorescence intensity in the donor channel.}
#'     }
#'     The output of \code{\link{fret_average_replicates}} can be used directly
#'     as input for this function.
#'
#' @return A dataframe containing the corrected FRET signal. It contains three
#'     columns:
#'     \describe{
#'     \item{Experiment}{A unique name identifying each experiment (same as in
#'     the input data).}
#'     \item{concentration}{The ligand concentration in the titration series
#'     (same as in the input data).}
#'     \item{fret}{The corrected FRET signal.}
#'     }
#'
#' @seealso \code{\link{fret_average_replicates}} to prepare a dataset for
#'     use with \code{fret_correct_signal}.
#'
#'     For details on the signal correction applied by \code{fret_correct_signal},
#'     see:
#'     \itemize{
#'     \item Hieb AR \emph{et al} (2012) Fluorescence Strategies for High-Throughput
#'     Quantification of Protein Interactions. \emph{Nucleic Acids Research}
#'     40 (5): e33 (\href{https://doi.org/10.1093/nar/gkr1045}{doi:10.1093/nar/gkr1045}) and
#'     \item Winkler DD \emph{et al} (2012) Quantifying Chromatin-Associated
#'     Interactions: The HI-FI System. In \emph{Methods in Enzymology} pp
#'     243–274. Elsevier
#'     (\href{https://doi.org/10.1016/B978-0-12-391940-3.00011-1}{doi:10.1016/B978-0-12-391940-3.00011-1}).
#'     }
#'
#' @importFrom magrittr %>%

fret_correct_one_dataset <- function(one_dataset) {
    # Calculate donor bleed through
    donor_only <- one_dataset %>%
        dplyr::filter(Type == "donor_only") %>%
        dplyr::mutate(donor_bleed_through = fret_channel / donor_channel)

    # Calculate acceptor direct excitation
    acceptor_only <- one_dataset %>%
        dplyr::filter(Type == "acceptor_only") %>%
        dplyr::mutate(acceptor_direct_excitation = fret_channel / acceptor_channel)

    # If there are less controls than actual titration points, average controls
    # and warn the user.
    titration <- dplyr::filter(one_dataset, Type == "titration")
    if (nrow(donor_only) != nrow(titration)) {
        message("Donor only control has a different number of points compared to titration.")
        message("Averaging donor_bleed_through values.")
        donor_bleed_through <- mean(donor_only$donor_bleed_through)
    } else {
        donor_bleed_through <- donor_only$donor_bleed_through
    }
    if (nrow(acceptor_only) != nrow(titration)) {
        message("Acceptor only control has a different number of points compared to titration.")
        message("Averaging acceptor_direct_excitation values.")
        acceptor_direct_excitation <- mean(acceptor_only$acceptor_direct_excitation)
    } else {
        acceptor_direct_excitation <- acceptor_only$acceptor_direct_excitation
    }

    # Apply correction factors
    titration$donor_bleed_through <- donor_bleed_through
    titration$acceptor_direct_excitation <- acceptor_direct_excitation
    corrected_data <- titration %>%
        dplyr::transmute(
            concentration = concentration,
            signal = fret_channel -
                donor_channel * donor_bleed_through -
                acceptor_channel * acceptor_direct_excitation
            ) %>%
    # Subtract baseline
        dplyr::mutate(signal = signal - min(signal))
}
Guilz/rfret documentation built on Oct. 18, 2021, 2:14 p.m.