0

I am trying to get input from multiple checkbox groups, but only the last checkbox group (labeled industry) displays its contents. What am I doing wrong here? Note how the checkbox options repeat under different sub-headings.

enter image description here

My code:

library(dplyr)
library(shiny)
dlxl<-function(url,sht){
  tmp = tempfile(fileext = ".xlsx")
  download.file(url = url, destfile = tmp, mode="wb")
  library(readxl)
  read_excel(tmp,sheet=sht)
}
csv<-dlxl("https://www.bls.gov/cps/cpsa2016.xlsx",sht="cpsaat14")
colnames(csv)<-csv[4,]
csv<-csv[6:81,]

ui = bootstrapPage(
  titlePanel("Occupation by Race and Age"),

  sidebarLayout(
    sidebarPanel(
      checkboxGroupInput('age',"Choose Age/Racial Group(s)", choices=csv[1,],selected=NULL),
      checkboxGroupInput('industry',"Choose Industries", choices=colnames(csv),selected=NULL)
    ),
    mainPanel(
      plotOutput("plot1"),
      htmlOutput("text1")
    )
  )
)
server = function(input, output, session){

  output$text1 <- renderUI({HTML(paste("GO"))})

  getData<-reactive({
    cat(paste0("in_get_data_\n",input$age))
    cat(paste0("in_get_data2_\n",input$industry))
    shiny::validate(need(input$age!="", "Please select an age"))
    shiny::validate(need(input$industry!="", "Please select an industry"))
    #ages are x axis, y are industry values
    data<-csv[grepl(input$age,row.names(csv)),] #filter only selected ages (rows)
    data<-data[,grepl(input$industry,colnames(csv))] #filter only selected industry (column)
    data
})

  output$plot1 <- renderPlot({
    data<-getData()
    shiny::validate(need(length(data)>1, "The data for the source you selected was not reported"))
    plot(data,names.arg=colnames(data),legend.text = T,beside=T,col =palette()[1:nrow(data)])
  })
}

shinyApp(ui, server)
Rilcon42
  • 9,584
  • 18
  • 83
  • 167

1 Answers1

2

There is quite a few things I would change.

age select box

You are passing wrong values to the first checkbox, try:

choices = unique(as.data.frame(csv)[,1])

Fixed checkboxes Fixed checkboxes

Update: Creating named list for the choices argument

In reply to the discussion, in comments, following this answer, if your intention is to utilise unique(as.data.frame(csv)[,1]) as both labels and values for the choices argument of the checkbox you could create the necessary list in the following manner:

choicesList <- as.list(unique(as.data.frame(csv)[,1]))
names(choicesList) <- as.list(unique(as.data.frame(csv)[,1]))

that you could later pass to the checkbox function: choices = choicesList.

Other issues

It's worth adding that you can filter for both conidtions simoultanously:

data <-
    csv[grepl(input$age, row.names(csv)) ,
        grepl(input$industry, colnames(csv))]

There are other things worth fixing. Running the code:

dlxl <- function(url, sht) {
    tmp = tempfile(fileext = ".xlsx")
    download.file(url = url,
                  destfile = tmp,
                  mode = "wb")
    library(readxl)
    read_excel(tmp, sheet = sht)
}
csv <-
    dlxl("https://www.bls.gov/cps/cpsa2016.xlsx", sht = "cpsaat14")
colnames(csv) <- csv[4,]
csv <- csv[6:81,]

will generate:

>> head(csv)
Error in x[needs_ticks] <- paste0("`", gsub("`", "\\\\`", x[needs_ticks]),  : 
  NAs are not allowed in subscripted assignments

if you have a look:

>> head(as.data.frame(csv))
                        NA Mining,\r\nquarry-\r\ning,\r\nand oil\r\nand gas\r\nextract-\r\nion
1                    TOTAL                                                                <NA>
2 Total, 16 years and over                                                                 792
3           16 to 19 years                                                                   4
4        20 years and over                                                                 788
5           20 to 24 years                                                                  45
6        25 years and over                                                                 743

Working with this data frame will be a nightmare. You could start from changing column names to syntactically correct ones, most brutal approach would involve making use of the make.names function:

>> make.names(names(as.data.frame(csv)))
 [1] "NA."                                                    
 [2] "Mining...quarry...ing...and.oil..and.gas..extract...ion"
 [3] "Con...struc...tion" 

IMHO, I think it would be worthwhile to fix then data frame first and then derive the UI elements and implement the subsetting logic as trying to utilise presently available values will prove problematic due to weird content: NA Mining,\r\nquarry-\r\ning,\r\

Community
  • 1
  • 1
Konrad
  • 17,740
  • 16
  • 106
  • 167
  • Thanks for the very thorough answer! I can't get the logic to work right when I try to subset the age however, I always wind up with a 0 dimensional table. Subsetting the industry works fine though. Any idea what could be wrong? I can post another question if needed. This was after implementing the `make.names` suggestion. – Rilcon42 Mar 05 '17 at 19:09
  • @Rilcon42 If you look at the help for the checkbox item, the choices should be a list. I would first tidy this data frame and then developed a list with names corresponding to what you end-user to see and values reflecting desired row entries. There are posts on how to construct *choice* items for shiny UI on SO (I've asked similar question in past). – Konrad Mar 05 '17 at 19:14