--- title: "Clinical workflow with ADaM data" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Clinical workflow with ADaM data} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 9, fig.height = 6, dpi = 150 ) library(mirrorslope) library(ggplot2) ``` ## Purpose This vignette shows a realistic pattern for producing a mirror slope plot from an analysis dataset structured along ADaM conventions. It covers merging a population flag from a subject-level dataset, filtering to the analysis population, and supplying model-based estimates. The package does not fit models. Estimates and their precision are computed upstream (for example from a mixed model for repeated measures) and passed in. This keeps the tool model-agnostic and the figure fully traceable to the values supplied. ## A simulated ADaM-style dataset We construct a basic-data-structure analysis dataset (`adqs`) with one record per subject per visit, and a subject-level dataset (`adsl`) carrying treatment assignment and a safety population flag. ```{r simulate} set.seed(7) n_subj <- 60 adsl <- data.frame( USUBJID = paste0("SUBJ-", sprintf("%03d", seq_len(n_subj))), TRT01P = rep(c("Placebo", "Active"), each = n_subj / 2), SAFFL = "Y", ITTFL = "Y", stringsAsFactors = FALSE ) # A few subjects out of the safety population adsl$SAFFL[c(3, 17, 42)] <- "N" base_val <- rnorm(n_subj, 0, 4) chg_val <- ifelse(adsl$TRT01P == "Placebo", rnorm(n_subj, -11, 6), rnorm(n_subj, -6, 6)) adqs <- data.frame( USUBJID = rep(adsl$USUBJID, each = 2), AVISIT = rep(c("Baseline", "Month 12"), times = n_subj), PARAMCD = "FUNCSCORE", CHG = as.numeric(rbind(rep(0, n_subj), chg_val)), stringsAsFactors = FALSE ) head(adqs, 4) ``` ## Merging the population flag from ADSL Population flags and planned treatment usually live in ADSL. Merge the needed columns into the analysis dataset before preparing the plot. Base R `merge()` or a `dplyr` join both work; here we use base R to avoid assumptions. ```{r merge} adqs <- merge( adqs, adsl[, c("USUBJID", "TRT01P", "SAFFL", "ITTFL")], by = "USUBJID", all.x = TRUE ) head(adqs, 4) ``` ## Preparing the data `prep_mirror_data()` filters to the two named arms, applies the population flags with AND logic, retains only the baseline and endpoint visits, and counts the analysed N per arm. Any subject lacking both timepoints is dropped with a message, so the reported N reflects the subjects actually contributing. ```{r prep} md <- prep_mirror_data( adqs, subject_var = "USUBJID", trt_var = "TRT01P", trt_levels = c("Placebo", "Active"), time_var = "AVISIT", time_baseline = "Baseline", time_endpoint = "Month 12", value_var = "CHG", pop_flags = list(SAFFL = "Y", ITTFL = "Y"), population_label = "Safety / ITT", value_label = "Change from Baseline (Functional Score)" ) md ``` ## Attaching model-based estimates In practice these come from your model output. If you use `emmeans`, extract the estimates and confidence limits and pass them as named vectors and lists. The named-vector interface shown here is stable, and a future release may add a convenience method to consume a model object directly. ```{r estimates} md <- add_summary( md, estimates = c("Placebo" = -11.3, "Active" = -6.1), stat_label = "LS-Mean" ) md <- add_precision( md, ci = list("Placebo" = c(-14.0, -8.6), "Active" = c(-8.7, -3.5)) ) md <- add_difference( md, estimate = 5.2, ci_lower = 1.9, ci_upper = 8.5, p_value = 0.003 ) md ``` ## Producing the figure ```{r figure} mirror_slope_plot( md, trt_colors = mirror_palette("colorblind"), show_difference = TRUE, show_slowing = TRUE, show_precision = TRUE, title = "Functional Score: Change from Baseline at Month 12", footnote = paste( "LS-means and 95% CIs from a mixed model for repeated measures.", "Safety/ITT population. Positive difference favours the active arm." ) ) ``` ## A note on direction and terminology `direction` describes the direction of numeric movement, derived by comparing the reference arm's endpoint estimate to its baseline. The default benefit wording follows from it (for example \dQuote{% less decline} when values move down). For an outcome where the favourable direction is unusual, set `outcome_label` and `benefit_label` explicitly rather than relying on the defaults. ## Traceability The `mirror_data` object records provenance in its metadata: the schema version, the population filters applied, the analysed N per arm, a creation timestamp, and the originating call. This supports reconstructing exactly which inputs produced a given figure, which is useful in regulated settings.