---
title: "Growth analysis report"
date: "`r format(Sys.time(), '%d %B, %Y')`"
geometry: margin=0.8cm
urlcolor: blue
mainfont: Arial
header-includes:
  - \usepackage{booktabs}
  - \usepackage{makecell}
  - \usepackage{longtable}
  - \usepackage{colortbl}

output:
  pdf_document:
    fig_caption: yes
    toc: false
    latex_engine: xelatex
  html_document:
    toc: true
    toc_float: true
    theme: united
---

```{r setup, include=FALSE}

dir.create(paste0(tempdir(),"/Plots"), showWarnings = F)
wd.plots <- paste0(wd,"/Plots")

if(parallelize){
  library(doParallel, quietly =  TRUE)
  library(foreach, quietly =  TRUE)
  cl <- parallel::makeCluster(parallel::detectCores(all.tests = FALSE, logical = TRUE)-1)
  doParallel::registerDoParallel(cl)
}
knitr::opts_chunk$set(dev = "pdf")
knitr::opts_chunk$set(tidy.opts=list(width.cutoff=80), tidy=TRUE)
knit_table <- function(df, caption){
  if (knitr::is_html_output()) {
    DT::datatable(df, caption = caption, filter = 'top', escape = FALSE,
                  extensions = c('FixedColumns',"FixedHeader"),
                  options = list(scrollX = FALSE, 
                                 paging=TRUE,
                                 pageLength = 15,
                                 fixedHeader=TRUE))
  } else {
    colnames(df) <- colnames(df) %>% str_replace_all(.,"<br>", "\n") %>%  str_replace_all(., "_", "\\\\char`_") %>% str_replace_all(., "µ<sub>max</sub>", "$\\\\mu_{max}$") %>% str_replace_all(., "λ", "$\\\\lambda$") %>% str_replace_all(., "Δ", "$\\\\Delta$") %>% str_replace_all(., "t<sub>start</sub>", "$t_{start}$") %>% str_replace_all(., "y<sub>0</sub>", "$y_{0}$") %>% str_replace_all(., "t<sub>D</sub>", "$t_{D}$") %>% str_replace_all(., "t<sub>end</sub>", "$t_{end}$") %>% str_replace_all(., "R<sup>2</sup>", "$R^2$") %>% str_replace_all(., "α", "$\\\\alpha$") %>% str_replace_all(., "t<sub>shift</sub>", "$t_{shift}$") %>% str_replace_all(., "ν", "$\\\\nu$") %>% str_replace_all(., "y<sub>max</sub>", "y$_{max}$") %>% str_replace_all(., "t<sub>max</sub>", "t$_{max}$") 
    colnames(df) <- kableExtra::linebreak(colnames(df), align = "c")
    for(i in 2:ncol(df)){
      df[,i] <- df[,i] %>% str_replace_all(., "^<b>", "\\\\textbf\\{") %>% str_replace_all(., "</b>", "\\}") 
    }
    df[,1] <- str_replace_all(df[,1], "_", "\\\\char`_") %>% str_replace_all(., "%", "\\\\%") 
    df %>% knitr::kable("latex", align = "c", booktabs = T, escape = F, linesep = "",  caption = caption, longtable = TRUE) %>% kableExtra::kable_styling(latex_options = c("hold_position", "repeat_header", "striped"), full_width = F, position = "center", font_size = 8)
  }
}
```
## Summary
The dataset contains _`r nrow(grofit[["time"]])`_ samples.\

_`r length(levels(grofit[["data"]][["condition"]]))`_ conditions were identified:\
`r colFmt(levels(grofit[["data"]][["condition"]]), 'NavyBlue')`\

_`r length(levels(grofit[["data"]][["concentration"]]))`_ different concentrations were identified:\
`r colFmt(levels(grofit[["data"]][["concentration"]]), 'NavyBlue')`\

The following parameters were used to fit the data: 

* minimum density considered: `r colFmt(ifelse(!is.null(grofit$control$min.density), grofit$control$min.density, "none"), 'NavyBlue')`
* minimum time considered for linear and spline fits (t0): `r colFmt(control$tmax, 'NavyBlue')`
* maximum density considered: `r colFmt(ifelse(!is.null(grofit$control$max.density), grofit$control$max.density, "none"), 'NavyBlue')`
* maximum time considered for linear and spline fits (tmax): `r colFmt(control$tmax, 'NavyBlue')`
* log-transform density values for linear fits: `r colFmt(grofit$control$log.y.lin, 'NavyBlue')`
* log-transform density values for spline fits: `r colFmt(grofit$control$log.y.spline, 'NavyBlue')`
* log-transform density values for parametric fits: `r colFmt(grofit$control$log.y.model, 'NavyBlue')`
* log-transform time values: `r colFmt(grofit$control$log.x.gc, 'NavyBlue')`
* perform dose-response analysis: `r colFmt(ec50, 'NavyBlue')`
`r if(ec50){paste0("* parameter used for dose-response analysis:")}` `r if(ec50){colFmt(control$dr.parameter, 'NavyBlue')}`
* growth threshold: `r colFmt(grofit$control$growth.thresh, 'NavyBlue')` * start_density
`r if(any(c("a", "l") %in% control$fit.opt)){paste0("* sliding window size in linear regression:")}` `r if(any(c("a", "l") %in% control$fit.opt)){colFmt(ifelse(!is.null(grofit$control$lin.h), grofit$control$lin.h, "automated calculation"), 'NavyBlue')}`
`r if(any(c("a", "l") %in% control$fit.opt)){paste0("* R2 threshold for linear regression:")}` `r if(any(c("a", "l") %in% control$fit.opt)){colFmt(grofit$control$lin.R2, 'NavyBlue')}`
`r if(any(c("a", "l") %in% control$fit.opt)){paste0("* RSD threshold for linear regression:")}` `r if(any(c("a", "l") %in% control$fit.opt)){colFmt(grofit$control$lin.RSD, 'NavyBlue')}`
`r if(any(c("a", "l") %in% control$fit.opt)){paste0("* Relative ΔY threshold for linear regression:")}` `r if(any(c("a", "l") %in% control$fit.opt)){colFmt(grofit$control$lin.dY, 'NavyBlue')}`

\pagebreak

## Growth fit results

### Grouped results
```{r table_linear_group, echo=F, warning=F, message=F, results='asis'}
if(any(c("a", "l") %in% control$fit.opt)){
  if(!all(is.na(res.table.gc$lambda.linfit))){
    table_linear_group <- table_group_growth_linear(res.table.gc,html = F)
    table_linear_group <- as.data.frame(apply(table_linear_group, 2, function(x) str_replace_all(x, "NA ± NA", "")))
    table_linear_group[is.na(table_linear_group)] <- ""
    if (knitr::is_html_output()) {
      knit_table(table_linear_group, caption = ifelse(control$biphasic, "Linear Fit (Values in parentheses indicate parameters for secondary growth phase)", "Linear Fit"))
    } else {
      knit_table(table_linear_group, caption = ifelse(control$biphasic, "Linear Fit (Values in parentheses indicate parameters for secondary growth phase)", "Linear Fit")) %>% kableExtra::column_spec(column=1, width = "4cm")
    }
  }
}
```
```{r parameter_plot_linear, fig.width=10, fig.height = 6, echo=F, warning=F, message=F, results='asis', fig.align='default', eval = any(c("a", "l") %in% control$fit.opt)}
try(plot.parameter(grofit, param = "mu.linfit", export = export, out.dir = normalizePath(wd.plots)))
try(plot.parameter(grofit, param = "lambda.linfit", export = export, out.dir = normalizePath(wd.plots)))
try(plot.parameter(grofit, param = "dY.linfit", export = export, out.dir = normalizePath(wd.plots)))
 
```
`r if(any(c("a", "l") %in% control$fit.opt)){"\\clearpage"}`
```{r table_model_group, echo=F, warning=F, message=F, results='asis', fig.align='center'}
if(any(c("a", "b", "m") %in% control$fit.opt)){
  if(!all(is.na(res.table.gc$lambda.model))){
    table_model_group <- table_group_growth_model(res.table.gc,html = F)
    
    table_model_group <- as.data.frame(apply(table_model_group, 2, function(x) str_replace_all(x, "NA ± NA", "")))
    table_model_group[is.na(table_model_group)] <- ""
    if (knitr::is_html_output()) {
      knit_table(table_model_group, caption = "Parametric Fit")
    } else {
      knit_table(table_model_group, caption = "Parametric Fit") %>% kableExtra::column_spec(column=1, width = "4cm")
    }
  }
}
```
```{r parameter_plot_model, fig.width=10, fig.height = 6, echo=F, warning=F, message=F, results='asis', fig.align='default', eval = any(c("a", "m") %in% control$fit.opt)}
try(plot.parameter(grofit, param = "mu.model", export = export, out.dir = normalizePath(wd.plots)))
try(plot.parameter(grofit, param = "lambda.model", export = export, out.dir = normalizePath(wd.plots)))
 
```
`r if(any(c("a", "m") %in% control$fit.opt)){"\\clearpage"}`
```{r table_spline_group, echo=F, warning=F, message=F, results='asis', fig.align='center'}
if(any(c("a", "b", "s") %in% control$fit.opt)){
  if(!all(is.na(res.table.gc$lambda.spline))){
    table_spline_group <- table_group_growth_spline(res.table.gc,html = F)
    
    table_spline_group <- as.data.frame(apply(table_spline_group, 2, function(x) str_replace_all(x, "NA ± NA", "")))
    table_spline_group[is.na(table_spline_group)] <- ""
    if (knitr::is_html_output()) {
      knit_table(table_spline_group, caption = ifelse(control$biphasic, "Smooth Spline Fit (Values in parentheses indicate parameters for secondary growth phase)", "Smooth Spline Fit"))
    } else {
      knit_table(table_spline_group, caption = ifelse(control$biphasic, "Smooth Spline Fit (Values in parentheses indicate parameters for secondary growth phase)", "Smooth Spline Fit")) %>% kableExtra::column_spec(column=1, width = "4cm")
    }
  }
}
```
```{r parameter_plot_spline, fig.width=10, fig.height = 6, echo=F, warning=F, message=F, results='asis', fig.align='default', eval = any(c("a", "s") %in% control$fit.opt)}
try(plot.parameter(grofit, param = "mu.spline", export = export, out.dir = normalizePath(wd.plots)))
try(plot.parameter(grofit, param = "lambda.spline", export = export, out.dir = normalizePath(wd.plots)))
try(plot.parameter(grofit, param = "dY.spline", export = export, out.dir = normalizePath(wd.plots)))
 
```
\clearpage

### Individual samples
```{r table_linear, echo=F, warning=F, message=F, results='asis'}
if(any(c("a", "l") %in% control$fit.opt)){
  if(!all(is.na(res.table.gc$lambda.linfit))){
    table_linear <- data.frame("Sample|Replicate|Conc." = paste(res.table.gc$TestId, res.table.gc$AddId, res.table.gc$concentration, sep = "|"),
                               
                               "µ<sub>max</sub>" = ifelse(res.table.gc$mu.linfit==0 | is.na(res.table.gc$mu.linfit), "", ifelse(is.na(res.table.gc$mu2.linfit), round(as.numeric(res.table.gc$mu.linfit), 3), paste0("<b>", round(as.numeric(res.table.gc$mu.linfit), 3), "</b>", " (", round(as.numeric(res.table.gc$mu2.linfit), 3), ")"))),
                               
                               "t<sub>D</sub>" = ifelse(res.table.gc$mu.linfit==0 | is.na(res.table.gc$mu.linfit), "",  ifelse(is.na(res.table.gc$mu2.linfit), round(log(2)/as.numeric(res.table.gc$mu.linfit), 2), paste0("<b>", round(log(2)/as.numeric(res.table.gc$mu.linfit), 2), "</b>", " (", round(log(2)/as.numeric(res.table.gc$mu2.linfit), 2), ")"))),
                               
                               "λ" = round(as.numeric(res.table.gc$lambda.linfit), 2), 
                               
                               
                               "ΔY" = round(as.numeric(res.table.gc$dY.linfit), 3),
                               
                               
                               "y<sub>max</sub>" = round(as.numeric(res.table.gc$A.linfit), 3),
                               
                               
                               "t<sub>start</sub><br>(µ<sub>max</sub>)" = ifelse(is.na(res.table.gc$mu2.linfit), round(as.numeric(res.table.gc$tmu.start.linfit), 2), paste0("<b>", round(as.numeric(res.table.gc$tmu.start.linfit), 2), "</b>", " (", round(as.numeric(res.table.gc$tmu2.start.linfit), 2), ")")),
                               
                               
                               "t<sub>end</sub><br>(µ<sub>max</sub>)" = ifelse(is.na(res.table.gc$mu2.linfit), round(as.numeric(res.table.gc$tmu.end.linfit), 2), paste0("<b>", round(as.numeric(res.table.gc$tmu.end.linfit), 2), "</b>", " (", round(as.numeric(res.table.gc$tmu2.end.linfit), 2), ")")),
                               
                               
                               
                               "R<sup>2</sup><br>(linear fit)" = ifelse(is.na(res.table.gc$mu2.linfit), round(as.numeric(res.table.gc$r2mu.linfit), 3), paste0("<b>", round(as.numeric(res.table.gc$r2mu.linfit), 3), "</b>", " (", round(as.numeric(res.table.gc$r2mu2.linfit), 3), ")")),
                               
                               
                               stringsAsFactors = F, check.names = F)
    table_linear <- as.data.frame(apply(table_linear, 2, function(x) str_replace_all(x, "NA ± NA", "")))
    table_linear[is.na(table_linear)] <- ""
    if (knitr::is_html_output()) {
      knit_table(table_linear, caption = ifelse(control$biphasic, "Linear Fit (Values in parentheses indicate parameters for secondary growth phase)", "Linear Fit"))
    } else {
      knit_table(table_linear, caption = ifelse(control$biphasic, "Linear Fit (Values in parentheses indicate parameters for secondary growth phase)", "Linear Fit")) %>% kableExtra::column_spec(column=1, width = "4cm")
    }
  }
}
```
`r if(any(c("a", "l") %in% control$fit.opt)){"\\clearpage"}`
```{r table_model, echo=F, warning=F, message=F, results='asis', fig.align='center'}
if(any(c("a", "b", "m") %in% control$fit.opt)){
  if(!all(is.na(res.table.gc$lambda.model))){
    table_model <- suppressWarnings(data.frame("Sample|Replicate|Conc." = paste(res.table.gc$TestId, res.table.gc$AddId, res.table.gc$concentration, sep = "|"),
                                               "Model" = res.table.gc$used.model,
                                               "µ<sub>max</sub>" = ifelse(res.table.gc$mu.model==0 | is.na(res.table.gc$mu.model), "", paste(round(as.numeric(res.table.gc$mu.model), 3),"\u00B1", round(as.numeric(res.table.gc$stdmu.model),3))),
                                               "t<sub>D</sub>" = paste(ifelse(res.table.gc$mu.model==0 | is.na(res.table.gc$mu.model), "", paste(round(log(2)/as.numeric(res.table.gc$mu.model), 2), "\u00B1", round(sqrt(((-log(2)*as.numeric(res.table.gc$stdmu.model))/(as.numeric(res.table.gc$mu.model))^2)^2), 2)))),
                                               "λ" = paste(round(as.numeric(res.table.gc$lambda.model), 2), "\u00B1", round(as.numeric(res.table.gc$stdlambda.model),3)),
                                               "A" = paste(round(as.numeric(res.table.gc$A.model), 3), "\u00B1", round(as.numeric(res.table.gc$stdA.model),3)),
                                               stringsAsFactors = F, check.names = F))
    if ( "richards" %in% res.table.gc$used.model  ){
      table_model <- suppressWarnings(cbind(table_model, data.frame("ν" = round(as.numeric(res.table.gc$parameter_nu.model), 3), stringsAsFactors = F, check.names = F)))
    }
    if ( "gompertz" %in% res.table.gc$used.model ){
      table_model <- suppressWarnings(cbind(table_model, data.frame("α" = round(as.numeric(res.table.gc$parameter_alpha.model), 3), stringsAsFactors = F, check.names = F)))
    }
    if ( "gompertz.exp" %in% res.table.gc$used.model ){
      table_model <- suppressWarnings(cbind(table_model, data.frame("t<sub>shift</sub>" = round(as.numeric(res.table.gc$parameter_t_shift.model), 3), stringsAsFactors = F, check.names = F)))
    }
    if ( "baranyi" %in% res.table.gc$used.model || "huang" %in% res.table.gc$used.model ){
      table_model <- suppressWarnings(cbind(table_model, data.frame("y<sub>0</sub>" = round(as.numeric(res.table.gc$parameter_y0.model), 3), stringsAsFactors = F, check.names = F)))
    }
    table_model <- as.data.frame(apply(table_model, 2, function(x) str_replace_all(x, "NA ± NA", "")))
    table_model[is.na(table_model)] <- ""
    if (knitr::is_html_output()) {
      knit_table(table_model, caption = "Parametric Fit")
    } else {
      knit_table(table_model, caption = "Parametric Fit") %>% kableExtra::column_spec(column=1, width = "4cm")
    }
  }
}
```
`r if(any(c("a", "m") %in% control$fit.opt)){"\\clearpage"}`
```{r table_spline, echo=F, warning=F, message=F, results='asis', fig.align='center'}
if(any(c("a", "b", "s") %in% control$fit.opt)){
  if(!all(is.na(res.table.gc$lambda.spline))){
    table_spline <- data.frame("Sample|Replicate|Conc." = paste(res.table.gc$TestId, res.table.gc$AddId, res.table.gc$concentration, sep = "|"),
                               
                               "µ<sub>max</sub>" = ifelse(res.table.gc$mu.spline==0 | is.na(res.table.gc$mu.spline), "", ifelse(is.na(res.table.gc$mu2.spline), round(as.numeric(res.table.gc$mu.spline), 3), paste0("<b>", round(as.numeric(res.table.gc$mu.spline), 3), "</b>", " (", round(as.numeric(res.table.gc$mu2.spline), 3), ")"))),
                               
                               "t<sub>D</sub>" = ifelse(res.table.gc$mu.spline==0 | is.na(res.table.gc$mu.spline), "",  ifelse(is.na(res.table.gc$mu2.spline), round(log(2)/as.numeric(res.table.gc$mu.spline), 2), paste0("<b>", round(log(2)/as.numeric(res.table.gc$mu.spline), 2), "</b>", " (", round(log(2)/as.numeric(res.table.gc$mu2.spline), 2), ")"))),
                               
                               "λ" = round(as.numeric(res.table.gc$lambda.spline), 2), 
                               
                               "y<sub>max</sub>" = round(as.numeric(res.table.gc$A.spline), 3),
                               
                               "ΔY" = round(as.numeric(res.table.gc$dY.spline), 3),
                               
                               "t<sub>max</sub>" = ifelse(is.na(res.table.gc$mu2.spline), round(as.numeric(res.table.gc$tmax.spline), 2), paste0("<b>", round(as.numeric(res.table.gc$tmax.spline), 2), "</b>", " (", round(as.numeric(res.table.gc$tmax2.spline), 2), ")")),
                               
                               "smooth.<br>fac" = res.table.gc$smooth.spline,
                               
                               stringsAsFactors = F, check.names = F)
    if ( grofit$control$nboot.gc > 1 ){
      table_spline <- cbind(table_spline, data.frame("µ<sub>max</sub><br>boot" = paste(round(as.numeric(res.table.gc$mu.bt), 3),"\u00B1", round(as.numeric(res.table.gc$stdmu.bt),3)), 
                                                     "λ<br>boot" = paste(round(as.numeric(res.table.gc$lambda.bt), 2),"\u00B1", round(as.numeric(res.table.gc$stdlambda.bt),2)),
                                                     "A<br>boot" = paste(round(as.numeric(res.table.gc$A.bt), 3),"\u00B1", round(as.numeric(res.table.gc$stdA.bt),3)),
                                                     stringsAsFactors = F, check.names = F))
    }
    table_spline <- as.data.frame(apply(table_spline, 2, function(x) str_replace_all(x, "NA ± NA", "")))
    table_spline[is.na(table_spline)] <- ""
    if (knitr::is_html_output()) {
      knit_table(table_spline, caption = ifelse(control$biphasic, "Smooth Spline Fit (Values in parentheses indicate parameters for secondary growth phase)", "Smooth Spline Fit"))
    } else {
      knit_table(table_spline, caption = ifelse(control$biphasic, "Smooth Spline Fit (Values in parentheses indicate parameters for secondary growth phase)", "Smooth Spline Fit")) %>% kableExtra::column_spec(column=1, width = "4cm")
    }
  }
}
```
\clearpage

## Plots
### `r if(any(c("a", "l") %in% control$fit.opt)){"Linear Fits"}`
```{r figure_linear, out.width = "33%", fig.show='hold', echo=F, warning=F, message=F, results='asis', fig.align='default'}
if(any(c("a", "l") %in% control$fit.opt)){
  plot.ggLinear <- function(){
    if(grofit[["gcFit"]][["gcFittedLinear"]][[i]][["fitFlag"]] == TRUE){
      x <- grofit[["gcFit"]][["gcFittedLinear"]][[i]]
      coef <- x[["par"]]
      lagtime <- coef["lag"]
      tangent.time  <- seq(lagtime, max(x[["raw.time"]]), length=200)
      
      fit_df <- data.frame("time" = x[["raw.time"]][x$ndx],
                           "y" = x[["raw.data"]][x$ndx] )
      
      tangent.df <- data.frame("time" = tangent.time,
                               "y" = coef["y0_lm"] * exp(coef["mumax"]*tangent.time) )
      
      df <- data.frame("time" = x[["raw.time"]],
                       "data" = x[["raw.data"]])
      
      df.lagtime <- data.frame("time" = c(x[["raw.time"]][x[["raw.time"]]>=control$t0][1], lagtime),
                               "y" = c(x[["raw.data"]][x[["raw.time"]]>=control$t0][1], x[["raw.data"]][x[["raw.time"]]>=control$t0][1]))
      
      # Plot raw data points
      p <-    ggplot(df, aes(x = time, y = data)) +
        geom_point(shape = 1, size = 1.7, alpha = 0.25, stroke=0.15) +
        xlab("Time") +
        ylab("Growth (density)") +
        theme_classic(base_size = 16) +
        scale_x_continuous(breaks = scales::pretty_breaks(n = 10)) +
        ggtitle(gsub(" \\| NA", "", paste(x$gcID, collapse=" | "))) +
        theme(
          plot.title = element_text(size = 20),
          panel.grid.major = element_blank(),
          panel.grid.minor = element_blank()
        )
      
      #color max µ points
      p <-  p + geom_point(
        aes(x = time, y = y),
        data = fit_df,
        size = 2, shape = 21, stroke=0.25, fill = "firebrick", color = ggplot2::alpha("black", 0.7)) +
        scale_y_continuous(trans = 'log',
                           breaks = QurvE:::base_breaks(),
                           expand = ggplot2::expansion(mult = c(0.05, 0.05)))
      
      
      
      
      if(x$fitFlag2){
        lagtime2 <- coef["lag2"]
        fit_df2 <- data.frame("time" = x[["raw.time"]][x$ndx2],
                              "y" = x[["raw.data"]][x$ndx2] )
        df.lagtime2 <- data.frame("time" = c(x[["raw.time"]][1], lagtime2),
                                  "y" = c(x[["raw.data"]][1], x[["raw.data"]][1]))
        #color µ2 points
        p <-  p + geom_point(
          aes(x = time, y = y),
          data = fit_df2,
          size = 2, shape = 21, stroke=0.25, fill = "magenta3", color = ggplot2::alpha("black", 0.7)) +
          scale_y_continuous(trans = 'log',
                             breaks = QurvE:::base_breaks(),
                             expand = ggplot2::expansion(mult = c(0.05, 0.05)))
        
        p.yrange.end <- exp(ggplot_build(p)$layout$panel_params[[1]]$y.range[2])
        
        if(lagtime2 < lagtime){
          tangent.time2  <- seq(lagtime2, max(x[["raw.time"]]), length=200)
          tangent.time <- seq(coef["tmax_start"]-0.25*(coef["tmax_end"]-coef["tmax_start"]), max(x[["raw.time"]]), length=200)
          tangent.df <- data.frame("time" = tangent.time,
                                   "y" = coef["y0_lm"] * exp(coef["mumax"]*tangent.time) )
          tangent.df2 <- data.frame("time" = tangent.time2,
                                    "y" = coef["y0_lm2"] * exp(coef["mumax2"]*tangent.time2) )
          # add tangent at µmax2
          p <- p + geom_segment(aes(x = time[1],y = y[1], xend = time[which.min(abs(exp(y) - exp(p.yrange.end)))], yend = y[which.min(abs(exp(y) - exp(p.yrange.end)))]),
                                data = tangent.df2,
                                linetype = "dashed",
                                color = ggplot2::alpha("magenta3", 0.85),
                                size = 0.3)
          
          #add lag time indicator at µmax2
          p <- p + geom_segment(
            aes(x = time[1], y = y[1], xend = time[2], yend = y[2]),
            data = df.lagtime2,
            linetype = "dashed",
            color = ggplot2::alpha("magenta3", 0.85),
            size = 0.3)
          
          # add tangent at µmax
          p <- p + geom_segment(aes(x = time[1],y = y[1], xend = time[which.min(abs(exp(y) - exp(p.yrange.end)))], yend = y[which.min(abs(exp(y) - exp(p.yrange.end)))]),
                                data = tangent.df,
                                linetype = "dashed",
                                color = ggplot2::alpha("firebrick", 0.85),
                                size = 0.3)
          
        } else {
          tangent.time2 <- seq(coef["tmax2_start"]-0.25*(coef["tmax2_end"]-coef["tmax2_start"]), max(x[["raw.time"]]), length=200)
          tangent.time <- seq(lagtime, max(x[["raw.time"]]), length=200)
          tangent.df <- data.frame("time" = tangent.time,
                                   "y" = coef["y0_lm"] * exp(coef["mumax"]*tangent.time) )
          tangent.df2 <- data.frame("time" = tangent.time2,
                                    "y" = coef["y0_lm2"] * exp(coef["mumax2"]*tangent.time2) )
          
          # add tangent at µmax
          p <- p + geom_segment(aes(x = time[1],y = y[1], xend = time[which.min(abs(exp(y) - exp(p.yrange.end)))], yend = y[which.min(abs(exp(y) - exp(p.yrange.end)))]),
                                data = tangent.df,
                                linetype = "dashed",
                                color = ggplot2::alpha("firebrick", 0.85),
                                size = 0.3)
          
          #add lag time indicator at µmax
          p <- p + geom_segment(
            aes(x = time[1], y = y[1], xend = time[2], yend = y[2]),
            data = df.lagtime,
            linetype = "dashed",
            color = ggplot2::alpha("firebrick", 0.85),
            size = 0.3)
          
          # add tangent at µmax2
          p <- p + geom_segment(aes(x = time[1],y = y[1], xend = time[which.min(abs(exp(y) - exp(p.yrange.end)))], yend = y[which.min(abs(exp(y) - exp(p.yrange.end)))]),
                                data = tangent.df2,
                                linetype = "dashed",
                                color = ggplot2::alpha("magenta3", 0.85),
                                size = 0.3)
        }
      } else {
        p.yrange.end <- exp(ggplot_build(p)$layout$panel_params[[1]]$y.range[2])
        p <- ggplot(df, aes(x = time, y = data)) +
          geom_point(shape = 1, size = 1.7, alpha = 0.25, stroke=0.15) +
          xlab("Time") +
          ylab("Growth (density)") +
          theme_classic(base_size = 16) +
          scale_x_continuous(breaks = scales::pretty_breaks(n = 10)) +
          ggtitle(gsub(" \\| NA", "", paste(x$gcID, collapse=" | "))) +
          theme(
            plot.title = element_text(size = 20),
            panel.grid.major = element_blank(),
            panel.grid.minor = element_blank()
          )
        
        p <-
          p + geom_point(
            aes(x = time, y = y),
            data = fit_df,
            size = 2, shape = 21, stroke=0.25, fill = "firebrick", color = ggplot2::alpha("black", 0.7)) +
          scale_y_continuous(trans = 'log',
                             breaks = QurvE:::base_breaks(),
                             expand = ggplot2::expansion(mult = c(0.05, 0.05)))
        
        p.yrange.end <- exp(ggplot_build(p)$layout$panel_params[[1]]$y.range[2])
        p <- p + geom_segment(
          aes(
            x = time[1],
            y = y[1],
            xend = time[which.min(abs(exp(y) - exp(p.yrange.end)))],
            yend = y[which.min(abs(exp(y) - exp(p.yrange.end)))]
          ),
          data = tangent.df,
          linetype = "dashed",
          color = ggplot2::alpha("firebrick3", 0.85),
          size = 0.3
        )
        
        p <- p + geom_segment(
          aes(
            x = time[1],
            y = y[1],
            xend = time[2],
            yend = y[2]
          ),
          data = df.lagtime,
          linetype = "dashed",
          color = ggplot2::alpha("firebrick3", 0.85),
          size = 0.3
        )
      }
      
      print(p)
    }
  }
  plotdir <- ifelse(export == TRUE, wd.plots, paste0(str_replace_all(tempdir(), "\\\\", "/"),"/Plots"))
  if(all(c('pdf', 'html') %in% format)){
    if (knitr::is_latex_output()) {
      if(parallelize){
        foreach(i = 1:length(grofit[["gcFit"]][["gcFittedLinear"]]),
                .packages = "ggplot2") %dopar% {
                  if(grofit[["gcFit"]][["gcFittedLinear"]][[i]][["fitFlag"]] == TRUE){
                    pdf(file=paste0(plotdir, "/PlotLinear_", gsub("∙|\\n|\\r", "_", gsub("\\?", "_", gsub(" ", "_", gsub("\\/", "_", gsub(" \\| ", "_", names(grofit[["gcFit"]][["gcFittedLinear"]])[i]))))), ".pdf"), width = 6, height = 4.5);   plot.ggLinear();   invisible(grDevices::dev.off())
                  }
                }
      } else {
        for(i in 1:length(grofit[["gcFit"]][["gcFittedLinear"]])){
          if(grofit[["gcFit"]][["gcFittedLinear"]][[i]][["fitFlag"]] == TRUE){
            pdf(file=paste0(plotdir, "/PlotLinear_", gsub("∙|\\n|\\r", "_", gsub("\\?", "_", gsub(" ", "_", gsub("\\/", "_", gsub(" \\| ", "_", names(grofit[["gcFit"]][["gcFittedLinear"]])[i]))))), ".pdf"), width = 6, height = 4.5);   plot.ggLinear();   invisible(grDevices::dev.off())
          }
        }
      }
    }
  } else{
    if(parallelize){
      foreach(i = 1:length(grofit[["gcFit"]][["gcFittedLinear"]]),
              .packages = "ggplot2") %dopar% {
                if(grofit[["gcFit"]][["gcFittedLinear"]][[i]][["fitFlag"]] == TRUE){
                  pdf(file=paste0(plotdir, "/PlotLinear_", gsub("∙|\\n|\\r", "_", gsub("\\?", "_", gsub(" ", "_", gsub("\\/", "_", gsub(" \\| ", "_", names(grofit[["gcFit"]][["gcFittedLinear"]])[i]))))), ".pdf"), width = 6, height = 4.5);   plot.ggLinear();   invisible(grDevices::dev.off())
                }
              }
    } else {
      for(i in 1:length(grofit[["gcFit"]][["gcFittedLinear"]])){
        if(grofit[["gcFit"]][["gcFittedLinear"]][[i]][["fitFlag"]] == TRUE){
          pdf(file=paste0(plotdir, "/PlotLinear_", gsub("∙|\\n|\\r", "_", gsub("\\?", "_", gsub(" ", "_", gsub("\\/", "_", gsub(" \\| ", "_", names(grofit[["gcFit"]][["gcFittedLinear"]])[i]))))), ".pdf"), width = 6, height = 4.5);   plot.ggLinear();   invisible(grDevices::dev.off())
        }
      }
    }
  } 
  
  Files_list <- list.files(path = plotdir, 
                           pattern = "^PlotLinear_",
                           full.names = TRUE)
  sort.ndx <- match(gsub("∙|\\n|\\r", "_", gsub("%", "_", gsub("\\?", "_", gsub(" ", "_", gsub("\\/", "_", gsub(" \\| ", "_", names(grofit$gcFit$gcFittedLinear))))))), gsub(".+PlotLinear_","", gsub(".pdf", "", Files_list)))
  sort.ndx <- sort.ndx[!is.na(sort.ndx)]
  
  knitr::include_graphics(Files_list[sort.ndx], dpi = 300, error = F)
}
 
```
`r if(any(c("a", "b", "m") %in% control$fit.opt)){"\\clearpage"}`

### `r if(any(c("a", "b", "m") %in% control$fit.opt)){"Parametric Fits"}`
```{r figure_model, out.width = "33%", fig.show='hold', echo=F, warning=F, message=F, results='asis', fig.align='default'}
if(any(c("a", "b", "m") %in% control$fit.opt)){
  plot.ggModel <- function(){
    if(grofit[["gcFit"]][["gcFittedModels"]][[i]][["fitFlag"]] == TRUE){
      x <- grofit[["gcFit"]][["gcFittedModels"]][[i]]
      coef <- x[["parameters"]]
      lagtime <- coef["lambda"][[1]][1]
      model <- as.character(x$model)
      # assign(paste(model.vec), x[["fit.data"]])
      df <- data.frame("time" = x[["raw.time"]],
                       "data" = x[["raw.data"]],
                       "fit.time" = x[["fit.time"]],
                       "fit.data" = x[["fit.data"]])
      
      p <-    ggplot(df, aes(x=time, y=data)) +
        geom_point(shape=1, size = 2,alpha = 0.5, stroke=0.15) + 
        geom_line(aes_(x=as.name(names(df)[3]), y = as.name(names(df)[4]), color = "model"), size = 0.7) +
        xlab("Time") +
        ylab(label = ifelse(x$control$log.y.model == TRUE, "Growth [Ln(y(t)/y0)]", "Growth [y(t)]")) +
        theme_classic(base_size = 16) +
        ggtitle(gsub(" \\| NA", "", paste(x$gcID, collapse=" | "))) +
        scale_x_continuous(breaks = scales::pretty_breaks(n = 10)) + 
        scale_y_continuous(breaks = scales::pretty_breaks()) + 
        theme(plot.title = element_text(size=15),
              panel.grid.major = element_blank(),
              panel.grid.minor = element_blank())
      
      if(x$model == "logistic"){
        p <- p + annotate(
          "text",
          label = "y(t) == frac(A , 1+exp(frac(4 %.% mu, A) %.% (lambda - t) + 2))",
          x = 1.05 * x$raw.time[length(x$raw.time)],
          y = 0.5 * ggplot_build(p)$layout$panel_params[[1]]$y.range[2],
          angle = 90, parse = TRUE, size = 3.2) +
          annotate("text",
                   label = bquote(A == .(round(x$parameters$A[1],3)) ~~~~ mu == .(round(x$parameters$mu[1],3)) ~~~~
                                    lambda == .(round(x$parameters$lambda[1],3)) ),
                   x = 1.13 * x$raw.time[length(x$raw.time)],
                   y = 0.5 * ggplot_build(p)$layout$panel_params[[1]]$y.range[2],
                   angle = 90, parse = F, size = 2.5) + 
          scale_color_manual(name='Growth Model',
                             breaks = "logistic",
                             values=c("model" = ggplot2::alpha("forestgreen", 0.85), "logistic" = ggplot2::alpha("forestgreen", 0.85)))
      }
      if(x$model == "baranyi"){
        p <- p + annotate(
          "text",
          label = "atop(B == t + frac(1,mu) %.% log(symbol(e)^{-mu%.%time} + symbol(e)^{-mu%.%lambda} - symbol(e)^{-mu%.%(time + lambda)}),
          y == y0 + mu%.%B - log(1 + (symbol(e)^{mu %.% B} - 1)/symbol(e)^{A - y0}))",
          x = 1.14 * x$raw.time[length(x$raw.time)],
          y = 0.5 * ggplot_build(p)$layout$panel_params[[1]]$y.range[2],
          angle = 90, parse = TRUE, size = 3.2) +
          annotate("text",
                   label = bquote(A == .(round(x$parameters$A[1],3)) ~~~~ mu == .(round(x$parameters$mu[1],3)) ~~~~
                                    lambda == .(round(x$parameters$lambda[1],3)) ),
                   x = 1.22 * x$raw.time[length(x$raw.time)],
                   y = 0.5 * ggplot_build(p)$layout$panel_params[[1]]$y.range[2],
                   angle = 90, parse = F, size = 2.5) + 
          scale_color_manual(name='Growth Model',
                             breaks = "baranyi",
                             values=c("model" = ggplot2::alpha("forestgreen", 0.85), "baranyi" = ggplot2::alpha("forestgreen", 0.85)))
      }
      if(x$model == "richards"){
        p <- p + annotate(
          "text",
          label = "y(t) == A%.%(1.0+nu%.%italic(e)^{1+nu}%.%exp(frac(mu,A)%.%(1+nu)^(1+frac(1,nu))%.%( lambda - t )))^(-1/nu)",
          x = 1.14 * x$raw.time[length(x$raw.time)],
          y = 0.5 * ggplot_build(p)$layout$panel_params[[1]]$y.range[2],
          angle = 90, parse = TRUE, size = 3.2) +
          annotate("text",
                   label = bquote(A == .(round(x$parameters$A[1],3)) ~~~~ mu == .(round(x$parameters$mu[1],3)) ~~~~
                                    lambda == .(round(x$parameters$lambda[1],3)) ~~~~ nu == .(round(as.numeric(x$parameters$fitpar$nu[1],3)))),
                   x = 1.22 * x$raw.time[length(x$raw.time)],
                   y = 0.5 * ggplot_build(p)$layout$panel_params[[1]]$y.range[2],
                   angle = 90, parse = F, size = 2.5) + 
          scale_color_manual(name='Growth Model',
                             breaks = "richards",
                             values=c("model" = ggplot2::alpha("forestgreen", 0.85), "richards" = ggplot2::alpha("forestgreen", 0.85)))
      }
      if(x$model == "gompertz"){
        p <- p + annotate(
          "text",
          label = "y(t) == A%.%exp(-exp(frac(mu%.%italic(e),A)%.%(lambda-t) +1))",
          x = 1.05 * x$raw.time[length(x$raw.time)],
          y = 0.5 * ggplot_build(p)$layout$panel_params[[1]]$y.range[2],
          angle = 90, parse = TRUE, size = 3.4) +
          annotate("text",
                   label = bquote(A == .(round(x$parameters$A[1],3)) ~~~~ mu == .(round(x$parameters$mu[1],3)) ~~~~ 
                                    lambda == .(round(x$parameters$lambda[1],3)) ),
                   x = 1.13 * x$raw.time[length(x$raw.time)],
                   y = 0.5 * ggplot_build(p)$layout$panel_params[[1]]$y.range[2],
                   angle = 90, parse = F, size = 2.5) + 
          scale_color_manual(name='Growth Model',
                             breaks = "gompertz",
                             values=c("model" = ggplot2::alpha("forestgreen", 0.85), "gompertz" = ggplot2::alpha("forestgreen", 0.85)))
      }
      if(x$model == "gompertz.exp"){
        lagtime <- lagtime - x$parameters$A[1]*exp(x$parameters$fitpar$alpha[1]*(x$parameters$lambda[1]-x$parameters$fitpar$t_shift[1]))
        p <- p + annotate(
          "text",
          label = "y(t) == A%.%exp(-exp(frac(mu%.%italic(e),A)%.%(lambda-t) +1)) + A%.%exp(alpha%.%(t-t[shift]))",
          x = 1.17 * x$raw.time[length(x$raw.time)],
          y = 0.5 * ggplot_build(p)$layout$panel_params[[1]]$y.range[2],
          angle = 90, parse = TRUE, size = 3.2) +
          annotate("text",
                   label = bquote(A == .(round(x$parameters$A[1],3)) ~~~~ mu == .(round(x$parameters$mu[1],3)) ~~~~
                                    lambda == .(round(x$parameters$lambda[1],2)) ~~~~ alpha == .(round(x$parameters$fitpar$alpha[1],3))  ~~~~
                                    t[shift] == .(round(x$parameters$fitpar$t_shift[1],2)) ),
                   x = 1.25 * x$raw.time[length(x$raw.time)],
                   y = 0.5 * ggplot_build(p)$layout$panel_params[[1]]$y.range[2],
                   angle = 90, parse = F, size = 2.5) + 
          scale_color_manual(name='Growth Model',
                             breaks = "gompertz.exp",
                             values=c("model" = ggplot2::alpha("forestgreen", 0.85), "gompertz.exp" = ggplot2::alpha("forestgreen", 0.85)))
        
      }
      if(x$model == "huang"){
        p <- p + annotate(
          "text",
          label = "y(t) == y0 + A - log( exp(y0) + (exp(A) - exp(y0)) * exp(-mu%.%(t+0.25%.%log(frac(1+exp(-4%.%(t-lambda)),1+exp(4%.%lambda))))) )",
          x = 1.16 * x$raw.time[length(x$raw.time)],
          y = 0.5 * ggplot_build(p)$layout$panel_params[[1]]$y.range[2],
          angle = 90, parse = TRUE, size = 2.2) +
          annotate("text",
                   label = bquote(A == .(round(x$parameters$A[1],3)) ~~~~ mu == .(round(x$parameters$mu[1],3)) ~~~~
                                    lambda == .(round(x$parameters$lambda[1],2)) ~~~~ y0 == .(round(x$parameters$fitpar$y0[1,1],3)) ),
                   x = 1.22 * x$raw.time[length(x$raw.time)],
                   y = 0.5 * ggplot_build(p)$layout$panel_params[[1]]$y.range[2],
                   angle = 90, parse = F, size = 2.0) +
          scale_color_manual(name='Growth Model',
                             breaks = "huang",
                             values=c("model" = ggplot2::alpha("forestgreen", 0.85), "huang" = ggplot2::alpha("forestgreen", 0.85)))
      }
      p <- p + theme(legend.key = element_blank(),
                     legend.background=element_blank(),
                     legend.title = element_blank(),
                     legend.position = c(0.70, 0.1),
                     plot.margin = unit(c(1, 5, 1, 1), "lines")) +
        coord_cartesian(
          xlim = c(
            ggplot_build(p)$layout$panel_params[[1]]$x.range[1],
            ggplot_build(p)$layout$panel_params[[1]]$x.range[2]
          ),
          ylim = c(
            ggplot_build(p)$layout$panel_params[[1]]$y.range[1],
            ggplot_build(p)$layout$panel_params[[1]]$y.range[2]
          ),
          clip = "off",
          expand = F
        )
      
      print(p)
    }
  }
  plotdir <- ifelse(export == TRUE, wd.plots, paste0(str_replace_all(tempdir(), "\\\\", "/"),"/Plots"))
  if(all(c('pdf', 'html') %in% format)){
    if (knitr::is_latex_output()) {
      if(parallelize){
        foreach(i = 1:length(grofit[["gcFit"]][["gcFittedModels"]]),
                .packages = "ggplot2") %dopar% {
                  if(grofit[["gcFit"]][["gcFittedModels"]][[i]][["fitFlag"]] == TRUE){
                    pdf(file=paste0(plotdir, "/PlotModel_", gsub("∙|\\n|\\r", "_", gsub("\\?", "_", gsub(" ", "_", gsub("\\/", "_", gsub(" \\| ", "_", names(grofit[["gcFit"]][["gcFittedModels"]])[i]))))), ".pdf"), width = 6, height = 4.5);   plot.ggModel();   invisible(grDevices::dev.off())
                  }
                }
      } else {
        for(i in 1:length(grofit[["gcFit"]][["gcFittedModels"]])){
          if(grofit[["gcFit"]][["gcFittedModels"]][[i]][["fitFlag"]] == TRUE){
            pdf(file=paste0(plotdir, "/PlotModel_", gsub("∙|\\n|\\r", "_", gsub("\\?", "_", gsub(" ", "_", gsub("\\/", "_", gsub(" \\| ", "_", names(grofit[["gcFit"]][["gcFittedModels"]])[i]))))), ".pdf"), width = 6, height = 4.5);   plot.ggModel();   invisible(grDevices::dev.off())
          }
        }
      }
    }
  } else{
    if(parallelize){
      foreach(i = 1:length(grofit[["gcFit"]][["gcFittedModels"]]),
              .packages = "ggplot2") %dopar% {
                if(grofit[["gcFit"]][["gcFittedModels"]][[i]][["fitFlag"]] == TRUE){
                  pdf(file=paste0(plotdir, "/PlotModel_", gsub("∙|\\n|\\r", "_", gsub("\\?", "_", gsub(" ", "_", gsub("\\/", "_", gsub(" \\| ", "_", names(grofit[["gcFit"]][["gcFittedModels"]])[i]))))), ".pdf"), width = 6, height = 4.5);   plot.ggModel();   invisible(grDevices::dev.off())
                }
              }
    } else {
      for(i in 1:length(grofit[["gcFit"]][["gcFittedModels"]])){
        if(grofit[["gcFit"]][["gcFittedModels"]][[i]][["fitFlag"]] == TRUE){
          pdf(file=paste0(plotdir, "/PlotModel_", gsub("∙|\\n|\\r", "_", gsub("\\?", "_", gsub(" ", "_", gsub("\\/", "_", gsub(" \\| ", "_", names(grofit[["gcFit"]][["gcFittedModels"]])[i]))))), ".pdf"), width = 6, height = 4.5);   plot.ggModel();   invisible(grDevices::dev.off())
        }
      }
    }
  }
  
  
  Files_list <- list.files(path = plotdir, 
                           pattern = "^PlotModel_",
                           full.names = TRUE)
  sort.ndx <- match(gsub("∙|\\n|\\r", "_", gsub("%", "_", gsub("\\?", "_", gsub(" ", "_", gsub("\\/", "_", gsub(" \\| ", "_", names(grofit$gcFit$gcFittedModels))))))), gsub(".+PlotModel_","", gsub(".pdf", "", Files_list)))
  sort.ndx <- sort.ndx[!is.na(sort.ndx)]
  knitr::include_graphics(Files_list[sort.ndx], dpi = 300, error = F)
}
 
```
`r if(any(c("a", "b", "s") %in% control$fit.opt)){"\\clearpage"}`

### `r if(any(c("a", "b", "s") %in% control$fit.opt)){"Nonparametric Fits"}`
```{r figure_spline, out.width = "33%", fig.asp=1.1, fig.show='hold', echo=F, warning=F, message=F, results='asis', fig.align='default'}
if(any(c("a", "b", "s") %in% control$fit.opt)) {
  #__________________ function definition ______________
  plot.ggSpline   <- function() {
    if (grofit[["gcFit"]][["gcFittedSplines"]][[i]][["fitFlag"]] == TRUE) {
      x <- grofit[["gcFit"]][["gcFittedSplines"]][[i]]
      coef <- x[["parameters"]]
      lagtime <- coef["lambda"][[1]][1]
      df <- data.frame(
        "time" = x[["raw.time"]],
        "data" = exp(x[["raw.data"]]) * x[["data.in"]][1],
        "fit.time" = c(rep(NA, length(x[["raw.time"]]) -
                             length(x[["fit.time"]])), x[["fit.time"]]),
        "fit.data" = c(rep(NA, length(x[["raw.data"]]) -
                             length(x[["fit.data"]])), exp(x[["fit.data"]]) * x[["data.in"]][1])
      )
      
      p <-    ggplot(df, aes(x = time, y = data)) +
        geom_point(
          shape = 1,
          size = 2,
          alpha = 0.5,
          stroke = 0.15
        ) +
        geom_line(aes(x = fit.time, y = fit.data, color = "spline"), size = 0.7) +
        xlab("Time") +
        ylab(label = "Growth [y(t)]") +
        theme_classic(base_size = 16) +
        ggtitle(gsub(" \\| NA", "", paste(x$gcID, collapse = " | "))) +
        scale_x_continuous(breaks = scales::pretty_breaks(n = 10)) +
        theme(
          legend.key = element_blank(),
          legend.background = element_blank(),
          legend.title = element_blank(),
          legend.position = c(0.90, 0.08),
          plot.title = element_text(size = 15),
          panel.grid.major = element_blank(),
          panel.grid.minor = element_blank()
        ) +
        scale_color_manual(
          name = 'Growth Model',
          breaks = "Spline fit",
          values = c(
            "spline" = ggplot2::alpha("dodgerblue3", 0.85),
            "Spline fit" = ggplot2::alpha("dodgerblue3", 0.85)
          )
        )
      
      if (x$control$log.y.spline == TRUE) {
        p <-
          p + scale_y_continuous(breaks = scales::pretty_breaks(),
                                 trans = 'log')
        p.yrange.end <-
          exp(ggplot_build(p)$layout$panel_params[[1]]$y.range[2])
      } else {
        p <- p + scale_y_continuous(breaks = scales::pretty_breaks())
        p.yrange.end <-
          ggplot_build(p)$layout$panel_params[[1]]$y.range[2]
      }
      
      # /// add tangent at maximum slope
      
      mu     <- as.numeric(coef$mu[1])
      if (x$fitFlag2) {
        lagtime2 <- coef$lambda2
        growth.time <-
          x$fit.time[which.max(x$fit.data)]
        mu2 <- coef$mu2
        if (lagtime2 < lagtime) {
          # time values for tangent at µmax
          time_start.ndx <-
            which.min(abs(
              x$fit.time - (coef$t.max - 0.15 * growth.time)
            ))
          time_start <- x$fit.time[time_start.ndx]
          time <-
            seq(time_start, max(x$fit.time), length = 200)
          # y values for tangent at µmax
          bla <-
            ifelse(
              x$control$log.y.spline == TRUE,
              exp(coef["b.tangent"][[1]]) * x[["data.in"]][1],
              coef["b.tangent"][[1]]
            ) * exp(mu * time)
          tangent.df <- data.frame("time" = time,
                                   "y" = bla)
          # time values for tangent at µmax2
          time2 <-
            seq(ifelse(lagtime2 < 0, 0, lagtime2),
                max(x$"fit.time"),
                length = 200)
          # y values for tangent at µmax
          bla2 <-
            ifelse(
              x$control$log.y.spline == TRUE,
              exp(coef["b.tangent2"][[1]]) * x[["data.in"]][1],
              coef["b.tangent2"][[1]]
            ) * exp(mu2 * time2)
          tangent.df2 <- data.frame("time" = time2,
                                    "y" = bla2)
          df.horizontal2 <-
            data.frame("time" = c(x[["raw.time"]][1], lagtime2),
                       "y" = x[["data.in"]][1])
          
          p <-
            p + geom_segment(
              aes(
                x = time[which.min(abs(bla))],
                y = y[which.min(abs(bla))],
                xend = time[which.min(abs(y - 1.1 *
                                            p.yrange.end))],
                yend = y[which.min(abs(y - 1.1 * p.yrange.end))]
              ),
              data = tangent.df,
              linetype = "dashed",
              color = ggplot2::alpha("dodgerblue3", 0.85),
              size = 0.5
            )
          p <-
            p + geom_segment(
              aes(
                x = time[which.min(abs(bla2))],
                y = y[which.min(abs(bla2))],
                xend = time[which.min(abs(y - 1.1 *
                                            p.yrange.end))],
                yend = y[which.min(abs(y - 1.1 * p.yrange.end))]
              ),
              data = tangent.df2,
              linetype = "dashed",
              color = ggplot2::alpha("darkviolet", 0.85),
              size = 0.5
            )
          
          if (!(lagtime2 < 0)) {
            p <-
              p + geom_segment(
                aes(
                  x = time[1],
                  y = y[1],
                  xend = time[2],
                  yend = y[2]
                ),
                data = df.horizontal2,
                linetype = "dashed",
                color = ggplot2::alpha("darkviolet", 0.85),
                size = 0.5
              )
          }
        } # if(lagtime2 < lagtime)
        else {
          # time values for tangent at µmax
          time <-
            seq(ifelse(lagtime < 0, 0, lagtime),
                max(x$"fit.time"),
                length = 200)
          # y values for tangent at µmax
          bla <-
            ifelse(
              x$control$log.y.spline == TRUE,
              exp(coef["b.tangent"][[1]]) * x[["data.in"]][1],
              coef["b.tangent"][[1]]
            ) * exp(mu * time)
          tangent.df <- data.frame("time" = time,
                                   "y" = bla)
          df.horizontal <-
            data.frame("time" = c(x[["raw.time"]][1], lagtime),
                       "y" = x[["data.in"]][1])
          # time values for tangent at µmax2
          time2_start.ndx <-
            which.min(abs(
              x$fit.time - (coef$t.max2 - 0.15 * growth.time)
            ))
          time2_start <- x$fit.time[time2_start.ndx]
          time2 <-
            seq(time2_start, max(x$"fit.time"), length = 200)
          # y values for tangent at µmax
          bla2 <-
            ifelse(
              x$control$log.y.spline == TRUE,
              exp(coef["b.tangent2"][[1]]) * x[["data.in"]][1],
              coef["b.tangent2"][[1]]
            ) * exp(mu2 * time2)
          tangent.df2 <- data.frame("time" = time2,
                                    "y" = bla2)
          
          p <-
            p + geom_segment(
              aes(
                x = time[which.min(abs(bla))],
                y = y[which.min(abs(bla))],
                xend = time[which.min(abs(y - 1.1 *
                                            p.yrange.end))],
                yend = y[which.min(abs(y - 1.1 * p.yrange.end))]
              ),
              data = tangent.df,
              linetype = "dashed",
              color = ggplot2::alpha("dodgerblue3", 0.85),
              size = 0.5
            )
          p <-
            p + geom_segment(
              aes(
                x = time[which.min(abs(bla2))],
                y = y[which.min(abs(bla2))],
                xend = time[which.min(abs(y - 1.1 *
                                            p.yrange.end))],
                yend = y[which.min(abs(y - 1.1 * p.yrange.end))]
              ),
              data = tangent.df2,
              linetype = "dashed",
              color = ggplot2::alpha("darkviolet", 0.85),
              size = 0.5
            )
          
          if (!(lagtime < 0)) {
            p <-
              p + geom_segment(
                aes(
                  x = time[1],
                  y = y[1],
                  xend = time[2],
                  yend = y[2]
                ),
                data = df.horizontal,
                linetype = "dashed",
                color = ggplot2::alpha("dodgerblue3", 0.85),
                size = 0.5
              )
          }
        }
      } # if(x$fitFlag2)
      else {
        # time values for tangent
        time <-
          seq(ifelse(lagtime < 0, 0, lagtime),
              max(x$"fit.time"),
              length = 200)
        # y values for tangent
        bla <-
          ifelse(
            x$control$log.y.spline == TRUE,
            exp(coef["b.tangent"][[1]]) * x[["data.in"]][1],
            coef["b.tangent"][[1]]
          ) * exp(mu * time)
        tangent.df <- data.frame("time" = time,
                                 "y" = bla)
        df.horizontal <-
          data.frame("time" = c(x[["raw.time"]][1], lagtime),
                     "y" = x[["data.in"]][1])
        p <-
          p + geom_segment(
            aes(
              x = time[which.min(abs(bla))],
              y = y[which.min(abs(bla))],
              xend = time[which.min(abs(y - 1.1 * p.yrange.end))],
              yend = y[which.min(abs(y - 1.1 * p.yrange.end))]
            ),
            data = tangent.df,
            linetype = "dashed",
            color = ggplot2::alpha("dodgerblue3", 0.85),
            size = 0.5
          )
        if (!(lagtime < 0)) {
          p <-
            p + geom_segment(
              aes(
                x = time[1],
                y = y[1],
                xend = time[2],
                yend = y[2]
              ),
              data = df.horizontal,
              linetype = "dashed",
              color = ggplot2::alpha("dodgerblue3", 0.85),
              size = 0.5
            )
        }
      } # else of if(x$fitFlag2)
      # /// add panel with growth rate vs. time
      df.mu <-
        data.frame(spline(x$spline.deriv1$x, x$spline.deriv1$y))
      #add missing time values due to min.density and t0
      df.mu <-
        dplyr::bind_rows(data.frame(x = df$time[is.na(df$fit.data)], y = rep(NA, length(df$time[is.na(df$fit.data)]))),
                         df.mu)
      
      p.mu <- ggplot(df.mu, aes(x = x, y = y)) +
        geom_line(color = "dodgerblue3") +
        theme_classic(base_size = 15) +
        xlab("Time") +
        ylab(label = bquote("Exp. growth rate µ " ~ (h ^ -1))) +
        scale_x_continuous(breaks = scales::pretty_breaks(n = 10))
      p.mu <- p.mu + scale_y_continuous(limits = c(mu.min, mu.max), breaks = scales::pretty_breaks(n = 10))
      print(ggpubr::ggarrange(
        p,
        p.mu,
        ncol = 1,
        nrow = 2,
        align = "v",
        heights = c(2, 1.3)
      ))
    }
  }
    #__________________ end function definition ______________
  plot_function <- function(i) {
        tryCatch({
          pdf_filename <- paste0(plotdir, "/PlotSpline_", gsub("∙|\\n|\\r", "_", gsub("%", "_", gsub("\\?", "_", gsub(" ", "_",
                                gsub("\\/", "_", gsub(" \\| ", "_", names(grofit[["gcFit"]][["gcFittedSplines"]])[i])))))), ".pdf")
          pdf(pdf_filename)
          plot.ggSpline()
        }, finally = {
          invisible(grDevices::dev.off()) # Ensure the device is closed
          })
      }
  plotdir <- ifelse(export == TRUE, wd.plots, paste0(str_replace_all(tempdir(), "\\\\", "/"), "/Plots"))
  if(all(c('pdf', 'html') %in% format)){
    if (knitr::is_latex_output()) {
      
      
      if(parallelize){
        foreach(i = 1:length(grofit[["gcFit"]][["gcFittedSplines"]]),
                .packages = "ggplot2") %dopar% {
                  if (grofit[["gcFit"]][["gcFittedSplines"]][[i]][["fitFlag"]] == TRUE) {
                    plot_function(i)
                  }
                }
      } else {
        for(i in 1:length(grofit[["gcFit"]][["gcFittedSplines"]])){
          if (grofit[["gcFit"]][["gcFittedSplines"]][[i]][["fitFlag"]] == TRUE) {
            plot_function(i)
          }
        }
      }
    }
  } else{ #if(all(c('pdf', 'html') %in% format)){
    if(parallelize){
      foreach(i = 1:length(grofit[["gcFit"]][["gcFittedSplines"]]),
              .packages = "ggplot2") %dopar% {
                if (grofit[["gcFit"]][["gcFittedSplines"]][[i]][["fitFlag"]] == TRUE) {
                  plot_function(i)
                }
              }
    } else {
      for(i in 1:length(grofit[["gcFit"]][["gcFittedSplines"]])){
        if (grofit[["gcFit"]][["gcFittedSplines"]][[i]][["fitFlag"]] == TRUE) {
          plot_function(i)
        }
      }
    }
  }
  
  Files_list <- list.files(path = plotdir,
                           pattern = "^PlotSpline_",
                           full.names = TRUE)
  sort.ndx <-
    match(gsub("∙|\\n|\\r", "_", gsub("%", "_", gsub("\\?", "_", gsub(" ", "_", gsub("\\/", "_", gsub(
      " \\| ", "_", names(grofit$gcFit$gcFittedSplines)
    )))))), gsub(".+PlotSpline_", "", gsub(".pdf", "", Files_list)))
  sort.ndx <- sort.ndx[!is.na(sort.ndx)]
  knitr::include_graphics(Files_list[sort.ndx], dpi = 300, error = F)
}
```
`r if(ec50){"\\clearpage"}`

## `r if(ec50){"Dose-response analysis"}`
```{r ec50_summary, echo=F, warning=F, message=F, results='asis', eval = ec50 && length(grofit[["drFit"]][["drFittedSplines"]]) > 0}
cat(paste0("_", length(levels(grofit[["data"]][["condition"]])), "_ conditions were identified::\n",
           paste(colFmt(levels(grofit[["data"]][["condition"]]), 'NavyBlue'), collapse = ", ")))
cat("  \n")
cat(paste0("_", length(levels(grofit[["data"]][["concentration"]])), "_ different concentrations were identified:\n",
           paste(colFmt(levels(grofit[["data"]][["concentration"]]), 'NavyBlue'), collapse = ", ")))
ec50.df <- data.frame()
for(i in 1:length(grofit$drFit$drFittedSplines)){
  ec50.df <- plyr::rbind.fill(ec50.df, data.frame("Condition" = names(grofit$drFit$drFittedSplines)[i],
                                                  "EC50" = round(grofit$drFit$drFittedSplines[[i]]$parameters$EC50, 3),
                                                  "Response" = round(grofit$drFit$drFittedSplines[[i]]$parameters$yEC50, 3))
  )
}
names(ec50.df)[3] <- paste0("Response (", grofit$drFit$drFittedSplines[[1]]$parameters$test, ")")
knit_table(ec50.df, caption = "Dose-Response Analysis - Spline Fits")
```
```{r ec50_summary_model, echo=F, warning=F, message=F, results='asis', eval = ec50 && length(grofit[["drFit"]][["drFittedModels"]]) > 0}
cat(paste0("_", length(levels(grofit[["data"]][["condition"]])), "_ conditions were identified::\n",
           paste(colFmt(levels(grofit[["data"]][["condition"]]), 'NavyBlue'), collapse = ", ")))
cat("  \n")
cat(paste0("_", length(levels(grofit[["data"]][["concentration"]])), "_ different concentrations were identified:\n",
           paste(colFmt(levels(grofit[["data"]][["concentration"]]), 'NavyBlue'), collapse = ", ")))
ec50.df <- data.frame()
for(i in 1:length(grofit$drFit$drFittedModels)){
  ec50.df <- plyr::rbind.fill(ec50.df, data.frame("Condition" = names(grofit$drFit$drFittedModels)[i],
                                                  "EC50" = paste0(round(grofit$drFit$drFittedModels[[i]]$parameters$EC50[1], 3), " \u00B1 ", round(grofit$drFit$drFittedModels[[i]]$parameters$EC50[2], 3)),
                                                  "Response" = round(grofit$drFit$drFittedModels[[i]]$parameters$yEC50[[1]], 3))
  )
}
names(ec50.df)[3] <- paste0("Response (", grofit$drFit$drFittedModels[[1]]$parameters$test, ")")
names(ec50.df)[2] <- paste0("EC50 \u00B1 SE")

knit_table(ec50.df, caption = "Dose-Response Analysis - Spline Fits")
```

```{r ec50_spline_plots, fig.width=8, fig.height=7, echo=F, warning=F, message=F, fig.align='center', eval = ec50 && length(grofit[["drFit"]][["drFittedSplines"]]) > 0}
plot.drFit(grofit$drFit, export = export, combine = TRUE, basesize = 12)
```

```{r ec50_model_plots, fig.width=8, fig.height=7, echo=F, warning=F, message=F, fig.align='center', eval = ec50 && length(grofit[["drFit"]][["drFittedModels"]]) > 0}
plot.drFit(grofit$drFit, export = export, basesize = 12)
```

```{r ec50.boot_summary, echo=F, warning=F, message=F, results='asis', eval = ec50 && grofit$control$dr.method == "spline" && length(grofit[["drFit"]][["drFittedSplines"]]) > 0 && (is.numeric(grofit$control$nboot.dr) && grofit$control$nboot.dr > 0)}
boot.ec50.df <- data.frame()
for (i in 1:length(grofit$drFit$drBootSplines)){
  boot.ec50.df <-
    plyr::rbind.fill(
      boot.ec50.df,
      data.frame(
        "Condition" = grofit$drFit$drTable$Test[i],
        "EC50.boot \u00B1 SD" = paste(round(as.numeric(grofit$drFit$drTable$drboot.meanEC50[i]), 3),"\u00B1", round(as.numeric(grofit$drFit$drTable$drboot.sdEC50[i]),3)),
        "Response.boot \u00B1 SD" = paste(round(as.numeric(grofit$drFit$drTable$drboot.meanEC50y[i]), 3),"\u00B1", round(as.numeric(grofit$drFit$drTable$drboot.sdEC50y[i]),3))
      )
    )
}
knit_table(boot.ec50.df, caption = "Dose-Response Analysis - Bootstrapping")
```

```{r ec50_boot_plots, fig.width=6, fig.height=4.5, echo=F, warning=F, message=F, fig.align='center', eval = ec50 && length(grofit[["drFit"]][["drFittedSplines"]]) > 0 && (is.numeric(grofit$control$nboot.dr) && grofit$control$nboot.dr > 0)}
for(i in 1:length(grofit$drFit$drBootSplines)){
  if(grofit$drFit$drBootSplines[[i]]$bootFlag == TRUE){
    plot.drBootSpline(grofit$drFit$drBootSplines[[i]], width = 6, height = 4.5, export = export, out.dir = normalizePath(wd.plots))
  }
}
```
`r if((!is.null(mean.grp) | !is.null(mean.conc)) && (!is.na(mean.grp) | !is.na(mean.conc)) ){"\\clearpage"}`

## `r if((!is.null(mean.grp) | !is.null(mean.conc)) && (!is.na(mean.grp) | !is.na(mean.conc)) ){"Group average plots"}`
```{r average_plots, fig.width=10, fig.height = 12, echo=F, warning=F, message=F, results='asis', fig.align='default', eval = ((!is.null(mean.grp) | !is.null(mean.conc)) && (!is.na(mean.grp) | !is.na(mean.conc)) )}
if("all" %in% mean.grp){
  if("s" %in% grofit$control$fit.opt){
    plot.grofit(grofit, basesize = 15, export = export, plot = TRUE, log.y = T, mean = T, out.dir = normalizePath(wd.plots), legend.position = "bottom", legend.ncol = 4)
  } else {
    plot.grofit(grofit, data.type = "raw", basesize = 15, export = export, plot = TRUE, log.y = T, mean = T, out.dir = normalizePath(wd.plots), legend.position = "bottom", legend.ncol = 4)
  }
} else if(!is.null(mean.grp) && !is.na(mean.grp)){
  for(i in 1:length(mean.grp)){
    if("s" %in% grofit$control$fit.opt){
      if(length(grep(mean.grp[i], as.character(names(grofit$gcFit$gcFittedSplines))))>0){
        plot.grofit(grofit, names = unlist(mean.grp[i]), basesize = 15, export = export, plot = TRUE, log.y = T, mean = T, out.dir = normalizePath(wd.plots), legend.position = "bottom", legend.ncol = 4)
      }
    } else {
      plot.grofit(grofit, data.type = "raw", names = unlist(mean.grp[i]), basesize = 15, export = export, plot = TRUE, log.y = T, mean = T, out.dir = normalizePath(wd.plots), legend.position = "bottom", legend.ncol = 4)
    }
  }
}
if(!is.null(mean.conc) && !is.na(mean.conc)){
  for(i in 1:length(mean.conc)){
    if("s" %in% grofit$control$fit.opt){
      if(length(grep(mean.conc[i], str_extract(names(grofit$gcFit$gcFittedSplines), "[:alnum:]+$")))>0){
        plot.grofit(grofit, conc = unlist(mean.conc[i]), basesize = 15, export = export, plot = TRUE, log.y = T, mean = T, out.dir = normalizePath(wd.plots), legend.position = "bottom", legend.ncol = 4)
      }
    } else {
      plot.grofit(grofit, data.type = "raw", conc = unlist(mean.conc[i]), basesize = 15, export = export, plot = TRUE, log.y = T, mean = T, out.dir = normalizePath(wd.plots), legend.position = "bottom", legend.ncol = 4)
    }
  }
}
```

