R Shiny Web Apps — Interactive Web Applications
Learning Objectives
By the end of this tutorial, you will be able to:
- Create basic Shiny applications with UI and server
- Use input and output widgets
- Implement reactive programming concepts
- Build interactive dashboards
- Deploy applications to shinyapps.io or RStudio Connect
Basic Shiny App Structure
library(shiny)
# UI — what the user sees
ui <- fluidPage(
titlePanel("My First Shiny App"),
sidebarLayout(
sidebarPanel(
sliderInput("n", "Number of observations:", min = 10, max = 1000, value = 100)
),
mainPanel(
plotOutput("distPlot")
)
)
)
# Server — what happens behind the scenes
server <- function(input, output) {
output$distPlot <- renderPlot({
hist(rnorm(input$n), main = "Random Normal", col = "steelblue")
})
}
# Run the app
shinyApp(ui = ui, server = server)
Input Widgets
# Numeric input
numericInput("num", "Number:", value = 0, min = 0, max = 100)
# Slider
sliderInput("slider", "Slider:", min = 0, max = 100, value = 50)
# Text input
textInput("text", "Text:")
# Text area
textAreaInput("textarea", "Long text:")
# Select input
selectInput("select", "Choose:", choices = c("A", "B", "C"))
# Radio buttons
radioButtons("radio", "Options:", choices = c("A", "B", "C"))
# Checkbox
checkboxInput("check", "Check me")
# Checkbox group
checkboxGroupInput("checks", "Multiple:", choices = c("A", "B", "C"))
# Date input
dateInput("date", "Date:")
# File upload
fileInput("file", "Upload file")
# Action button
actionButton("go", "Go!")
Output Functions
# Plot
plotOutput("plot")
# Table
tableOutput("table")
DT::dataTableOutput("datatable")
# Text
textOutput("text")
htmlOutput("html")
# Download
downloadButton("download", "Download")
# Verbatim (code)
verbatimTextOutput("code")
Reactive Programming
server <- function(input, output, session) {
# Reactive expression
data <- reactive({
req(input$file)
read.csv(input$file$datapath)
})
# Observer
observeEvent(input$go, {
cat("Button clicked!\n")
})
# Reactive values
values <- reactiveValues(count = 0)
observeEvent(input$add, {
values$count <- values$count + 1
})
# Render functions
output$plot <- renderPlot({
req(data())
plot(data()$x, data()$y)
})
output$table <- renderTable({
req(data())
head(data())
})
}
Layouts
# Fluid row
fluidRow(
column(6, plotOutput("plot1")),
column(6, plotOutput("plot2"))
)
# Tab panels
tabsetPanel(
tabPanel("Tab 1", plotOutput("plot1")),
tabPanel("Tab 2", tableOutput("table1"))
)
# Navbar page
navbarPage("My App",
tabPanel("Home", plotOutput("home")),
tabPanel("About", "About page")
)
# Sidebar layout
sidebarLayout(
sidebarPanel(selectInput("var", "Variable:", names(mtcars))),
mainPanel(plotOutput("plot"))
)
Practical Example: Dashboard
library(shiny)
library(ggplot2)
library(dplyr)
ui <- fluidPage(
titlePanel("MTcars Dashboard"),
sidebarLayout(
sidebarPanel(
selectInput("x_var", "X variable:", names(mtcars)[sapply(mtcars, is.numeric)]),
selectInput("y_var", "Y variable:", names(mtcars)[sapply(mtcars, is.numeric)]),
sliderInput("point_size", "Point size:", min = 1, max = 10, value = 3),
checkboxInput("show_smooth", "Show trend line")
),
mainPanel(
plotOutput("scatter_plot"),
verbatimTextOutput("summary_stats")
)
)
)
server <- function(input, output) {
output$scatter_plot <- renderPlot({
p <- ggplot(mtcars, aes_string(x = input$x_var, y = input$y_var)) +
geom_point(size = input$point_size)
if (input$show_smooth) {
p <- p + geom_smooth(method = "lm")
}
p
})
output$summary_stats <- renderPrint({
summary(mtcars[, c(input$x_var, input$y_var)])
})
}
shinyApp(ui, server)
Deployment
# Install rsconnect
install.packages("rsconnect")
# Configure account
rsconnect::setAccountInfo(
name = "your-account",
token = "your-token",
secret = "your-secret"
)
# Deploy
rsconnect::deployApp("path/to/your/app")
Practice Exercises
Exercise 1: Interactive Plot
Build a Shiny app that lets users select a dataset, choose plot type, and customize colors.
Solution
library(shiny)
ui <- fluidPage(
titlePanel("Interactive Plot"),
sidebarLayout(
sidebarPanel(
selectInput("dataset", "Dataset:", c("mtcars", "iris", "airquality")),
selectInput("plot_type", "Plot type:", c("scatter", "histogram", "boxplot")),
colorInput("color", "Color:", value = "steelblue")
),
mainPanel(plotOutput("plot"))
)
)
server <- function(input, output) {
data <- reactive({
get(input$dataset)
})
output$plot <- renderPlot({
df <- data()
if (input$plot_type == "scatter") {
plot(df[, 1], df[, 2], col = input$color, pch = 19,
xlab = names(df)[1], ylab = names(df)[2])
} else if (input$plot_type == "histogram") {
hist(df[, 1], col = input$color, main = names(df)[1])
} else {
boxplot(df[, 1], col = input$color, main = names(df)[1])
}
})
}
shinyApp(ui, server)
Key Takeaways
fluidPage()creates the UI — contains all UI elementsserverfunction handles logic — receives input, produces outputrender*()functions create outputs — renderPlot, renderTablereactive()expressions cache calculationsobserveEvent()reacts to button clicksreactiveValues()stores mutable state- Deploy with
rsconnectto shinyapps.io or RStudio Connect
Next: Learn about R Advanced Topics — OOP, functional programming, and best practices.