A Guide to Exposure-Response Plots

Visualizing the relationship between drug exposures and treatment response using R and ggplot.

August 16, 2022

E-R Log-Reg Plot

Exposure-Response Analyses: Introduction

In the past few decades, exposure-response analyses have become an integral part of the development of new drug products, and have become an important (and expected) component in the justification of dose selection when submitting for regulatory approval. Assessing the relationship between drug exposure and treatment response provides a level of granularity which can't be achieved by only looking at the dose-response relationship. Exposure-response analyses can assist in making critical decisions around a variety of topics including:

  • Optimal Dose for Benefit:Risk:

    • Is an efficacy plateau achieved within the range of studied drug exposures?
    • At what exposures is a response plateau seen for key efficacy and safety measures?
  • Dosage Form Reformulation/Dose Interval Extension:

    • What is the best exposure metric (AUC, Cmax, Ctrough) which correlates with treatment response/adverse events?
    • What dose would match those exposures when transitioning to an extended-release formulation?
    • Is there an opportunity to extend the dosing interval of the current formulation while still achieving adequate AUC or Ctrough exposures for efficacy while avoiding toxic Cmax exposures?
  • Dose Selection in Subpopulations

    • Is the exposure-response relationship different within different subpopulations?
    • Are there statistically significant covariate effects with the exposure-response model?
  • Dose-Extrapolation to Pediatric Subjects

    • Is the exposure-response relationship in pediatric subjects and adults similar?
    • What pediatric dose would result in similar exposures as those studied extensively in adult subjects?

Data Needed for Exposure-Response Analyses

  • Drug-exposure metrics (AUC, Cavg, Cmax, and/or Ctrough) for individual subjects

    • Drug exposure metrics can be obtained from population PK analysis or NCA (if densely sampled PK is available)
  • Treatment response variable(s)

    • These should be aligned with the primary and key secondary clinical endpoints of the trial.
  • Covariates

    • Patient demographics and other key patient characteristics

Graphical Assessment of Exposure-Response Relationships

This post will focus on strategies and examples for graphically assessing exposure-response relationships. The code used in this example was designed to be general and can be adapted to be used for other datasets.

In this post we will (1) simulate dummy exposure-response data, (2) summarize treatment response by exposure quartile, and (3) visualize the exposure-response relationship using two common E-R plots - bar plot of response variable by exposure quartile, and regression line of relationship between exposure metric and treatment response.

Load Libraries

library(dplyr)     # for data manipulation
library(ggplot2)   # for plotting
library(binom)     # for calculation of confidence interval
library(patchwork) # for combining plots

#Setting ggplot theme
theme_set(theme_bw())

Simulate Exposure Response Data

Exposures (AUC) were simulated from a log-normal distribution at 3 active dose levels and a placebo group. 200 subjects were included in each arm. The response variable is a binary response, with the probability of achieving response correlated with AUC.

# Generating Exposure-Response Dataset with AUC (log normal) as exposure metric
placebo <- data.frame(Dose = "Placebo", AUC24 =  rep(0, 200))
dose1 <- data.frame(Dose = "150 mg", AUC24 =  rlnorm(200, meanlog = log(10), sdlog = log(1.5)))
dose2 <- data.frame(Dose = "300 mg", AUC24 =  rlnorm(200, meanlog = log(20), sdlog = log(1.5)))
dose3 <- data.frame(Dose = "600 mg", AUC24 =  rlnorm(200, meanlog = log(40), sdlog = log(1.5)))

exposure_data <- rbind(placebo, dose1, dose2, dose3) %>%
  mutate(z = .035*AUC24, pr = 1/(1+exp(-z)) - 0.3, resp = rbinom(800,1,pr))

print(head(exposure_data,10))
IDDoseAUC24zprresp
1Placebo000.20
2Placebo000.20
3Placebo000.20
4Placebo000.20
5Placebo000.20
6Placebo000.21
7Placebo000.20
8Placebo000.20
9Placebo000.20
10Placebo000.20
# Setting Dose as a factor will ensure Dose levels show up in the correct order when plotting.

exposure_data$Dose <- factor(exposure_data$Dose, levels = c("Placebo", "150 mg", "300 mg", "600 mg"))


# Separate placebo and active treatment groups
exposure_data_placebo <- filter(exposure_data, Dose == "Placebo")
exposure_data_active <- filter(exposure_data, Dose != "Placebo")

Choosing the Number of Quantiles

The number of quantiles that you choose depends on the size of your dataset, the spread of exposures within the dataset, and the variability associated with the response. Larger datasets with small variability in response support the use of a greater number of quantiles and vice-versa. Generally, four quantiles (quartiles) is a good balance to provide enough exposure bins to elucidate the E-R relationship while not too many that there are large fluctuations between bins due to random variability of treatment response. However, it is also a good idea to test different quantiles (usually between 2-10) to see when the randomness in quantile bins begins to outweigh the extra granularity of using more bins.

For this code example, 4 quantiles are used, although it is set up in a way that the number of quantiles can be updated and rerun to produce figures with different numbers of quantiles.

# Update n_quantile and rerun to view ER plot with different number of quantiles
n_quantile <- 4

step <- 1/n_quantile
quantiles <- seq(0, 1, step)
print(quantiles)
## [1] 0.00 0.25 0.50 0.75 1.00


# Define exposure cutoffs
breaks <- quantile(exposure_data_active$AUC24, quantiles)
print(breaks)
##         0%        25%        50%        75%       100%
##   2.900026  12.002059  19.683045  33.981775 111.558171

Partitioning the exposures into quantiles and summarize

We will use a handy function called cut in base R to bin the individual exposures into their associated exposure bin.

# Use cut function to place each subjects exposure into the correct bin
exposure_data_active <- exposure_data_active %>%
  mutate(quantile = cut(AUC24, breaks, include.lowest = TRUE))

# Setting Placebo group quantile to "Placebo" for plotting purposes
exposure_data_placebo <- exposure_data_placebo %>%
  mutate(quantile = "Placebo")

# Combine placebo and active treatment groups
exposure_data_all <- rbind(exposure_data_placebo, exposure_data_active)

# Set quantile factors to ensure quantile labels show up in the correct
#   order when plotting.
exposure_data_all$quantile <- factor(exposure_data_all$quantile,
                                     levels = c("Placebo", levels(cut(exposure_data_active$AUC24, breaks,  include.lowest = TRUE))))

er_summary <- exposure_data_all %>%
  group_by(quantile) %>%
  summarise(median_AUC = median(AUC24),
            n = n(),
            resp_n = sum(resp),
            resp_perc = sum(resp)/n()*100,
            placebo = quantile[1] == "Placebo",
            ci = binom.confint(sum(resp), n(),
                               conf.level = 0.95, methods = "exact"))
print (er_summary)

## # A tibble: 5 x 7
##   quantile median_AUC     n resp_n resp_perc placebo ci$method    $x    $n $mean
##   <fct>         <dbl> <int>  <int>     <dbl> <lgl>   <chr>     <int> <int> <dbl>
## 1 Placebo        0      200     51      25.5 TRUE    exact        51   200 0.255
## 2 [2.9,12]       8.27   150     46      30.7 FALSE   exact        46   150 0.307
## 3 (12,19.~      15.8    150     41      27.3 FALSE   exact        41   150 0.273
## 4 (19.7,3~      25.7    150     64      42.7 FALSE   exact        64   150 0.427
## 5 (34,112]      44.5    150     87      58   FALSE   exact        87   150 0.58

Plot Exposure-Response Quantile Plot

# Exposure Response Quantile Plot
ggplot(er_summary, aes(x = quantile, y = resp_perc )) +
  geom_col( aes(fill = placebo), alpha = 0.6) +
  geom_text(aes(label = paste0("(",resp_n,"/", n, ")")), vjust = -0.5, color = "grey30", size = 3,
            position = position_dodge(width = 0.9)) +
  geom_text(aes(label = paste0(round(resp_perc,1),"%")), vjust = -1.9, color = "grey30", size = 3,
            position = position_dodge(width = 0.9)) +
  labs(x = "AUC Exposure Quantile (ng/ml*hr)",
       y = "Percent Responders (%)",
       title = "Exposure-Response Quantile Plot",
       subtitle = paste(n_quantile, "Bins") ) +
  scale_y_continuous(limits = c(0, 100)) +
  scale_fill_manual(values = c( "purple4", "grey20")) +
  guides(fill = "none")

E-R Quartile Plot

Plot Exposure-Response Quantile Plot

# Exposure Response Logistic Regression Plot
er_plot <- ggplot(er_summary, aes(x = median_AUC, y = resp_perc/100)) +
  geom_point() +
  geom_errorbar(aes(ymax = ci$upper, ymin = ci$lower)) +
  geom_jitter(data = exposure_data_all,
              aes(x = AUC24,y =resp, color = Dose ),
              height = 0.05,
              alpha = 0.5) +
  geom_smooth(data = exposure_data_all,
              aes(x = AUC24,y =resp ),
              color = "grey10",
              method = "glm",
              method.args = list(family = "binomial")) +
  labs(x= "AUC (ng/ml*hr)", y = "Probability of Response") +
  scale_x_continuous(limits= c(-1, 125))

# Summary plot of exposures
exposure_plot <- ggplot(exposure_data,
                        aes(x = AUC24, y = Dose, fill = Dose, color = Dose)) +
  stat_boxplot(geom = "errorbar", width = 0.5) +
  geom_boxplot(outlier.colour = NA, width = 0.7,
               alpha = 0.5) +
  scale_x_continuous(limits= c(-1, 125)) +
  labs(x= "AUC (ng/ml*hr)", y = "Dose Group") +
  guides(color = "none", fill = "none")


# Combining  ER Plot and exposure summary plot
er_plot/exposure_plot  + plot_layout(heights = c(2, 1))

E-R Log-Reg Plot

That's all there is to it. For any given exposure-response analysis, there will be dozens of plots such as the ones above exploring different exposure metrics, different clinical efficacy endpoints and adverse events, and different numbers of quantiles. The code in this example can be updated or even made into a function to loop through different inputs of interest.

Additional Resources

xGx R Package: An R package for exploratory graphical analyses with some functions geared towards E-R visualizations.

Establishing Good Practices for Exposure–Response Analysis of Clinical Endpoints in Drug Development: Paper with more details and background on Exposure-Response analyses. RV Overgaard, SH Ingwersen, and CW Tornøe.

Thanks for reading.
Like the post? Give it a thumbs up.
Have some feedback? Leave us a comment.