Skip to contents

The goal of pmxhelpr is to make pharmacometrics workflows more standardized, efficient, and reproducible. This package provides helper and wrapper functions for common steps in the modeling analysis workflow, outside of model parameter estimation. Currently, workflows cover key steps in exploratory data analysis, model evaluation, and forest plot model applications.

Documentation

Full narrative documentation, including worked examples for every plotting workflow, lives on the pmxhelpr website. Start with the articles:

Installation

pmxhelpr and its styling dependency ggstylekit are distributed through the PRISM package repository rather than CRAN. Each release of each package has its own PRISM repository, so declare both alongside a CRAN mirror for the remaining dependencies.

The recommended way to install pmxhelpr is with rv. Add the two PRISM repositories and pmxhelpr to your project’s rproject.toml, then run rv sync:

repositories = [
    { alias = "CRAN", url = "https://packagemanager.posit.co/cran/latest" },
    { alias = "pmxhelpr", url = "https://prism.dev.a2-ai.cloud/rpkgs/pmxhelpr/0.7.0/" },
    { alias = "ggstylekit", url = "https://prism.dev.a2-ai.cloud/rpkgs/ggstylekit/0.4.1/" }
]

dependencies = [
    "pmxhelpr"
]

Alternatively, install from the same repositories with install.packages():

install.packages("pmxhelpr",
                 repos = c("https://prism.dev.a2-ai.cloud/rpkgs/pmxhelpr/0.7.0",
                           "https://prism.dev.a2-ai.cloud/rpkgs/ggstylekit/0.4.1",
                           getOption("repos")))

To install a development version or another tagged release from GitHub, install ggstylekit from PRISM first, then use devtools:

# install.packages("devtools")
install.packages("ggstylekit",
                 repos = c("https://prism.dev.a2-ai.cloud/rpkgs/ggstylekit/0.4.1",
                           getOption("repos")))
devtools::install_github("ryancrass/pmxhelpr@v0.7.0")

The README examples use a package from Suggests that isn’t installed automatically:

install.packages("patchwork")

Function Naming Conventions

Exported functions follow a ReturnType_Purpose naming convention where the prefix indicates what the function returns:

  • plot_* — returns a ggplot object
  • df_* — returns a data.frame, or a pmx_stats container ($stats, $obs, $config) for the stats functions
  • var_* — returns a vector (vectorized helpers for use inside mutate)
  • style_* — returns a ggstylekit::style_spec (plot-family style preset)

Exploratory Data Analysis

  • Longitudinal PK and PK/PD Analysis:
    • plot_dvtime() — dependent variable versus time (e.g., concentration-time profiles)
    • plot_dvconc() — dependent variable versus a continuous independent variable (e.g., response vs concentration)
  • Dose Proportionality:
    • df_doseprop() — log-log regression parameters for multiple exposure metrics versus dose
    • plot_doseprop() — log-log regression plots of exposure metric(s) versus dose

Model Evaluation

  • Overlay Goodness-of-Fit Diagnostics:
    • plot_gof() — observed, population-, and individual-predicted values overlaid versus time
  • Visual Predictive Check (VPC):

Model Application

Styling

Plot aesthetics are controlled with ggstylekit. Each plot function has a corresponding style_*() preset that returns a ggstylekit::style_spec() pre-filled with the plot family defaults:

Styling is based on maps for plot aesthetics, which are keyed by roles in the output plot (e.g. obs_point, cent_line, cent_errorbar, ref_line, loq_line). The per-series maps (colors, shapes, sizes, linetypes, linewidths, alphas) are keyed by role, and only the roles specified override the defaults.

Additional variables in the dataset can be surfaced after the fact with reveal(), legends are described with legend_spec(), and styled plots are assembled with combine_styled_plots().

S3 Class System

pmxhelpr returns class-tagged objects for stats outputs, with predicates and print()/summary() methods for interactive inspection and programmatic validation.

pmxhelpr returns a class tagged object for VPC plot outputs to warn users via the +.pmx_vpc_plot method when facet_*() layers are added outside the returned object directing users to the correct stratification method using the strat_var argument.

See the Plot Styling and Aesthetics and VPC / Dose-Proportionality / Forest Plot workflow articles for worked examples.

Vectorized Helpers

mrgsolve Wrappers

Internal Datasets

  • data_sad — single ascending dose (SAD) study with parallel food effect cohort formatted for NLME modeling
  • data_sad_nca — PK parameters derived using non-compartmental analysis (NCA)
  • data_sad_pkfit — data_sad with individual (IPRED) and population (PRED) PK model predictions
  • data_sad_pkforest_sim — data_sad PK model replicate simulation output: exposure metrics across covariate scenarios, one row per scenario per replicate
  • data_sad_pkforest — long-format replicate draws of absolute and test/reference ratio exposure metrics for a forest plot

Note on bundled data. data_sad and data_sad_pkfit use ODV (original DV), to note that it is provided in original units from the source data. Functions like plot_dvtime() default dv_var = DV to match the standard NONMEM convention; when running examples on the bundled data, one may derive a variable DV or pass the argument dv_var = "ODV" (as every example below does).

Example Exploratory Data Analysis Workflow

This is a basic example which illustrates a simple exploratory data analysis workflow using pmxhelpr:

library(pmxhelpr)
library(dplyr)
library(ggplot2)

#Read internal analysis-ready dataset for an example Phase 1 study
glimpse(data_sad)

#Pre-process data for plotting
data <- data_sad %>%
  mutate(Food = ifelse(FOOD == 1, "Fed", "Fasted"),
         DoseFood = paste(DOSE,"mg x1", Food),
         Regimen = var_addn(DoseFood, ID))

#Plot drug concentration-time
plot_dvtime(data = filter(data, CMT == 2), dv_var = "ODV", cent = "mean_sdl",
            col_var = "Regimen", log_y = TRUE, show_obs = FALSE) +
  labs(y = "Concentration (ng/mL)")

#Plot response versus concentration
plot_dvconc(data = filter(data, CMT == 3), dv_var = "CFB", ref = 0,
            col_var = "Regimen", loess = TRUE, linear = TRUE) +
  labs(y = "Response (% Change)")

#Assess dose proportionality in the fasted state
glimpse(data_sad_nca)
data_sad_nca_part1 <- filter(data_sad_nca, PART == "Part 1-SAD")

#Tabulated dose-proportionality
table <- df_doseprop(data_sad_nca_part1, metrics = c("aucinf.obs", "cmax"))
table

#Visualize dose-proportionality
plot_doseprop(table)
plot_doseprop(data_sad_nca_part1, metrics = c("aucinf.obs", "cmax"))

Example Population Overlay Goodness-of-Fit Plot Workflow

This is a basic example which illustrates a simple model diagnostic workflow using pmxhelpr:

library(pmxhelpr)
library(dplyr)
library(ggplot2)
library(mrgsolve)
library(patchwork)
library(withr)

##Pre-process Data for Plotting
data <- data_sad_pkfit %>%
  mutate(Food = ifelse(FOOD == 1, "Fed", "Fasted"),
         DoseFood = paste(DOSE,"mg x1", Food),
         Regimen = var_addn(DoseFood, ID))

##Generate Population Overlay Goodness-of-fit Fit Plots by Food Status
plot_gof(data = data, dv_var = "ODV", dosenorm = TRUE) +
  facet_wrap(~Food) +
  labs(y = "Dose-normalized Conc. (ng/mL/mg)")

plot_gof(data = data, dv_var = "ODV", log_y = TRUE) +
  facet_wrap(~Regimen) +
  labs(y = "Concentration (ng/mL)")

Example Visual Predictive Check Analysis Workflow

This is a basic example which illustrates a simple VPC workflow using pmxhelpr:

library(pmxhelpr)
library(dplyr)
library(ggplot2)
library(mrgsolve)
library(patchwork)
library(withr)

#Read internal mrgsolve model file
model <- model_mread_load("pkmodel")

#Process Data
data <- data_sad %>% 
  filter(CMT %in% c(1, 2)) %>% 
  mutate(Food = ifelse(FOOD == 1, "Fed", "Fasted")) %>% 
  mutate(Food = var_addn(Food, ID))

#Simulated replicates of the dataset using mrgsim
  #The input `dv_var` is preserved in the output as `OBSDV` (observed) and the
  #simulated values are written to `SIMDV` --- these are the columns `plot_vpc_cont()` reads.
  #Pass any input columns you want carried to the output via `carry_out` (numeric)
  #and `recover` (character / factor), which flow through to `mrgsolve::mrgsim_df()`.
simout <- df_mrgsim_replicate(data = data, model = model, replicates = 100,
                              dv_var = "ODV",
                              carry_out = c("DOSE", "FOOD", "BLQ", "LLOQ"),
                              recover  = c("PART", "Food"))
glimpse(simout)

#Plot output in a Censored Visual Predictive Check (VPC)

plot_obj_cens <- plot_vpc_cens(
  data = simout,
  strat_var = "DOSE"
) +
scale_x_continuous(breaks = c(0,24,72,120,168)) +
labs(y = "Proportion BLQ", x = "Time (hours)")

plot_obj_cens

#Add Legend
shown_cens <- plot_vpc_shown(obs_pi_line = FALSE, sim_pi_ci = FALSE, obs_point = FALSE)
plot_obj_cens_leg <- plot_vpc_legend(shown = shown_cens, type = "cens")
plot_obj_cens_leg

plot_obj_cens_wleg <- plot_obj_cens + plot_obj_cens_leg + plot_layout(heights = c(2,1))
plot_obj_cens_wleg

#Plot output in a Prediction-corrected Visual Predictive Check (VPC)
  #Exact nominal time bins present in data_sad ("NTIME") are used to plot summary statistics
  #Actual time ("TIME") is used to plot observed data points (prediction-corrected if pcvpc=TRUE)


plot_obj_food <- plot_vpc_cont(
  data = simout, 
  strat_var = "Food",
  pcvpc = TRUE
) + 
 scale_x_continuous(breaks = c(0,24,72,120,168)) +
 scale_y_log10(guide = "axis_logticks") +
 labs(y = "Pred-corrected Conc. (ng/mL)", x = "Time (hours)")

plot_obj_food

#Add Legend
plot_obj_leg <- plot_vpc_legend()
plot_obj_leg

plot_obj_food_wleg <- plot_obj_food + plot_obj_leg + plot_layout(heights = c(2,1))
plot_obj_food_wleg

Example Forest Plot Workflow

This is a basic example which illustrates a forest plot workflow using pmxhelpr:

library(pmxhelpr)
library(dplyr)
library(ggplot2)

#Read View Internal Datasets
glimpse(data_sad_pkforest)

#Generate the summary dataset using df_forest()
forest_obj <- df_forest(data_sad_pkforest, 
                        cov_level_ref = c(FOOD = "Fasted", WTBL = "70 kg"))

#Consume the summary dataset to generate the Forest Plot using plot_forest()
plot_forest(forest_obj, 
            metric = "AUCRATIO",
            ref_band = c(0.8, 1.25)) +
  scale_x_log10(limits = c(0.5, 5), 
            breaks = c(0.5, 0.8, 1, 1.25, 2, 3, 4, 5)) +
  labs(subtitle = "Ratio (90% CI)")