Skip to contents

This vignette will review the functionality for updating aesthetic elements of VPC plots generated using vpc() with the new_vpc_theme() function from the vpc package.

plot_legend() is a helper plotting function that creates a legend for plots generated using vpc(). These legends can then be merged with the VPC plot into a single plot object using the patchwork package.

Let’s get started. First, we will load the required packages.

options(scipen = 999, rmarkdown.html_vignette.check_title = FALSE)
library(pmxhelpr)
library(dplyr, warn.conflicts =  FALSE)
library(ggplot2, warn.conflicts =  FALSE)
library(vpc, warn.conflicts =  FALSE)
library(mrgsolve, warn.conflicts =  FALSE)
library(withr, warn.conflicts =  FALSE)
library(patchwork, warn.conflicts = FALSE)

Next, let’s load use the internal data and model objects from pmxhelpr and df_mrgsim_replicate to run the simulation.

data <- data_sad
model <- model_mread_load("model")
#> Building model_cpp ... done.

simout <- df_mrgsim_replicate(data = data, model = model,replicates = 100, 
                     dv_var = "ODV",
                     time_vars = c(TIME = "TIME", NTIME = "NTIME"),
                     output_vars = c(PRED = "PRED", IPRED = "IPRED", DV = "DV"),
                     num_vars = c("CMT", "BLQ", "LLOQ", "EVID", "MDV", "DOSE", "FOOD"),
                     char_vars = c("PART"),
                     obsonly = TRUE)

Now let’s plot all data together in a prediction-corrected VPC (pcVPC). There is only single dose administration in this dataset, thus we are able to pool across doses and food conditions with prediction-correction. We will set min_bin_count = 5 to avoid the simulated intervals extending to the final timepoint with only a single observation.

vpc_pc <- plot_vpc_exactbins(
  sim = simout,
  xlab = "Time (hours)",
  ylab = "Concentration (ng/mL)",
  pcvpc = TRUE,
  min_bin_count = 5
) +
  scale_y_log10(guide = "axis_logticks")
#> Joining with `by = join_by(NTIME, CMT)`
#> Joining with `by = join_by(NTIME, CMT)`

vpc_pc

Plot Elements

Default Elements

The default elements shown in the plot are inherited from vpc(). The shown argument can be provided to plot_vpc_exactbins() and passed on to the show argument of vpc().

The default is as follows:

shown_list <- list(obs_dv = TRUE, obs_ci = TRUE,
                   pi = FALSE, pi_as_area = FALSE, pi_ci = TRUE,
                   obs_median = TRUE, sim_median =FALSE, sim_median_ci = TRUE)

The components of the list correspond to the following vpc plot elements:

  • Observed points: obs_dv
  • Observed quantiles: obs_ci
  • Simulated inter-quantile range: pi
  • Simulated inter-quantile area: pi_as_area
  • Simulated Quantile CI: pi_ci
  • Observed Median: obs_median
  • Simulated Median: sim_median
  • Simulated Median CI: sim_median_ci

One or more elements to be updated from the defaults above can be passed as a list to the argument shown. Any elements not specified in shown will inherit the defaults.

Adjusting Elements

For example, we may want to visualize the 90% prediction interval (i.e., 5th to 95th percentiles) derived from the simulation, rather than the confidence intervals of the 5th and 95th percentiles independently. In this case, we want to also see how close the simulated median falls relative to the observed median.

Let’s see how this can be down using shown!


vpc_pc_pi <- plot_vpc_exactbins(
  sim = simout, 
  time_vars = c(TIME = "TIME", NTIME = "NTIME"),
  output_vars = c(PRED = "PRED", IPRED = "IPRED", SIMDV = "SIMDV", OBSDV = "OBSDV"),
  xlab = "Time (hours)",
  ylab = "Concentration (ng/mL)",
  pcvpc = TRUE,
  min_bin_count = 5,
  shown = list(obs_ci = FALSE, pi_ci = FALSE, sim_median_ci = FALSE, sim_median = TRUE, pi_as_area = TRUE)
) +
  scale_y_log10(guide = "axis_logticks")
#> Joining with `by = join_by(NTIME, CMT)`
#> Joining with `by = join_by(NTIME, CMT)`

vpc_pc_pi

Now, let’s say we want to remove the observed data points from the plot above to better visualize the observed quantile lines relative to their corresponding simulated confidence intervals. We can do this as follows.


vpc_pc_noobs <- plot_vpc_exactbins(
  sim = simout, 
  time_vars = c(TIME = "TIME", NTIME = "NTIME"),
  output_vars = c(PRED = "PRED", IPRED = "IPRED", SIMDV = "SIMDV", OBSDV = "OBSDV"),
  xlab = "Time (hours)",
  ylab = "Concentration (ng/mL)",
  pcvpc = TRUE,
  min_bin_count = 5,
  shown = list(obs_dv = FALSE)
) +
  scale_y_log10(guide = "axis_logticks")
#> Joining with `by = join_by(NTIME, CMT)`
#> Joining with `by = join_by(NTIME, CMT)`

vpc_pc_noobs

We could also take this one step further and only look at the median and the simulated confidence interval of the median, to closely interrogate central tendency. This is common for VPC strata which have few observations, leading to inadequate sample size to discriminate between the confidence intervals of the median and the extremes. This is common scenario when evaluating VPC plots stratified by individual study arms in early phase trials.


vpc_pc_noobs_medonly <- plot_vpc_exactbins(
  sim = simout, 
  time_vars = c(TIME = "TIME", NTIME = "NTIME"),
  output_vars = c(PRED = "PRED", IPRED = "IPRED", SIMDV = "SIMDV", OBSDV = "OBSDV"),
  xlab = "Time (hours)",
  ylab = "Concentration (ng/mL)",
  pcvpc = TRUE,
  min_bin_count = 5,
  shown = list(obs_dv = FALSE, obs_ci = FALSE, pi_ci = FALSE)
) +
  scale_y_log10(guide = "axis_logticks")
#> Joining with `by = join_by(NTIME, CMT)`
#> Joining with `by = join_by(NTIME, CMT)`

vpc_pc_noobs_medonly

Plot Aesthetics

Default Aesthetics

Similarly, the default aesthetics for vpc plots in pmxhelpr use the classical red-blue-green brewer color schema. The defaults for pmxhelpr can be visualized by specifying the pmxhlepr_vpc_theme() function with no arguments.

pmxhelpr_theme_list <- pmxhelpr_vpc_theme()
print(pmxhelpr_theme_list)
#> $obs_color
#> [1] "#0000FF"
#> 
#> $obs_size
#> [1] 1
#> 
#> $obs_median_color
#> [1] "#FF0000"
#> 
#> $obs_median_linetype
#> [1] "solid"
#> 
#> $obs_median_size
#> [1] 1
#> 
#> $obs_alpha
#> [1] 0.7
#> 
#> $obs_shape
#> [1] 1
#> 
#> $obs_ci_color
#> [1] "#0000FF"
#> 
#> $obs_ci_linetype
#> [1] "dashed"
#> 
#> $obs_ci_fill
#> [1] "#80808033"
#> 
#> $obs_ci_size
#> [1] 0.5
#> 
#> $sim_pi_fill
#> [1] "#0000FF"
#> 
#> $sim_pi_alpha
#> [1] 0.15
#> 
#> $sim_pi_color
#> [1] "#000000"
#> 
#> $sim_pi_linetype
#> [1] "dotted"
#> 
#> $sim_pi_size
#> [1] 1
#> 
#> $sim_median_fill
#> [1] "#FF0000"
#> 
#> $sim_median_alpha
#> [1] 0.3
#> 
#> $sim_median_color
#> [1] "#000000"
#> 
#> $sim_median_linetype
#> [1] "dashed"
#> 
#> $sim_median_size
#> [1] 1
#> 
#> $bin_separators_color
#> [1] "#000000"
#> 
#> $loq_color
#> [1] "#990000"
#> 
#> attr(,"class")
#> [1] "vpc_theme"

We can compare to the corresponding aesthetics from the vpc package, which can be viewed by running new_vpc_theme() with no arguments.

vpc_theme_list <- new_vpc_theme()
print(vpc_theme_list)
#> $obs_color
#> [1] "#000000"
#> 
#> $obs_size
#> [1] 1
#> 
#> $obs_median_color
#> [1] "#000000"
#> 
#> $obs_median_linetype
#> [1] "solid"
#> 
#> $obs_median_size
#> [1] 1
#> 
#> $obs_alpha
#> [1] 0.7
#> 
#> $obs_shape
#> [1] 1
#> 
#> $obs_ci_color
#> [1] "#000000"
#> 
#> $obs_ci_linetype
#> [1] "dashed"
#> 
#> $obs_ci_fill
#> [1] "#80808033"
#> 
#> $obs_ci_size
#> [1] 0.5
#> 
#> $sim_pi_fill
#> [1] "#3388cc"
#> 
#> $sim_pi_alpha
#> [1] 0.15
#> 
#> $sim_pi_color
#> [1] "#000000"
#> 
#> $sim_pi_linetype
#> [1] "dotted"
#> 
#> $sim_pi_size
#> [1] 1
#> 
#> $sim_median_fill
#> [1] "#3388cc"
#> 
#> $sim_median_alpha
#> [1] 0.3
#> 
#> $sim_median_color
#> [1] "#000000"
#> 
#> $sim_median_linetype
#> [1] "dashed"
#> 
#> $sim_median_size
#> [1] 1
#> 
#> $bin_separators_color
#> [1] "#000000"
#> 
#> $loq_color
#> [1] "#990000"
#> 
#> attr(,"class")
#> [1] "vpc_theme"

Adjusting Aesthetics

Now, suppose we want to change the default aesthetics of the VPC plot, without changing what is being shown. This can be accomplished by passing a named list of elements to update to the function pmxhelpr_vpc_theme(). The named list object generated from this function can then be passed to the theme argument in vpc_plot_exactbins, which is also an alias for the vpc_theme argument in vpc().

Let’s say we prefer a the blue-grey color scheme native to the vpc package! We can reproduce this by passing vpc::new_vpc_theme():

  1. to the update argument of pmxhelpr_vpc_theme()
vpc_pc_vpctheme <- plot_vpc_exactbins(
  sim = simout, 
  time_vars = c(TIME = "TIME", NTIME = "NTIME"),
  output_vars = c(PRED = "PRED", IPRED = "IPRED", SIMDV = "SIMDV", OBSDV = "OBSDV"),
  xlab = "Time (hours)",
  ylab = "Concentration (ng/mL)",
  pcvpc = TRUE,
  theme = pmxhelpr_vpc_theme(update = vpc::new_vpc_theme()),
  min_bin_count = 5
) +
  scale_y_log10(guide = "axis_logticks")
#> Joining with `by = join_by(NTIME, CMT)`
#> Joining with `by = join_by(NTIME, CMT)`

vpc_pc_vpctheme

2) to the theme argument of plot_vpc_exactbins.

vpc_pc_vpctheme2 <- plot_vpc_exactbins(
  sim = simout, 
  time_vars = c(TIME = "TIME", NTIME = "NTIME"),
  output_vars = c(PRED = "PRED", IPRED = "IPRED", SIMDV = "SIMDV", OBSDV = "OBSDV"),
  xlab = "Time (hours)",
  ylab = "Concentration (ng/mL)",
  pcvpc = TRUE,
  theme = vpc::new_vpc_theme(),
  min_bin_count = 5
) +
  scale_y_log10(guide = "axis_logticks")
#> Joining with `by = join_by(NTIME, CMT)`
#> Joining with `by = join_by(NTIME, CMT)`

vpc_pc_vpctheme2

Adding Layers

Let’s say we would like to visualize the major x-axis grid lines to help locate data corresponding to each sampling timepoint with our plot using the vpc package aesthetic defaults. Conveniently, plot_vpc_exactbins returns a ggplot2 plot object, which we can modify by adding layers just like like any other ggplot2 object.

vpc_pc_vpctheme_xgrid <- plot_vpc_exactbins(
  sim = simout, 
  time_vars = c(TIME = "TIME", NTIME = "NTIME"),
  xlab = "Time (hours)",
  ylab = "Concentration (ng/mL)",
  pcvpc = TRUE,
  min_bin_count = 5,
  theme = vpc::new_vpc_theme()
) + 
  scale_y_log10(guide = "axis_logticks") + 
  theme(panel.grid.major.x = element_line())
#> Joining with `by = join_by(NTIME, CMT)`
#> Joining with `by = join_by(NTIME, CMT)`

vpc_pc_vpctheme_xgrid

VPC Plot Legends

Defaults Legend

Okay, now we have gotten the plot aesthetics where we want them; however, there is one other element we may like to include in the figure to make it more easily interpreted in isolation - a legend.

pmxhelpr provides a useful helper function for this purpose, plot_legend(). To obtain a legend for a plot using default aesthetics, simply run plot_legend() without any arguments specified.

vpc_pc_legend <- plot_legend()
vpc_pc_legend

Now we have a ggplot object legend for our first plot!

To generate one for our second plot with updated aesthetics to match the vpc package defaults, let’s pass the named list output from vpc::new_vpc_theme() to the update argument.

vpc_pc_new_legend <- plot_legend(update = vpc::new_vpc_theme())
vpc_pc_new_legend

Okay, now that we have our legend plot objects, let’s combine them with the VPC plot objects into a single plot object with the patchwork package.

vpc_pc_wleg <- vpc_pc + vpc_pc_legend + plot_layout(heights = c(2.5,1))
vpc_pc_wleg

vpc_pc_new_wleg <- vpc_pc_vpctheme_xgrid + vpc_pc_new_legend + plot_layout(heights = c(2.5,1))
vpc_pc_new_wleg