library(shiny) library(bslib) library(mrgsolve) library(dplyr) library(ggplot2) # ───────────────────────────────────────────────────────────────────────────── # Docetaxel 3-Compartment Population PK Model # Source: Bruno et al. (1996) J Pharmacokinet Biopharm 24:153-172 (model) # Bruno et al. (1998) J Clin Oncol 16:187-196 (PK/PD analysis) # Structural model: 3-CMT, IV infusion (1-hour), first-order elimination # CL affected by: BSA, AAG, hepatic function (ALT + ALP elevation) # ───────────────────────────────────────────────────────────────────────────── model_code <- ' $PARAM @annotated CL : 35.6 : Clearance (L/h) — typical patient, 100 mg/m2 q3w V1 : 5.1 : Central volume of distribution (L) Q2 : 14.0 : Intercompartmental clearance, CMT1-CMT2 (L/h) V2 : 95.0 : Peripheral volume 1 (L) Q3 : 3.5 : Intercompartmental clearance, CMT1-CMT3 (L/h) V3 : 60.0 : Peripheral volume 2 (L) BSA : 1.73 : Body surface area (m2) AAG : 0.7 : Alpha-1-acid glycoprotein (g/L) HEPF : 1.0 : Hepatic function (1 = normal, 0.73 = elevated enzymes) $CMT @annotated CENT : Central compartment (mg) PERI1 : Peripheral compartment 1 (mg) PERI2 : Peripheral compartment 2 (mg) $MAIN // Covariate effects on CL (Bruno 1996/1998): // BSA: CL proportional to BSA/1.73 // AAG: higher AAG → lower CL (protein binding) // Hepatic: 27% decrease in CL if ALT>1.5xULN AND ALP>2.5xULN double CLi = CL * (BSA / 1.73) * (0.7 / AAG) * HEPF; double V1i = V1 * (BSA / 1.73); double V2i = V2 * (BSA / 1.73); double V3i = V3 * (BSA / 1.73); $ODE dxdt_CENT = - (CLi/V1i) * CENT - (Q2/V1i) * CENT + (Q2/V2i) * PERI1 - (Q3/V1i) * CENT + (Q3/V3i) * PERI2; dxdt_PERI1 = (Q2/V1i) * CENT - (Q2/V2i) * PERI1; dxdt_PERI2 = (Q3/V1i) * CENT - (Q3/V3i) * PERI2; $TABLE double CP = CENT / V1i; $CAPTURE CP ' mod <- mcode("docetaxel_3cmt", model_code) app_theme <- bs_theme( version = 5, bootswatch = "flatly", primary = "#8b5cf6" ) |> bs_add_rules(" .metric-card { background: #f8f9fa; border-radius: 8px; padding: 15px; margin: 5px; text-align: center; border: 1px solid #dee2e6; } .metric-value { font-size: 24px; font-weight: bold; color: #2c3e50; } .metric-label { font-size: 12px; color: #7f8c8d; } .metric-success .metric-value { color: #10b981; } .metric-warning .metric-value { color: #f59e0b; } .metric-primary .metric-value { color: #8b5cf6; } .metric-info .metric-value { color: #0dcaf0; } .ref-box { background: #f0f4ff; border-left: 4px solid #8b5cf6; padding: 12px 16px; border-radius: 4px; margin-top: 10px; font-size: 13px; } .ref-box a { color: #8b5cf6; } .safety-box { background: #fff8f0; border-left: 4px solid #f59e0b; padding: 10px 14px; border-radius: 4px; margin-top: 8px; font-size: 13px; } ") ui <- page_sidebar( title = "Docetaxel (Taxotere) PK Simulator", theme = app_theme, sidebar = sidebar( title = "Simulation Settings", width = 360, h6("Dosing"), sliderInput("dose_bsa", "Dose (mg/m²)", min = 60, max = 100, value = 75, step = 5), sliderInput("n_cycles", "Number of Cycles (q3w)", min = 1, max = 6, value = 1, step = 1), hr(), h6("Patient Characteristics"), sliderInput("bsa", "Body Surface Area (m²)", min = 1.2, max = 2.4, value = 1.73, step = 0.05), sliderInput("aag", "AAG – α1-Acid Glycoprotein (g/L)", min = 0.3, max = 2.0, value = 0.7, step = 0.1), selectInput("hepf", "Hepatic Function", choices = c( "Normal (ALT/ALP normal)" = "1.0", "Elevated enzymes (ALT>1.5×ULN + ALP>2.5×ULN): −27% CL" = "0.73" ), selected = "1.0"), hr(), checkboxInput("log_scale", "Log Scale (Y-axis)", value = FALSE) ), layout_column_wrap( width = 1/4, fill = FALSE, div(class="metric-card metric-success", div(class="metric-value", textOutput("cmax")), div(class="metric-label", "Cmax (µg/mL)")), div(class="metric-card metric-info", div(class="metric-value", textOutput("auc")), div(class="metric-label", "AUC (µg·h/mL)")), div(class="metric-card metric-primary", div(class="metric-value", textOutput("thalf")), div(class="metric-label", "t½ terminal (h)")), div(class="metric-card metric-warning", div(class="metric-value", textOutput("cl_ind")), div(class="metric-label", "Individual CL (L/h)")) ), card( full_screen = TRUE, height = "520px", plotOutput("pkPlot", height = "480px") ), navset_card_underline( nav_panel("Model Information", markdown(" ## Docetaxel (Taxotere) — 3-Compartment Population PK Model **Drug class:** Taxane — microtubule stabilizer **Indication:** Breast, NSCLC, prostate, gastric, head & neck cancers **Standard regimen:** 75–100 mg/m² IV over 1 hour, every 3 weeks **Route:** IV infusion only (1-hour infusion) --- ### Structural Model (Bruno 1996) A three-compartment open model with zero-order IV infusion and first-order elimination was used to describe the plasma concentration–time course of docetaxel in 521 patients across 22 Phase II studies. | Parameter | Population Value | IIV (CV%) | |-----------|-----------------|-----------| | CL (L/h) | 35.6 | ~33% | | V1 (L) | 5.1 | ~ | | Q2 (L/h) | 14.0 | — | | V2 (L) | 95.0 | — | | Q3 (L/h) | 3.5 | — | | V3 (L) | 60.0 | — | *Parameters normalized to BSA 1.73 m²* --- ### Covariate Effects on CL - **BSA:** Dose-normalized exposure is BSA-independent (justifies BSA-based dosing) - **AAG (α1-acid glycoprotein):** Higher AAG → lower free fraction → lower CL. Major predictor of toxicity (83% lower odds of grade 4 neutropenia per 1 g/L increase in AAG) - **Hepatic impairment:** 27% decrease in CL when ALT >1.5× ULN **and** ALP >2.5× ULN simultaneously → 25% dose reduction recommended --- ### PK/PD Relationships (Bruno 1998) This landmark study in 640 cancer patients demonstrated: - **Neutropenia (grade 4):** Strongly predicted by AUC and CL (CLf: 4.3-fold increase in odds for 50% CL decrease) - **Febrile neutropenia:** 3.0-fold increased odds for 50% CL decrease - **Fluid retention:** Cumulative dose + t₀.₂₀ (duration above 0.20 µmol/L) are key predictors - **NSCLC efficacy:** Higher AUC predicts longer time to progression (11% risk reduction per AUC unit) --- ### Toxicity Reference | Toxicity | Key Predictor | Threshold | |--------------------|--------------------|----------------------------------| | Grade 4 neutropenia | CL, AUC, AAG | ~64% incidence at 100 mg/m² | | Febrile neutropenia | CL, AAG | ~4.5% incidence | | Fluid retention | Cumulative dose | Median onset ~85 days (53% pts) | ")), nav_panel("References", div(class = "ref-box", tags$h5("📚 Key References"), tags$ol( tags$li("Bruno R, Vivier N, Vergniol JC, De Phillips SL, Montay G, Sheiner LB. A population pharmacokinetic model for docetaxel (Taxotere): model building and validation. ", tags$em("J Pharmacokinet Biopharm."), " 1996;24(2):153-172. doi:10.1007/BF02353487"), tags$li("Bruno R, Hille D, Riva A, et al. Population pharmacokinetics/pharmacodynamics of docetaxel in phase II studies in patients with cancer. ", tags$em("J Clin Oncol."), " 1998;16(1):187-196. doi:10.1200/JCO.1998.16.1.187"), tags$li("Taxotere® (docetaxel) Prescribing Information. Sanofi-Aventis US LLC. 2010.") ), tags$h5("💊 Therapeutic Context"), tags$ul( tags$li(tags$strong("Drug class:"), " Taxane / antimitotic"), tags$li(tags$strong("Route:"), " IV infusion over 1 hour"), tags$li(tags$strong("Standard dose:"), " 75–100 mg/m² q3w"), tags$li(tags$strong("Metabolism:"), " CYP3A4 (hepatic)"), tags$li(tags$strong("Protein binding:"), " ~94% (AAG + albumin)"), tags$li(tags$strong("Elimination t½:"), " ~11 hours (terminal)") ) ), div(class = "safety-box", tags$strong("⚠️ Dose Reduction Guidance:"), tags$ul( tags$li("Hepatic impairment (ALT >1.5× ULN AND ALP >2.5× ULN): reduce dose by 25% (75→56 mg/m² or 100→75 mg/m²)"), tags$li("Grade ≥3 neutropenia or febrile neutropenia in prior cycle: reduce dose"), tags$li("Fluid retention: dexamethasone premedication strongly recommended") ) ) ) ), div(style = "text-align: center; padding: 20px; margin-top: 30px; border-top: 1px solid #e9ecef; color: #6c757d; font-size: 12px;", "Powered by ", tags$a(href="https://www.pkpdbuilder.com", target="_blank", style="color: #8b5cf6; font-weight: 500;", "PKPDBuilder.com"), " • For research and educational purposes only. Not for clinical decision-making." ) ) server <- function(input, output, session) { get_params <- reactive({ bsa <- as.numeric(input$bsa) aag <- as.numeric(input$aag) hepf <- as.numeric(input$hepf) dose_total <- as.numeric(input$dose_bsa) * bsa # total mg list(bsa = bsa, aag = aag, hepf = hepf, dose_total = dose_total) }) sim_data <- reactive({ shiny::req(input$bsa, input$aag, input$hepf, input$dose_bsa, input$n_cycles) p <- get_params() n_cycles <- as.integer(input$n_cycles) infusion_dur <- 1 # 1-hour infusion # Build dosing events: zero-order infusion (rate = dose/1h) dose_mg <- p$dose_total evs <- lapply(seq_len(n_cycles), function(i) { ev(amt = dose_mg, cmt = 1, rate = dose_mg / infusion_dur, time = (i - 1) * 21 * 24) }) ev_all <- do.call(c, evs) sim_end <- n_cycles * 21 * 24 mod |> param(BSA = p$bsa, AAG = p$aag, HEPF = p$hepf) |> ev(ev_all) |> mrgsim(end = sim_end, delta = 0.1) |> as.data.frame() }) output$cmax <- renderText({ d <- sim_data() # Cmax from first cycle (0-48h) first <- dplyr::filter(d, time <= 48) sprintf("%.2f", max(first$CP, na.rm = TRUE)) }) output$auc <- renderText({ d <- sim_data() # AUC 0→24h, first cycle first <- dplyr::filter(d, time >= 0, time <= 24) auc <- sum(diff(first$time) * (head(first$CP, -1) + tail(first$CP, -1)) / 2) sprintf("%.2f", auc) }) output$thalf <- renderText({ # Terminal t½ approximated from CL and V_ss # V_ss = V1 + V2 + V3 (scaled by BSA) p <- get_params() bsa <- p$bsa cl_i <- 35.6 * (bsa / 1.73) * (0.7 / p$aag) * p$hepf vss <- (5.1 + 95.0 + 60.0) * (bsa / 1.73) # Rough terminal slope approximation (lambda_z ≈ CL/Vss) lam_z <- cl_i / vss sprintf("%.1f", log(2) / lam_z) }) output$cl_ind <- renderText({ p <- get_params() cl_i <- 35.6 * (p$bsa / 1.73) * (0.7 / p$aag) * p$hepf sprintf("%.1f", cl_i) }) output$pkPlot <- renderPlot({ d <- sim_data() n_cycles <- as.integer(input$n_cycles) # Threshold concentrations (µg/mL converted from µmol/L) # MW docetaxel ≈ 807.9 g/mol # 0.20 µmol/L = 0.20 * 807.9 / 1000 µg/mL ≈ 0.162 µg/mL thresh_020 <- 0.162 # µg/mL (0.20 µmol/L — PD toxicity threshold) p <- ggplot(d, aes(x = time / 24, y = CP)) + geom_hline(yintercept = thresh_020, linetype = "dashed", color = "#f59e0b", linewidth = 0.7, alpha = 0.8) + annotate("text", x = max(d$time / 24) * 0.02, y = thresh_020 * 1.3, label = "t₀.₂₀ threshold (0.20 µmol/L)", hjust = 0, size = 3.2, color = "#f59e0b") + geom_line(color = "#8b5cf6", linewidth = 0.9) + scale_x_continuous( breaks = seq(0, n_cycles * 21, by = 21), labels = paste0("Day ", seq(0, n_cycles * 21, by = 21)) ) + labs( x = "Time (days)", y = "Docetaxel Plasma Concentration (µg/mL)", title = paste0("Docetaxel ", input$dose_bsa, " mg/m² q3w × ", n_cycles, " cycle(s) | BSA ", input$bsa, " m² | AAG ", input$aag, " g/L") ) + theme_minimal(base_size = 13) + theme( plot.title = element_text(size = 12, face = "bold"), axis.text.x = element_text(angle = 30, hjust = 1) ) if (input$log_scale) { p <- p + scale_y_log10() + aes(y = pmax(CP, 1e-4)) # avoid log(0) } p }) } shinyApp(ui = ui, server = server)