Files
dashboard-app/R/Global.R
T
Simon Innerbichler 4cfdc288a8
Build and deploy Roxygen2|pkgdown documentation site / build-and-deploy-documentation (push) Successful in 44s
run tests / build-and-deploy-documentation (push) Successful in 8s
IMPORTANT added linting configuration
linting can be started by clicking Addins in RStudio, then
"Lint current file". This commit also contains quick fixes for common
linter messages like changing F to FALSE and T to TRUE.
2026-06-03 10:33:40 +02:00

1509 lines
59 KiB
R

################################################################################
# All functions for plateflow
################################################################################
library(shiny)
library(shinydashboard)
library(shinyjs)
library(shinyAce)
library(shinycssloaders)
library(shinyBS)
library(purrr)
library(gslnls)
library(tidyverse)
library(ggplot2)
library(reshape2)
library(openxlsx)
library(DT)
library(ggpubr)
library(gridExtra)
library(drc)
library(twopartm)
library(car)
library(dplyr)
library(scales)
#' Levenberg Marquard fit of 4 pl
#'
#' Returns list of following: summary of restricted and unrestricted model fits of the 4pl function,
#' potency estimates and respective CIs of restricted and unrestricted models, and the predictions thereof.
#'
#' @param ro_new The dilution series readouts for REF and TEST + 1 column log(loncentration) or concentration.
#' @param TransFlag A boolean if the plot should be with natural log as readout (TRUE) or not (FALSE).
#' @returns Returns list of following: summary of restricted and unrestricted model fits of the 4pl function,
#' potency estimates and respective CIs of restricted and unrestricted models, and the predictions thereof.
#' @export
#' @examples
#' dat <- data.frame(
#' REF1 = c(1547, 1620, 1644, 2504, 3426, 3512, 3401, 3787), REF2 = c(1492, 1536, 1384, 2286, 3046, 3479, 3516, 3497),
#' REF3 = c(1468, 1827, 1558, 2252, 3002, 3349, 2945, 3665),
#' TEST1 = c(1405, 1523, 1502, 1474, 2383, 3221, 3589, 3445), TEST2 = c(1420, 1516, 1544, 1512, 2226, 3219, 3327, 3591),
#' TEST3 = c(1399, 1376, 1588, 1475, 2148, 3083, 2942, 3466), log_dose = c(5.01, 3.401, 2.708, 2.015, 1.32176, 0.62861, -0.0645385, -1.6739764)
#' )
#' TransF <- FALSE
#' Dat <- list()
#' te <- Fitting_FUNC(dat, TransF)
#' print(te)
Fitting_FUNC <- function(ro_new, TransFlag = FALSE) {
CORro <- cor(ro_new[, 1], ro_new[, ncol(ro_new)])
# browser()
all_l <- melt(data.frame(ro_new), id.vars = "log_dose", variable.name = "replname", value.name = "readout")
isRef <- rep(c(1, 0), 1, each = nrow(all_l) / 2)
isSample <- rep(c(0, 1), 1, each = nrow(all_l) / 2)
all_l2 <- cbind(all_l, isRef, isSample)
# browser()
if (CORro < 0) SLOPE <- -1 else SLOPE <- 1
if (!TransFlag) {
startlist <- list(a = min(ro_new[, 2]), b = SLOPE, d = max(ro_new[, 2]), cs = mean(all_l$log_dose), r = 0)
mr <- tryCatch(
{
gsl_nls(
fn = readout ~ a + (d - a) / (1 + exp(b * ((cs - r * isSample) - log_dose))),
data = all_l2,
start = startlist, # race=T,
control = gsl_nls_control(xtol = 1e-6, ftol = 1e-6, gtol = 1e-6)
)
},
warning = function(e) {
mr <<- "In nlsModel singular gradient matrix"
}
)
# Stop if singular gradient matrix
if (is.character(mr)) {
return(mr)
}
s_mr <- tryCatch(
{
s_mr <- summary(mr)
},
error = function(err) {
s_mr <- NULL
}
)
} else {
startlist <- list(a = log(min(ro_new[, 2])), b = SLOPE, d = log(max(ro_new[, 2])), cs = mean(all_l$log_dose), r = 0)
mrT <- gsl_nls(
fn = log(readout) ~ a + (d - a) / (1 + exp(b * ((cs - r * isSample) - log_dose))),
data = all_l2,
start = startlist,
control = gsl_nls_control(xtol = 1e-6, ftol = 1e-6, gtol = 1e-6)
)
s_mr <- summary(mrT)
}
if (!TransFlag) {
startlistmu <- list(
as = min(ro_new[, 2]), bs = SLOPE, ds = max(ro_new[, 2]), cs = mean(all_l$log_dose),
at = min(ro_new[, 2]), bt = SLOPE, dt = max(ro_new[, 2]), r = 0
)
tryCatch(
{
mu <- gsl_nls(
fn = readout ~ as * isRef + at * isSample + (ds * isRef + dt * isSample - as * isRef - at * isSample) /
(1 + isRef * exp(bs * (cs - log_dose)) + isSample * exp(bt * (cs - r * isSample - log_dose))),
data = all_l,
start = startlistmu,
control = gsl_nls_control(xtol = 1e-6, ftol = 1e-6, gtol = 1e-6)
)
},
error = function(msg) {
return(0)
}
)
Sum_u <- tryCatch(
{
summary(mu)
},
error = function(msg) {
return(0)
}
)
} else {
startlistmu <- list(
as = log(min(ro_new[, 2])), bs = SLOPE, ds = log(max(ro_new[, 2])), cs = mean(all_l$log_dose),
at = log(min(ro_new[, 2])), bt = SLOPE, dt = log(max(ro_new[, 2])), r = 0
)
tryCatch(
{
muT <- gsl_nls(
fn = log(readout) ~ as * isRef + at * isSample + (ds * isRef + dt * isSample - as * isRef - at * isSample) /
(1 + isRef * exp(bs * (cs - log_dose)) + isSample * exp(bt * (cs - r * isSample - log_dose))),
data = all_l,
start = startlistmu,
control = gsl_nls_control(xtol = 1e-6, ftol = 1e-6, gtol = 1e-6)
)
},
error = function(msg) {
return(0)
}
)
Sum_u <- tryCatch(
{
summary(muT)
},
error = function(msg) {
return(0)
}
)
}
if (!TransFlag) {
pot_est <- exp(confintd(mr, "r", method = "asymptotic"))
potU_est <- exp(confintd(mu, "r", method = "asymptotic"))
PRED <- predict(mr)
PREDu <- predict(mu)
} else {
pot_est <- exp(confintd(mrT, "r", method = "asymptotic"))
potU_est <- exp(confintd(muT, "r", method = "asymptotic"))
PRED <- predict(mrT)
PREDu <- predict(muT)
}
return(list(s_mr, Sum_u, pot_est, potU_est, PRED, PREDu))
}
#' Plot when the fitting has a singularity
#'
#' Returns the scatter plot of the data, with REF in blue and TEST in red.
#' One plots are returned.
#'
#' @param dat The dilution series readouts for REF and TEST + 1 column log(loncentration) or concentration.
#' @returns A grid object with 2 linearity plots, restricted and unrestricted model.
#' @export
#' @examples
#' data.frame(
#' R_dil1 = c(
#' 10.0651024695491, 10.9844983291817, 10.7635586089293, 10.4597656321327, 10.3898668457823, 10.8171761349909,
#' 10.319758021908, 10.1304854046653
#' ),
#' R_dil2 = c(
#' 10.9649145494504, 10.0202868589385, 10.8424145955735, 10.9311360356894, 10.3284659026404,
#' 10.6890147558796, 10.3014450252305, 10.9594838595181
#' ),
#' R_dil3 = c(
#' 10.4630510824383, 10.4566715089363, 10.2350765290036, 10.3300581874798, 10.9648088137065,
#' 10.286893755805, 10.4856643841389, 10.5275521552307
#' ),
#' T_dil1 = c(
#' 12.732175566336, 12.7756403995095, 12.1672539684741, 12.7060603907892, 12.8000685682832,
#' 12.8800092157515, 12.7160581291873, 12.6996878912416
#' ),
#' T_dil2 = c(
#' 12.3923194313831, 12.0943488144175, 12.7955302154828, 12.4825917078735, 12.6856540203788,
#' 12.7348548498556, 12.9222470610476, 12.1186618671252
#' ),
#' T_dil3 = c(
#' 12.7899182255274, 12.9722600411128, 12.7078445380891, 12.4913523531941, 12.1718281909609,
#' 12.5313873615133, 12.952802332772, 12.5960321394342
#' ),
#' log_dose = c(
#' 0, -1.09861228866811, -2.19722457733622, -3.29583686600433, -4.39444915467244,
#' -5.49306144334055, -6.59167373200866, -7.69028602067677
#' )
#' )
#'
#'
#' p <- plotSingularity(dat)
#' print(p)
plotSingularity <- function(dat) { # sigmoid,det_sig,
CORdat <- cor(dat[, 1], dat[, ncol(dat)])
# browser()
all_l <- melt(data.frame(dat), id.vars = "log_dose", variable.name = "replname", value.name = "readout")
isRef <- rep(c(1, 0), 1, each = nrow(all_l) / 2)
isSample <- rep(c(0, 1), 1, each = nrow(all_l) / 2)
all_l2 <- cbind(all_l, isRef, isSample)
# browser()
log_dose <- unique(all_l$log_dose)
seq_x <- seq(min(log_dose), max(log_dose), 0.1)
# browser()
# all_l2$readout[all_l2$readout < 0] <- 0.01
all_l2$readouttrans <- log(all_l2$readout)
# browser()
pSing <- ggplot(all_l2, aes(x = log_dose, y = readout, color = factor(isRef))) +
geom_point(shape = factor(isRef), size = 3, alpha = 0.8) +
labs(
title = paste("No 4pl fit possible"),
color = "product"
) +
scale_color_manual(labels = c("test", "reference"), values = c("#C2173F", "#4545BA")) +
scale_shape_manual(labels = c("test", "reference")) +
scale_x_continuous(breaks = scales::pretty_breaks(n = 10)) +
scale_y_continuous(breaks = scales::pretty_breaks(n = 10)) +
# theme_bw() +
theme(axis.text = element_text(size = 14))
return(pSing)
}
#' Plot sigmoidal curve
#'
#' Returns the final plots of the 4pl function as sigmoidal lines, and the single readouts as scatter, with REF in blue and TEST in red.
#' Two plots are returned in a grid object: the unrestricted model and the restricted model.
#'
#' @param dat The dilution series readouts for REF and TEST + 1 column log(loncentration) or concentration.
#' @param sigmoid The parameters of the 4pl fit of unrestricted model from EXCEL input.
#' @param det_sig The parameters of the 4pl fit of unrestricted model from the metadata input.
#' @param TransFlag A boolean if the plot should be with natural log as readout (TRUE) or not (FALSE).
#' @returns A grid object either of the original scale or the natural log of the readouts.
#' @export
#' @examples
#' dat <- data.frame(
#' REF1 = c(1547, 1620, 1644, 2504, 3426, 3512, 3401, 3787), REF2 = c(1492, 1536, 1384, 2286, 3046, 3479, 3516, 3497),
#' REF3 = c(1468, 1827, 1558, 2252, 3002, 3349, 2945, 3665),
#' TEST1 = c(1405, 1523, 1502, 1474, 2383, 3221, 3589, 3445), TEST2 = c(1420, 1516, 1544, 1512, 2226, 3219, 3327, 3591),
#' TEST3 = c(1399, 1376, 1588, 1475, 2148, 3083, 2942, 3466), log_dose = c(5.01, 3.401, 2.708, 2.015, 1.32176, 0.62861, -0.0645385, -1.6739764)
#' )
#' sigmoid <- c(0.7163324, 0.5636804, 10.6156340, 9.9784160, -0.7504673, -0.7108692, -3.5788141, -0.6662962)
#' det_sig <- FALSE
#' TransF <- FALSE
#' Dat <- list()
#' p <- plot_f(dat, sigmoid, det_sig, TransF)
#' print(p)
plot_f <- function(dat, TransFlag = FALSE) { # sigmoid,det_sig,
CORdat <- cor(dat[, 1], dat[, ncol(dat)])
# browser()
all_l <- melt(data.frame(dat), id.vars = "log_dose", variable.name = "replname", value.name = "readout")
isRef <- rep(c(1, 0), 1, each = nrow(all_l) / 2)
isSample <- rep(c(0, 1), 1, each = nrow(all_l) / 2)
all_l2 <- cbind(all_l, isRef, isSample)
# browser()
MODLS <- Fitting_FUNC(dat, TransFlag = FALSE)
s_mr <- MODLS[[1]]
a <- s_mr$coefficients["a", 1]
b <- s_mr$coefficients["b", 1]
c <- s_mr$coefficients["cs", 1]
d <- s_mr$coefficients["d", 1]
r <- s_mr$coefficients["r", 1]
log_dose <- unique(all_l$log_dose)
seq_x <- seq(min(log_dose), max(log_dose), 0.1)
SAMPLE <- a + (d - a) / (1 + exp(b * ((c - r) - seq_x)))
REF <- a + (d - a) / (1 + exp(b * (c - seq_x)))
s_mu <- MODLS[[2]]
as <- s_mu$coefficients["as", 1]
bs <- s_mu$coefficients["bs", 1]
cs <- s_mu$coefficients["cs", 1]
ds <- s_mu$coefficients["ds", 1]
at <- s_mu$coefficients["at", 1]
bt <- s_mu$coefficients["bt", 1]
ct <- s_mu$coefficients["cs", 1] - s_mu$coefficients["r", 1]
dt <- s_mu$coefficients["dt", 1]
r <- s_mu$coefficients["r", 1]
SAMPLEtrue <- at + (dt - at) / (1 + exp(bt * ((cs - r - seq_x))))
REFtrue <- as + (ds - as) / (1 + exp(bs * ((cs - seq_x))))
# browser()
pl_df <- cbind(seq_x, SAMPLE, REF, SAMPLEtrue, REFtrue)
all_l2$readout[all_l2$readout < 0] <- 0.01
all_l2$readouttrans <- log(all_l2$readout)
slopeEC50 <- b * (d - a) / 4
Intercept <- a + (d - a) / 2 - b * (d - a) / 4 * c
# browser()
Xbendl3 <- c - (1.5434 / b)
Xbendu3 <- c + (1.5434 / b)
XbendlT <- c - r - (1.5434 / b)
XbenduT <- c - r + (1.5434 / b)
XasymplS <- c - (3 / b)
XasympuS <- c + (3 / b)
XasymplT <- c - r - (3 / b)
XasympuT <- c - r + (3 / b)
bendpoints <- c(
bendREF_lower = round(Xbendl3, 3), bendREF_upper = round(Xbendu3, 3),
bendSAMPLE_lower = round(XbendlT, 3), bendSAMPLE_upper = round(XbenduT, 3),
asympREF_lower = round(XasymplS, 3), asympREF_upper = round(XasympuS, 3),
asympSAMPLE_lower = round(XasymplT, 3), asympSAMPLE_upper = round(XasympuT, 3)
)
Dat$bendpoints <- bendpoints
Dat$cfordils <- cs
# browser()
p <- ggplot(all_l2, aes(x = log_dose, y = readout, color = factor(isRef))) +
geom_point(shape = factor(isRef), size = 3, alpha = 0.8) +
labs(
title = paste("restricted 4pl model"),
color = "product"
) +
scale_color_manual(labels = c("test", "reference"), values = c("#C2173F", "#4545BA")) +
scale_shape_manual(labels = c("test", "reference")) +
scale_x_continuous(breaks = scales::pretty_breaks(n = 10)) +
scale_y_continuous(breaks = scales::pretty_breaks(n = 10)) +
# theme_bw() +
theme(axis.text.x = element_text(size = 12, angle = 90), axis.text.y = element_text(size = 12))
p2 <- p + geom_line(
data = as.data.frame(pl_df), aes(x = seq_x, y = SAMPLE), color = "#C2173F",
inherit.aes = FALSE
) +
geom_line(
data = as.data.frame(pl_df), aes(x = seq_x, y = REF), color = "#4545BA",
inherit.aes = FALSE
) +
geom_line(
data = as.data.frame(pl_df), aes(x = seq_x, y = SAMPLEtrue), color = "#C2173F", linetype = 2, alpha = 0.4,
inherit.aes = FALSE
) +
geom_line(
data = as.data.frame(pl_df), aes(x = seq_x, y = REFtrue), color = "#4545BA", linetype = 2, alpha = 0.4,
inherit.aes = FALSE
) +
geom_vline(xintercept = c(Xbendl3, Xbendu3), col = "#4545BA", linetype = 2) +
geom_vline(xintercept = c(XbendlT, XbenduT), col = "#C2173F", linetype = 2) +
geom_vline(xintercept = c(XasymplS, XasympuS), col = "#4545BABB", linetype = 3) +
geom_vline(xintercept = c(XasymplT, XasympuT), col = "#C2173FBB", linetype = 3) +
annotate("text", x = c, y = a + (d - a) / 2, label = "0", size = 5) +
geom_abline(slope = slopeEC50, intercept = Intercept) +
theme(legend.position = "none")
Dat$p2 <- p2
# transformed plots
p_rt <- ggplot(all_l2, aes(x = log_dose, y = readouttrans, color = factor(isRef))) +
geom_point(shape = factor(isRef), size = 3, alpha = 0.8) +
labs(title = paste("restricted transformed 4pl"), color = "product") +
scale_color_manual(labels = c("test", "reference"), values = c("#C2173F", "#4545BA")) +
theme_bw()
MODLStrans <- Fitting_FUNC(dat, TransFlag = TRUE)
s_mrt <- MODLStrans[[1]]
a_trans <- s_mrt$coefficients["a", 1]
b_trans <- s_mrt$coefficients["b", 1]
cs_trans <- s_mrt$coefficients["cs", 1]
d_trans <- s_mrt$coefficients["d", 1]
r_trans <- s_mrt$coefficients["r", 1]
XbendlTrans <- cs_trans - (1.5434 / b_trans)
XbenduTrans <- cs_trans + (1.5434 / b_trans)
XbendlTransT <- cs_trans - r_trans - (1.5434 / b_trans)
XbenduTransT <- cs_trans - r_trans + (1.5434 / b_trans)
bendpointsTRANS <- c(
bendREF_lower = round(XbendlTrans, 3), bendREF_upper = round(XbenduTrans, 3),
bendSAMPLE_lower = round(XbendlTransT, 3), bendSAMPLE_upper = round(XbenduTransT, 3)
)
Dat$bendpointsTRANS <- bendpointsTRANS
SAMPLEtrans <- a_trans + (d_trans - a_trans) / (1 + exp(b_trans * ((cs_trans - r_trans) - seq_x)))
REFtrans <- a_trans + (d_trans - a_trans) / (1 + exp(b_trans * ((cs_trans) - seq_x)))
pl_df_trans <- cbind(seq_x, SAMPLEtrans, REFtrans)
p_rt2 <- p_rt + geom_line(
data = as.data.frame(pl_df_trans), aes(x = seq_x, y = SAMPLEtrans), color = "#C2173F",
inherit.aes = FALSE
) +
geom_line(
data = as.data.frame(pl_df_trans), aes(x = seq_x, y = REFtrans), color = "#4545BA",
inherit.aes = FALSE
) +
geom_vline(xintercept = c(XbendlTrans, XbenduTrans), col = "#4545BA", linetype = 2) +
geom_vline(xintercept = c(XbendlTransT, XbenduTransT), col = "#C2173F", linetype = 2) +
theme(legend.position = "none", axis.text = element_text(size = 14))
# browser()
Sum_u <- MODLS[[2]]
# browser()
# if (is.null(det_sig)) {
ast <- Sum_u$coefficients["as", 1]
ate <- Sum_u$coefficients["at", 1]
bst <- Sum_u$coefficients["bs", 1]
bte <- Sum_u$coefficients["bt", 1]
cst <- Sum_u$coefficients["cs", 1]
cte <- Sum_u$coefficients["cs", 1] - Sum_u$coefficients["r", 1]
dst <- Sum_u$coefficients["ds", 1]
dte <- Sum_u$coefficients["dt", 1]
REFu <- ast + (dst - ast) / (1 + exp(bst * (cst - seq_x)))
SAMPLEu <- ate + (dte - ate) / (1 + exp(bte * (cte - seq_x)))
pl_df2 <- cbind(seq_x, SAMPLEu, REFu)
# browser()
pu <- ggplot(all_l2, aes(x = log_dose, y = readout, color = factor(isRef))) +
geom_point(size = 3) +
labs(title = "unrestricted 4pl model", color = "product") +
scale_color_manual(labels = c("test", "reference"), values = c("#C2173F88", "#4545BA88")) +
theme_bw()
pu2 <- pu + geom_line(
data = as.data.frame(pl_df2), aes(x = seq_x, y = SAMPLEu),
color = "#C2173F", inherit.aes = FALSE
) +
geom_line(
data = as.data.frame(pl_df2), aes(x = seq_x, y = REFu),
color = "#4545BA", inherit.aes = FALSE,
show.legend = FALSE
)
pu2_ <- pu2 +
theme(legend.position = "none", axis.text = element_text(size = 14))
putrans <- ggplot(all_l2, aes(x = log_dose, y = readouttrans, color = factor(isRef))) +
geom_point(size = 3) +
labs(title = "unrestricted transformed 4_pl-Model", color = "product") +
scale_color_manual(labels = c("test", "reference"), values = c("#C2173FAA", "#4545BAAA")) +
theme_bw()
Sum_ut <- MODLStrans[[2]]
ast_t <- Sum_ut$coefficients["as", 1]
ate_t <- Sum_ut$coefficients["at", 1]
bst_t <- Sum_ut$coefficients["bs", 1]
bte_t <- Sum_ut$coefficients["bt", 1]
cst_t <- Sum_ut$coefficients["cs", 1]
cte_t <- Sum_ut$coefficients["cs", 1] - Sum_ut$coefficients["r", 1]
dst_t <- Sum_ut$coefficients["ds", 1]
dte_t <- Sum_ut$coefficients["dt", 1]
REFu_trans <- ast_t + (dst_t - ast_t) / (1 + exp(bst_t * (cst_t - seq_x)))
SAMPLEu_trans <- ate_t + (dte_t - ate_t) / (1 + exp(bte_t * (cte_t - seq_x)))
pl_df2u_t <- cbind(seq_x, SAMPLEu_trans, REFu_trans)
pu2_t <- putrans + geom_line(
data = as.data.frame(pl_df2u_t), aes(x = seq_x, y = SAMPLEu_trans),
color = "#C2173F", inherit.aes = FALSE
) +
geom_line(
data = as.data.frame(pl_df2u_t), aes(x = seq_x, y = REFu_trans),
color = "#4545BA", inherit.aes = FALSE,
show.legend = FALSE
)
pu3_t <- pu2_t
if (TransFlag) grid.arrange(p_rt2, pu3_t, nrow = 1) else grid.arrange(p2, pu2_, nrow = 1)
}
#' Simulate a well-plate readout
#'
#' Returns a possible well-plate result based on the metadata provided and a variability.
#' Homo- and heteroscedasticity can be simulated.
#'
#' @param as, bs, cs, ds, at, bt, dt,r,ct, gt, gs are the parameter of the 5pl logistic regression.
#' @param sd_fac The standard deviation with units in % of upper-lower asymptote.
#' @param log_conc The natural log of the concentrations.
#' @param heteroNoise Boolean if heteroscedstic noise should be added.
#' @param noDilSeries A number >1 indicating how many dilution series per product should be simulated.
#' @param noDils A number >7 indicating how many dilutions steps per product should be simulated.
#' @returns A data-frame with readouts and natural log of concentrations.
#' @export
#' @examples
#' as <- 3
#' bs <- 1
#' cs <- -4
#' ds <- 10
#' at <- 3
#' bt <- 1
#' dt <- 10
#' r <- 0.0001
#' ct <- cs - r
#' sd_fac <- 0.1
#' gt <- 1
#' gs <- 1
#' lnConc <- c(1, 0, -1, -2, -3, -4, -5, -6)
#' heteroNoise <- FALSE
#' noDilS <- 3
#' noD <- 8
#' Calc_DilRes(as, bs, cs, ds, at, bt, dt, r, ct, sd_fac, gt, gs, log_conc = lnConc, heteroNoise, noDilS, noD)
Calc_DilRes <- function(as = 3, bs = 1, cs = -4, ds = 10, at = 3, bt = 1, dt = 10, r = 0.0001, ct = cs - r,
sd_fac = 0.1, gt = 1, gs = 1, log_conc,
heteroNoise = FALSE, noDilSeries, noDils) {
yAxfac <- (ds - as)
log_dose <- log_conc
isRef <- rep(c(1, 0), 1, each = length(log_conc) * noDilSeries)
isSample <- rep(c(0, 1), 1, each = length(log_conc) * noDilSeries)
# browser()
av <- as * isRef + at * isSample + (ds * isRef + dt * isSample - as * isRef - at * isSample) /
(1 + isRef * exp(bs * (cs - log_dose)) + isSample * exp(bt * (ct - log_dose)))
if (heteroNoise) {
# heterosc noise
ro_jit <- matrix(unlist(map(av, function(x) x + rnorm(1, 0, x * sd_fac / 100))), nrow = noDils, ncol = noDilSeries * 2)
} else {
# homosc noise
ro_jit <- matrix(unlist(map(av, function(x) x + rnorm(1, 0, sd_fac * yAxfac / 100))), nrow = noDils, ncol = noDilSeries * 2)
}
ro_jit <- abs(ro_jit)
ro_jit2 <- cbind(ro_jit, log_dose)
if (noDilSeries == 3) {
colnames(ro_jit2) <- c("R_dil1", "R_dil2", "R_dil3", "T_dil1", "T_dil2", "T_dil3", "log_dose")
} else {
colnames(ro_jit2) <- c("R_dil1", "R_dil2", "T_dil1", "T_dil2", "log_dose")
}
return(ro_jit2)
}
#' Calculate the potency of linear PLA
#'
#' The delta Method is used for calculating the potency using a restricted linear model.
#' Absolute and relative CIs are calculated. The model RMSE or the Pure Error can be used.
#'
#' @param circles Data frame with the 3 consecutive concentrations and the respective readouts.
#' @param Lim The limits to check if the relative CI is within the limits.
#' @param PureErrFlag Boolean if Pure Error should be used.
#' @returns A data-frame with potency estimate, absolute CIs, test result, relative CIs.
#' @export
#' @examples
#' CIRC <- data.frame(
#' log_dose = c(
#' -2.5, -2.5, -2.5, -3.2, -3.2, -3.2, -3.9, -3.9, -3.9,
#' -3.2, -3.2, -3.2, -3.9, -3.9, -3.9, -4.7, -4.7, -4.7
#' ),
#' replname = c(
#' "R_dil1", "R_dil1", "R_dil1", "R_dil2", "R_dil2", "R_dil2", "R_dil3", "R_dil3", "R_dil3",
#' "T_dil1", "T_dil1", "T_dil1", "T_dil2", "T_dil2", "T_dil2", "T_dil3", "T_dil3", "T_dil3"
#' ),
#' readout = c(72.1, 75.8, 76.04, 59.8, 61, 62.7, 43.6, 45, 41.5, 53.5, 62.2, 65.9, 48.3, 43.8, 43.14, 28.17, 29.2, 31.2),
#' isRef = c(rep(1, 9), rep(0, 9)),
#' isSample = c(rep(0, 9), rep(1, 9))
#' )
#' Lim <- c(rep(0, 8), 70, 130) # only Lim 9 and 10 relevant
#' PureErrF <- TRUE
#'
#'
#' LinPotTab(circles = CIRC, Lim, PureErrF)
LinPotTab <- function(circles, Lim, PureErrFlag) {
circ_ABl <- circles
circ_Al <- circ_ABl[circ_ABl$isSample == 1, ]
circ_Al <- circ_ABl[circ_ABl$isSample == 0, ]
# restr CSSI model
modAB <- lm(readout ~ log_dose + isSample, circ_ABl)
coeffs <- modAB$coefficients
SU_modAB <- tryCatch(
{
SU_modAB <- summary(modAB)
},
error = function(msg) {
return(NA)
}
)
# Intercept diff/slope modAB
linPot <- exp(modAB$coefficients[3] / modAB$coefficients[2])
if (PureErrFlag) {
FitAnova <- anova(lm(readout ~ factor(log_dose) * isSample, circ_ABl))
meanPureErr <- FitAnova[4, 3]
DFsPure <- FitAnova[4, 1]
VCOV <- vcov(modAB)
V_V <- VCOV / SU_modAB$sigma^2
VCOVpure <- V_V * meanPureErr
SEsPure <- sqrt(diag(V_V) * meanPureErr)
}
log_pot_delta <- car::deltaMethod(modAB, "isSample/log_dose")
if (PureErrFlag) {
V_ <- log_pot_delta$SE^2 / SU_modAB$sigma^2
V_p <- V_ * meanPureErr
potDeltaPureSE <- sqrt(V_p)
CI_log_low <- log_pot_delta$Estimate - qt(0.975, DFsPure) * potDeltaPureSE
CI_log_up <- log_pot_delta$Estimate + qt(0.975, DFsPure) * potDeltaPureSE
} else {
CI_log_low <- log_pot_delta$Estimate - qt(0.975, df.residual(modAB)) * log_pot_delta$SE
CI_log_up <- log_pot_delta$Estimate + qt(0.975, df.residual(modAB)) * log_pot_delta$SE
}
# browser()
ExpLinPot <- exp(c(log_pot_delta$Estimate, CI_log_low, CI_log_up))
# Rel pot CI
relLinpotCI <- ExpLinPot / linPot * 100
if (relLinpotCI[2] > Lim[[9]] & relLinpotCI[3] < Lim[[10]]) test_potCI <- 0 else test_potCI <- 1
pottab <- cbind(
round(linPot * 100, 3), round(ExpLinPot[2] * 100, 3), round(ExpLinPot[3] * 100, 3),
round(test_potCI, 3), round(relLinpotCI[2], 3), round(relLinpotCI[3], 3)
)
colnames(pottab) <- c("Potency", "lower 95%CI", "upper 95%CI", "test_result", "lowerRel95%CI", "upperRel95%CI")
return(pottab)
}
#' Calculate the ANOVA of linear PLA and restricted and unrestr. model summaries
#'
#' The delta Method is used for calculating the potency using a restricted linear model.
#' Absolute and relative CIs are calculated. The model RMSE or the Pure Error can be used.
#'
#' @param circles Data frame with the 3 consecutive concentrations and the respective readouts.
#' @param Lim The limits to check if the relative CI is within the limits.
#' @param PureErrFlag Boolean if Pure Error should be used.
#' @returns A data-frame with 1) data.frame with F-tests ANOVA and test results
#' 2) summary of unrestricted linear model 3) Slope difference +CIs
#' 4) summary of restricted linear model.
#' @export
#' @examples
#' dat <- data.frame(
#' R_dil1 = c(10221, 18258, 31993, 49336, 68332, 83527, 95584, 102229),
#' R_dil2 = c(10136, 19078, 31925, 49003, 68034, 83776, 95495, 101608),
#' T_dil1 = c(10830, 19891, 33915, 52131, 70617, 85784, 95937, 102791),
#' T_dil2 = c(11169, 20153, 34007, 52179, 69962, 85543, 96439, 102655),
#' log_dose = c(-1.2029, -1.89712, -2.590267, -3.2834, -3.97656, -4.66917, -5.362323, -6.05334)
#' )
#' CIRC <- data.frame(
#' log_dose = c(-2.590267, -2.590267, -3.2834, -3.2834, -3.97656, -3.97656, -2.590267, -2.590267, -3.2834, -3.2834, -3.97656, -3.97656),
#' replname = c("R_dil1", "R_dil2", "R_dil1", "R_dil2", "R_dil1", "R_dil2", "T_dil1", "T_dil2", "T_dil1", "T_dil2", "T_dil1", "T_dil2"),
#' readout = c(31993, 31925, 49336, 49003, 68332, 68034, 33915, 34007, 52131, 52179, 70617, 69962),
#' isRef = c(rep(1, 6), rep(0, 6)),
#' isSample = c(rep(0, 6), rep(1, 6))
#' )
#' Lim <- c(rep(0, 8), 70, 130) # only Lim 9 and 10 relevant
#' PureErrF <- TRUE
#'
#'
#' ANOVAlintests(ro_new, circles, Lim, PureErrF)
ANOVAlintests <- function(ro_new, circles, Lim, PureErrFlag) {
all_l <- melt(data.frame(ro_new), id.vars = "log_dose", variable.name = "replname", value.name = "readout")
isRef <- rep(c(1, 0), 1, each = nrow(all_l) / 2)
isSample <- rep(c(0, 1), 1, each = nrow(all_l) / 2)
all_l$isRef <- isRef
all_l$isSample <- isSample
all_l$Conc <- exp(all_l$log_dose)
all_lA <- all_l[all_l$isSample == 1, ] # TEST
all_lB <- all_l[all_l$isSample == 0, ] # REF
# browser()
circ_ABl <- circles
circ_Al <- circ_ABl[circ_ABl$isSample == 1, ]
circ_Bl <- circ_ABl[circ_ABl$isSample == 0, ]
# restr CSSI model
modAB <- lm(readout ~ log_dose + isSample, circ_ABl)
# unrestr with interact term SSSI
modABu <- lm(readout ~ log_dose + isSample + log_dose * isSample, circ_ABl)
modA <- lm(readout ~ log_dose + isSample, circ_Al)
modB <- lm(readout ~ log_dose + isSample, circ_Bl)
log_pot_delta <- car::deltaMethod(modAB, "isSample/log_dose")
CI_log_low <- log_pot_delta$Estimate - qt(0.975, df.residual(modAB)) * log_pot_delta$SE
CI_log_up <- log_pot_delta$Estimate + qt(0.975, df.residual(modAB)) * log_pot_delta$SE
ExpLinPot <- exp(c(log_pot_delta$Estimate, CI_log_low, CI_log_up))
if (ExpLinPot[2] * 100 > Lim[9] & ExpLinPot[3] * 100 > Lim[10]) test_potCI <- 0 else test_potCI <- 1
su_mod <- summary(modAB)$coefficients
su_mod2 <- cbind(data.frame(parameter = c("intercept REF", "slope REF", "intercepts diff.")), su_mod)
su_modU <- summary(modABu)$coefficients
su_modU2 <- cbind(data.frame(parameter = c("intercept REF", "slope REF", "intercepts diff.", "slope difference")), su_modU)
uCI_SloDiff <- su_modU[4, 1] + qt(0.975, 8) * su_modU[4, 2]
lCI_SloDiff <- su_modU[4, 1] - qt(0.975, 8) * su_modU[4, 2]
SlopeDiffCI <- c(su_modU[4, 1], lCI_SloDiff, uCI_SloDiff)
lenCirc <- nrow(circ_ABl)
dfTreat <- 3
dfPrep <- 1
dfReg <- 1
dfnonP <- 1
dfRMSE <- c(lenCirc - 3 - 1)
dfTotal <- lenCirc - 1
dfPureE <- lenCirc - 6
dfNonLin <- dfRMSE - dfPureE
RSS <- sum(resid(lm(readout ~ log_dose * isSample, circ_ABl))^2)
MSE <- RSS / dfRMSE
SSE <- sum(resid(lm(readout ~ factor(log_dose) * isSample, circ_ABl))^2)
MSpure <- SSE / dfPureE
if (PureErrFlag) {
FitAnova <- anova(lm(readout ~ factor(log_dose) * isSample, circ_ABl))
meanPureErr <- FitAnova[4, 3]
SU_modAB <- tryCatch(
{
SU_modAB <- summary(modAB)
},
error = function(msg) {
return(NA)
}
)
if (length(SU_modAB) > 1) s_modABcoeffs <- summary(modAB)$coefficients
DFsPure <- FitAnova[4, 1]
VCOV <- vcov(modAB)
V_V <- VCOV / SU_modAB$sigma^2
VCOVpure <- V_V * meanPureErr
SEsPure <- sqrt(diag(V_V) * meanPureErr)
su_mod2[, 3] <- SEsPure
su_mod2[, 4] <- su_mod2[, 2] / su_mod2[, 3]
su_mod2[, 5] <- 2 * (1 - pt(abs(su_mod[, 4]), FitAnova[4, 1]))
s_mu <- summary(modABu)$coefficients
SU_modABu <- summary(modABu)
VCOVu <- vcov(modABu)
V_Vu <- VCOVu / SU_modABu$sigma^2
SEsPureU <- sqrt(diag(V_Vu) * meanPureErr)
su_modU2[, 3] <- SEsPureU
su_modU2[, 4] <- su_modU2[, 2] / su_modU2[, 3]
su_modU2[, 5] <- 2 * (1 - pt(abs(su_modU2[, 4]), FitAnova[4, 1]))
uCI_SloDiffP <- su_modU[4, 1] + qt(0.975, 8) * SEsPureU[4]
lCI_SloDiffP <- su_modU[4, 1] - qt(0.975, 8) * SEsPureU[4]
SlopeDiffCI <- c(su_modU[4, 1], lCI_SloDiffP, uCI_SloDiffP)
SSRes <- SSE
dfRes <- dfPureE
} else {
SSRes <- RSS
dfRes <- dfRMSE
}
# treatment
SStreat <- print(sum((predict(lm(readout ~ factor(log_dose) * isSample, circ_ABl)) - mean(circ_ABl$readout))^2))
F_treat <- (SStreat / dfTreat) / (SSRes / dfRes)
# Preparation
SSprep <- print(sum((predict(lm(readout ~ isSample, circ_ABl)) - mean(circ_ABl$readout))^2))
F_prep <- (SSprep / dfTreat) / (SSRes / dfRes)
# Regression
# ANOVA tape II SS of regression
SSreg <- Anova(lm(readout ~ log_dose + isSample, circ_ABl))[1, 1]
# Non-parallelism
# diff of RSS of restricted and unrestricted model
SSnonpar <- sum(resid(modAB)^2) - sum(resid(modABu)^2)
F_nonpar <- SSnonpar / (sum(resid(lm(readout ~ factor(log_dose) * isSample, circ_ABl))^2) / (lenCirc - 4))
# non-linearity
SSnonlin <- sum((predict(modABu) - predict(lm(readout ~ as.factor(log_dose) * isSample, circ_ABl)))^2)
# = RSS-SSE
# Total SS
SStot <- sum((circ_ABl$readout - mean(circ_ABl$readout))^2)
# Significance of R^2 F-ratio
# MSR/MSE
# sample A
F_R2_A <- sum((predict(lm(readout ~ log_dose + I(log_dose^2), circ_Al)) - mean(predict(modA)))^2 - (predict(modA) - mean(circ_Al$readout))^2) /
(sum((predict(lm(readout ~ log_dose + I(log_dose^2), circ_Al)) - circ_Al$readout)^2) / (nrow(circ_Al) - 3))
pFR2_A <- round(pf(F_R2_A, 1, 6), 4)
# sample B
F_R2_B <- sum((predict(lm(readout ~ log_dose + I(log_dose^2), circ_Bl)) - mean(predict(modB)))^2 - (predict(modB) - mean(circ_Bl$readout))^2) /
(sum((predict(lm(readout ~ log_dose + I(log_dose^2), circ_Bl)) - circ_Bl$readout)^2) / (nrow(circ_Bl) - 3))
pFR2_B <- round(pf(F_R2_B, 1, 6), 4)
# sign of non-lin with pure error: MSSnonlin/MSSE
F_nonlin <- (SSnonlin / 2) / (SSE / dfPureE)
# sign of slope
F_slope_B <- sum((predict(modB) - mean(circ_Bl$readout))^2) / (sum((circ_Bl$readout - predict(modB))^2) / (nrow(circ_Bl) - 2))
F_slope_A <- sum((predict(modA) - mean(circ_Al$readout))^2) / (sum((circ_Al$readout - predict(modA))^2) / (nrow(circ_Al) - 2))
# F-test on regression: MSSreg/MSSE
if (is.na(F_nonlin)) F_nonlin <- 0
if (F_nonlin > 0) {
p_F_nonlin <- round(pf(F_nonlin, 2, dfPureE, lower.tail = FALSE), 5)
} else {
p_F_nonlin <- "SSnonlin neg or 0"
}
# significances
F_regr <- (SSreg / 1) / (SSRes / dfRes)
p_F_regr <- round(pf(F_regr, 1, dfRes, lower.tail = FALSE), 3)
p_F_treat <- round(pf(F_treat, 3, dfRes, lower.tail = FALSE), 3)
p_F_prep <- round(pf(F_prep, 1, dfRes, lower.tail = FALSE), 3)
p_F_slope_A <- round(pf(F_slope_A, 1, (nrow(circ_Al) - 2), lower.tail = FALSE), 3)
p_F_slope_B <- round(pf(F_slope_B, 1, (nrow(circ_Bl) - 2), lower.tail = FALSE), 3)
p_F_nonp <- round(pf(F_nonpar, 1, dfRes, lower.tail = FALSE), 3)
p_F_LoF <- p_F_nonlin
res_tab_lin <- data.frame(
test = c(
"F-test on sign. of regression", "F_test on non-lin",
"F-test on R^2 A", "F_test on R^2 B",
"F-test on slope A", "F-test on slope B",
"F-test on non-parallelism", "F-test on preparation"
),
test_results = c(
ifelse(p_F_regr < 0.05, 0, 1), ifelse(p_F_nonlin < 0.05, 1, 0),
ifelse(pFR2_A < 0.05, 1, 0), ifelse(pFR2_B < 0.05, 1, 0),
ifelse(p_F_slope_A < 0.05, 0, 1), ifelse(p_F_slope_B < 0.05, 0, 1),
ifelse(p_F_nonp < 0.05, 1, 0), ifelse(p_F_prep < 0.05, 0, 1)
),
estimate = c(
p_F_regr, p_F_nonlin, pFR2_A, pFR2_B, p_F_slope_A,
p_F_slope_B, p_F_nonp, p_F_prep
),
Source = c(
"Treatment", "Preparation", "Regression", "Non-parallelism",
"Resid Error", "Non-linearity", "Pure error", "Total"
),
df = c(dfTreat, 1, 1, 1, dfRMSE, 2, dfPureE, lenCirc - 1),
SumSquares = c(
round(SStreat, 5), round(SSprep, 5), round(SSreg, 5),
round(SSnonpar, 5), round(RSS, 5), round(SSnonlin, 5),
round(SSE, 5), round(SStot, 5)
),
MS = c(
round(SStreat / dfTreat, 5), round(SSprep, 5), round(SSreg, 5),
round(SSnonpar, 5), round(RSS / dfRMSE, 5), round(SSnonlin / 2, 5),
round(SSE / dfPureE, 5), round(SStot / dfTotal, 5)
),
"F-value" = c(
round(F_treat, 5), round(F_prep, 5), round(F_regr, 5),
round(F_nonpar, 5), "", round(F_nonlin, 5), "", ""
),
"p-value" = c(p_F_treat, p_F_prep, p_F_regr, p_F_nonp, "", p_F_LoF, "", "")
)
RET <- list(res_tab_lin, su_modU2, SlopeDiffCI, su_mod2)
return(RET)
}
#' Plots linear regression on the scatterplot.
#'
#' Restricted and unrestricted model are plotted. The number of dilution steps used for the regression
#' are printed in the title. Reference is blue, red is the sample. The points used for regression
#' are highlighted with a circle.
#'
#' @param circle Data frame with the 3 consecutive concentrations and the respective readouts.
#' @param sigmoid Parameters of the unrestricted fit of the full dataset for drawing the curves.
#' @param all_l2 Long format data.frame of the readout data incl log(concentration) and isRef (0s and 1s).
#' @param pl_df Data.frame for plotting the regression lines.
#' @param indS Index of dilution, where regression starts for reference sample.
#' @param indT Index of dilution, where regression starts for test sample.
#' @returns A grid object of 2 plots of unrestricted and restricted linear PLA models.
#' @export
#' @examples
#' circle <- read.csv("~/plateflow/circle.csv")
#' all_l2 <- read.csv("~/plateflow/all_l2.csv")
#' sigmoid <- c(10.0, 10.0, 110.0, 110.0, 1.0, 1.0, -3.5, 0.0)
#' indS <- 3
#' indT <- 3
#' pl_df <- data.frame(
#' lnC = c(-1.203973, -1.897120, -2.590267, -3.283414, -3.976562, -4.669176, -5.362323, -6.053340),
#' plotS = c(113.772511, 97.668371, 81.564231, 65.460091, 49.355952, 33.264200, 17.160060, 1.105405),
#' plotT = c(114.213375, 97.588663, 80.963951, 64.339239, 47.714527, 31.102604, 14.477892, -2.095735)
#' )
#'
#'
#' PlotLinPLA_FUNC(circle, sigmoid, all_l2, pl_df, indS, indT)
PlotLinPLA_FUNC <- function(circle, sigmoid, all_l2, pl_df, indS, indT) {
# browser()
mLin <- gsl_nls(readout ~ (intS + r) * isSample + intS * isRef + k * log_dose,
data = circle,
start = list(intS = 0, k = 1, r = 0),
control = gsl_nls_control(xtol = 1e-10, ftol = 1e-10, gtol = 1e-10)
)
# alternativ: modAB <- lm(readout ~ log_dose+isSample, circle)
sum_mLin <- summary(mLin)
log_dose <- unique(all_l2$log_dose)
seq_x <- seq(min(log_dose), max(log_dose), 0.1)
if (!is.null(sigmoid)) {
SAMPLEtrue <- sigmoid[5] + (sigmoid[7] - sigmoid[5]) / (1 + exp(sigmoid[6] * ((sigmoid[4] - sigmoid[8] - seq_x))))
REFtrue <- sigmoid[1] + (sigmoid[3] - sigmoid[1]) / (1 + exp(sigmoid[2] * ((sigmoid[4] - seq_x))))
truePL_df <- cbind(seq_x, SAMPLEtrue, REFtrue)
} else {
SAMPLEtrue <- NULL
REFtrue <- NULL
truePL_df <- NULL
}
p <- ggplot(all_l2, aes(x = log_dose, y = readout, color = factor(isRef))) +
geom_point(size = 2) +
# labs(title=paste("linear regression model", indS,indT), color="product") +
scale_colour_manual(labels = c("test", "reference"), values = c("#C2173F", "#4545BA")) +
ylim(min(all_l2$readout), max(all_l2$readout)) +
scale_x_continuous(breaks = scales::pretty_breaks(n = 10)) +
scale_y_continuous(breaks = scales::pretty_breaks(n = 10)) +
theme_bw()
p2 <- p + geom_line(
data = pl_df, aes(x = lnC, y = plotS), color = "#4545BA",
inherit.aes = FALSE
) +
geom_line(
data = pl_df, aes(x = lnC, y = plotT), color = "#C2173F",
inherit.aes = FALSE
) +
{
if (!is.null(truePL_df)) {
geom_line(
data = data.frame(truePL_df), aes(x = seq_x, y = SAMPLEtrue), color = "#C2173F", linetype = 2, alpha = 0.4,
inherit.aes = FALSE
)
}
} +
{
if (!is.null(truePL_df)) {
geom_line(
data = data.frame(truePL_df), aes(x = seq_x, y = REFtrue), color = "#4545BA", linetype = 2, alpha = 0.4,
inherit.aes = FALSE
)
}
} +
labs(title = paste("unrestricted PLA model"), subtitle = paste("Regression starts for reference sample:", indS, "for test sample:", indT)) +
theme(legend.position = "none", axis.text = element_text(size = 14))
p3 <- p2 + geom_point(circle, mapping = aes(
x = log_dose, y = readout, shape = factor(isRef),
size = 5, alpha = 0.2
), col = c("black"), inherit.aes = FALSE) +
scale_shape_manual(labels = c("test", "reference"), values = c(21, 21))
# fit intercept for test and ref and common slope
pl_restS <- sum_mLin$coefficients[1, 1] + sum_mLin$coefficients[2, 1] * log_dose
pl_restT <- sum_mLin$coefficients[1, 1] + sum_mLin$coefficients[3, 1] + sum_mLin$coefficients[2, 1] * log_dose
pl_rest <- data.frame(lnC = log_dose, plotS = pl_restS, plotT = pl_restT)
pr2 <- p + geom_line(
data = pl_rest, aes(x = lnC, y = plotS), color = "#4545BA",
inherit.aes = FALSE
) +
geom_line(
data = pl_rest, aes(x = lnC, y = plotT), color = "#C2173F",
inherit.aes = FALSE
) +
{
if (!is.null(truePL_df)) {
geom_line(
data = data.frame(truePL_df), aes(x = seq_x, y = SAMPLEtrue), color = "#C2173F", linetype = 2, alpha = 0.4,
inherit.aes = FALSE
)
}
} +
{
if (!is.null(truePL_df)) {
geom_line(
data = data.frame(truePL_df), aes(x = seq_x, y = REFtrue), color = "#4545BA", linetype = 2, alpha = 0.4,
inherit.aes = FALSE
)
}
} +
labs(
title = paste("restricted linear regression model"),
subtitle = paste("Regression on highlighted points")
) +
theme(legend.position = "none", axis.text = element_text(size = 14))
pr3 <- pr2 + geom_point(circle, mapping = aes(
x = log_dose, y = readout, shape = factor(isRef),
size = 5, alpha = 0.2
), col = c("black"), inherit.aes = FALSE) +
scale_shape_manual(labels = c("test", "reference"), values = c(21, 21))
return(grid.arrange(p3, pr3, nrow = 1))
}
#' Calculates the potency of 4PL PLA of all models model
#'
#' The gradient method is used for calculating the potency for a restricted model, an unrestricteed model,
#' and the log-transformations thereof.
#' Absolute and relative CIs are calculated. The model RMSE or the Pure Error can be used.
#'
#' @param ro_new The dilution series readouts for REF and TEST + 1 column log(concentration).
#' @param PureErrFlag Boolean if Pure Error should be used.
#' @returns A data-frame with 1) data.frame with F-tests ANOVA and test results
#' 2) summary of unrestricted linear model 3) Slope difference +CIs
#' 4) summary of restricted linear model.
#' @export
#' @examples
#' ro_new <- data.frame(
#' R_dil1 = c(10221, 18258, 31993, 49336, 68332, 83527, 95584, 102229),
#' R_dil2 = c(10136, 19078, 31925, 49003, 68034, 83776, 95495, 101608),
#' T_dil1 = c(10830, 19891, 33915, 52131, 70617, 85784, 95937, 102791),
#' T_dil2 = c(11169, 20153, 34007, 52179, 69962, 85543, 96439, 102655),
#' log_dose = c(-1.2029, -1.89712, -2.590267, -3.2834, -3.97656, -4.66917, -5.362323, -6.05334)
#' )
#' PureErrF <- TRUE
#'
#'
#' pot4plFUNC(ro_new, PureErrF)
pot4plFUNC <- function(ro_new, PureErrFlag) {
all_l <- melt(data.frame(ro_new), id.vars = "log_dose", variable.name = "replname", value.name = "readout")
isRef <- rep(c(1, 0), 1, each = nrow(all_l) / 2)
isSample <- rep(c(0, 1), 1, each = nrow(all_l) / 2)
all_l$isRef <- isRef
all_l$isSample <- isSample
all_l$Conc <- exp(all_l$log_dose)
all_l$readout[all_l$readout < 0] <- 0.01
all_l$readouttrans <- log(all_l$readout)
# browser()
CORdat <- cor(ro_new[, 1], ro_new[, ncol(ro_new)])
if (CORdat < 0) SLOPE <- -1 else SLOPE <- 1
#
FITs <- Fitting_FUNC(ro_new, TransFlag = FALSE)
if (!PureErrFlag) {
pot_est <- FITs[[3]]
potU_est <- FITs[[4]]
} else {
FitAnova <- anova(lm(readout ~ factor(Conc) * isSample, all_l))
meanPureErr <- FitAnova[4, 3]
DFsPure <- FitAnova[4, 1]
# SU_mr <- tryCatch({
# SU_mr <- summary(mr)
# }, error = function(msg) {
# return()
# })
SU_mr <- FITs[[1]]
SU_mrCoeff <- SU_mr$coefficients
# if (length(SU_mr)>1) {
# SU_mrCoeff <- SU_mr$coefficients
# } else { SU_mrCoeff <- rep(NA,5) }
# te2$cov.unscaled[1,1]*te2$sigma^2
# VCOV <- vcov(mr)
# V_V <- VCOV/SU_mr$sigma^2
V_V <- SU_mr$cov.unscaled
SEsPure <- sqrt(diag(V_V) * meanPureErr)
pot_est <- c(
exp(SU_mrCoeff["r", 1]), exp(SU_mrCoeff["r", 1] - qt(0.975, DFsPure) * SEsPure["r"]),
exp(SU_mrCoeff["r", 1] + qt(0.975, DFsPure) * SEsPure["r"])
)
# unrestricted
SU_mu <- FITs[[2]]
s_muCoeff <- SU_mu$coefficients
# SU_mu <- summary(mu)
# VCOVu <- vcov(mu)
V_Vu <- SU_mu$cov.unscaled
SEsPureU <- sqrt(diag(V_Vu) * meanPureErr)
potU_est <- c(
exp(s_muCoeff["r", 1]), exp(s_muCoeff["r", 1] - qt(0.975, DFsPure) * SEsPureU["r"]),
+exp(s_muCoeff["r", 1] + qt(0.975, DFsPure) * SEsPureU["r"])
)
} # PureErrFlag
FITstrans <- Fitting_FUNC(ro_new, TransFlag = TRUE)
# pot_est_log <- exp(confintd(mr_log, "r", method="asymptotic"))
# potU_est_log <- exp(confintd(mu_log, "r", method="asymptotic"))
pot_est_log <- FITstrans[[3]]
potU_est_log <- FITstrans[[4]]
colnames(pot_est_log) <- c("estimate", "lowerCI2", "upperCI")
colnames(potU_est_log) <- c("estimate", "lowerCI2", "upperCI")
# browser()
su_mr_log <- FITstrans[[1]] # summary(mr_log)
Dat$RMSE_Rlog <- su_mr_log$sigma
su_mu_log <- FITstrans[[2]] # summary(mu_log)
Dat$RMSE_Ulog <- su_mu_log$sigma
Dat$up_lowAslog <- su_mu_log$coefficients[1, 1] - su_mu_log$coefficients[4, 1]
potALL <- rbind(round(pot_est, 6), round(potU_est, 6), round(pot_est_log, 6), round(potU_est_log, 6))
potALL2 <- cbind(c("restricted", "unrestricted", "ln-transformed restr", "ln-transformed unrestr"), potALL)
return(potALL2)
}
#' Calculates logarithmized CIs for ratios
#'
#' Ratio CIs can be unbound, and not calulatable. Therefore the ratios are logarithmized.
#' The Covariance is not used, as it is 0 for comparisons between products.
#'
#' @param xs The estimate of the reference sample.
#' @param xt The estimate of the test sample.
#' @param se_xs The standard error of the estimate of the reference sample.
#' @param se_xt The standard error of the estimate of the test sample.
#' @param CoVar The covariance between test and reference estimate (set to 0).
#' @param DFs Degrees of freedom, either from pure error term (no of readouts - no of concentrations*2), or RMSE term (no of readouts - 8 parameters).
#' @param Conf The confidence of the Confidence Interval (default 95% which requires 0.975).
#' @returns A data-frame with the lower and upper CI in anti-log form.
#' @export
#' @examples
#' xs <- 2
#' xt <- 3.2
#' se_xt <- 0.34
#' se_xs <- 0.23
#' DFs <- 32 - 16
#'
#'
#' ParamCI_F(xt, xs, se_xt, se_xs, CoVar, DFs, Conf = 0.975)
ParamCI_F <- function(xt, xs, se_xt, se_xs, CoVar, DFs, Conf = 0.975) {
log_xs <- log(abs(xs))
log_xt <- log(abs(xt))
var_log_xs <- (se_xs / xs)^2 # approximate variance of log(xs)
var_log_xt <- (se_xt / xt)^2
se_log_ratio <- sqrt(var_log_xs + var_log_xt) #-2*CoVar/(xs*xt)
lower_log_ratio <- log_xt - log_xs - qt(Conf, DFs) * se_log_ratio
upper_log_ratio <- log_xt - log_xs + qt(Conf, DFs) * se_log_ratio
ci_ratio <- exp(c(lower_log_ratio, upper_log_ratio))
return(ci_ratio)
}
#' Calculates EQ tests and F-Tests for 4P
#'
#' CIs of asmptote ratios,slope ratios, asympt-difference ratio, and lower asympt-diff. calculated.
#' In addition the F-test on significance of regression and non-linearity are calculated.
#'
#' @param ro_new Data frame with the concentrations and the respective readouts.
#' @param Lim The limits to check if the relative CI is within the limits.
#' @param PureErrFlag Boolean if Pure Error should be used.
#' @returns A data-frame with the lower and upper CI in anti-log form.
#' @export
#' @examples
#'
#' dat <- data.frame(
#' REF1 = c(1547, 1620, 1644, 2504, 3426, 3512, 3401, 3787), REF2 = c(1492, 1536, 1384, 2286, 3046, 3479, 3516, 3497),
#' REF3 = c(1468, 1827, 1558, 2252, 3002, 3349, 2945, 3665),
#' TEST1 = c(1405, 1523, 1502, 1474, 2383, 3221, 3589, 3445), TEST2 = c(1420, 1516, 1544, 1512, 2226, 3219, 3327, 3591),
#' TEST3 = c(1399, 1376, 1588, 1475, 2148, 3083, 2942, 3466), log_dose = c(5.01, 3.401, 2.708, 2.015, 1.32176, 0.62861, -0.0645385, -1.6739764)
#' )
#' Lim <- c(-1, 1, 0.005, 2, 0.5, 2, 0.5, 2, 75, 133, 75, 133)
#' PureErrF <- FALSE
#'
#' tests_FUNC(ro_new, Lim, PureErrF)
tests_FUNC <- function(ro_new, Lim, PureErrFlag) {
all_l <- melt(data.frame(ro_new), id.vars = "log_dose", variable.name = "replname", value.name = "readout")
isRef <- rep(c(1, 0), 1, each = nrow(all_l) / 2)
isSample <- rep(c(0, 1), 1, each = nrow(all_l) / 2)
all_l$isRef <- isRef
all_l$isSample <- isSample
all_l$Conc <- exp(all_l$log_dose)
all_l$readout[all_l$readout < 0] <- 0.01
# browser()
FITs <- Fitting_FUNC(ro_new = ro_new, TransFlag = FALSE)
if (is.character(FITs)) {
return(FITs)
} # if singularity
POTr_CI <- FITs[[3]][2:3]
potAll2 <- FITs[[3]]
smr <- FITs[[1]]
smu <- FITs[[2]]
FitAnova <- anova(lm(readout ~ factor(Conc) * isSample, all_l))
# pure error
pureSS <- FitAnova[4, 2]
pureSS_df <- FitAnova[4, 1]
meanPureErr <- FitAnova[4, 3]
# vcovMU <- vcov(mu)
V_V <- smu$cov.unscaled
SEsPure <- sqrt(diag(V_V) * meanPureErr)
VCOVpure <- V_V * meanPureErr
DFsPure <- FitAnova[4, 1]
testPOTr <- logical()
if (POTr_CI[1] * 100 > Lim[[9]] & POTr_CI[2] * 100 < Lim[[10]]) testPOTr <- 0 else testPOTr <- 1
potAllU2 <- FITs[[4]]
test_c <- logical()
if ((potAllU2[2] > Lim[[9]] / 100 & potAllU2[3] < Lim[[10]] / 100)) test_c <- 0 else test_c <- 1
predPot <- FITs[[5]]
predPotU <- FITs[[6]]
vcovMU <- V_V * smu$sigma^2
#### ANOVA ----
noConc <- length(unique(all_l$Conc))
nofitted <- noConc
AnovaDFs <- c(nofitted - 1, 1, 3, nofitted - 4 - 1, nrow(all_l) - nofitted, nofitted, nrow(all_l) - 2 * nofitted, nrow(all_l) - 1)
SStreat <- round(sum((predPotU - mean(all_l$readout))^2), 5)
SSregr <- round(sum((predPot - mean(all_l$readout))^2), 5)
# non-parallelism
SSnonparall <- round(sum(smr$residuals^2) - sum(smu$residuals^2), 5)
SSprep <- round(sum((predict(lm(readout ~ isSample, all_l)) - mean(all_l$readout))^2), 5)
RSS <- round(sum(smu$residuals^2), 5)
RSS_df <- AnovaDFs[5]
MSEunr <- RSS / RSS_df
RMSEunr <- sqrt(RSS / RSS_df)
# Pure Err
FitAnova <- anova(lm(readout ~ factor(Conc) * isSample, all_l))
SSE <- sum(resid(lm(readout ~ factor(Conc) * isSample, all_l))^2) # =FitAnova[4,2]
SSE_df <- FitAnova[4, 1]
PureMSE <- SSE / SSE_df
RMSE_pure <- sqrt(PureMSE)
## non-lin = LoF
if (PureErrFlag) {
ERR <- PureMSE
ERR_df <- SSE_df
} else {
ERR <- MSEunr
ERR_df <- RSS_df
}
SSnonlin <- sum((predict(lm(readout ~ factor(Conc) * isSample, all_l)) - predPotU)^2)
LoF_df <- FitAnova[1, 1] + FitAnova[2, 1]
F_regr <- (SSregr / AnovaDFs[3]) / ERR
p_F_regr <- round(pf(F_regr, AnovaDFs[3], ERR_df, lower.tail = FALSE), 5)
if (ncol(ro_new) < 4) F_nonlin <- 0 else F_nonlin <- (SSnonlin / AnovaDFs[6]) / ERR
if (F_nonlin > 0) {
p_F_nonlin <- round(pf(F_nonlin, AnovaDFs[6], ERR_df, lower.tail = FALSE), 5)
} else {
p_F_nonlin <- "SSnonlin neg or single dilutions"
}
test_a <- test_b <- test_d <- test_ad <- logical()
RSS_r <- round(sum(smr$residuals^2), 5)
MSE_r <- RSS_r / (nrow(all_l) - 5)
RMSE_r <- round(sqrt(MSE_r), 6)
Dat$RMSE_r <- RMSE_r
Dat$RMSE_pure <- RMSE_pure
Dat$RMSE_unr <- round(RMSEunr, 6)
coeffs <- smu$coefficients[, 1]
# browser()
## EQ test on lower As diff
as <- coeffs["as"]
at <- coeffs["at"]
lAs_diff <- (at - as)
uCI_laDiff <- lAs_diff + qt(0.975, smu$df[2]) * sqrt(smu$coefficients["ds", 2]^2 + smu$coefficients["dt", 2]^2)
lCI_laDiff <- lAs_diff - qt(0.975, smu$df[2]) * sqrt(smu$coefficients["ds", 2]^2 + smu$coefficients["dt", 2]^2)
if (uCI_laDiff < Lim[[2]] & lCI_laDiff > Lim[[1]]) test_la_diff <- 0 else test_la_diff <- 1
#### EQ test on upper asymptote ratio ----
# as <- coeffs["as"]
# at <- coeffs["at"]
# uAsRatio <- compParm(potU, "a","/",display=F)
# uAsCI <- c(uAsRatio[1]-qt(0.975,RSS_df)*uAsRatio[2], uAsRatio[1]+qt(0.975,RSS_df)*uAsRatio[2])
# browser()
ds <- smu$coefficients["ds", 1]
dt <- smu$coefficients["dt", 1]
if (PureErrFlag) se_ds <- sqrt(VCOVpure["ds", "ds"]) else se_ds <- smu$coefficients["ds", 2]
if (PureErrFlag) se_dt <- sqrt(VCOVpure["dt", "dt"]) else se_dt <- smu$coefficients["dt", 2]
if (PureErrFlag) CoVarlog_d <- VCOVpure["dt", "ds"] else CoVarlog_d <- vcovMU["dt", "ds"]
if (PureErrFlag) DFs <- DFsPure else DFs <- nrow(all_l) - 8
uAsCI2 <- ParamCI_F(dt, ds, se_dt, se_ds, CoVarlog_d, DFs, Conf = 0.975)
if (uAsCI2[1] > Lim[[7]] & uAsCI2[2] < Lim[[8]]) test_a <- 0 else test_a <- 1
estUppA <- round(at / as, 5)
Dat$uAsCI <- uAsCI2
#### EQ test on slope ratio ----
# bs <- coeffs["bs"]
# bt <- coeffs["bt"]
# slopeRatio <- compParm(potU, "b","/",display=F)
# slopeCI <- c(slopeRatio[1,1]-qt(0.975,RSS_df)*slopeRatio[1,2], slopeRatio[1,1]+qt(0.975,RSS_df)*slopeRatio[1,2])
bs <- smu$coefficients["bs", 1]
bt <- smu$coefficients["bt", 1]
if (PureErrFlag) se_bs <- sqrt(VCOVpure["bs", "bs"]) else se_bs <- smu$coefficients["bs", 2]
if (PureErrFlag) se_bt <- sqrt(VCOVpure["bt", "bt"]) else se_bt <- smu$coefficients["bt", 2]
if (PureErrFlag) CoVarlog_b <- VCOVpure["bt", "bs"] else CoVarlog_b <- vcovMU["bt", "bs"]
slopeCI2 <- ParamCI_F(bt, bs, se_bt, se_bs, CoVarlog_b, DFs, Conf = 0.975)
if (slopeCI2[1] > Lim[[5]] & slopeCI2[2] < Lim[[6]]) test_b <- 0 else test_b <- 1
estUppA <- round(at / as, 5)
Dat$slopeRatioCI <- slopeCI2
#### EQ test on lower As ratio ----
# lAsRatio <- compParm(potU, "d","/",display=F)
# slopeCI <- c(lAsRatio[1,1]-qt(0.975,RSS_df)*lAsRatio[1,2], lAsRatio[1,1]+qt(0.975,RSS_df)*lAsRatio[1,2])
as <- smu$coefficients["as", 1]
at <- smu$coefficients["at", 1]
if (PureErrFlag) se_as <- sqrt(VCOVpure["as", "as"]) else se_as <- smu$coefficients["as", 2]
if (PureErrFlag) se_at <- sqrt(VCOVpure["at", "at"]) else se_at <- smu$coefficients["at", 2]
if (PureErrFlag) CoVarlog_a <- VCOVpure["at", "as"] else CoVarlog_a <- vcovMU["at", "as"]
lAsCI2 <- ParamCI_F(at, as, se_at, se_as, CoVarlog_a, DFs, Conf = 0.975)
if (lAsCI2[1] > Lim[[3]] & lAsCI2[2] < Lim[[4]]) test_d <- 0 else test_d <- 1
estLowA <- round(at / as, 5)
Dat$lAsCI <- lAsCI2
#### EQtest on ratio of As difference ----
AsDiffRatio <- (dt - at) / (ds - as)
dt_at <- (dt - at)
ds_as <- (ds - as)
se_ds_asPure <- sqrt(VCOVpure["as", "as"] + VCOVpure["ds", "ds"] - 2 * VCOVpure["as", "ds"])
se_dt_atPure <- sqrt(VCOVpure["at", "at"] + VCOVpure["dt", "dt"] - 2 * VCOVpure["at", "dt"])
se_ds_asRMSE <- sqrt(vcovMU["as", "as"] + vcovMU["ds", "ds"] - 2 * vcovMU["as", "ds"])
se_dt_atRMSE <- sqrt(vcovMU["at", "at"] + vcovMU["dt", "dt"] - 2 * vcovMU["at", "dt"])
if (PureErrFlag) se_ds_as <- se_ds_asPure else se_ds_as <- se_ds_asRMSE
if (PureErrFlag) se_dt_at <- se_dt_atPure else se_dt_at <- se_dt_atRMSE
AsDiffCI2 <- ParamCI_F(dt_at, ds_as, se_dt_at, se_ds_as, CoVar = 0, DFs, Conf = 0.975)
if (AsDiffCI2[1] > Lim[[11]] & AsDiffCI2[2] < Lim[[12]]) test_ad <- 0 else test_ad <- 1
estLowA <- round(at / as, 5)
Dat$up_lowAs <- abs(ds - as)
lowerCIlowerA <- lAsCI2[1]
lowerCIupperA <- uAsCI2[1]
upperCIlowerA <- lAsCI2[2]
upperCIupperA <- uAsCI2[2]
test_lowA <- test_d
test_uppA <- test_a
# browser()
res_tab <- data.frame(
test = c(
"F-test on sign. of regression*",
"EQ test on lower asymptotes difference",
"EQ test ratio of lower asymptotes",
"EQ test ratio of Hill slopes",
"EQ test ratio of upper asymptotes",
"F-test on Lack-of-Fit*",
"EQ test ratio of asymptote difference",
"geom. rel. CI restr. model",
"geom. rel. CI unrestr. model"
),
test_results = c(
ifelse(p_F_regr < 0.05, 0, 1), test_la_diff, test_lowA, test_b, test_uppA,
ifelse(p_F_nonlin > 1, 1, ifelse(p_F_nonlin < 0.05, 1, 0)), test_ad,
testPOTr, test_c
),
estimate = c(
round(p_F_regr, 3), round(lAs_diff, 5),
estLowA, round(bs / bt, 5), estUppA, p_F_nonlin,
round(dt_at / ds_as, 5), round(potAll2[1] * 100, 2), round(potAllU2[1] * 100, 2)
),
lower_limit = c("-", Lim[[1]], Lim[[3]], Lim[[5]], Lim[[7]], "-", Lim[[11]], Lim[[9]], Lim[[9]]),
upper_limit = c("-", Lim[[2]], Lim[[4]], Lim[[6]], Lim[[8]], "-", Lim[[12]], Lim[[10]], Lim[[10]]),
lower_CI = c(
RMSE_r, round(lCI_laDiff, 3), round(lAsCI2[1], 5), round(slopeCI2[1], 5),
round(uAsCI2[1], 5), "-", round(AsDiffCI2[1], 5), round(potAll2[2], 2), round(potAllU2[2], 2)
),
upper_CI = c(
RMSE_pure, round(uCI_laDiff, 3), round(lAsCI2[2], 5), round(slopeCI2[2], 5),
round(uAsCI2[2], 5), "-", round(AsDiffCI2[2], 5), round(potAll2[3], 2), round(potAllU2[3], 2)
)
)
return(res_tab)
}
#' ANOVA unrestricted model
#'
#' ANOVA with unrestricted model.
#'
#'
#' @param ro_new Data frame with the concentrations and the respective readouts.
#' @returns A data-frame with the analysis of variance.
#' @export
#' @examples
#'
#' ro_new <- data.frame(
#' REF1 = c(1547, 1620, 1644, 2504, 3426, 3512, 3401, 3787), REF2 = c(1492, 1536, 1384, 2286, 3046, 3479, 3516, 3497),
#' REF3 = c(1468, 1827, 1558, 2252, 3002, 3349, 2945, 3665),
#' TEST1 = c(1405, 1523, 1502, 1474, 2383, 3221, 3589, 3445), TEST2 = c(1420, 1516, 1544, 1512, 2226, 3219, 3327, 3591),
#' TEST3 = c(1399, 1376, 1588, 1475, 2148, 3083, 2942, 3466), log_dose = c(5.01, 3.401, 2.708, 2.015, 1.32176, 0.62861, -0.0645385, -1.6739764)
#' )
#'
#'
#' ANOVA4plUnresfunc(ro_new)
ANOVA4plUnresfunc <- function(ro_new) {
all_l <- melt(data.frame(ro_new), id.vars = "log_dose", variable.name = "replname", value.name = "readout")
all_len <- nrow(all_l)
isRef <- rep(c(1, 0), 1, each = all_len / 2)
isSample <- rep(c(0, 1), 1, each = all_len / 2)
all_l$isRef <- isRef
all_l$isSample <- isSample
all_l$Conc <- exp(all_l$log_dose)
all_l$readout[all_l$readout < 0] <- 0.01
FITs <- Fitting_FUNC(ro_new = ro_new, TransFlag = FALSE)
smr <- FITs[[1]]
smu <- FITs[[2]]
smrPREDs <- FITs[[5]]
smuPREDs <- FITs[[6]]
# pot <- drm(readout ~ Conc, isSample, data=all_l, fct=LL.4(names=c("b","d","a","c")),
# pmodels=data.frame(1,1,1,isSample))
# potU <- drm(readout ~ Conc, isSample, data=all_l, fct=LL.4(names=c("b","d","a","c")),
# pmodels=data.frame(isSample, isSample,isSample,isSample))
SStreat <- round(sum((smuPREDs - mean(all_l$readout))^2), 5)
SStreat_df <- length(unique(all_l$log_dose)) - 1
SSregr <- round(sum((smrPREDs - mean(all_l$readout))^2), 5)
## Non-parallel
SSnonparallel <- round(sum(smr$residuals^2) - sum(smu$residuals^2), 5)
## Preparation
SSprep <- round(sum((predict(lm(readout ~ isSample, all_l)) - mean(all_l$readout))^2), 5)
## Resid Err
RSS <- round(sum(smu$residuals^2), 5)
RSS_df <- nrow(all_l) - SStreat_df - 1
FitAnova <- anova(lm(readout ~ factor(Conc) * isSample, all_l))
# PureErr
SSE <- round(FitAnova[4, 3], 5)
SSE_df <- FitAnova[4, 1]
# Lack-of-Fit
SSnonlin <- round(sum((predict(lm(readout ~ factor(Conc) * isSample, all_l)) - smuPREDs)^2), 4)
LoF_df <- FitAnova[1, 1] + FitAnova[2, 1]
## Total
SStot <- round(sum((all_l$readout - mean(all_l$readout))^2), 5)
MSE <- RSS / RSS_df
noConc <- length(unique(all_l$Conc))
AnovaDFs <- c(noConc - 1, 1, 3, noConc - 4 - 1, nrow(all_l) - noConc, noConc, nrow(all_l) - noConc - noConc, nrow(all_l) - 1)
p_SStreat <- round(pf((SStreat / AnovaDFs[1]) / MSE, AnovaDFs[1], RSS_df, lower.tail = FALSE), 3)
p_SSprep <- round(pf((SSprep / AnovaDFs[2]) / MSE, AnovaDFs[2], RSS_df, lower.tail = FALSE), 3)
p_SSregr <- round(pf((SSregr / AnovaDFs[3]) / MSE, AnovaDFs[3], RSS_df, lower.tail = FALSE), 3)
p_SSnonp <- round(pf((SSnonparallel / AnovaDFs[4]) / MSE, AnovaDFs[3], RSS_df, lower.tail = FALSE), 3)
p_SSLoF <- round(pf((SSnonlin / LoF_df) / (SSE / SSE_df), LoF_df, SSE_df, lower.tail = FALSE), 5)
ANOVAtab <- data.frame(
Source = c(
"Treatment", "Preparation", "Regression",
"Non-Parallelism", "Residual Error", "Lack-of-Fit",
"Pure Error", "Total"
),
DF = AnovaDFs,
SumSquares = c(
SStreat, SSprep, SSregr, SSnonparallel,
RSS, SSnonlin, SSE, SStot
),
MeanSquares = c(
round(SStreat / AnovaDFs[1], 3), SSprep, round(SStreat / AnovaDFs[3], 3), round(SSnonparallel / AnovaDFs[4], 3),
round(MSE, 5), round(SSnonlin / LoF_df, 5), round(SSE / SSE_df, 5), ""
),
"F-value" = c(
round((SStreat / AnovaDFs[1]) / MSE, 5), round((SSprep / AnovaDFs[2]) / MSE, 5),
round((SSregr / AnovaDFs[3]) / MSE, 5), round((SSnonparallel / AnovaDFs[4]) / MSE, 5),
"", round((SSnonlin / LoF_df) / (SSE / SSE_df), 5), "", ""
),
"p_value" = c(round(p_SStreat, 3), p_SSprep, round(p_SSregr, 3), p_SSnonp, "", p_SSLoF, "", "")
)
return(ANOVAtab)
}
#' Calculates descriptive statistics per concentration
#'
#' Mean, SD, and CV% per concentration and product..
#'
#'
#' @param ro_new Data frame with the concentrations and the respective readouts.
#' @returns A data-frame with the concentrations and metadata.
#' @export
#' @examples
#'
#' ro_new <- data.frame(
#' REF1 = c(1547, 1620, 1644, 2504, 3426, 3512, 3401, 3787), REF2 = c(1492, 1536, 1384, 2286, 3046, 3479, 3516, 3497),
#' REF3 = c(1468, 1827, 1558, 2252, 3002, 3349, 2945, 3665),
#' TEST1 = c(1405, 1523, 1502, 1474, 2383, 3221, 3589, 3445), TEST2 = c(1420, 1516, 1544, 1512, 2226, 3219, 3327, 3591),
#' TEST3 = c(1399, 1376, 1588, 1475, 2148, 3083, 2942, 3466), log_dose = c(5.01, 3.401, 2.708, 2.015, 1.32176, 0.62861, -0.0645385, -1.6739764)
#' )
#'
#'
#' perConcTab(ro_new, noDilSeries = 3)
perConcTab <- function(ro_new, noDilSeries) {
Reftab <- ro_new[, c(1:noDilSeries)]
Testtab <- ro_new[, c((noDilSeries + 1):(2 * noDilSeries))]
tReftab <- t(Reftab)
colnames(tReftab) <- round(ro_new[, ncol(ro_new)], 5)
avs <- apply(tReftab, 2, mean)
sds <- apply(tReftab, 2, sd)
cv <- sds / avs * 100
tReftab2 <- rbind(tReftab, avs, sds, cv)
tTesttab <- t(Testtab)
colnames(tTesttab) <- round(ro_new[, ncol(ro_new)], 5)
avs_test <- apply(tTesttab, 2, mean)
sds_test <- apply(tTesttab, 2, sd)
cv_test <- sds_test / avs_test * 100
tTesttab2 <- rbind(tTesttab, avs_test, sds_test, cv_test)
concTab <- rbind(tReftab2, tTesttab2)
return(concTab)
}
#' Calculates dilution series.
#'
#' Recursive function to calcuate a geometric dilution series.
#'
#' @param x Starting concentration.
#' @param Div Divisor to get next concentration.
#' @param N Number of dilution step, increases.
#' @param res Vector of results.
#' @param noDil Final number of concentrations -1 (the initial one).
#' @returns A data-frame with the concentrations and metadata.
#' @export
#' @examples
#'
#' x <- 1
#' Div <- 3
#' N <- 0
#' res <- c()
#' noDil <- 7
#'
#' divFUN(x, Div, N, res, noDil)
divFUN <- function(x, Div, N, res, noDil) {
N <- N + 1
y <- x / Div
res <- c(res, y)
if (N == noDil) {
return(res)
}
divFUN(y, Div, N, res, noDil)
}