5
votes

I have an app with conditional panels that depend on a series of user choices. It's too complex to provide a reproducible example, but I'll try to give a simplified version to get what I'm asking and also include relevant sections from the actual app.

In my app, a certain conditional panel appears if the user loads an Excel file and then selects another condition from a radio button. If an Excel file is loaded and the appropriate selection made, the given conditional panel appears as expected. If a csv file is loaded, the conditional panel does not appear, but there is a red message around where it should be object sheetrID not found. The error (which is actually a warning in Shiny) is purely cosmetic, but I would like to understand why this is happening.

As a way to get at this, what would be a way of getting an analogous error message on the conditional panel in this simple app:

library(shiny)

ui <- fluidPage(

  column(3,
         h3("Add new data"),
         uiOutput("dummyslider")
  ), # close column

  column(9,
         h3("Matching"),
         uiOutput("condition_select")
  ) # close column

) # close fluidPage


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

  output$dummyslider <- renderUI({ 
    sliderInput(inputId = "num",
                label = "Choose a number",
                value = 25, min = 1, max = 100)
  })

  output$condition_select <- shiny::renderUI({
  shiny::conditionalPanel(
    condition="input.num > 40",
    shiny::sliderInput(
      inputId="slider2",
      label="test label",
      min=0,
      max=1,
      value=0.1,
      step=0.01
    )
  )
})

} # close server

shinyApp(ui = ui, server = server)

EDIT: In response to @Pork Chop recommendation - it's unclear where exactly I would insert the req statement. The conditional panel relies on input$method_cat being 'both' in order for the panel to display. I inserted print statements that verify that the input$method_cat is not sheet, and also verifies that getExtension is 'csv':

output$condition_cat_both <- shiny::renderUI({
print(input$method_cat)
print(getExtension())
shiny::conditionalPanel(
  condition="input.method_cat == 'both'",
  shinyWidgets::pickerInput(
    inputId="cat_vars_selected_both",
    label="Select variables you wish to be categorical:",
    choices=smartSelectionCatVars(importDataSet(), importCatVarLookup()),
    multiple=TRUE,
    options = list(`actions-box` = TRUE)
  ), # close pickerInput
) # close conditionalPanel

method_cat is the output of a radio button:

output$select_method_cat <- shiny::renderUI({
    shinyWidgets::awesomeRadio(
      inputId="method_cat",
      label="Select the method to treat categorical variables:",
      choices=getMethodCatOptions(),
      selected="thresh"
    )
  }) # close renderUI

getMethodCatOptions in turn returns 'both' as one of the radio button choices only when the loaded file is an Excel:

getMethodCatOptions <- shiny::reactive({
    req(input$variable_relations)
    req(input$cat_var_lookup)
    if(getExtension() == "xlsx" && input$variable_relations == "Yes" && 
      input$cat_var_lookup == "Yes") {
      return(c("Threshold"="thresh", "Select Variables Specifically"="pick", 
        "Use categorical variable lookup"="sheet", 
        "Select both"="both"))
    }
    return(c("Threshold"="thresh", "Select Variables Specifically"="pick"))
  }) # close reactive

Thus, it's unclear where I would insert the req statement, as by definition the conditional panel should appear only when the input file is an Excel (because that's the only thing that triggers 'sheet' to be output as one of the options of the radio button).

Update: I realized that this purported error message is actually a warning in Shiny: `Warning: Error in match: object 'sheetrId' not found

I can suppress the warning and thereby eliminate the issue, but I would rather understand why this is happening. Could it be that it's because the conditional panel is inside a renderUI function?

Then again, my toy example has the same situation and there is no issue with that conditional panel...

1
sheetrID is assigned to excel workbook. add req() statement in between and see if that helps - Pork Chop
Is the error due to the command being used to read the file possibly? Perhaps adding a conditional that depends on your file type would help. - A Duv
@ADuv, I already have a condition that getExtension==xlsx in order for the panel to appear.... - matsuo_basho
Are you using openxlsx::loadWorkbook() to load the Excel file? sheetrID is a temporary object used for a variety of purposes in the loadWorkbook function. If you create a csv file and try to use loadWorkbook to access it in your local R environment, you get the same error. I'm guessing that the error in your app is just to do with the use of that function, and not anything to do with your app or the construction. So @ADuv was on the right track, I think... - phalteman
Just a general statement that might (or might not) work in your case, but I've previous run into an issue with problems like this involving environments. In these cases, I've found that shiny places a variable in the environment of the function in question (such as an observeEvent). If you're trying to refer to this somewhere else in shiny then you need to assign the variable to the global environment, using <<- rather than <-. Thought it worth mentioning in case it helps you in this instance. - p0bs

1 Answers

0
votes

To demonstrate my comment above, here is an adapted version of your example app that produces the same error message. However, as I mentioned, the error has nothing to do with your app and instead is a result of the use of openxlsx::loadWorkbook().

In this example, the conditional panel will open once you've moved the slider past 40 and successfully uploaded a file. If you use openxlsx::loadWorkbook() to try to access a .csv, you get the error you describe (not a successful upload) and the panel won't open. You can switch to read.csv() to avoid the error and open the panel.

In your case, if you don't want the panel to open if a user attempts to upload a .csv file, it might be more instructive to include a validate() function to tell the user to upload an Excel file rather than .csv.

Updated UI:

library(shiny)

ui <- fluidPage(  
  column(3,
     h3("Add new data"),
     uiOutput("dummyslider")
  ), # close column
  column(3,
     h3("Matching"),
     uiOutput("condition_select")
  ), # close column
  column(3,
     h3("Table/error"),
     tableOutput("tbl")
  )
) # close fluidPage

Updated Server:

server <- function(input, output, session) {
  output$dummyslider <- renderUI({
    tagList(
      sliderInput(inputId = "num",
            label = "Choose a number",
            value = 25, min = 1, max = 100),
      fileInput("upl", label = "Upload any .csv file:")
    )
  })
  output$condition_select <- shiny::renderUI({
    shiny::conditionalPanel(
      condition="input.num > 40 & output.uploaded",
      shiny::sliderInput(
        inputId="slider2",
        label="test label",
        min=0,
        max=1,
        value=0.1,
        step=0.01
      )
    )
  })
  data <- reactive({
    uplFile <- input$upl
    if (is.null(uplFile))
      return(NULL)
    #tbl <- read.csv(uplFile$datapath)
    tbl <- openxlsx::loadWorkbook(file=as.character(uplFile$datapath))
    return(tbl)
  })
  output$uploaded <- reactive({ return( !is.null(data()) ) })
  outputOptions(output, "uploaded", suspendWhenHidden=FALSE)
  output$tbl <- renderTable ({
    if (is.null(data())) return()
    head(data.frame(read.xlsx(data())),10)
  })
}

shinyApp(ui, server)