library(shiny) library(bslib) library(mrgsolve) library(dplyr) library(ggplot2) model_code <- ' $PARAM @annotated CL : 0.0955 : Linear clearance (L/day) for 74.1 kg V2 : 2.56 : Central volume (L) for 74.1 kg K23 : 0.109 : Central to peripheral rate constant (1/day) K32 : 0.124 : Peripheral to central rate constant (1/day) VMAX : 3.16 : Max target-mediated elimination rate (mg/day) KM : 1.02 : Michaelis-Menten constant (mg/L) KA : 0.181 : Absorption rate constant (1/day) F1 : 0.714 : SC bioavailability APTS : 0.168 : Absorption lag time (days) WT : 74.1 : Body weight (kg) HOFH : 1 : Disease state (0=Healthy, 1=HoFH) ROUTE: 0 : Administration route (0=IV, 1=SC) $CMT @annotated DEPOT : SC depot (mg) CENT : Central (mg) PERI : Peripheral (mg) $MAIN // Allometric scaling double CLi = CL * pow(WT / 74.1, 0.75); double V2i = V2 * pow(WT / 74.1, 0.875); double K23i = K23; double K32i = K32; // Disease state effect on Vmax: HoFH reduces Vmax by 28.9% double VMAXi = VMAX * (1.0 - 0.289 * HOFH); // SC route parameters if (ROUTE == 1) { F_DEPOT = F1; ALAG_DEPOT = APTS; } else { F_DEPOT = 1.0; ALAG_DEPOT = 0.0; } $ODE double CP = CENT / V2i; double CLNL = VMAXi / (KM + CP); // nonlinear CL contribution dxdt_DEPOT = -KA * DEPOT; dxdt_CENT = KA * DEPOT - (CLi / V2i) * CENT - (CLNL / V2i) * CENT - K23i * CENT + K32i * PERI; dxdt_PERI = K23i * CENT - K32i * PERI; $TABLE double CPtab = CENT / V2i; $CAPTURE CPtab ' mod <- mcode("evinacumab", 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; } ") ui <- page_sidebar( title = "Evinacumab (Evkeeza\u00AE) PK Simulator", theme = app_theme, sidebar = sidebar( title = "Simulation Settings", width = 340, h6("Dosing"), radioButtons("route", "Route of Administration", choices = c("IV (15 mg/kg q4w)" = "IV", "SC (450 mg qw)" = "SC"), selected = "IV" ), conditionalPanel( condition = "input.route == 'IV'", sliderInput("iv_dose", "IV Dose (mg/kg)", min = 5, max = 20, value = 15, step = 5), sliderInput("iv_interval", "Dosing Interval (weeks)", min = 1, max = 12, value = 4, step = 1) ), conditionalPanel( condition = "input.route == 'SC'", sliderInput("sc_dose", "SC Dose (mg)", min = 75, max = 450, value = 450, step = 75), sliderInput("sc_interval", "Dosing Interval (weeks)", min = 1, max = 4, value = 1, step = 1) ), numericInput("n_weeks", "Simulation Duration (weeks)", value = 24, min = 4, max = 52), hr(), h6("Patient Characteristics"), sliderInput("wt", "Body Weight (kg)", min = 40, max = 150, value = 74, step = 1), radioButtons("disease", "Disease State", choices = c("HoFH" = "1", "Healthy Volunteer" = "0"), selected = "1" ), hr(), checkboxInput("log_scale", "Log Scale (Y-axis)", value = FALSE) ), navset_card_tab( title = "Evinacumab PK Simulator", full_screen = TRUE, nav_panel("Simulation", 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 (mg/L)")), div(class = "metric-card metric-warning", div(class = "metric-value", textOutput("ctrough")), div(class = "metric-label", "Ctrough (mg/L)")), div(class = "metric-card metric-primary", div(class = "metric-value", textOutput("auc")), div(class = "metric-label", HTML("AUC\u03C4 (mg\u00B7day/L)"))), div(class = "metric-card metric-info", div(class = "metric-value", textOutput("thalf")), div(class = "metric-label", HTML("t\u00BD (days)"))) ), plotOutput("pkPlot", height = "500px") ), nav_panel("Model Information", markdown(" ## Evinacumab (Evkeeza\u00AE) \u2014 Population PK Model **Structure:** Two-compartment with parallel linear and saturable (Michaelis\u2013Menten) elimination and first-order SC absorption ### Population PK Parameters (Typical Values) | Parameter | Value | Description | |-----------|-------|-------------| | CL | 0.0955 L/day | Linear clearance (74.1 kg subject) | | V2 (Central) | 2.56 L | Central volume of distribution | | V3 (Peripheral) | 2.25 L | Peripheral volume | | Q (K23/K32) | 0.109 / 0.124 day\u207B\u00B9 | Intercompartmental rate constants | | Vmax | 3.16 mg/day | Max saturable elimination rate | | KM | 1.02 mg/L | Michaelis\u2013Menten constant | | Ka | 0.181 day\u207B\u00B9 | SC absorption rate constant | | F | 0.714 | SC bioavailability | | ALAG | 0.168 days | Absorption lag time | ### Covariate Effects - **Body weight:** Allometric scaling on CL (exponent 0.75) and V2 (exponent 0.875), reference 74.1 kg - **Disease state:** HoFH reduces Vmax by 28.9% vs. healthy volunteers - **ANGPTL3:** Positive relationship with Vmax (exponent 0.405) ### Clinical Context - **Approved dose:** 15 mg/kg IV every 4 weeks for HoFH - At clinically relevant concentrations, linear CL dominates - Weight-based dosing provides consistent exposure across weight ranges ")), nav_panel("References", div(class = "ref-box", tags$h5("\U0001F4DA Key References"), tags$ol( tags$li("Pu X et al. (2021) CPT Pharmacometrics Syst Pharmacol 10:1412-1421 \u2014 Population PK and exposure\u2013response modeling for evinacumab in HoFH"), tags$li("Raal FJ et al. (2020) N Engl J Med 383:711-720 \u2014 ELIPSE HoFH phase III trial"), tags$li("Evkeeza (evinacumab-dgnb) US Prescribing Information, Regeneron Pharmaceuticals, Inc.") ), tags$h5("\U0001F48A Therapeutic Context"), tags$ul( tags$li(tags$strong("Class:"), " Fully human monoclonal antibody, ANGPTL3 inhibitor"), tags$li(tags$strong("Indication:"), " Adjunct to other LDL-C\u2013lowering therapies for HoFH (adults and pediatric \u226512 years)"), tags$li(tags$strong("Approved dose:"), " 15 mg/kg IV every 4 weeks"), tags$li(tags$strong("Mechanism:"), " Inhibits ANGPTL3 \u2192 reduces LDL-C independent of LDL receptor pathway"), tags$li(tags$strong("Approval:"), " FDA February 2021") ) )) ), 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"), " \u2022 Built by Sunny \u2600\uFE0F (Husain Attarwala's AI Assistant)", br(), tags$span(style = "font-size: 10px;", "For research and educational purposes only. Not for clinical decision-making.")) ) server <- function(input, output, session) { sim_data <- reactive({ n_days <- input$n_weeks * 7 if (input$route == "IV") { dose_mg <- input$iv_dose * input$wt ii_days <- input$iv_interval * 7 n_doses <- floor(n_days / ii_days) ev1 <- ev(amt = dose_mg, cmt = 2, ii = ii_days, addl = max(n_doses - 1, 0), rate = dose_mg / (1/24)) route_flag <- 0 } else { dose_mg <- input$sc_dose ii_days <- input$sc_interval * 7 n_doses <- floor(n_days / ii_days) ev1 <- ev(amt = dose_mg, cmt = 1, ii = ii_days, addl = max(n_doses - 1, 0)) route_flag <- 1 } mod %>% param(WT = input$wt, HOFH = as.numeric(input$disease), ROUTE = route_flag) %>% ev(ev1) %>% mrgsim(end = n_days, delta = 0.1) %>% as.data.frame() %>% mutate(time_d = time, time_w = time / 7) }) # Get the last dosing interval data last_interval <- reactive({ d <- sim_data() if (input$route == "IV") { ii_days <- input$iv_interval * 7 } else { ii_days <- input$sc_interval * 7 } n_days <- input$n_weeks * 7 last_start <- n_days - ii_days d %>% filter(time_d >= last_start) }) output$cmax <- renderText({ li <- last_interval() sprintf("%.1f", max(li$CPtab, na.rm = TRUE)) }) output$ctrough <- renderText({ li <- last_interval() sprintf("%.2f", min(li$CPtab, na.rm = TRUE)) }) output$auc <- renderText({ li <- last_interval() if (nrow(li) < 2) return("--") auc <- sum(diff(li$time_d) * (head(li$CPtab, -1) + tail(li$CPtab, -1)) / 2) sprintf("%.0f", auc) }) output$thalf <- renderText({ CLi <- 0.0955 * (input$wt / 74.1)^0.75 V2i <- 2.56 * (input$wt / 74.1)^0.875 # Apparent terminal half-life (linear component dominates at therapeutic concentrations) sprintf("%.1f", log(2) / (CLi / V2i)) }) output$pkPlot <- renderPlot({ d <- sim_data() # Therapeutic window: approximate target concentrations # At 15 mg/kg q4w, typical Ctrough ~100 mg/L, Cmax ~800 mg/L # Use approximate efficacious trough for reference p <- ggplot(d, aes(x = time_w, y = CPtab)) + annotate("rect", xmin = -Inf, xmax = Inf, ymin = 50, ymax = 500, fill = "#10b981", alpha = 0.1) + geom_hline(yintercept = c(50), linetype = "dashed", color = "#10b981", alpha = 0.6) + annotate("text", x = max(d$time_w) * 0.02, y = 55, label = "Approximate efficacious trough (~50 mg/L)", hjust = 0, vjust = -0.5, size = 3.5, color = "#10b981") + geom_line(color = "#8b5cf6", linewidth = 0.8) + labs( x = "Time (weeks)", y = "Evinacumab Concentration (mg/L)", title = if (input$route == "IV") { paste0("Evinacumab ", input$iv_dose, " mg/kg IV Q", input$iv_interval, "W (", round(input$iv_dose * input$wt), " mg) — ", ifelse(input$disease == "1", "HoFH", "Healthy")) } else { paste0("Evinacumab ", input$sc_dose, " mg SC Q", input$sc_interval, "W — ", ifelse(input$disease == "1", "HoFH", "Healthy")) } ) + theme_minimal(base_size = 14) + theme(plot.title = element_text(face = "bold")) if (input$log_scale) p <- p + scale_y_log10() p }) } shinyApp(ui = ui, server = server)