简体   繁体   English

Shiny 验证不显示错误信息

[英]Shiny validate does not show error message

My R Shiny app has two textAreaInput() , one for x values and the other for y values.我的 R Shiny 应用有两个textAreaInput() ,一个用于 x 值,另一个用于 y 值。 When a button is pressed a simple linear regression model is fit and the results is printed on the mainPanel.当一个按钮被按下时,一个简单的线性回归 model 被拟合并且结果被打印在 mainPanel 上。 This works perfectly fine.这工作得很好。

I am trying to validate the textAreaInput() so I can show an error message我正在尝试验证textAreaInput()以便显示错误消息

--- when the length(x) != length(y) --- 当长度(x) != 长度(y)

--- when the x or y boxes are empty --- 当 x 或 y 框为空时

--- when the x or y boxes contains not enough values (less than two data pairs) --- 当 x 或 y 框包含的值不够时(少于两个数据对)

--- when the x or y boxes contains NA or invalid characters --- 当 x 或 y 框包含 NA 或无效字符时

Here a minimal reprex code.这是一个最小的 reprex 代码。 I see the Shiny validations for the above requirements are not properly displaying on the mainPanel when the conditions met.我看到满足上述要求的 Shiny 验证在满足条件时未正确显示在主面板上。 EDITED CODE BELOW: Made the reprex code minimal and removed all reactive() as advised下面的编辑代码:使 reprex 代码最小化,并按照建议删除所有reactive()

library(shiny)
library(shinythemes)
library(shinyjs)
library(shinyvalidate)

ui <- fluidPage(theme = bs_theme(version = 4, bootswatch = "minty"),
           
  navbarPage(title = div(span("Simple Linear Regression", style = "color:#000000; font-weight:bold; font-size:18pt")),

                tabPanel(title = "",
                  sidebarLayout(
                    sidebarPanel(
                      shinyjs::useShinyjs(),
                      id = "sideBar", 

                      textAreaInput("x", label = strong("x (Independent Variable)"), value = "87, 92, 100, 103, 107, 110, 112, 127", placeholder = "Enter values separated by a comma with decimals as points", rows = 3),
                      textAreaInput("y", label = strong("y (Dependent Variable)"), value = "39, 47, 60, 50, 60, 65, 115, 118", placeholder = "Enter values separated by a comma with decimals as points", rows = 3),

                      actionButton(inputId = "goRegression", label = "Calculate",
                                   style="color: #fff; background-color: #337ab7; border-color: #2e6da4"),
                      actionButton("resetAllRC", label = "Reset Values",
                                   style="color: #fff; background-color: #337ab7; border-color: #2e6da4"), #, onclick = "history.go(0)"
                    ),
                    
                    mainPanel(
                      div(id = "RegCorMP",
                            textOutput("xArray"),
                            
                            textOutput("yArray"),
                          
                            textOutput("arrayLengths"),

                            verbatimTextOutput("linearRegression"),
                      ) # RegCorMP
                  ) # mainPanel
               ) # sidebarLayout
          )
      )
  )
  
server <- function(input, output) {
    
    # Data validation
    iv <- InputValidator$new()

    iv$add_rule("x", sv_required())
    iv$add_rule("y", sv_required())

    iv$enable()
    
    # String List to Numeric List
    createNumLst <- function(text) {
      text <- gsub("","", text)
      split <- strsplit(text, ",", fixed = FALSE)[[1]]
      as.numeric(split)
    }

    observeEvent(input$goRegression, {
      
      datx <- createNumLst(input$x)
      daty <- createNumLst(input$y)

      if(length(datx)<2){
        output$xArray <- renderPrint({
          "Not enough x values"
        })
      }
      
      else if(length(daty)<2){
        output$yArray <- renderPrint({
          "Not enough y values"
        })
      }
      
      if (length(datx) != length(daty)) {
        print(length(datx))
        print(length(daty))
        
        output$arrayLengths <- renderPrint({
          "Length of x and length of y must be the same"
        })
      }
     
      else if (length(datx) == length(daty)) {
          output$linearRegression <- renderPrint({ 
            summary(lm(daty ~ datx))
          })
      }
    })

    observeEvent(input$goRegression, {
      show(id = "RegCorMP")
    })
    
    observeEvent(input$resetAllRC, {
      hide(id = "RegCorMP")
      shinyjs::reset("RegCorMP")
    })
}
  
shinyApp(ui = ui, server = server)```

I think this comes close to what you want.我认为这接近你想要的。 Note how every reactive is defined in the body of the server function, not within the body of another reactive .请注意每个reactive是如何在服务器 function 的主体中定义的,而不是在另一个reactive的主体中。 This is critical .这很关键 And also removes the need for your observeEvent entirely.并且还完全消除了对observeEvent的需求。

I have removed more material ( div s, theme s, etc) that is not relevant to your question.我删除了更多与您的问题无关的材料( divtheme等)。 I'm not sure shinyjs is necessary either.我也不确定shinyjs是否必要。 Also, I'm not sure what you're trying to do with your reset button (it appears to do nothing at the moment), so I've left it in.另外,我不确定你想用你的重置按钮做什么(它现在似乎什么也没做),所以我把它留在里面了。

I've added validation to ensure there are no NAs in either input, but have left it to you to implement a check for equality of length.我添加了验证以确保两个输入中都没有 NA,但将其留给您来执行长度相等性检查。

As an aside, there's no need to comma separate your inputs: spaces would suffice... ;=)顺便说一句,没有必要用逗号分隔您的输入:空格就足够了...;=)

library(shiny)
library(shinyjs)
library(shinyvalidate)

ui <- fluidPage(
        useShinyjs(),
        navbarPage(
          title = "Simple Linear Regression",
          tabPanel(
            title = "",
            sidebarLayout(
            sidebarPanel(
              id = "sideBar", 
              textAreaInput(
                "x", 
                label = strong("x (Independent Variable)"), 
                value = "87, 92, 100, 103, 107, 110, 112, 127", 
                placeholder = "Enter values separated by a comma with decimals as points", 
                rows = 3
              ),
              textAreaInput(
                "y", 
                label = strong("y (Dependent Variable)"), 
                value = "39, 47, 60, 50, 60, 65, 115, 118", 
                placeholder = "Enter values separated by a comma with decimals as points", 
                rows = 3
              ),
              actionButton(
                inputId = "goRegression", 
                label = "Calculate",
              ),
              actionButton(
                "resetAllRC", 
                label = "Reset Values",
              )
            ),
            mainPanel(
              div(
                textOutput("xArray"),
                textOutput("yArray"),
                textOutput("arrayLengths"),
                verbatimTextOutput("linearRegression"),
              ) # RegCorMP
            ) # mainPanel
          ) # sidebarLayout
        )
      )
    )

server <- function(input, output) {
  # Data validation
  iv <- InputValidator$new()
  iv$add_rule("x", sv_required())
  iv$add_rule("x", ~ if (any(is.na(as.numeric(strsplit(., ",", fixed = FALSE)[[1]])))) "NAs are not allowed")
  iv$add_rule("y", sv_required())
  iv$add_rule("y", ~ if (any(is.na(as.numeric(strsplit(., ",", fixed = FALSE)[[1]])))) "NAs are not allowed")
  iv$enable()
  # See https://rstudio.github.io/shinyvalidate/articles/advanced.html for clues on
  # how to implement length(x) == length(y) validation

  createNumLst <- function(text) {
    text <- gsub("","", text)
    split <- strsplit(text, ",", fixed = FALSE)[[1]]
    d <- as.numeric(split)
    if (length(d) < 2) "Not enough values"
    d
  }
  
  xData <- reactive({
    createNumLst(input$x)
  })
  
  yData <- reactive({
    createNumLst(input$y)
  })
  
  output$xArray <- renderPrint({ xData() })

    output$yArray <- renderPrint({ yData() })
  
  output$arrayLengths <- renderPrint({
    if (length(xData()) != length(yData())) "Length of x and length of y must be the same"
  })
  
  # Use isolate to ensure that results are updated only when action button is clicked, not 
  # every time the input data changes
  output$linearRegression <- renderPrint({
    input$goRegression
    isolate({
      summary(lm(yData() ~ xData()))
    })
  })
  
  observeEvent(input$goRegression, {
    show(id = "RegCorMP")
  })
  
  # Not sure what you are trying to do here
  observeEvent(input$resetAllRC, {
    hide(id = "RegCorMP")
    shinyjs::reset("RegCorMP")
  })
}

shinyApp(ui = ui, server = server)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM