diff --git a/server.R b/server.R index 6401301..a0bf786 100644 --- a/server.R +++ b/server.R @@ -12,21 +12,24 @@ library("pwr") server <- function(input, output) { - # ---------------General npRCT function------------- + # ---------------General npRCT functions------------- + + ## T-test - npRCT <- reactive({ + npRCT.t <- reactive({ # Run power calculation for first t-test (traditional part of RCST) - t1 <- pwr.t.test(d = input$d1, - sig.level = input$sig.level1, - power = input$power1, - alternative = input$alternative1, + t1 <- pwr.t.test(d = input$t.d1, + sig.level = input$t.sig.level1, + power = input$t.power1, + alternative = input$t.alternative1, type = "two.sample") # Run power calculation for second t-test (stratified part of RCST) - t2 <- pwr.t.test(d = input$d2, sig.level = input$sig.level2, power = input$power2, + t2 <- pwr.t.test(d = input$t.d2, sig.level = input$t.sig.level2, + power = input$t.power2, type = "two.sample", - alternative = input$alternative2) + alternative = input$t.alternative2) # Compute sample sizes (per group) n1 = ceiling(t1$n) @@ -34,64 +37,141 @@ server <- function(input, output) { n2_rct = ceiling(n2 / 2) # n still traditionally randomised in stratified part # Compute output - n_strat = n1 - n2_rct - n_total = n_strat + n2 + n_trad = n1 - n2_rct + n_total = n_trad + n2 n_saved = (n1 + n2) - n_total n_ind = n1 + n2 # Save output - npRCT <- data.frame(n_total = round(n_total), - n_strat = n_strat, + npRCT.t <- data.frame(n_total = round(n_total), + n_trad = n_trad, n_saved = n_saved, n_ind = n_ind) # Return output - npRCT + npRCT.t }) + ## Chisquare test + + npRCT.chisquare <- reactive({ + + # Run power calculation for first chisquare-test (traditional part of npRCT) + chisq1 <- pwr.chisq.test(w = input$chisquare.w1, sig.level = input$chisquare.sig.level1, + power = input$chisquare.power1, + df = (input$chisquare.k-1)*(input$chisquare.ycat-1)) + + # Run power calculation for second chisquare-test (stratified part of npRCT) + chisq2 <- pwr.chisq.test(w = input$chisquare.w2, sig.level = input$chisquare.sig.level2, + power = input$chisquare.power2, df = (input$chisquare.ycat-1)) + + # Compute sample sizes (per group) + n1 = ceiling(chisq1$N / input$chisquare.k) + n2 = chisq2$N / 2 + n2_rct = ceiling(n2 / input$chisquare.k) # n still traditionally randomised in stratified part + + n_trad = n1 - n2_rct + n_total = ceiling(n_trad + n2) + n_ind = n1 + n2 + n_saved = n_ind - n_total + + + + # Save output + npRCT.chisquare <- data.frame(n_total = n_total, + n_trad = n_trad, + n_saved = n_saved, + n_ind = n_ind) + + # Return output + npRCT.chisquare + + }) + + + ## ANOVA + + npRCT.anova <- reactive({ + + + # Run power calculation for first t-test (traditional part of npRCT) + anova1 <- pwr.anova.test(k = input$anova.k, f = input$anova.f1, + sig.level = input$anova.sig.level1, power = input$anova.power1) + + # Run power calculation for second t-test (stratified part of npRCT) + t2 <- pwr.t.test(d = input$anova.d2, sig.level = input$anova.sig.level2, + power = input$anova.power2, type = input$anova.type2, + alternative = input$anova.alternative2) + + # Compute sample sizes (per group) + n1 = ceiling(anova1$n) + n2 = t2$n + n2_rct = ceiling(n2 / input$anova.k) # n still traditionally randomised in stratified part + + n_trad = n1 - n2_rct + n_total = n_trad + n2 + n_ind = n1 + n2 + n_saved = n_ind - n_total + + + # Save output + npRCT.anova <- data.frame(n_total = round(n_total), + n_trad = n_trad, + n_saved = n_saved, + n_ind = n_ind) + + # Return output + npRCT.anova + + }) + + + # ---------------Define output as text-------------- - output$n_total <- renderText({ + ## T-test + + output$t.n_total <- renderText({ - temp <- npRCT() + temp <- npRCT.t() paste("Total npRCT sample size: ", temp$n_total * 2, sep = "") }) - output$n_traditional <- renderText({ + output$t.n_traditional <- renderText({ - temp <- npRCT() + temp <- npRCT.t() paste("Traditional RCT sample size (per group): ", - temp$n_strat, sep = "") + temp$n_trad, sep = "") }) - output$n_precision <- renderText({ + output$t.n_precision <- renderText({ - temp <- npRCT() + temp <- npRCT.t() paste("Precision RCT sample size (per group): ", - as.character(temp$n_total - temp$n_strat), sep = "") + as.character(temp$n_total - temp$n_trad), sep = "") }) - output$n_saved <- renderText({ + output$t.n_saved <- renderText({ - temp <- npRCT() + temp <- npRCT.t() as.character(temp$n_saved) paste("Using the npRCT design (as compared to two independent RCTs) thus saves a sample size of ", temp$n_saved, " participants per group.", sep = "") }) - output$warning <- renderText({ + output$twarning <- renderText({ - temp <- npRCT() + temp <- npRCT.t() - if(temp$n_strat < 20) { - if(temp$n_strat >= 0) { + if(temp$n_trad < 20) { + if(temp$n_trad >= 0) { as.character("Please note that the sample size (per group) of the traditional RCT is relatively small (i.e., smaller than 20). If you aim for online identification of a precision algorithm, you may need to adjust your parameters. Visit the Explanations tab for more insights on practical considerations.") } else { as.character("WARNING: You have obtained a negative sample size for the traditional RCT. This occurs, if the to-be-detected effect of the precision RCT is much smaller than for the traditional RCT (i.e., all participants required for testing the traditional research question (intervention A or B) are recruited as part of the precision RCT. If you want to use the npRCT, please adjust parameters accordingly and visit the Explanations tab for more insights on practical considerations.") @@ -104,4 +184,112 @@ server <- function(input, output) { }) + ## Chisquare + + output$chisquare.n_total <- renderText({ + + temp <- npRCT.chisquare() + paste("Total npRCT sample size: ", + temp$n_total * 2, sep = "") + + }) + + output$chisquare.n_traditional <- renderText({ + + temp <- npRCT.chisquare() + paste("Traditional RCT sample size (per group): ", + temp$n_trad, sep = "") + + }) + + + output$chisquare.n_precision <- renderText({ + + temp <- npRCT.chisquare() + paste("Precision RCT sample size (per group): ", + as.character(temp$n_total - temp$n_trad), sep = "") + + }) + + output$chisquare.n_saved <- renderText({ + + temp <- npRCT.chisquare() + as.character(temp$n_saved) + paste("Using the npRCT design (as compared to two independent RCTs) thus saves a sample size of ", + temp$n_saved, " participants per group.", sep = "") + }) + + output$chisquarewarning <- renderText({ + + temp <- npRCT.chisquare() + + if(temp$n_trad < 20) { + if(temp$n_trad >= 0) { + as.character("Please note that the sample size (per group) of the traditional RCT is relatively small (i.e., smaller than 20). If you aim for online identification of a precision algorithm, you may need to adjust your parameters. Visit the Explanations tab for more insights on practical considerations.") + } else { + as.character("WARNING: You have obtained a negative sample size for the traditional RCT. This occurs, if the to-be-detected effect of the precision RCT is much smaller than for the traditional RCT (i.e., all participants required for testing the traditional research question (intervention A or B) are recruited as part of the precision RCT. If you want to use the npRCT, please adjust parameters accordingly and visit the Explanations tab for more insights on practical considerations.") + } + } else { + as.character("") + } + + + }) + + + + ## ANOVA + + output$anova.n_total <- renderText({ + + temp <- npRCT.anova() + paste("Total npRCT sample size: ", + temp$n_total * 2, sep = "") + + }) + + output$anova.n_traditional <- renderText({ + + temp <- npRCT.anova() + paste("Traditional RCT sample size (per group): ", + temp$n_trad, sep = "") + + }) + + + output$anova.n_precision <- renderText({ + + temp <- npRCT.anova() + paste("Precision RCT sample size (per group): ", + as.character(temp$n_total - temp$n_trad), sep = "") + + }) + + output$anova.n_saved <- renderText({ + + temp <- npRCT.anova() + as.character(temp$n_saved) + paste("Using the npRCT design (as compared to two independent RCTs) thus saves a sample size of ", + temp$n_saved, " participants per group.", sep = "") + }) + + output$anovawarning <- renderText({ + + temp <- npRCT.anova() + + if(temp$n_trad < 20) { + if(temp$n_trad >= 0) { + as.character("Please note that the sample size (per group) of the traditional RCT is relatively small (i.e., smaller than 20). If you aim for online identification of a precision algorithm, you may need to adjust your parameters. Visit the Explanations tab for more insights on practical considerations.") + } else { + as.character("WARNING: You have obtained a negative sample size for the traditional RCT. This occurs, if the to-be-detected effect of the precision RCT is much smaller than for the traditional RCT (i.e., all participants required for testing the traditional research question (intervention A or B) are recruited as part of the precision RCT. If you want to use the npRCT, please adjust parameters accordingly and visit the Explanations tab for more insights on practical considerations.") + } + } else { + as.character("") + } + + + }) + + + } \ No newline at end of file diff --git a/ui.R b/ui.R index b324d90..a9949a5 100644 --- a/ui.R +++ b/ui.R @@ -19,7 +19,12 @@ sidebar <- dashboardSidebar( sidebarMenu( - menuItem("Power Calculation", tabName = "calculation", icon = icon("calculator")), + menuItem("T-Test", tabName = "tcalculation", + icon = icon("calculator")), + menuItem("Chisquare-Test", tabName = "chisquarecalculation", + icon = icon("calculator")), + menuItem("ANOVA", tabName = "anovacalculation", + icon = icon("calculator")), menuItem("Explanations", tabName = "explanation", icon = icon("th")), menuItem("Reference", tabName = "reference", icon = icon("info circle")) @@ -31,8 +36,8 @@ sidebar <- dashboardSidebar( body <- dashboardBody( tabItems( - # -----------------Power Calculation Tab---------------- - tabItem(tabName = "calculation", + # -----------------Power Calculation T-test------------- + tabItem(tabName = "tcalculation", fluidRow( @@ -51,12 +56,12 @@ body <- dashboardBody( collapsible = FALSE, h3("Estimated Sample Sizes"), - strong(textOutput("n_total")), + strong(textOutput("t.n_total")), br(), - strong(textOutput("n_traditional")), - strong(textOutput("n_precision")), - textOutput("warning"), - tags$head(tags$style("#warning{color: red; + strong(textOutput("t.n_traditional")), + strong(textOutput("t.n_precision")), + textOutput("twarning"), + tags$head(tags$style("#twarning{color: red; font-style: italic; }" @@ -64,7 +69,7 @@ body <- dashboardBody( ), br(), - textOutput("n_saved"), + textOutput("t.n_saved"), tags$hr(), p("Please note that ", em("per group"), "refers to main groups of the nested RCTs, which are the two groups intervention ", em("A"), " versus ", em("B"), " for the ", em("traditional"), "RCT and the two groups ", em("randomisation"), " versus ", em("stratification"), " for the ", em("precision"), " RCT. See the explanations tab for details.") @@ -80,28 +85,28 @@ body <- dashboardBody( # ----------Traditional RCT Parameters------------ h2("Traditional RCT"), - sliderInput("d1", - "Effect Size", + sliderInput("t.d1", + "Effect Size (d)", step = 0.01, min = 0, max = 1, value = 0.5), br(), - sliderInput("power1", + sliderInput("t.power1", "Power", step = 0.01, min = 0.5, max = 1, value = 0.8), br(), - sliderInput("sig.level1", + sliderInput("t.sig.level1", "Significance Level", step = 0.001, min = 0.001, max = 0.1, value = 0.05), br(), - radioButtons("alternative1", + radioButtons("t.alternative1", NULL, c("Two Sided Test"= "two.sided", "One Sided Test"= "greater"), @@ -110,28 +115,28 @@ body <- dashboardBody( # ----------Precision RCT Parameters------------ h2("Precision RCT"), - sliderInput("d2", - "Effect Size", + sliderInput("t.d2", + "Effect Size (d)", step = 0.01, min = 0, max = 1, value = 0.5), br(), - sliderInput("power2", + sliderInput("t.power2", "Power", step = 0.01, min = 0.5, max = 1, value = 0.8), br(), - sliderInput("sig.level2", + sliderInput("t.sig.level2", "Significance Level", step = 0.001, min = 0.001, max = 0.1, value = 0.05), br(), - radioButtons("alternative2", + radioButtons("t.alternative2", NULL, c("Two Sided Test"= "two.sided", "One Sided Test"= "greater"), @@ -147,6 +152,249 @@ body <- dashboardBody( ), + # --------------------Power Calculation Chisquare---- + + tabItem(tabName = "chisquarecalculation", + + + fluidRow( + + + # ----------Power Analysis Output--------- + box( + title = "Power Analysis", + color = "blue", + + h1("Power Calculation"), + p("Below you can find results from power analysis for the", strong("nested-precision Randomised Controlled Trial (npRCT)"),". You can set parameters for power analysis in the box to the right. Results from power analysis will change accordingly below."), + box( + title = "Results", + color = "blue", + collapsible = FALSE, + + h3("Estimated Sample Sizes"), + strong(textOutput("chisquare.n_total")), + br(), + strong(textOutput("chisquare.n_traditional")), + strong(textOutput("chisquare.n_precision")), + textOutput("chisquarewarning"), + tags$head(tags$style("#chisquarewarning{color: red; + + font-style: italic; + }" + ) + ), + + br(), + textOutput("chisquare.n_saved"), + tags$hr(), + p("Please note that ", em("per group"), "refers to main groups of the nested RCTs, which are the two groups intervention ", em("A"), " versus ", em("B"), " for the ", em("traditional"), "RCT and the two groups ", em("randomisation"), " versus ", em("stratification"), " for the ", em("precision"), " RCT. See the explanations tab for details.") + + ) + ), + + + # ----------Set RCT Parameters------------ + box( + title = "Set Parameters", + color = "blue", + + + # ----------Traditional RCT Parameters------------ + h2("Traditional RCT"), + sliderInput("chisquare.w1", + "Effect Size (W)", + step = 0.01, + min = 0, + max = 1, + value = 0.5), + br(), + sliderInput("chisquare.power1", + "Power", + step = 0.01, + min = 0.5, + max = 1, + value = 0.8), + br(), + sliderInput("chisquare.sig.level1", + "Significance Level", + step = 0.001, + min = 0.001, + max = 0.1, + value = 0.05), + br(), + sliderInput("chisquare.k", + "Number of groups", + step = 1, + min = 2, + max = 10, + value = 2), + br(), + sliderInput("chisquare.ycat", + "Number of outcome variable categories", + step = 1, + min = 2, + max = 10, + value = 2), + + + # ----------Precision RCT Parameters------------ + h2("Precision RCT"), + sliderInput("chisquare.w2", + "Effect Size (W)", + step = 0.01, + min = 0, + max = 1, + value = 0.5), + br(), + sliderInput("chisquare.power2", + "Power", + step = 0.01, + min = 0.5, + max = 1, + value = 0.8), + br(), + sliderInput("chisquare.sig.level2", + "Significance Level", + step = 0.001, + min = 0.001, + max = 0.1, + value = 0.05) + + + ) + + + + + ) + + + ), + + + + # --------------------Power Calculation ANOVA-------- + + tabItem(tabName = "anovacalculation", + + + fluidRow( + + + # ----------Power Analysis Output--------- + box( + title = "Power Analysis", + color = "blue", + + h1("Power Calculation"), + p("Below you can find results from power analysis for the", strong("nested-precision Randomised Controlled Trial (npRCT)"),". You can set parameters for power analysis in the box to the right. Results from power analysis will change accordingly below."), + box( + title = "Results", + color = "blue", + collapsible = FALSE, + + h3("Estimated Sample Sizes"), + strong(textOutput("anova.n_total")), + br(), + strong(textOutput("anova.n_traditional")), + strong(textOutput("anova.n_precision")), + textOutput("anovawarning"), + tags$head(tags$style("#anovawarning{color: red; + + font-style: italic; + }" + ) + ), + + br(), + textOutput("anova.n_saved"), + tags$hr(), + p("Please note that ", em("per group"), "refers to main groups of the nested RCTs, which are the two groups intervention ", em("A"), " versus ", em("B"), " for the ", em("traditional"), "RCT and the two groups ", em("randomisation"), " versus ", em("stratification"), " for the ", em("precision"), " RCT. See the explanations tab for details.") + + ) + ), + + + # ----------Set RCT Parameters------------ + box( + title = "Set Parameters", + color = "blue", + + + # ----------Traditional RCT Parameters------------ + h2("Traditional RCT"), + sliderInput("anova.f1", + "Effect Size (F)", + step = 0.01, + min = 0, + max = 0.75, + value = 0.25), + br(), + sliderInput("anova.power1", + "Power", + step = 0.01, + min = 0.5, + max = 1, + value = 0.8), + br(), + sliderInput("anova.sig.level1", + "Significance Level", + step = 0.001, + min = 0.001, + max = 0.1, + value = 0.05), + br(), + sliderInput("anova.k", + "Number of groups", + step = 1, + min = 2, + max = 10, + value = 2), + + + + # ----------Precision RCT Parameters------------ + h2("Precision RCT"), + sliderInput("anova.d2", + "Effect Size (d)", + step = 0.01, + min = 0, + max = 1, + value = 0.5), + br(), + sliderInput("anova.power2", + "Power", + step = 0.01, + min = 0.5, + max = 1, + value = 0.8), + br(), + sliderInput("anova.sig.level2", + "Significance Level", + step = 0.001, + min = 0.001, + max = 0.1, + value = 0.05), + br(), + radioButtons("anova.alternative2", + NULL, + c("Two Sided Test"= "two.sided", + "One Sided Test"= "greater"), + selected = "two.sided") + + + ) + + + + + ) + + + ), + + # -----------------Explanation Tab---------------------- tabItem(tabName = "explanation",