Uploading and dowloading data in RShiny - Answer Key

Author

Will Gammerdinger

Published

November 10, 2025

Exercise 1

Create an app in R Shiny that lets users upload the iris dataset that can be found here. Then create a scatterplot where the user selects x-axis and y-axis from separate selectInput() menus, containing the values Sepal.Length, Sepal.Width, Petal.Length and Petal.Width. Lastly, allow the user to be able to download the scatterplot to a .png.

The app will look like:

  1. Write the UI with the appropriate fileInput(), selectInput(), plotOutput and downloadButton() functions
# User Interface
ui <- fluidPage(
  # Upload the file
  fileInput("input_file", "Upload file"),
  # Select from the dropdown menu the column you want on the x-axis
  selectInput("x_axis_input", "Select x-axis", choices = c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width")),
  # Select from the dropdown menu the column you want on the y-axis
  selectInput("y_axis_input", "Select y-axis", choices = c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width")),
  # The output plot
  plotOutput("plot"),
  # The download plot button
  downloadButton("download_button", "Download the data .png")
)
  1. Write the server side with, a reactive() function for reading in the CSV file
# Server
server <- function(input, output) {
  # Reactive expression to hold the uploaded data 
  iris_data <- reactive({
    req(input$input_file)
    read.csv(input$input_file$datapath)
  })
}
  1. Add a reactive() function to create the ggplot figure to the server side
# Server
server <- function(input, output) {
  ...
  # Reactive expression to create a scatterplot from the uploaded data and user selected axes
  iris_plot <- reactive ({
  ggplot(iris_data()) +
    geom_point(aes_string(x = input$x_axis_input, y = input$y_axis_input))
  })
}
  1. Add a renderPlot() function to render the ggplot figure from the reactive expression to the server side
# Server
server <- function(input, output) {
  ...
    # Render the plot from the iris_plot() reactive expression
  output$plot <- renderPlot({
    iris_plot()
  })
}
  1. Add a downloadHandler() function for downloading the image to the server side
# Server
server <- function(input, output) {
  ...
  # Download the data
  output$download_button <- downloadHandler(
    # The placeholder name for the file will be called iris_plot.png
    filename = function() {
      "iris_plot.png"
    },
    # The content of the file will be the contents of the iris_plot() reactive expression
    content = function(file) {
      png(file)
      print(iris_plot())
      dev.off()
    }
  )
}

All together the code should look like:

library(shiny)
library(DT)
library(tidyverse)

# User Interface
ui <- fluidPage(
  # Upload the file
  fileInput("input_file", "Upload file"),
  # Select from the dropdown menu the column you want on the x-axis
  selectInput("x_axis_input", "Select x-axis", choices = c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width")),
  # Select from the dropdown menu the column you want on the y-axis
  selectInput("y_axis_input", "Select y-axis", choices = c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width")),
  # The output plot
  plotOutput("plot"),
  # The download plot button
  downloadButton("download_button", "Download the data .png")
)

# Server
server <- function(input, output) {
  # Reactive expression to hold the uploaded data 
  iris_data <- reactive({
    req(input$input_file)
    read.csv(input$input_file$datapath)
  })
  # Reactive expression to create a scatterplot from the uploaded data and user selected axes
  iris_plot <- reactive ({
  ggplot(iris_data()) +
    geom_point(aes_string(x = input$x_axis_input, y = input$y_axis_input))
  })
  # Render the plot from the iris_plot() reactive expression
  output$plot <- renderPlot({
    iris_plot()
  })
  # Download the data
  output$download_button <- downloadHandler(
    # The placeholder name for the file will be called iris_plot.png
    filename = function() {
      "iris_plot.png"
    },
    # The content of the file will be the contents of the iris_plot() reactive expression
    content = function(file) {
      png(file)
      print(iris_plot())
      dev.off()
    }
  )
}

# Run the app
shinyApp(ui = ui, server = server)

Reuse

CC-BY-4.0