|
| 1 | +#' Plot sampled PSA parameter distributions |
| 2 | +#' |
| 3 | +#' \code{plot_psa_distributions} melts PSA draws, classifies parameters |
| 4 | +#' prefixes ("p_", "u_", "c_"), optionally caps extreme values by quantiles, and |
| 5 | +#' produces separate ridge-density plots per group (Probabilities / Utilities / Costs / Other). |
| 6 | +#' |
| 7 | +#' @param df_psa_random data frame of PSA draws (rows = draws, columns = parameters). |
| 8 | +#' Only numeric columns are used. |
| 9 | +#' @param cap_quantiles numeric length-2 vector (in (0,1)) giving lower/upper quantiles |
| 10 | +#' for optional capping, e.g., \code{c(0.01, 0.99)}. Use \code{NULL} to disable capping. |
| 11 | +#' Default = c(0.01, 0.99). |
| 12 | +#' @param base_size base font size for \code{theme_bw}. Default = 14. |
| 13 | +#' @param scale ridge height scaling for \code{geom_density_ridges}. Default = 1.5. |
| 14 | +#' @param rel_min_height minimum ridge height to display. Default = 0.01. |
| 15 | +#' @param print_group_table print \code{table(df_melt$Group)} for a quick check. Default = TRUE. |
| 16 | +#' @return |
| 17 | +#' a named list containing: |
| 18 | +#' \itemize{ |
| 19 | +#' \item \code{df_melt}: long-format data with \code{Parameter}, \code{value}, \code{Group} |
| 20 | +#' \item \code{group_table}: frequency table of groups |
| 21 | +#' \item \code{plots}: named list of ggplot objects for "Probabilities", "Utilities", |
| 22 | +#' "Costs", and "Other" (missing groups return \code{NULL}) |
| 23 | +#' } |
| 24 | +#' @examples |
| 25 | +#' \donttest{ |
| 26 | +#' set.seed(1); n <- 1000 |
| 27 | +#' df <- data.frame( |
| 28 | +#' p_event = rbeta(n, 2, 8), p_death = rbeta(n, 5, 3), |
| 29 | +#' u_base = rbeta(n, 20, 5), u_treated = pmin(pmax(rnorm(n, .82, .06), 0), 1), |
| 30 | +#' c_tx = rgamma(n, 2, 0.001), c_hosp = rgamma(n, 3, 0.005), |
| 31 | +#' other_noise = rnorm(n, 10, 1) |
| 32 | +#' ) |
| 33 | +#' |
| 34 | +#' # Separate panels: one plot per group; no global capping to keep axes sensible. |
| 35 | +#' out <- plot_psa_distributions(df, cap_quantiles = NULL) |
| 36 | +#' out$group_table |
| 37 | +#' |
| 38 | +#' # Print each panel (Probabilities / Utilities / Costs / Other if present) |
| 39 | +#' for (nm in c("Probabilities", "Utilities", "Costs", "Other")) { |
| 40 | +#' if (!is.null(out$plots[[nm]])) print(out$plots[[nm]]) |
| 41 | +#' } |
| 42 | +#' } |
| 43 | +#' @export |
| 44 | +plot_psa_distributions <- function(df_psa_random, |
| 45 | + cap_quantiles = c(0.01, 0.99), |
| 46 | + base_size = 14, |
| 47 | + scale = 1.5, |
| 48 | + rel_min_height = 0.01, |
| 49 | + print_group_table = TRUE) { |
| 50 | + # deps via :: to keep lightweight |
| 51 | + if (!requireNamespace("reshape2", quietly = TRUE)) stop("Please install.packages('reshape2').") |
| 52 | + if (!requireNamespace("dplyr", quietly = TRUE)) stop("Please install.packages('dplyr').") |
| 53 | + if (!requireNamespace("stringr", quietly = TRUE)) stop("Please install.packages('stringr').") |
| 54 | + if (!requireNamespace("ggplot2", quietly = TRUE)) stop("Please install.packages('ggplot2').") |
| 55 | + if (!requireNamespace("ggridges", quietly = TRUE)) stop("Please install.packages('ggridges').") |
| 56 | + |
| 57 | + # keep only numeric columns |
| 58 | + stopifnot(is.data.frame(df_psa_random)) |
| 59 | + num_cols <- vapply(df_psa_random, is.numeric, logical(1)) |
| 60 | + if (!any(num_cols)) stop("No numeric columns found in df_psa_random.") |
| 61 | + df_num <- df_psa_random[, num_cols, drop = FALSE] |
| 62 | + |
| 63 | + # Melt the dataset (as in the example) |
| 64 | + df_melt <- reshape2::melt(df_num, variable.name = "Parameter", value.name = "value") |
| 65 | + |
| 66 | + # Optionally cap extreme values (global, like the example) |
| 67 | + xlim_global <- NULL |
| 68 | + if (!is.null(cap_quantiles) && length(cap_quantiles) == 2) { |
| 69 | + q <- stats::quantile(df_melt$value, probs = cap_quantiles, na.rm = TRUE) |
| 70 | + df_melt <- df_melt[df_melt$value >= q[[1]] & df_melt$value <= q[[2]], , drop = FALSE] |
| 71 | + xlim_global <- c(q[[1]], q[[2]]) |
| 72 | + } |
| 73 | + |
| 74 | + # Create a new column to classify parameters by prefix (as in the example) |
| 75 | + df_melt <- dplyr::mutate( |
| 76 | + df_melt, |
| 77 | + Group = dplyr::case_when( |
| 78 | + stringr::str_starts(Parameter, "p_") ~ "Probabilities", |
| 79 | + stringr::str_starts(Parameter, "u_") ~ "Utilities", |
| 80 | + stringr::str_starts(Parameter, "c_") ~ "Costs", |
| 81 | + TRUE ~ "Other" |
| 82 | + ) |
| 83 | + ) |
| 84 | + |
| 85 | + # Optionally check the groups |
| 86 | + group_tab <- table(df_melt$Group) |
| 87 | + if (isTRUE(print_group_table)) print(group_tab) |
| 88 | + |
| 89 | + # Helper to draw one group's ridges (NULL if empty) |
| 90 | + mk_plot <- function(dat, title_txt) { |
| 91 | + if (nrow(dat) == 0) return(NULL) |
| 92 | + # order y by median for readability |
| 93 | + ord <- dat |> |
| 94 | + dplyr::group_by(Parameter) |> |
| 95 | + dplyr::summarise(.med = stats::median(value, na.rm = TRUE), .groups = "drop") |> |
| 96 | + dplyr::arrange(.med) |
| 97 | + dat$Parameter <- factor(dat$Parameter, levels = ord$Parameter) |
| 98 | + |
| 99 | + p <- ggplot2::ggplot(dat, ggplot2::aes(x = value, y = Parameter)) + |
| 100 | + ggridges::geom_density_ridges(scale = scale, rel_min_height = rel_min_height, linewidth = 0.3) + |
| 101 | + ggplot2::theme_bw(base_size = base_size) + |
| 102 | + ggplot2::ggtitle(title_txt) |
| 103 | + if (!is.null(xlim_global)) { |
| 104 | + p <- p + ggplot2::coord_cartesian(xlim = xlim_global) |
| 105 | + } |
| 106 | + p |
| 107 | + } |
| 108 | + |
| 109 | + # Split and plot (each panel is a separate plot; y only shows that group's parameters) |
| 110 | + plots <- list( |
| 111 | + Probabilities = mk_plot(dplyr::filter(df_melt, Group == "Probabilities"), "Probabilities"), |
| 112 | + Utilities = mk_plot(dplyr::filter(df_melt, Group == "Utilities"), "Utilities"), |
| 113 | + Costs = mk_plot(dplyr::filter(df_melt, Group == "Costs"), "Costs"), |
| 114 | + Other = mk_plot(dplyr::filter(df_melt, Group == "Other"), "Other") |
| 115 | + ) |
| 116 | + |
| 117 | + list(df_melt = df_melt, group_table = group_tab, plots = plots) |
| 118 | +} |
| 119 | + |
0 commit comments