0
votes

Hope someone can help with this tricky one: The Shiny app runs perfectly with the template Excel but when the user loads a new file and refreshes the calculation, this error appears:

Warning: Unknown or uninitialised column: `Distribution`.
Warning: Unknown or uninitialised column: `Distribution`.
Warning: Unknown or uninitialised column: `Distribution`.
Warning: Error in : Problem with `filter()` input `..1`.
x Input `..1` must be of size 3 or 1, not size 0.
i Input `..1` is `!is.na(rv$RRDTRaw$Likelihood) & !is.na(rv$RRDTRaw$Distribution)`.
  59: <Anonymous>

This issue only shows when the last "observe" function with a filter function in it is activein the code. If I comment it, the issue is gone. See below the code:

## LIBRARIES
        library(tidyverse)
        library(stats)
        library(data.table)
        library(triangle)
        library(base)
        library(matrixStats)
        library(ggplot2)
        library(ggthemes)
        library(readxl)
        library(httr)
        library(shiny)

## DEFINITIONS

    vQuantiles <- c(P00 = 0, P05 = .05, P50 = .50, P80 = .80, P95 = .95, P100 = 1)
        vtQuantiles <- names(vQuantiles)

    MCScenarioTotals <- list()
    MCTotalsQuantiles <- list()
    MCRecordsQuantiles <- list()
    MCRecordsQuantilesTop10 <- list()

## LOAD RR TEMPLATES

    ExcelTemplate <- tempfile(fileext = ".xlsx")
    GET(url = "https://www.openmontecarlo.com/SampleS.xlsx",write_disk(ExcelTemplate))
    defaultRR <- read_excel(ExcelTemplate)

## DEFINE UI

ui <-

fluidPage(
    hr(),
    h1("Monte Carlo Simulation",align = "center"),

    fluidRow(
        hr(),
        column(3,
            checkboxGroupInput("ISvModels", label = h3("Step 1:",br(),"Select which Models to Run"), 
            choices = list(
            "100 Scenarios" = 100,
            "1000 Scenarios" = 1000,
            "5000 Scenarios" = 5000,
            "10000 Scenarios" = 10000),
            selected = 100),offset = 1
        ),

        column(7,
            selectInput("templateSelection",h3("Step 2:",br(),"Select an existing Risk Register sample"),
                c(1,2,3,4),selected = 3,multiple = FALSE,selectize = TRUE,width = NULL,size = NULL),
            
            fileInput("userExcel", h3("Or upload your own Risk Register"),accept = ".xlsx"),
            offset = 1,
        ),
    ),
    hr(),

    fluidRow(
        column(5,
            h3("Step 3: Click to run the models"),
            offset = 1,
        ),

        column(6,
            br(),
            actionButton(inputId = "Refresh", label = "Run Simulation",
            ),
            offset = 0,
        ),
    ),
    hr(),

    mainPanel(  

        h3(strong("Risk Register - Imported Data")),
        br(),
        dataTableOutput("SRRImport"),

        h3(strong("Risk Register - Raw Data")),
        br(),
        dataTableOutput("SRRDTRaw"),

        h3(strong("Risk Register - Invalid Likelihood Data")),
        br(),
        dataTableOutput("SLikelihoodQADrop"),

        h3(strong("Risk Register - Invalid Impact Data")),
        br(),
        dataTableOutput("SImpactQADrop"),

        h3(strong("Risk Register - Valid Data")),
        br(),
        dataTableOutput("SRRDT"),

    )
)

server <- function(input, output) {

## CREATE DEFAULT RR AND REACTIVE VARIABLES

rv <- reactiveValues(
    inputRR = tempfile(fileext = ".xlsx"),
    inputPath = NULL,
    vModels = c(100),
    RRImport = defaultRR,
    RRuserExcel = data.frame(),
    RRDTRaw = data.frame(),
    LikelihoodQADrop = data.frame(),
    ImpactQADrop = data.frame(),
    RRDT = data.frame(),
    nDrop = 0,
    nRisks = 1,
    RRDTLong = data.frame()
    )

# SHINY INPUT REFRESH

    observeEvent(input$Refresh,{if (is.null(input$userExcel)) {rv$RRImport <- defaultRR}
        else {
        rv$inputPath <- input$userExcel
        output$SinputPath <- renderPrint({rv$inputPath[,4]})
        rv$inputRR <- read_excel(paste0(rv$inputPath[,4]))
        rv$RRImport <- rv$inputRR
        }
    })

# data.frame(suppressWarnings(

    output$SRRImport <- renderDataTable({rv$RRImport})

    observe({rv$nRisksImported <- nrow(rv$RRImport)})
        output$SnRisksImported <- renderPrint({rv$nRisksImported})

## PROCESS MODELS INPUT

    observeEvent(input$Refresh,{rv$vModels <- as.numeric(unlist(input$ISvModels))})
        output$vModelsText <- renderPrint({unlist(rv$vModels)})

    qtModels <- reactive({length(unlist(rv$vModels))})
        output$qtModelsText <- renderPrint({unlist(qtModels())})

    vtModels <- reactive({paste0("M",1:qtModels()," n = ",rv$vModels," scenarios")})
        output$vtModelsText <- renderPrint({unlist(vtModels())})

## RR RAW

    observe({rv$RRDTRaw <- rv$RRImport})
    observe({rv$RRDTRaw$Likelihood <- suppressWarnings(as.numeric(rv$RRDTRaw$Likelihood))})
    observe({rv$RRDTRaw$Min <- suppressWarnings(as.numeric(rv$RRDTRaw$Min))})
    observe({rv$RRDTRaw$ML <- suppressWarnings(as.numeric(rv$RRDTRaw$ML))})
    observe({rv$RRDTRaw$Max <- suppressWarnings(as.numeric(rv$RRDTRaw$Max))})
      
## QUALITY CHECK LIKELIHOOD

    observe({rv$RRDTRaw$Likelihood <- ifelse (rv$RRDTRaw$Likelihood <=0 | rv$RRDTRaw$Likelihood >=100,NA,rv$RRDTRaw$Likelihood)})

    observe({rv$LikelihoodQADrop <- rv$RRImport[which(is.na(rv$RRDTRaw$Likelihood)),]})
        output$SLikelihoodQADrop <- renderDataTable({rv$LikelihoodQADrop})

## CLASSIFY AND QUALITY CHECK DISTRIBUTIONS

    observe({rv$RRDTRaw <- mutate(rv$RRDTRaw,Distribution = case_when(is.na(rv$RRDTRaw$Min) & is.na(rv$RRDTRaw$Max) & !is.na(rv$RRDTRaw$ML) ~ "Single Point",
                                        is.na(rv$RRDTRaw$ML) & !is.na(rv$RRDTRaw$Min) & !is.na(rv$RRDTRaw$Max) & rv$RRDTRaw$Min<rv$RRDTRaw$Max ~ "Uniform",
                                        !is.na(rv$RRDTRaw$Min) & !is.na(rv$RRDTRaw$Max) & !is.na(rv$RRDTRaw$ML) & rv$RRDTRaw$Min<rv$RRDTRaw$ML & rv$RRDTRaw$ML<rv$RRDTRaw$Max ~ "3 Points"))
            })
        output$SRRDTRaw <- renderDataTable({rv$RRDTRaw})

    observe({rv$ImpactQADrop <- rv$RRImport[which(is.na(rv$RRDTRaw$Distribution)),]})
        output$SImpactQADrop <- renderDataTable({rv$ImpactQADrop})

## DROP + DECLARE NAs AND PROCEED + PRINT THE RISK REGISTER

    observe({rv$RRDT <- filter(rv$RRDTRaw, !is.na(rv$RRDTRaw$Likelihood) & !is.na(rv$RRDTRaw$Distribution))})

}

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

Difficult to understand how the functions can work for the first automatically loaded file and why the user input file breaks the app. This happens even if I upload the same file as the template.

Hope you can help. Thanks!!

1
Try dplyr::filter(...) in the last observe as you may have filter from other packages. - YBS
Hi @YBS. That is a really good call, thanks! Unfortunately I still get the same situation: it runs perfectly with the initially loaded Excel file but I get the error message after I upload a new file and click on Run, even if I upload the same template Excel file. How come that is possible??? - julianobats
Hey thanks again for the advice. Believe me, I tryed all sort of workarounds, changing separate if functions and other logic operators as is.na, !is.na... - julianobats
Also tried to substitute the filter function for "complete.cases" and "which" but both give the exact same error message. It seems the root of the problem resides in the creation of the Distribution column with mutate and any implications this "non initialized" column generates, seems a usual problem with Shiny especially when using mutate. Because it only happens with the user input file, I also imagine there may be some error in my reactive values declaration, but I spent a lot of time trying different approaches and they all work for the template file but break with the user input file - julianobats

1 Answers

2
votes

Your read_excel is not working for the user input file as it is just a path. Try read_xlsx as shown below.

observeEvent(input$Refresh,{if (is.null(input$userExcel)) {rv$RRImport <- defaultRR}
    else {
      inFile <- input$userExcel
      rv$inputPath <- inFile
      output$SinputPath <- renderPrint({rv$inputPath[,4]})
      #rv$inputRR <- read_excel(paste0(rv$inputPath[,4]))
      rv$inputRR <- read_xlsx(inFile$datapath, sheet =  1)
      rv$RRImport <- rv$inputRR
    }
  })