Skip to content

Commit ed41fd3

Browse files
committed
shiny app code
1 parent c8f92a2 commit ed41fd3

18 files changed

+811
-61
lines changed

DESCRIPTION

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ RoxygenNote: 7.3.2
1616
Depends:
1717
R (>= 4.1.0)
1818
Imports:
19+
Rcpp,
1920
dplyr,
2021
purrr,
2122
binom,
@@ -35,5 +36,6 @@ Suggests:
3536
tinytest,
3637
kableExtra,
3738
tibble
39+
LinkingTo: Rcpp
3840
SystemRequirements: JAGS (>= 4.0.0)
3941
Config/testthat/edition: 3

NAMESPACE

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,13 @@ export(plot_prior_weight)
3737
export(posterior)
3838
export(power)
3939
export(power_fisher)
40+
export(run_bcts_app)
4041
export(sim_rct_normal)
42+
export(singlearm_beta_power)
43+
export(singlearm_beta_type1)
4144
export(ssre)
4245
import(ggplot2)
46+
importFrom(Rcpp,evalCpp)
4347
importFrom(binom,binom.confint)
4448
importFrom(dplyr,"%>%")
4549
importFrom(dplyr,add_row)
@@ -70,3 +74,4 @@ importFrom(stats,update)
7074
importFrom(stats,var)
7175
importFrom(utils,setTxtProgressBar)
7276
importFrom(utils,txtProgressBar)
77+
useDynLib(bcts, .registration = TRUE)

R/RcppExports.R

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Generated by using Rcpp::compileAttributes() -> do not edit by hand
2+
# Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393
3+
4+
beta_prob_gt <- function(a, b, M, n_draws) {
5+
.Call(`_bcts_beta_prob_gt`, a, b, M, n_draws)
6+
}
7+
8+
#' @title Compute p-values for a t-distribution with Fixed Degrees of Freedom
9+
#'
10+
#' @description Simulates a single-arm binomial trial with a conjugate Beta prior,
11+
#' and computes the Bayesian power - the proportion of trials where the posterior
12+
#' probability that the response rate exceeds a threshold \code{M} is greater than or equal
13+
#' to a specified decision threshold.
14+
#'
15+
#' @param B Integer. Number of trial simulations.
16+
#' @param p_t Numeric in \[0, 1\]. True response probability for the treatment arm.
17+
#' @param n_t Integer. Sample size of the treatment arm.
18+
#' @param M Numeric in \[0, 1\]. Decision threshold on the response rate, e.g., \code{M = 0.6}.
19+
#' @param threshold Numeric in \[0, 1\]. Posterior probability cutoff for declaring success,
20+
#' e.g., \code{0.95}.
21+
#' @param prior Character string. Either \code{"flat"} for a Beta(1,1) prior or
22+
#' \code{"beta"} to specify a custom prior using \code{a_base} and \code{b_base}.
23+
#' @param a_base Numeric. Alpha parameter for the Beta prior (only used if \code{prior = "beta"}).
24+
#' @param b_base Numeric. Beta parameter for the Beta prior (only used if \code{prior = "beta"}).
25+
#' @param n_draws Integer. Number of posterior draws per trial.
26+
#' @param show_progress Logical. If \code{TRUE}, prints a simple progress bar to console.
27+
#'
28+
#' @return A list with: estimate (power), mc_se, successes, B.
29+
#'
30+
#' @examples
31+
#' singlearm_beta_power(
32+
#' B = 1000, p_t = 0.75, n_t = 35, M = 0.60,
33+
#' threshold = 0.95, prior = "flat", n_draws = 2000
34+
#' )
35+
#'
36+
#' @author Thomas Debray \email{[email protected]}
37+
#' @export
38+
singlearm_beta_power <- function(B, p_t, n_t, M, threshold, prior = "flat", a_base = 1, b_base = 1, n_draws = 2000L, show_progress = TRUE) {
39+
.Call(`_bcts_singlearm_beta_power`, B, p_t, n_t, M, threshold, prior, a_base, b_base, n_draws, show_progress)
40+
}
41+
42+
#' @title Estimate Type-I Error for Single-Arm Trial
43+
#'
44+
#' @description Simulates a single-arm binomial trial under the null hypothesis,
45+
#' and computes the type-I error: the proportion of simulations where posterior
46+
#' Pr(θ > M) ≥ threshold even though θ = p_null.
47+
#'
48+
#' @param B Integer. Number of simulations.
49+
#' @param n_t Integer. Sample size of the treatment arm.
50+
#' @param M Numeric. Decision threshold for θ (on probability scale, e.g., 0.6).
51+
#' @param threshold Posterior probability threshold γ (e.g., 0.95).
52+
#' @param prior "flat" or "beta".
53+
#' @param a_base Alpha parameter for Beta prior (if prior = "beta").
54+
#' @param b_base Beta parameter for Beta prior (if prior = "beta").
55+
#' @param n_draws Number of posterior draws per trial.
56+
#' @param show_progress Logical. Show progress in console?
57+
#'
58+
#' @return A list with \code{estimate} (type-I error), \code{mc_se}, \code{B}, and \code{rejections}.
59+
#'
60+
#' @examples
61+
#' singlearm_beta_type1(
62+
#' B = 1000, n_t = 35, M = 0.6,
63+
#' threshold = 0.95, prior = "flat", n_draws = 2000
64+
#' )
65+
#'
66+
#' @author Thomas Debray \email{[email protected]}
67+
#' @export
68+
singlearm_beta_type1 <- function(B, n_t, M, threshold, prior = "flat", a_base = 1, b_base = 1, n_draws = 2000L, show_progress = TRUE) {
69+
.Call(`_bcts_singlearm_beta_type1`, B, n_t, M, threshold, prior, a_base, b_base, n_draws, show_progress)
70+
}
71+

R/bcts_power_sat_betaBinom_conj.R

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#' Simulate Bayesian power for a single-arm binomial trial (via Rcpp)
2+
#'
3+
#' @param B Number of trial simulations.
4+
#' @param p_t True response probability.
5+
#' @param n_t Sample size.
6+
#' @param M Threshold for success (e.g. 0.6).
7+
#' @param threshold Posterior probability threshold (e.g. 0.95).
8+
#' @param prior Prior type: "flat" or "beta".
9+
#' @param a_base Alpha of Beta prior (only used if prior = "beta").
10+
#' @param b_base Beta of Beta prior (only used if prior = "beta").
11+
#' @param n_draws Number of posterior samples per trial.
12+
#' @param show_progress Show progress bar?
13+
#'
14+
#' @return A list with `estimate` (power), `mc_se`, `successes`, and `B`.
15+
#'
16+
#' @export
17+
singlearm_beta_power <- function(B, p_t, n_t, M, threshold,
18+
prior = "flat", a_base = 1, b_base = 1,
19+
n_draws = 2000, show_progress = TRUE) {
20+
.Call(`_bcts_singlearm_beta_power`, B, p_t, n_t, M, threshold,
21+
prior, a_base, b_base, n_draws, show_progress)
22+
}

R/bcts_type1_sat_betaBinom_conj.R

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#' Simulate Bayesian Type-I error for a single-arm binomial trial (via Rcpp)
2+
#'
3+
#' @param B Number of trial simulations.
4+
#' @param n_t Sample size.
5+
#' @param M Decision threshold (also used as null hypothesis value).
6+
#' @param threshold Posterior probability threshold (e.g. 0.95).
7+
#' @param prior Prior type: "flat" or "beta".
8+
#' @param a_base Alpha of Beta prior (only used if prior = "beta").
9+
#' @param b_base Beta of Beta prior (only used if prior = "beta").
10+
#' @param n_draws Number of posterior samples per trial.
11+
#' @param show_progress Show progress bar?
12+
#'
13+
#' @return A list with `estimate` (type-I error), `mc_se`, `rejections`, and `B`.
14+
#'
15+
#' @export
16+
singlearm_beta_type1 <- function(B, n_t, M, threshold,
17+
prior = "flat", a_base = 1, b_base = 1,
18+
n_draws = 2000, show_progress = TRUE) {
19+
.Call(`_bcts_singlearm_beta_type1`, B, n_t, M, threshold,
20+
prior, a_base, b_base, n_draws, show_progress)
21+
}

R/run_bcts_app.R

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#' Run the BCTS Shiny App
2+
#'
3+
#' Launches the interactive Shiny app included in the \code{bcts} package, which supports
4+
#' Bayesian clinical trial simulations for both single-arm and randomized trials. This app provides
5+
#' user-friendly controls to explore design parameters, power, and Type-I error.
6+
#'
7+
#' @param ... Additional arguments passed to \code{\link[shiny]{runApp}}, such as host or port.
8+
#' @param launch.browser Logical. Should the app be launched in the system browser? Defaults to \code{TRUE}.
9+
#'
10+
#' @details This function locates the Shiny app bundled in the \code{inst/app} directory of the
11+
#' \code{bcts} package and runs it using \code{shiny::runApp}. Ensure that the package was installed
12+
#' with the app directory included.
13+
#'
14+
#' @return None. This function is called for its side effect of launching the app.
15+
#'
16+
#' @examples
17+
#' if (interactive()) {
18+
#' run_bcts_app()
19+
#' }
20+
#'
21+
#' @export
22+
run_bcts_app <- function(..., launch.browser = TRUE) {
23+
app_dir <- system.file("app", package = "bcts")
24+
if (app_dir == "") {
25+
stop("App not found. Try reinstalling the bcts package.", call. = FALSE)
26+
}
27+
shiny::runApp(app_dir, launch.browser = launch.browser, ...)
28+
}

R/zzz.R

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#' @useDynLib bcts, .registration = TRUE
2+
#' @importFrom Rcpp evalCpp
3+
NULL
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# inst/app/R/ui_rct_decision_criteria.R
2+
3+
decision_criteria_ui <- function(id = NULL) {
4+
ns <- NS(id) # allows modular usage, or just use identity
5+
6+
wellPanel(
7+
h4("Decision criteria"),
8+
sliderInput(
9+
ns("M"),
10+
label = HTML("Decision Margin (\\( \\Delta \\))"),
11+
min = -100, max = 100, value = -20, step = 1, post = "%"
12+
),
13+
helpText(
14+
"Δ < 0: non-inferiority (treatment may be up to |Δ| worse).",
15+
"Δ ≥ 0: superiority (treatment must be at least Δ better).",
16+
"Assumes higher response rates are better (responder events)."
17+
),
18+
19+
radioButtons(ns("decision_mode"), "Threshold specification:",
20+
choices = c(
21+
"Specify posterior probability threshold γ" = "gamma",
22+
"Specify target Type-I error α" = "alpha"
23+
),
24+
selected = "gamma"),
25+
26+
conditionalPanel(
27+
condition = sprintf("input['%s'] == 'gamma'", ns("decision_mode")),
28+
sliderInput(
29+
ns("gamma"),
30+
label = HTML("Posterior probability threshold (\\( \\gamma \\))"),
31+
min = 80, max = 99, value = 90, step = 1, post = "%"
32+
),
33+
uiOutput(ns("decision_rule"))
34+
),
35+
36+
conditionalPanel(
37+
condition = sprintf("input['%s'] == 'alpha'", ns("decision_mode")),
38+
sliderInput(
39+
ns("alpha"),
40+
label = HTML("Target Type-I error (\\( \\alpha \\))"),
41+
value = 10, min = 1, max = 20, step = 1, post = "%"
42+
),
43+
selectInput(
44+
ns("calibrate_on"),
45+
"Calibrate Type-I on:",
46+
choices = c(
47+
"Point estimate Pr(reject | H₀)" = "point",
48+
"Upper 95% MC CI (conservative)" = "upper",
49+
"Lower 95% MC CI (liberal)" = "lower"
50+
),
51+
selected = "upper"
52+
),
53+
helpText("γ will be calibrated so that the chosen Type-I metric ≈ α (within tolerance) at the least-favourable null.")
54+
)
55+
)
56+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# inst/app/R/ui_sat_decision_criteria.R
2+
3+
sat_decision_criteria_ui <- function(id = NULL) {
4+
ns <- NS(id)
5+
6+
wellPanel(
7+
h4("Decision Criteria"),
8+
9+
sliderInput(
10+
ns("M_sa"),
11+
label = HTML("Decision Margin (\\( M \\))"),
12+
min = 0, max = 100, value = 65, step = 1, post = "%"
13+
),
14+
15+
helpText(
16+
"Define the threshold on the response rate (M) that must be exceeded to declare success.",
17+
"Higher values make the design more stringent."
18+
),
19+
20+
radioButtons(
21+
ns("decision_mode_sa"),
22+
label = "Threshold Specification Method:",
23+
choices = c(
24+
"Specify posterior probability threshold (\\( \\gamma \\))" = "gamma",
25+
"Specify target Type-I error (\\( \\alpha \\))" = "alpha"
26+
),
27+
selected = "gamma"
28+
),
29+
30+
conditionalPanel(
31+
condition = sprintf("input['%s'] == 'gamma'", ns("decision_mode_sa")),
32+
sliderInput(
33+
ns("gamma_sa"),
34+
label = HTML("Posterior probability threshold (\\( \\gamma \\))"),
35+
min = 80, max = 99, value = 90, step = 1, post = "%"
36+
),
37+
uiOutput(ns("decision_rule"))
38+
),
39+
40+
conditionalPanel(
41+
condition = sprintf("input['%s'] == 'alpha'", ns("decision_mode_sa")),
42+
sliderInput(
43+
ns("alpha_sa"),
44+
label = HTML("Target Type-I error (\\( \\alpha \\))"),
45+
min = 1, max = 20, value = 10, step = 1, post = "%"
46+
),
47+
selectInput(
48+
ns("calibrate_on_sa"),
49+
label = "Calibrate Type-I error based on:",
50+
choices = c(
51+
"Point estimate Pr(reject | H₀)" = "point",
52+
"Upper 95% MC CI (conservative)" = "upper",
53+
"Lower 95% MC CI (liberal)" = "lower"
54+
),
55+
selected = "upper"
56+
),
57+
helpText(
58+
"The threshold γ will be calibrated such that the chosen Type-I error metric",
59+
"approximates α at the least-favorable null scenario."
60+
)
61+
)
62+
)
63+
}

0 commit comments

Comments
 (0)