Building Shiny Apps
Because Shiny apps require a background server loop to handle reactive user inputs, they cannot be run directly inside the browser's webR engine. All examples and exercises on this page must be run locally in RStudio.
Why Learn Shiny in Exploratory Data Analysis?
In data science, your final step is communicating results to stakeholders, who are often not programmers.
- If you send them a static PDF plot showing flight delays for 3 selective airports, they might ask: "What about the other 50 airports?"
- If you tell them to write R commands to filter the dataset themselves, they cannot do it.
To bridge this gap, you need Shiny. Shiny is an R package that allows you to build interactive web dashboards and applications directly in R—no HTML, CSS, or JavaScript required.
With Shiny, you can create slider bars, drop-down menus, and search boxes that allow users to explore and filter plots dynamically. Let's learn how to build reactive web apps in R.
1. The Architecture of a Shiny App
Every Shiny application consists of three main components:
- User Interface (
ui): Defines the visual layout, styles, and interactive input widgets (dropdowns, sliders) that the user sees on the webpage. - Server Function (
server): Contains the R code and logic that processes data, generates plots, and handles calculations based on what the user clicked. - App Constructor (
shinyApp): Combines theuiand theserverinto a running web application.
library(shiny)
# 1. Define the User Interface
ui <- fluidPage(
titlePanel("Hello Shiny!")
)
# 2. Define the Server Logic
server <- function(input, output) {
# Logic goes here
}
# 3. Launch the App
# (Uncomment below to run inside RStudio)
# shinyApp(ui = ui, server = server)
2. Designing the UI (Layouts and Inputs)
Shiny uses layout templates to structure the webpage. The most common is the sidebarLayout, which splits the page into a side panel for inputs and a main panel for charts.
Input Controllers (User Interactions)
sliderInput(id, label, min, max, value): A slide bar to choose numbers.selectInput(id, label, choices): A dropdown menu to select categories.textInput(id, label): A text box to type strings.
Output Holders (Placeholders for Server Results)
plotOutput(id): Displays a ggplot or base R plot.tableOutput(id): Displays a data table.textOutput(id): Displays simple text logs.
ui <- fluidPage(
titlePanel("Automotive Performance Explorer"),
sidebarLayout(
# Input panel on the left
sidebarPanel(
# Dropdown for selecting car class
selectInput(
inputId = "car_class",
label = "Select Vehicle Class:",
choices = unique(mpg$class)
),
# Slider for engine displacement limit
sliderInput(
inputId = "engine_size",
label = "Minimum Engine Size (Litres):",
min = 1.6, max = 7.0, value = 2.0, step = 0.1
)
),
# Output panel on the right
mainPanel(
plotOutput(outputId = "mileage_plot")
)
)
)
3. The Server and Reactivity
The server connects user inputs to output renders using Reactivity. When a user changes an input widget (e.g. adjusts the slider), the server automatically detects the change, updates the data filter, re-draws the plot, and pushes it back to the UI.
Reactivity Rules
- Inputs are read from the
inputlist (e.g.input$engine_size). They are read-only. - Outputs are written to the
outputlist (e.g.output$mileage_plot). - To render dynamic outputs, wrap your calculations inside matching reactive rendering functions:
renderPlot({ ... })pairs withplotOutput().renderTable({ ... })pairs withtableOutput().renderText({ ... })pairs withtextOutput().
library(tidyverse)
server <- function(input, output) {
# Connect plot output to UI plot placeholder
output$mileage_plot <- renderPlot({
# 1. Filter dataset dynamically based on user UI inputs
filtered_mpg <- mpg |>
filter(
class == input$car_class,
displ >= input$engine_size
)
# 2. Return a ggplot chart
ggplot(filtered_mpg, aes(x = displ, y = hwy)) +
geom_point(size = 4, color = "steelblue") +
theme_minimal() +
labs(x = "Engine Size", y = "Highway Mileage")
})
}
Hands-on Exercises
Exercise 1: Building a Dynamic Text Display
Create a simple Shiny UI and server that greets the user by name. Write R code to:
- Define a UI containing:
- A title panel
"Greeting App". - A text input box with ID
"username"and label"Type your name:". - A text output placeholder with ID
"greeting".
- A title panel
- Define a Server function that:
- Uses
renderText()to create a greeting string:paste("Hello,", input$username, "!"). - Assigns this render block to
output$greeting.
- Uses
- Combine them using
shinyApp().
# Write your code below and click Run Code
Click to view Answer
library(shiny)
# Define UI
ui <- fluidPage(
titlePanel("Greeting App"),
textInput(inputId = "username", label = "Type your name:", value = "User"),
textOutput(outputId = "greeting")
)
# Define Server
server <- function(input, output) {
output$greeting <- renderText({
paste("Hello,", input$username, "!")
})
}
# Launch App
# shinyApp(ui = ui, server = server)
Exercise 2: Scatter Plot Filter Panel
Create a reactive Shiny dashboard filtering a scatter plot. Write R code to:
- Define a UI with a
sidebarLayoutcontaining:- A dropdown selector
selectInput()with ID"mfg"to select the manufacturer (e.g."audi","honda", etc.). - A
plotOutput()placeholder in the main panel with ID"scatter".
- A dropdown selector
- Define a Server that:
- Filters the
mpgdataset dynamically so thatmanufacturer == input$mfg. - Plots a scatter plot of
ctyvshwyfor the filtered manufacturer. - Renders the plot inside
output$scatter.
- Filters the
# Write your code below and click Run Code
Click to view Answer
library(shiny)
library(tidyverse)
# Define UI
ui <- fluidPage(
titlePanel("Manufacturer Performance Plot"),
sidebarLayout(
sidebarPanel(
selectInput(
inputId = "mfg",
label = "Select Manufacturer:",
choices = unique(mpg$manufacturer)
)
),
mainPanel(
plotOutput(outputId = "scatter")
)
)
)
# Define Server
server <- function(input, output) {
output$scatter <- renderPlot({
# Filter dynamically based on selection
mfg_data <- mpg |> filter(manufacturer == input$mfg)
# Plot
ggplot(mfg_data, aes(x = cty, y = hwy)) +
geom_point(size = 3, color = "darkorange") +
theme_light() +
labs(x = "City Mileage (MPG)", y = "Highway Mileage (MPG)")
})
}
# Launch App
# shinyApp(ui = ui, server = server)
4. Alternative: Running Shiny in Google Colab
If you do not have RStudio installed locally, you can run Shiny apps directly inside a Google Colab notebook. However, because Colab executes R on a remote virtual machine, you cannot access the Shiny server via localhost directly. You must tunnel or proxy the network port to view the user interface.
Follow this two-step process in Colab:
Step 1: Run the R Code (R Cell / Notebook)
Install the shiny package, then launch your app on a fixed port (e.g. 8080) and bind it to host 0.0.0.0 (which tells it to listen to requests from external networks). Set launch.browser = FALSE so it does not attempt to open a desktop browser.
# Install package if needed
# install.packages("shiny")
library(shiny)
ui <- fluidPage(
titlePanel("Colab Shiny App!"),
textInput("name", "Enter your name:"),
textOutput("greeting")
)
server <- function(input, output) {
output$greeting <- renderText({
paste("Hello,", input$name, "!")
})
}
# Run the app on host 0.0.0.0 and port 8080
runApp(shinyApp(ui = ui, server = server), port = 8080, host = "0.0.0.0", launch.browser = FALSE)
Step 2: Render the App UI (Python Cell)
To link your browser to the Shiny app running on the remote VM, create a new Python cell in your Colab notebook and run Colab's port proxying helper. This will display the active Shiny interface as an interactive iframe directly under your cell:
from google.colab import output
# Render the active R Shiny server running on port 8080 inside an iframe
output.serve_kernel_port_as_iframe(8080)