Calculator: \(Z\)-testing
Summary
A calculator to provide \(p\)-values when a \(Z\)-test is being used.
#| '!! shinylive warning !!': |
#| shinylive does not work in self-contained HTML documents.
#| Please set `embed-resources: false` in your metadata.
#| standalone: true
#| viewerHeight: 620
library(shiny)
library(bslib)
library(ggplot2)
ui <- page_fluid(
title = "Z-Test Calculator",
layout_columns(
col_widths = c(4, 8),
# Left column - Input parameters
card(
card_header("Input Parameters"),
card_body(
numericInput("zscore", "Z-score", value = 1.96, step = 0.01),
radioButtons("test_type", "Test Type",
choices = list("Two-tailed" = "two",
"One-tailed (upper)" = "upper",
"One-tailed (lower)" = "lower"),
selected = "two"),
hr(),
helpText("This app calculates p-values for Z-tests based on the standard normal distribution.")
)
),
# Right column - Graphical representation
card(
card_header("Graphical Representation"),
card_body(
plotOutput("density_plot", height = "300px")
)
)
),
# Results at the bottom
card(
card_header("Z-Test Results"),
card_body(
verbatimTextOutput("pvalue_result")
)
)
)
server <- function(input, output, session) {
# Calculate p-value based on test type
p_value <- reactive({
z <- input$zscore
test <- input$test_type
if (test == "two") {
p <- 2 * pnorm(-abs(z))
result <- paste0("Two-tailed p-value: ", round(p, 6))
} else if (test == "upper") {
p <- pnorm(z, lower.tail = FALSE)
result <- paste0("Upper-tailed p-value: ", round(p, 6))
} else if (test == "lower") {
p <- pnorm(z, lower.tail = TRUE)
result <- paste0("Lower-tailed p-value: ", round(p, 6))
}
return(list(p = p, result = result, test = test))
})
# Display p-value
output$pvalue_result <- renderText({
p_value()$result
})
# Create density plot
output$density_plot <- renderPlot({
z <- input$zscore
test <- p_value()$test
# Generate x values for normal distribution
x <- seq(-4, 4, length.out = 1000)
y <- dnorm(x)
df <- data.frame(x = x, y = y)
# Base plot
p <- ggplot(df, aes(x = x, y = y)) +
geom_line() +
labs(x = "Z-score", y = "Density") +
theme_minimal() +
theme(panel.grid.minor = element_blank()) +
geom_vline(xintercept = 0, linetype = "dashed", alpha = 0.5)
# Add shaded area based on test type, using #3F6BB6 as the color
if (test == "two") {
# Two-tailed test: shade both tails
if (z > 0) {
p <- p +
geom_area(data = subset(df, x >= z), aes(x = x, y = y), fill = "#3F6BB6", alpha = 0.5) +
geom_area(data = subset(df, x <= -z), aes(x = x, y = y), fill = "#3F6BB6", alpha = 0.5) +
geom_vline(xintercept = z, color = "#3F6BB6") +
geom_vline(xintercept = -z, color = "#3F6BB6")
} else {
p <- p +
geom_area(data = subset(df, x <= z), aes(x = x, y = y), fill = "#3F6BB6", alpha = 0.5) +
geom_area(data = subset(df, x >= -z), aes(x = x, y = y), fill = "#3F6BB6", alpha = 0.5) +
geom_vline(xintercept = z, color = "#3F6BB6") +
geom_vline(xintercept = -z, color = "#3F6BB6")
}
} else if (test == "upper") {
# Upper-tailed test: shade area above z
p <- p +
geom_area(data = subset(df, x >= z), aes(x = x, y = y), fill = "#3F6BB6", alpha = 0.5) +
geom_vline(xintercept = z, color = "#3F6BB6")
} else if (test == "lower") {
# Lower-tailed test: shade area below z
p <- p +
geom_area(data = subset(df, x <= z), aes(x = x, y = y), fill = "#3F6BB6", alpha = 0.5) +
geom_vline(xintercept = z, color = "#3F6BB6")
}
return(p)
})
}
shinyApp(ui, server)
Further reading
Version history
v1.0: initial version created 12/24 by Ellie Trace as part of a University of St Andrews VIP project.
- v1.1: updated to R Shiny interface by tdhc 04/25.