#' Concentration-time plots of the full time range, first dose, and last dose
#'
#' Conveniently group three concentration-time plots of multiple-dose regimen
#' data together: \enumerate{\item{the full time range across the top,}
#' \item{the first dose in the lower left quadrant, and} \item{the last dose in
#' the lower right quadrant.}} This uses either \code{\link{ct_plot}} or
#' \code{\link{ct_plot_overlay}} behind the scenes to make the graphs, so most
#' of the options available for those functions will work here.
#'
#' @param ct_dataframe the input concentration-time data generated by running
#' either the function \code{\link{extractConcTime}} or the function
#' \code{\link{extractConcTime_mult}}
#' @param overlay TRUE or FALSE for whether to make overlaid graphs, i.e.,
#' whether to use \code{\link{ct_plot_overlay}} (TRUE) or use
#' \code{\link{ct_plot}} (FALSE) to generate the graphs. If you have more than
#' one kind of tissue or more than one simulation file or more than one
#' compound, we'll set this to TRUE automatically.
#' @param figure_type type of figure to plot. Options are:
#'
#' \describe{
#'
#' \item{"percentiles"}{(default) plots an opaque line for the mean data,
#' lighter lines for the 5th and 95th percentiles of the simulated data, and
#' open circles for the observed data. If an effecter were present, the
#' default is dashed lines for the data in the presence of a perpetrator.}
#'
#' \item{"trial means"}{plots an opaque line for the mean data, lighter lines
#' for the mean of each trial of simulated data, and open circles for the
#' observed data. If a perpetrator were present, lighter dashed lines indicate
#' the mean of each trial of simulated data in the presence of the perpetrator.}
#'
#' \item{"percentile ribbon"}{plots an opaque line for the mean data,
#' transparent shading for the 5th to 95th percentiles of the simulated data,
#' and open circles for the observed data. If a perpetrator were present, the
#' default is to show the data without the perpetrator in blue and the data in
#' the presence of the perpetrator in red. Note: You may sometimes see some
#' artifacts -- especially for semi-log plots -- where the ribbon gets partly
#' cut off. For arcane reasons we don't want to bore you with here, we can't
#' easily prevent this. However, a possible fix is to set your y axis limits
#' for the semi-log plot to be wider using \code{y_axis_limits_log}.}
#'
#' \item{"means only"}{plots a black line for the mean data and, if an
#' perpetrator was modeled, a dashed line for the concentration-time data with
#' Inhibitor 1.}
#'
#' \item{"Freddy"}{Freddy's favorite style of plot with trial means in light
#' gray, the overall mean in thicker black, the 5th and 95th percentiles in
#' dashed lines, and the observed data in semi-transparent purple-blue. Graphs
#' with a perpetrator present lose the trial means, and the percentiles switch
#' to solid, gray lines. \strong{An editorial comment:} While this does not
#' align with the officially sanctioned template at this time, this looks
#' \emph{sharp}, makes it easy to see the defining characteristics of the
#' data, and I recommend checking it out, even just for your own purposes of
#' examining your data. If the color is too much for you but you like the
#' rest, try setting \code{obs_color = "black", obs_shape = c(1, 2)}. -LSh}}
#'
#' @param mean_type graph "arithmetic" (default) or "geometric" means or
#' "median" for median concentrations. If that option was not included in the
#' output, you'll get a warning and the graph will include one that was.
#' @param linear_or_log the type of graph to be returned. Options: \describe{
#' \item{"semi-log"}{y axis is log transformed}
#'
#' \item{"linear"}{no axis transformation}
#'
#' \item{"both vertical"}{(default) both the linear and the semi-log graphs
#' will be returned, and graphs are stacked vertically}
#'
#' \item{"both horizontal"}{both the linear and the semi-log graphs will be
#' returned, and graphs are side by side horizontally}
#'
#' \item{"horizontal and vertical"}{both the linear and the semi-log graphs
#' will be returned, and graphs are side by side horizontally (one graph; file
#' name will end in "- horizontal") and stacked vertically (second graph; file
#' name will end in "- vertical"). This option, which was designed to create
#' the vertically stacked version of a graph for a report and the horizontal,
#' side-by-side version for a presentation, is a bit different from the others
#' since it will return two separate files. In the RStudio "Plots" window,
#' you'll only see the vertically stacked version. Setting \code{fig_height}
#' and \code{fig_width} will adjust only the dimensions of the horizontal
#' figure; the default values will be used for the vertical one. If you
#' request Word output, only the vertical plot will be saved in Word format;
#' the horizontal plot will be saved as a png file.}}
#' @param time_range_LL time range to use for the lower-left graph; defaults to
#' "first dose" but any option acceptable for \code{time_range} for the
#' function \code{\link{ct_plot}} will also work.
#' @param x_axis_interval_LL optionally set the lower left graph x-axis major
#' tick-mark interval. Acceptable input: any number or leave as NA to accept
#' default values, which are generally reasonable guesses as to aesthetically
#' pleasing and PK-relevant intervals.
#' @param x_axis_interval_U optionally set the upper graph x-axis major
#' tick-mark interval. Acceptable input: any number or leave as NA to accept
#' default values, which are generally reasonable guesses as to aesthetically
#' pleasing and PK-relevant intervals.
#' @param time_range_LR time range to use for the lower-right graph; defaults to
#' "first dose" but any option acceptable for \code{time_range} for the
#' function \code{\link{ct_plot}} will also work.
#' @param x_axis_interval_LR optionally set the lower right graph x-axis major
#' tick-mark interval. Acceptable input: any number or leave as NA to accept
#' default values, which are generally reasonable guesses as to aesthetically
#' pleasing and PK-relevant intervals.
#' @param graph_title_U graph title for the upper, full-time-range graph;
#' defaults to "Full time range"
#' @param graph_title_LL graph title for the lower left graph; defaults to
#' "First dose"
#' @param graph_title_LR graph title for the lower right graph; defaults to
#' "Last dose"
#' @param conc_units_to_use concentration units to use for graphs. If left as
#' NA, the concentration units in the source data will be used. Acceptable
#' options are "mg/L", "mg/mL", "µg/L" (or "ug/L"), "µg/mL" (or "ug/mL"),
#' "ng/L", "ng/mL", "µM" (or "uM"), or "nM". If you want to use a molar
#' concentration and your source data were in mass per volume units or vice
#' versa, you'll need to provide something for the argument
#' \code{existing_exp_details}.
#' @param hline_position numerical position(s) of any horizontal lines to add to
#' the graph. The default is NA to have no lines, and good syntax if you
#' \emph{do} want lines would be, for example, \code{hline_position = 10} to
#' have a horizontal line at 10 ng/mL (or whatever your concentration units
#' are) or \code{hline_position = c(10, 100, 1000)} to have horizontal lines
#' at each of those y values. Examples of where this might be useful would be
#' to indicate a toxicity threshold, a target Cmin, or the lower limit of
#' quantification for the assay used to generate the concentration-time data.
#' @param hline_style the line color and type to use for any horizontal lines
#' that you add to the graph with \code{hline_position}. Default is "red
#' dotted", but any combination of 1) a color in R and 2) a named linetype is
#' acceptable. Examples: "red dotted", "blue dashed", or "#FFBE33 longdash".
#' To see all the possible linetypes, type \code{ggpubr::show_line_types()}
#' into the console.
#' @param vline_position numerical position(s) of any vertical lines to add to
#' the graph. The default is NA to have no lines, and good syntax if you
#' \emph{do} want lines would be, for example, \code{vline_position = 12} to
#' have a vertical line at 12 h or \code{vline_position = seq(from = 0, to =
#' 168, by = 24)} to have horizontal lines every 24 hours for one week.
#' Examples of where this might be useful would be indicating dosing times or
#' the time at which some other drug was started or stopped.
#' @param vline_style the line color and type to use for any vertical lines that
#' you add to the graph with \code{vline_position}. Default is "red dotted",
#' but any combination of 1) a color in R and 2) a named linetype is
#' acceptable. Examples: "red dotted", "blue dashed", or "#FFBE33 longdash".
#' To see all the possible linetypes, type \code{ggpubr::show_line_types()}
#' into the console.
#' @param legend_position Specify where you want the legend to be. Options are
#' "left", "right", "bottom", "top", or "none" (default) if you don't want one
#' at all. If you include the legend but then some graphs do have a legend and
#' some graphs do not (e.g., some have perpetrators and some do not so there's
#' nothing to put in a legend), the alignment between sets of graphs will be a
#' bit off.
#' @param legend_orientation optionally specify how the legend entries should be
#' oriented. Options are "vertical" or "horizontal", and, if left as NA, the
#' legend entries will be "vertical" when the legend is on the left or right
#' and "horizontal" when it's on the top or bottom.
#' @param qc_graph TRUE or FALSE (default) on whether to create a second copy of
#' the graph where the left panel shows the original graph and the right panel
#' shows information about the simulation trial design. This works MUCH faster
#' when you have already used \code{\link{extractExpDetails_mult}} to get
#' information about how your simulation or simulations were set up and supply
#' that object to the argument \code{existing_exp_details}.
#' @param existing_exp_details output from \code{\link{extractExpDetails}} or
#' \code{\link{extractExpDetails_mult}} to be used with \code{qc_graph}
#' @param prettify_compound_names TRUE (default), FALSE or a character vector:
#' This is asking whether to make compound names prettier in legend entries
#' and in any Word output files. This was designed for simulations where the
#' substrate and any metabolites, perpetrators, or perpetrator metabolites are
#' among the standard options for the simulator, and leaving
#' \code{prettify_compound_names = TRUE} will make the name of those compounds
#' something more human readable. For example, "SV-Rifampicin-MD" will become
#' "rifampicin", and "Sim-Midazolam" will become "midazolam". Setting this to
#' FALSE will leave the compound names as is. For an approach with more
#' control over what the compound names will look like in legends and Word
#' output, set each compound to the exact name you want with a named
#' character vector. For example, \code{prettify_compound_names =
#' c("Sim-Ketoconazole-400 mg QD" = "ketoconazole", "Wks-Drug ABC-low_ka" =
#' "Drug ABC")} will make those compounds "ketoconazole" and "Drug ABC" in a
#' legend.
#' @param name_clinical_study optionally specify the name(s) of the clinical
#' study or studies for any observed data. This only affects the caption of
#' the graph. For example, specifying \code{name_clinical_study = "101, fed
#' cohort"} will result in a figure caption that reads in part "clinical study
#' 101, fed cohort". If you have more than one study, that's fine; we'll take
#' care of stringing them together appropriately. Just list them as a
#' character vector, e.g., \code{name_clinical_study = c("101",
#' "102", "103")} will become "clinical studies 101, 102, and 103."
#' @param return_caption TRUE or FALSE (default) for whether to return any
#' caption text to use with the graph. This works best if you supply something
#' for the argument \code{existing_exp_details}. If set to TRUE, you'll get as
#' output a list of the graph, the figure heading, and the figure caption.
#' @param save_graph optionally save the output graph by supplying a file name
#' in quotes here, e.g., "My conc time graph.png" or "My conc time
#' graph.docx". If you leave off ".png" or ".docx" from the file name, it will
#' be saved as a png file, but if you specify a different graphical file
#' extension, it will be saved as that file format. Acceptable graphical file
#' extensions are "eps", "ps", "jpeg", "jpg", "tiff", "png", "bmp", or "svg".
#' Do not include any slashes, dollar signs, or periods in the file name.
#' Leaving this as NA means the file will not be saved to disk.
#' @param fig_height figure height in inches; default is 6
#' @param fig_width figure width in inches; default is 5
#' @param ... arguments that pass through to \code{\link{ct_plot}} or
#' \code{\link{ct_plot_overlay}}
#' @param graph_labels TRUE (default) or FALSE for whether to include labels (A,
#' B, C) for each of the small graphs.
#'
#' @return a set of 3 arranged ggplot2 graphs
#' @export
#'
#' @examples
#'
#' # We'll use the objects LMVct and MDZ_Keto for these examples. They're
#' # included in the package.
#'
#' # Examples with a single compound, tissue, and simulation ----------------------
#'
#' # These are all graphs where, if you made one of the panels on its own, you
#' # would use the function ct_plot.
#'
#' # Simplest option:
#' ct_plot3(ct_dataframe = LMVct)
#'
#' # Change the 3 graph titles
#' ct_plot3(ct_dataframe = LMVct,
#' graph_title_U = "Full time range for letermovir",
#' graph_title_LL = "Dose 1 of letermovir",
#' graph_title_LR = "Dose 8 of letermovir")
#'
#' # Tweak the time intervals for the bottom row graphs
#' ct_plot3(ct_dataframe = LMVct,
#' graph_title_LL = "Dose 1 & 2",
#' time_range_LL = "doses 1 to 2",
#' graph_title_LR = "Dose 7 & 8",
#' time_range_LR = "doses 7 to 8")
#'
#' # Make any other adjustments that you would typically make with ct_plot.
#'
#'
#' # Examples with multiple compounds, tissues, and/or simulations overlaid -------
#'
#' # These are all graphs where, if you made one of the panels on its own, you
#' # would use the function ct_plot_overlay.
#' ct_plot3(ct_dataframe = MDZ_Keto %>%
#' filter(CompoundID == "substrate" &
#' Tissue == "plasma"),
#' overlay = TRUE, colorBy_column = Inhibitor)
#'
#' # Make any other adjustments that you would typically make with ct_plot_overlay.
#' # This option might be a bit much! But at least it shows how it would be
#' # done. :)
#' ct_plot3(ct_dataframe = MDZ_Keto,
#' overlay = TRUE,
#' colorBy_column = Inhibitor,
#' facet1_column = Tissue,
#' facet2_column = Compound)
#'
#'
#' # You can adjust the graph titles and time ranges the same way as with a single
#' # simulation.
#'
ct_plot3 <- function(ct_dataframe,
overlay = FALSE,
figure_type = "means only",
mean_type = "arithmetic",
linear_or_log = "semi-log",
graph_title_U = "Full time range",
x_axis_interval_U = NA,
graph_title_LL = "First dose",
time_range_LL = "first dose",
x_axis_interval_LL = NA,
graph_title_LR = "Last dose",
time_range_LR = "last dose",
x_axis_interval_LR = NA,
legend_position = "none",
legend_orientation = NA,
graph_labels = TRUE,
conc_units_to_use = NA,
hline_position = NA,
hline_style = "red dotted",
vline_position = NA,
vline_style = "red dotted",
qc_graph = FALSE,
existing_exp_details = NA,
prettify_compound_names = TRUE,
name_clinical_study = NA,
return_caption = FALSE,
save_graph = NA,
fig_height = 6,
fig_width = 5,
...){
# error catching ---------------------------------------------------
# Check whether tidyverse is loaded
if("package:tidyverse" %in% search() == FALSE){
stop("The SimcypConsultancy R package requires the package tidyverse to be loaded, and it doesn't appear to be loaded yet. Please run\nlibrary(tidyverse)\n ...and then try again.",
call. = FALSE)
}
if(length(sort(unique(ct_dataframe$DoseNum))) == 1){
stop("ct_plot3 is only for multiple-dose scenarios, but these data appear to be for only one dose.")
}
if(hasArg("time_range")){
stop("You cannot supply anything for 'time_range' here because ct_plot3 needs to set the time range automatically. Please remove 'time_range' from your arguments.")
}
if(nrow(ct_dataframe) == 0){
stop("Please check your input. The data.frame you supplied for ct_dataframe doesn't have any rows.",
call. = FALSE)
}
# Getting experimental details if they didn't supply them and want to have a
# QC graph
if(qc_graph == TRUE | "logical" %in% class(existing_exp_details) == FALSE){
if("logical" %in% class(existing_exp_details)){
Deets <- tryCatch(
extractExpDetails(sim_data_file = unique(ct_dataframe$File),
exp_details = "Summary and Input")[["MainDetails"]],
error = function(x) "missing file")
} else {
Deets <- harmonize_details(existing_exp_details)[["MainDetails"]] %>%
filter(File %in% unique(ct_dataframe$File))
if(nrow(Deets == 0)){
Deets <- tryCatch(
extractExpDetails(sim_data_file = unique(ct_dataframe$File),
exp_details = "Summary and Input")[["MainDetails"]],
error = function(x) "missing file")
}
}
if(qc_graph == TRUE &
(class(Deets)[1] == "character" || nrow(Deets) == 0)){
warning("We couldn't find the source Excel file for this graph, so we can't QC it.",
call. = FALSE)
qc_graph <- FALSE
}
}
# main body of function -------------------------------------------
if(graph_labels){
labels <- "AUTO"
} else {
labels <- NULL
}
MyTissue <- unique(ct_dataframe$Tissue)
MyTissueSubtype <- ifelse("Tissue_subtype" %in% names(ct_dataframe),
unique(ct_dataframe$Tissue_subtype),
"none")
MyCompoundID <- unique(as.character(ct_dataframe$CompoundID))
NumProfiles <- ifelse(length(MyTissue) == 1 & length(MyCompoundID) == 1 &
length(MyTissueSubtype) == 1,
"single", "multiple")
overlay <- ifelse(NumProfiles == "multiple", TRUE, overlay)
if(overlay){
A <- ct_plot_overlay(ct_dataframe = ct_dataframe,
figure_type = figure_type,
mean_type = mean_type,
linear_or_log = linear_or_log,
time_range = NA,
x_axis_interval = x_axis_interval_U,
existing_exp_details = existing_exp_details,
conc_units_to_use = conc_units_to_use,
graph_title = graph_title_U,
qc_graph = FALSE,
graph_labels = FALSE,
legend_position = legend_position,
legend_orientation = legend_orientation,
...,
save_graph = NA)
# Suppressing messages and warnings after the 1st set.
suppressWarnings(suppressMessages(
B <- ct_plot_overlay(ct_dataframe = ct_dataframe,
figure_type = figure_type,
mean_type = mean_type,
linear_or_log = linear_or_log,
time_range = time_range_LL,
x_axis_interval = x_axis_interval_LL,
existing_exp_details = existing_exp_details,
conc_units_to_use = conc_units_to_use,
graph_title = graph_title_LL,
qc_graph = FALSE,
graph_labels = FALSE,
legend_position = "none",
legend_orientation = legend_orientation,
...,
save_graph = NA)))
suppressWarnings(suppressMessages(
C <- ct_plot_overlay(ct_dataframe = ct_dataframe,
figure_type = figure_type,
mean_type = mean_type,
linear_or_log = linear_or_log,
time_range = time_range_LR,
graph_title = graph_title_LR,
x_axis_interval = x_axis_interval_LR,
existing_exp_details = existing_exp_details,
conc_units_to_use = conc_units_to_use,
qc_graph = FALSE,
graph_labels = FALSE,
legend_position = "none",
legend_orientation = legend_orientation,
...,
save_graph = NA)))
suppressWarnings(
Out <- ggpubr::ggarrange(A,
ggpubr::ggarrange(
B, C,
labels = switch(as.character(graph_labels),
"TRUE" = list("", "C"),
"FALSE" = NULL),
legend = "none"),
nrow = 2,
labels = labels,
common.legend = TRUE, legend = legend_position)
)
} else {
if(hasArg("colorBy_column") | hasArg("facet1_column") |
hasArg("facet2_column")){
stop("It looks like you wanted to use 'ct_plot_overlay' with this function to create graphs of overlaid concentration-time data, but you have specified 'overlay = FALSE' (or left it as the default). Please change 'overlay' to TRUE and try again.")
}
A <- ct_plot(ct_dataframe = ct_dataframe,
figure_type = figure_type,
mean_type = mean_type,
linear_or_log = linear_or_log,
legend_position = legend_position,
legend_orientation = legend_orientation,
time_range = NA,
x_axis_interval = x_axis_interval_U,
graph_title = graph_title_U,
existing_exp_details = existing_exp_details,
conc_units_to_use = conc_units_to_use,
save_graph = NA,
qc_graph = FALSE,
graph_labels = FALSE,
...)
suppressWarnings(suppressMessages(
B <- ct_plot(ct_dataframe = ct_dataframe,
figure_type = figure_type,
mean_type = mean_type,
linear_or_log = linear_or_log,
legend_position = "none",
legend_orientation = legend_orientation,
...,
time_range = time_range_LL,
x_axis_interval = x_axis_interval_LL,
graph_title = graph_title_LL,
existing_exp_details = existing_exp_details,
conc_units_to_use = conc_units_to_use,
qc_graph = FALSE,
graph_labels = FALSE,
save_graph = NA)))
suppressWarnings(suppressMessages(
C <- ct_plot(ct_dataframe = ct_dataframe,
figure_type = figure_type,
mean_type = mean_type,
linear_or_log = linear_or_log,
legend_position = "none",
legend_orientation = legend_orientation,
qc_graph = FALSE,
...,
time_range = time_range_LR,
x_axis_interval = x_axis_interval_LR,
existing_exp_details = existing_exp_details,
conc_units_to_use = conc_units_to_use,
graph_title = graph_title_LR,
graph_labels = FALSE,
save_graph = NA)))
if(legend_position == "none"){
Out <- ggpubr::ggarrange(
A,
ggpubr::ggarrange(
B, C,
labels = switch(as.character(graph_labels),
"TRUE" = list("", "C"),
"FALSE" = NULL),
legend = "none"),
labels = labels,
nrow = 2, legend = "none")
} else {
Out <- ggpubr::ggarrange(
A,
ggpubr::ggarrange(
B, C,
labels = switch(as.character(graph_labels),
"TRUE" = list("", "C"),
"FALSE" = NULL),
legend = "none"),
labels = labels,
nrow = 2, common.legend = TRUE, legend = "bottom")
}
}
# Setting up figure caption --------------------------------------------
FigText <- make_ct_caption(ct_dataframe = ct_dataframe,
single_or_multiple_profiles = NumProfiles,
plot_type = "concentration-time",
existing_exp_details = existing_exp_details,
mean_type = mean_type,
linear_or_log = linear_or_log,
figure_type = figure_type,
prettify_compound_names = prettify_compound_names,
name_clinical_study = name_clinical_study,
hline_position = hline_position,
vline_position = vline_position,
hline_style = hline_style,
vline_style = vline_style)
# Saving ------------------------------------------------------------------
Out <- list("graph" = Out)
if(qc_graph){
QCTable <- formatTable_Simcyp(
annotateDetails(as.data.frame(Deets) %>%
filter(File %in% unique(ct_dataframe$File)),
detail_set = "Methods") %>%
select(-c(SimulatorSection, matches("All files"), Sheet,
Notes, CompoundID, Compound)),
shading_column = Detail)
Out[["QCgraph"]] <- ggpubr::ggarrange(
plotlist = list(Out$graph, flextable::gen_grob(QCTable)),
font.label = list(size = graph_title_size))
}
if(complete.cases(save_graph)){
FileName <- save_graph
if(str_detect(FileName, "\\.")){
# Making sure they've got a good extension
Ext <- sub("\\.", "", str_extract(FileName, "\\..*"))
FileName <- sub(paste0(".", Ext), "", FileName)
Ext <- ifelse(Ext %in% c("eps", "ps", "jpeg", "tiff",
"png", "bmp", "svg", "jpg", "docx"),
Ext, "png")
FileName <- paste0(FileName, ".", Ext)
} else {
FileName <- paste0(FileName, ".png")
Ext <- "png"
}
if(qc_graph & Ext != "docx"){
ggsave(sub(paste0("\\.", Ext), " - QC.png", FileName),
height = fig_height, width = fig_width * 2, dpi = 600,
ggpubr::ggarrange(plotlist = list(Out$QCgraph),
nrow = 1))
}
if(Ext == "docx"){
# This is when they want a Word file as output
OutPath <- dirname(FileName)
if(OutPath == "."){
OutPath <- getwd()
}
FileName <- basename(FileName)
# Setting some values that don't make sense for this scenario but are
# needed for making the Rmd file work.
EnzPlot <- FALSE
ReleaseProfPlot <- FALSE
DissolutionProfPlot <- FALSE
rmarkdown::render(system.file("rmarkdown/templates/multctplot/skeleton/skeleton.Rmd",
package="SimcypConsultancy"),
output_dir = OutPath,
output_file = FileName,
quiet = TRUE)
# Note: The "system.file" part of the call means "go to where the
# package is installed, search for the file listed, and return its
# full path.
} else {
# This is when they want any kind of graphical file format.
ggsave(FileName, height = fig_height, width = fig_width, dpi = 600,
plot = Out$graph)
}
}
if(return_caption){
Out[["figure_heading"]] <- FigText$heading
Out[["figure_caption"]] <- FigText$caption
}
if(length(Out) == 1){
Out <- Out[[1]]
}
return(Out)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.