5

I am trying a small shiny app wherein I load a CSV file from the local directory and then select specific columns from the dataframe and use this subsetted dataframe for further data analysis.

library(shiny)

# Define UI for application that draws a histogram
ui <- fluidPage(

   # Application title
   titlePanel("Old Faithful Geyser Data"),

   # Sidebar with a slider input for number of bins 
   sidebarLayout(
      sidebarPanel(
        fileInput("dataset", "Choose CSV File",
                  multiple = TRUE,
                  accept = c("text/csv",
                             "text/comma-separated-values,text/plain",
                             ".csv")),
        # Include clarifying text ----
        #helpText(em("Note: This app requires file in csv format only!!")),
        helpText(em("Note:Select all the inputs and click on button as given below to exectute the app")),
        # Input: Checkbox if file has header ----
        checkboxInput("header", "Header", TRUE),
        # Input: Select separator ----
        radioButtons("sep", "Separator",
                     choices = c(Comma = ",",
                                 Semicolon = ";",
                                 Tab = "\t"),
                     selected = ","),
        selectInput("select", "Select columns to display", names(datasetInput), multiple = TRUE),
        actionButton("update", "Update Data set", class = "btn-primary",style='padding:4px; font-size:120%')
      ),

      # Show a plot of the generated distribution
      mainPanel(
        h2('The Mydata'),
        dataTableOutput('mytable')
      )
   )
)

# Define server logic required to draw a histogram
server <- function(input, output) {

  datasetInput <- eventReactive(input$update, {
    validate(need(input$dataset != "", "Please select a data set in csv format only!!!"))# custom error message on opening the app
    read.csv(input$dataset$datapath,
             header = input$header,
             sep = input$sep)
  }, ignoreNULL = FALSE)

  dataset <- reactive({
    df_input<-datasetInput()
    df_input$x<-NULL
    df_input
  })

   output$mytable = renderDataTable({
     columns = names(dataset)
     if (!is.null(input$select)) {
       columns = input$select
     }
     dataset[,columns,drop=FALSE]
   })
}

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

Looking in some SO answers;got a few; one as given below:

shiny allowling users to choose which columns to display

But this answer, the dataset is predefined; I want to the user to download his own dataset.

I am getting the following error:

Error in lapply(obj, function(val) { : object 'datasetInput' not found

I think somewhere I have to use an observeEvent function?

Agaz Wani
  • 5,514
  • 8
  • 42
  • 62
Nishant
  • 1,063
  • 13
  • 40
  • The error occurs due to the `choices` argument of the `selectInput`. `datasetInput` doesn't exist while the UI of the app is being rendered. – Imran Ali Sep 02 '17 at 06:08
  • @Imran Ali I know....need to knw how can i connect the uploaded csv file and display the columns of the uploaded file.....What shud be the dataset id in`selectInput` argument – Nishant Sep 02 '17 at 06:14
  • You need to dynamically `renderUI`. [Dynamic selectInput in R shiny](https://stackoverflow.com/questions/34080629/dynamic-selectinput-in-r-shiny) might help you getting started – Imran Ali Sep 02 '17 at 06:32
  • Possible duplicate of [How to pass values (choices) to selectizeInput() after selecting data from UI in shiny app?](https://stackoverflow.com/questions/34524036/how-to-pass-values-choices-to-selectizeinput-after-selecting-data-from-ui-in) – Imran Ali Sep 02 '17 at 06:35

3 Answers3

7

Here's a variant of server.R; use it with akrun's ui.R. This one dynamically adapts the filtering choices, and allows you to add columns back by adding their column name even after clicking the button.

library(shiny)
library(DT)

server <- function(session, input, output) {

  data <- reactive({
    req(input$dataset)
    read.csv(input$dataset$datapath, header = input$header,sep = input$sep)
    })

  filtereddata <- eventReactive({
      input$update
      data()
    },  {
    req(data())
    if(is.null(input$select) || input$select == "")
      data() else 
        data()[, colnames(data()) %in% input$select]
  })

  observeEvent(data(), {
    updateSelectInput(session, "select", choices=colnames(data()))
  })

  output$mytable  <- renderDataTable(filtereddata())

} 
Christoph Wolk
  • 1,748
  • 1
  • 7
  • 12
3

We could modify it

library(shiny)
library(DT)

-ui

ui <- fluidPage(

  # Application title
  titlePanel("Old Faithful Geyser Data"),

  # Sidebar with a slider input for number of bins 
  sidebarLayout(
    sidebarPanel(
      fileInput("dataset", "Choose CSV File",
                multiple = TRUE,
                accept = c("text/csv",
                           "text/comma-separated-values,text/plain",
                           ".csv")),
      # Include clarifying text ----
      #helpText(em("Note: This app requires file in csv format only!!")),
      helpText(em("Note:Select all the inputs and click on button as given below to exectute the app")),
      # Input: Checkbox if file has header ----
      checkboxInput("header", "Header", TRUE),
      # Input: Select separator ----
      radioButtons("sep", "Separator",
                   choices = c(Comma = ",",
                               Semicolon = ";",
                               Tab = "\t"),
                   selected = ","),
      selectInput("select", "Select columns to display", c('col1', 'col2'), multiple = TRUE),
      actionButton("update", "Update Data set", class = "btn-primary",style='padding:4px; font-size:120%')
    ),

    # Show a plot of the generated distribution
    mainPanel(
      h2('The Mydata'),
      #tableOutput("mytable")
      DT::dataTableOutput("mytable")

    )
  )
)

-server

server <- function(input, output) {

  values <- reactiveValues(df_data = NULL)
  observeEvent(input$dataset, {
      values$df_data <- read.csv(input$dataset$datapath,
                                header = input$header,
                                sep = input$sep
                                )}

               )
  observeEvent(input$update, {
    temp <- values$df_data[input$select]
    values$df_data <- temp

  })
  output$mytable  <- renderDataTable(values$df_data)

}

-Run the application

shinyApp(ui = ui, server = server)

-output

enter image description here

-after updating

enter image description here

akrun
  • 874,273
  • 37
  • 540
  • 662
  • 1
    ALmost there,,, u r not calling the column names dynamically in `selectInput` function as u r explicitly defining column names of imported dataset.....it wont work for any other datasets......so what shud the argument be instead of `c('col1', 'col2')`..... – Nishant Sep 02 '17 at 08:47
0

@Christoph Wolk.....excellent it Worked!

Just a small change....since i do not want to show the data as soon it is selected using browse but only when update data set button is clicked i commented out outdata() as below"

filtereddata <- eventReactive({
    input$update
    #data()
    },  {
    req(data())
        if(is.null(input$select) || input$select == "")
      data() else 
        data()[, colnames(data()) %in% input$select]
  })

  observeEvent(data(), {
    updateSelectInput(session, "select", choices=colnames(data()))
  })

Is there a way to show a custom message instead of blank in the main panel when the app is opened ;something like this:

Please select a data set in csv format only

Somewhere we need to put some sort of condition i suppose in above filtereddata() :

validate(need(input$dataset != "","Please select a data set in csv format only!!!"))# custom error message on opening the app

Solved it!!!!!

filtereddata <- eventReactive({
    validate(need(input$dataset != "","Please select a data set in csv format only!!!"))# custom error message on opening the app
    input$update
    #data()
    },  {
       req(data())

    if(is.null(input$select) || input$select == "")
      data() else 
        data()[, colnames(data()) %in% input$select]
  })

in ui

add this to get custom colour for the error msg

# Custom error message with green colour ----



tags$head(
    tags$style(HTML("
                    .shiny-output-error-validation {
                    color: green;
                    }
                    ")))

enter image description here

Nishant
  • 1,063
  • 13
  • 40