Shiny is an R package for building interactive web applications without requiring any web development experience.
It is ideal for dashboards, teaching tools, and interactive reporting.
Tip:
Use reactive() for values, observe() for actions.
10.5 Examples
10.5.1 Example 1: Normal Distribution Explorer
This is the simplest Shiny app. It lets users change the mean and standard deviation of a normal distribution and immediately see the updated histogram.
The UI side:
Code
library(shiny)ui <-fluidPage(titlePanel("Normal Distribution Explorer"),sidebarLayout(sidebarPanel(sliderInput("mean", "Mean (μ):", min =-5, max =5, value =0, step =0.1),sliderInput("sd", "Standard deviation (σ):", min =0.1, max =5, value =1, step =0.1) ),mainPanel(plotOutput("hist") ) ))
The Server side:
Code
server <-function(input, output) { output$hist <-renderPlot({ x <-rnorm(1000, mean = input$mean, sd = input$sd)hist(x, main ="Histogram of Random Normal Data",xlab ="Value", col ="skyblue", border ="white") })}
Run the App:
Code
shinyApp(ui, server)
10.5.2 Example 2: Comparing Two Distributions
This second app is adapted from the original version. It lets users control the parameters of two normal distributions and visualize their frequency polygons side by side.
The UI side:
Code
library(shiny)library(ggplot2)library(tibble)ui <-fluidPage(titlePanel("Compare Two Normal Distributions"),sidebarLayout(sidebarPanel(numericInput("n1", "Sample size (Dist 1)", value =1000, min =100),numericInput("mean1", "μ (Dist 1)", value =0, step =0.1),numericInput("sd1", "σ (Dist 1)", value =1, min =0.1, step =0.1),numericInput("n2", "Sample size (Dist 2)", value =1000, min =100),numericInput("mean2", "μ (Dist 2)", value =1, step =0.1),numericInput("sd2", "σ (Dist 2)", value =0.5, min =0.1, step =0.1),sliderInput("range", "X-axis range", value =c(-5, 5), min =-10, max =10),actionButton("go", "Generate Samples") ),mainPanel(plotOutput("plot2"),verbatimTextOutput("ttest") ) ))
The Server side:
Code
server <-function(input, output) {# Reactive data: generate both samples together only when button clicked samples <-reactive({ input$goisolate({tibble(x =c(rnorm(input$n1, input$mean1, input$sd1),rnorm(input$n2, input$mean2, input$sd2)),grp =rep(c("Dist 1", "Dist 2"), c(input$n1, input$n2)) ) }) })# Plot: smooth density curves output$plot2 <-renderPlot({req(samples())ggplot(samples(), aes(x = x, color = grp, fill = grp)) +geom_density(alpha =0.25, linewidth =1) +scale_color_manual(values =c("Dist 1"="blue", "Dist 2"="red")) +scale_fill_manual(values =c("Dist 1"="blue", "Dist 2"="red")) +coord_cartesian(xlim = input$range) +labs(title ="Two Normal Distributions",x ="Value", y ="Density", color ="Distribution", fill ="Distribution") +theme_minimal(base_size =14) }, res =96)# t-test: reuse the same simulated data output$ttest <-renderPrint({req(samples())t.test(x ~ grp, data =samples()) })}
Run the App:
Code
shinyApp(ui, server)
10.5.3 Example 3: Reactivity
This example illustrate how reactivity:
reactive() defines a reactive expression — a cached computation that automatically re-runs when its inputs change and can be reused across outputs.
isolate() lets you access reactive inputs without triggering a re-execution. Useful when you want a computation to happen only when explicitly requested.
observeEvent() is used to perform an action (not return a value) when an input changes — like printing to console, showing a message, or updating another output.
Code
library(shiny)ui <-fluidPage(titlePanel("Reactive, Isolate, and ObserveEvent Together"),numericInput("mean", "Mean:", 0),numericInput("sd", "SD:", 1, min =0.1),actionButton("go", "Generate Sample"),plotOutput("hist"),verbatimTextOutput("summary"))server <-function(input, output) {# reactive container to hold the current dataset data <-reactiveVal(NULL)# observeEvent: generate new data only when button clickedobserveEvent(input$go, { m <-isolate(input$mean) s <-isolate(input$sd)data(rnorm(1000, m, s)) })# outputs that react to data() output$hist <-renderPlot({req(data()) # only plot if availablehist(data(), main ="Generated Data", col ="lightgreen") }) output$summary <-renderPrint({req(data())summary(data()) })}shinyApp(ui, server)
10.6 Deployment
Deploying a Shiny app means making it available to others.