Calculator: \(Z\)-testing

Author

Tom Coleman

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

This interactive element appears in Guide: Introduction to hypothesis testing. Please click this link to go to the guide.

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.

This work is licensed under CC BY-NC-SA 4.0.

Mailing List



Feedback

Your feedback is appreciated and useful. Feel free to leave a comment here,
but please be specific with any issues you encounter so we can help to resolve them
(for example, what page it occured on, what you tried, and so on).