3

I am trying to build a shiny app where I can upload a csv file and based on the column names, populate the check boxes on the left column (slidebar column) in ui. And based on which column selected for the y-axis and which column selected for the x-axis, need to able to create a chart using ggplot.

my ui.R looks like this:

shinyUI(pageWithSidebar(
  headerPanel("CSV Viewer"),
  sidebarPanel(
    fileInput('file1', 'Choose CSV File',
              accept=c('text/csv', 'text/comma-separated-values,text/plain', '.csv')),
    tags$hr(),
    checkboxInput('header', 'Header', TRUE),
    radioButtons('sep', 'Separator',
                 c(Comma=',',
                   Semicolon=';',
                   Tab='\t'),
                 'Comma'),
    radioButtons('quote', 'Quote',
                 c(None='',
                   'Double Quote'='"',
                   'Single Quote'="'"),
                 'Double Quote'),

   checkboxGroupInput("variable", "Variable:", choices = names(data_set))
  ),
  mainPanel(
    tableOutput('contents')


  )
))

Server.R looks like this:

shinyServer(function(input, output) {
  output$contents <- renderTable({

    # input$file1 will be NULL initially. After the user selects and uploads a 
    # file, it will be a data frame with 'name', 'size', 'type', and 'datapath' 
    # columns. The 'datapath' column will contain the local filenames where the 
    # data can be found.

    inFile <- input$file1

    if (is.null(inFile))
      return(NULL)

    data_set<-read.csv(inFile$datapath, header=input$header, sep=input$sep, quote=input$quote)
  })

  output$choose_dataset <- renderUI({
    selectInput("dataset", "Data set", as.list(data_sets))
  })

  # Check boxes
  output$choose_columns <- renderUI({
    # If missing input, return to avoid error later in function
    if(is.null(input$dataset))
      return()

    # Get the data set with the appropriate name

    colnames <- names(contents)

    # Create the checkboxes and select them all by default
    checkboxGroupInput("columns", "Choose columns", 
                       choices  = colnames,
                       selected = colnames)
  })

})

I cannot get it to load column names in my data set in the slider bar? any pointers how I could do this. I am loading a csv file, once the file loaded, I need to be able to load populate the sliderbar with the column names of my dataset.

Update-edit:

added a request from OP (see comments in accepted answer) to read in a csv and select axes for plotting with ggplot. Added an additional answer for this as well.

Mike Wise
  • 22,131
  • 8
  • 81
  • 104
user1471980
  • 10,127
  • 48
  • 136
  • 235

2 Answers2

6

This answer just fixes the csv loading problem, see my next answer below for one that actually does the plotting with ggplot.

So (after combining into one file to make it easier to work on), I added a checkboxGroupInput to the ui part and a corresponding updateCheckboxGroupInput to the server part. I needed it to update the group when the dataset changed, so I restructured the code a bit, making the data_set loading part a reactive encapsulating the updateCheckboxGroupInput inside an observer.

And so this does what you want:

library(shiny)
library(shinydashboard)
library(leaflet)
library(data.table)

ui <- pageWithSidebar(
  headerPanel("CSV Viewer"),
  sidebarPanel(
    fileInput('file1', 'Choose CSV File',
              accept=c('text/csv', 'text/comma-separated-values,text/plain', '.csv')),
    tags$hr(),
    checkboxInput('header', 'Header', TRUE),
    checkboxGroupInput("inCheckboxGroup",
                       "Checkbox group input:",
                       c("label 1" = "option1",
                         "label 2" = "option2")),
    radioButtons('sep', 'Separator',
                 c(Comma=',',
                   Semicolon=';',
                   Tab='\t'),
                 ','),
    radioButtons('quote', 'Quote',
                 c(None='',
                   'Double Quote'='"',
                   'Single Quote'="'"),
                 '"'),
    uiOutput("choose_columns")
  ),
  mainPanel(
    tableOutput('contents')
  )
)

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

  data_set <- reactive({
    req(input$file1)
    inFile <- input$file1
    data_set<-read.csv(inFile$datapath, header=input$header, 
                       sep=input$sep, quote=input$quote)
  })
  output$contents <- renderTable({
    data_set()
  })
  observe({
    req(input$file1)
    dsnames <- names(data_set())
    cb_options <- list()
    cb_options[ dsnames] <- dsnames
    updateCheckboxGroupInput(session, "inCheckboxGroup",
                             label = "Check Box Group",
                             choices = cb_options,
                             selected = "")
  })

  output$choose_dataset <- renderUI({
    selectInput("dataset", "Data set", as.list(data_sets))
  })

  # Check boxes
  output$choose_columns <- renderUI({
    # If missing input, return to avoid error later in function
    if(is.null(input$dataset))
      return()

    # Get the data set with the appropriate name

    colnames <- names(contents)

    # Create the checkboxes and select them all by default
    checkboxGroupInput("columns", "Choose columns", 
                       choices  = colnames,
                       selected = colnames)
  })
}
shinyApp(ui, server)

Here is a screenshot:

enter image description here

Mike Wise
  • 22,131
  • 8
  • 81
  • 104
  • Why is there no syntax highlighing on this or the OP question? – Mike Wise Jan 04 '16 at 17:57
  • this is great. One quick queistion, if I wanted to create a ggplot x-axis being the default date field all the time, based on selected items from the the checkboxgroup, how could I create a ggplot? – user1471980 Jan 04 '16 at 17:58
  • I can do that, and will be happy to add it (but after dinner :) ). I would appreciate it even because I want the ggplot2 votes for a badge :) – Mike Wise Jan 04 '16 at 18:02
  • I also would like to know how would you go about formatting the time field (is it ui.R or the server.R section) – user1471980 Jan 04 '16 at 18:31
  • I see that u crate the plot in server and call the output from ui. How would you subset the data based on input from ui etc. For example, I would like my x-axis to be date all the time but y-axis values would change based on user selection from the ui. Thank you so much for helping me with this? – user1471980 Jan 04 '16 at 18:47
  • No problem, but actually best would be to formulate it as a new question and post that. Then other people will have a chance to answer it too. I am going to bed soon. When I wake up, if it is still around, I could answer it. – Mike Wise Jan 04 '16 at 18:53
  • I am running out of energy today :) – Mike Wise Jan 04 '16 at 18:54
  • Could I get this marked as a solution though? I need the points today :) – Mike Wise Jan 04 '16 at 20:56
  • can you explain how you fixed the problem? – MLavoie Jan 05 '16 at 10:24
  • I added a checkbox group to the `ui` and an `updateCheckboxGroupInput` to the server, and restructured the reactive code to contain an observer. Will add text like that to the solution. – Mike Wise Jan 05 '16 at 10:27
  • @MikeWise, would you be able to add x-axis and y-axis group, populated it based on selection then whichever check, create ggplot ouput? Forexample, x-axis being a datetime field, and y-axis being cpu, memory usage etc. – user1471980 Jan 20 '16 at 18:38
  • Yeah, I suppose I could. Want to chat? – Mike Wise Jan 20 '16 at 18:46
  • @MikeWise, Hi, I had a similar requirement where I wanted to filter my data dynamically basis the filter variable options that are displayed and selected. So user can change the filter variable and accordingly the filter option changes. I hope you would be able to help me. Thank you!! Link to my post is http://stackoverflow.com/questions/41187194/shiny-dynamic-filter-variable-selection-and-display-of-variable-values-for-sel – user1412 Dec 23 '16 at 06:17
  • Probably I could, but I am going off the grid (computer-less, although not cell-phone less) for 6 days now on vacation - so it will have to wait. Sorry. – Mike Wise Dec 23 '16 at 06:40
  • @MikeWise, I shall wait for your response and continue with other parts of my code. Enjoy your vacation. Wishing you Merry Christmas and Happy New Year!! – user1412 Dec 23 '16 at 12:09
  • @MikeWise, Happy New year!! Hope you enjoyed your vacation. I was hoping you would be able to help me with my question on filter data basis dynamic filter variable option. Thank you!! Link to my post is http://stackoverflow.com/questions/41187194/shiny-dynamic-filter-variable-selection-and-display-of-variable-values-for-sel – user1412 Jan 03 '17 at 13:47
  • Can you explain why your `checkboxGroupInput` contains 2 definitions for labels and options, but: 1) They don't show up until a file is loaded 2) After a file is loaded, the number of boxes can be anything? Why isn't it limited to the two you set? – jzadra Mar 04 '17 at 23:49
  • I think this script is not working on current version of shiny. Neither the combined script from the second answer nor the separate scripts from the original answer work beyond loading the data. – jzadra Mar 05 '17 at 00:29
  • What does not work? This answer was not supposed to plot anything, it was supposed to populate columns on the left with the columns from a csv on disk. Which is what it does.. – Mike Wise Mar 14 '17 at 21:42
  • As to your question as to why the initial two settings in the Check Box Group do now show up, it is because all shiny reactive and observe nodes get called once at the beginning with input values set to NULL (Wierd but true). Thus the `observe` re-initializes everything to NULL. If you add a `req(input$header` at the beginning of that observe node you get the two choices back. – Mike Wise Mar 14 '17 at 22:07
  • I made the change so as not to confuse people in the future. – Mike Wise Mar 14 '17 at 22:07
5

So adding another answer to accommodate an additional request - it not only reads in the file but and allows you to select columns for plotting, it actually does the plot in a separate tab with ggplot2:

library(shiny)
library(shinydashboard)
library(leaflet)
library(data.table)
library(ggplot2)

ui <- pageWithSidebar(
  headerPanel("CSV Viewer"),
  sidebarPanel(
    fileInput('file1', 'Choose CSV File',
              accept=c('text/csv','text/comma-separated-values,text/plain','.csv')),
    tags$hr(),
    checkboxInput('header', 'Header', TRUE),
    fluidRow(
      column(6,radioButtons("xaxisGrp","X-Axis:", c("1"="1","2"="2"))),
      column(6,checkboxGroupInput("yaxisGrp","Y-axis:", c("1"="1","2"="2")))
    ),
    radioButtons('sep', 'Separator',
                 c(Comma=',', Semicolon=';',Tab='\t'), ','),
    radioButtons('quote', 'Quote',
                 c(None='','Double Quote'='"','Single Quote'="'"),'"'),
    uiOutput("choose_columns")
  ),
  mainPanel(
    tabsetPanel(
      tabPanel("Plot",plotOutput("plot")),
      tabPanel("Data", tableOutput('contents'))
    )
  )
)
server <- function(input, output,session) {
  dsnames <- c()

  data_set <- reactive({
    inFile <- input$file1

    if (is.null(inFile))
      return(mtcars)

    data_set<-read.csv(inFile$datapath, header=input$header, 
                       sep=input$sep, quote=input$quote)
  })

  output$contents <- renderTable({data_set()})

  observe({
    dsnames <- names(data_set())
    cb_options <- list()
    cb_options[ dsnames] <- dsnames
    updateRadioButtons(session, "xaxisGrp",
                             label = "X-Axis",
                             choices = cb_options,
                             selected = "")
    updateCheckboxGroupInput(session, "yaxisGrp",
                             label = "Y-Axis",
                             choices = cb_options,
                             selected = "")
  })
  output$choose_dataset <- renderUI({
    selectInput("dataset", "Data set", as.list(data_sets))
  })
  output$plot = renderPlot(
    {
      df <- data_set()
      gp <- NULL
      if (!is.null(df)){
        xv <- input$xaxisGrp
        yv <- input$yaxisGrp
        if (!is.null(xv) & !is.null(yv)){
          if (sum(xv %in% names(df))>0){ # supress error when changing files
            mdf <- melt(df,id.vars=xv,measure.vars=yv)
            gp <- ggplot(data=mdf) + 
               geom_point(aes_string(x=xv,y="value",color="variable"))
          }
        }
      }
      return(gp)
    }
  )
  output$choose_columns <- renderUI({

    if(is.null(input$dataset))
      return()
    colnames <- names(contents)
    checkboxGroupInput("columns", "Choose columns", 
                       choices  = colnames,
                       selected = colnames)
  }) 
}
shinyApp(ui, server)

Yielding: enter image description here

Mike Wise
  • 22,131
  • 8
  • 81
  • 104
  • Well, isn't this what you wanted? – Mike Wise Jan 22 '16 at 16:07
  • Some feedback would be appreciated. – Mike Wise Jan 24 '16 at 17:00
  • sorry for the late response, I am getting this "Error: id variables not found in data" complaining about the col names – user1471980 Mar 18 '16 at 14:37
  • Ok, let me look. Yeah, there is a bug when you load a file. Let me look. – Mike Wise Mar 18 '16 at 14:55
  • I changed mtcars to df in output$plot section it works. I have a quick question. Let's say I'll pick a column which has datetime or date data in it. This data comes in as factors, how could I format this data in date or datetime format so that the chart is readable. – user1471980 Mar 18 '16 at 15:07
  • I found that bug too, and fixed another. For your question use lubridate's functions or `as.POSIXct` to convert it to a date I would I say. But dates are problematic. I waste a lot of my life dealing with dates. – Mike Wise Mar 18 '16 at 15:21
  • hi @Mike Wise, yes, if I am working in R console in rscript, I can apply as.Posixct. But in this case xaxis may not always be date, it can be datetime but working with csv file, it can also be something else check correlation between two variables. I am thinking there should be radio button if the xasis in datetime format, if check there should be a text box to take in the format of the datetime column and apply it to the data set. Does that make sense? If you could help out with this? – user1471980 Mar 18 '16 at 17:20
  • when can you chat? – user1471980 Mar 18 '16 at 19:53
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/106765/discussion-between-mike-wise-and-user1471980). – Mike Wise Mar 18 '16 at 21:12
  • let me know when you're back. I'd like to chat. – user1471980 Mar 21 '16 at 15:22
  • I am online now. Invite me into a chat if you want. – Mike Wise Mar 22 '16 at 15:07
  • can we go to your chat room you created the other day? – user1471980 Mar 22 '16 at 15:59
  • the requirements changed, I need to be able to add textInput() into my main panel with a command button and to be able to use the values inside those text boxes later on. I tried to look at some examples but they are not working for me: http://stackoverflow.com/questions/36160053/how-do-you-dynamically-add-inputtext-in-shiny-application/36161998#36161998 – user1471980 Mar 22 '16 at 19:38