闪亮:如何在通过 actionButton 评估输入条件时更改输出(视觉数据到警告消息,反之亦然)

Shiny: How to change output (visual data to warning message & vice-versa) when input conditions are evaluated via actionButton

我正在开发一个应用程序,该应用程序应该接受数字输入,然后根据所述输入生成一些可视化和优化结果。问题是输入应该满足一些条件,如果违反了条件,我希望为用户弹出一条消息,而不是无意义的结果。

每个数字输入都有一个最小值和最大值。在这种情况下,采用输入 'X',其中我需要 X 大于 比 'X MIN' 和 小于 'X MAX'。我正在考虑让算法立即或单击操作按钮后检查输入,如果违反条件,则隐藏输出并弹出一条消息并说明 'please ensure X is greater than the minimum value and less than the maximum value' 。这将适用于任何违反的输入。然后 运行 成功并在条件验证正确后显示输出。

我已经进行了几次不同的尝试,'feel' observeEvent 是可行的方法,但我的逻辑并不完全正确。 shinyjs::hide 命令似乎只在第一次单击操作按钮时有效,而不是第二次、第三次等...当单击按钮且未评估条件时。令人惊讶的是,'warning' 消息似乎在我自己更改输入时立即发生变化,而不仅仅是当我按下 actionButton 时,所以很明显这里的范围界定与我认为我正在编码的内容 vs .这是怎么回事

除了这些观察之外,我现在意识到这段代码无法同时显示 xwarningywarning如果不满足 input$xinput$y 或任何组合的输入条件,因为这也是可取的,因此也将不胜感激。从我下面的示例中,我希望人们会在第一个 运行 之后注意到算法没有成功 隐藏显示 视觉效果。我将继续致力于此,但如有任何帮助,我们将不胜感激。

也探索 validate 作为一个选项。这也是我的第一个 post,所以对我如何提出这个问题的任何评论也表示赞赏。

library(DT)
library(shiny)
library(shinyjs)
library(plyr)
library(lubridate)
library(data.table)
library(tidyr)
options(scipen=999)
gc()

ui <- dashboardPage(
  
  dashboardHeader(),   # Have to try this one, title is not popping up 
  
  dashboardSidebar(size = "wide", 
                   
                   sidebarMenu(  # Removes spinner from input boxes
                     
                     tags$head(
                       tags$style(HTML("hr {border-top: 1px solid #000000;}"))
                     ),
                     
                     
                     hr(),
                     
                     numericInput('x','X Spend:', value = 1000000, min = 2, max = 5000000),
                     numericInput('y', 'Y Spend:', value = 50000, min = 2, max = 5000000), 
                     numericInput('z', 'Z Spend:', value = 1500000, min = 2, max = 5000000),
                     
                     
                     hr(),
                     
                     
                     numericInput('xlb', 'X MIN:', value = 0, min = 1, max = 5000000),
                     numericInput('ylb', 'Y MIN:', value = 0, min = 1, max = 5000000),
                     numericInput('zlb', 'Z MIN:', value = 0, min = 1, max = 5000000), 
                     
                     hr(),
                     
                     numericInput('xub', 'X MAX:', value = 2500000, min = 1, max = 5000000),
                     numericInput('yub', 'Y MAX:', value = 1500000, min = 1, max = 5000000),
                     numericInput('zub', 'Z MAX:', value = 3000000, min = 1, max = 5000000), 
                     
          
                     hr(),
          
                     
                     menuItem(tabName=  "main","X-Y-Z", icon = icon('chart area')),
                     menuItem(tabName = "xtb", "X Breakdown", icon = icon("table")),
                     menuItem(tabName = "yvb", "Y Breakdown", icon = icon("table")),
                     menuItem(tabName = "zbb", "Z Breakdown", icon = icon("table")),
                
                     
                     actionButton('Run', 'Run App')
                   )
  ),
  
  dashboardBody(
    # Suppresses warning messages
    tags$style(type="text/css",
               ".shiny-output-error { visibility: hidden; }",
               ".shiny-output-error:before { visibility: hidden; }"),
    
    
    
    # Set up Tab regimen
    tabItems(selected = 1,
             
             # Main tab 
             tabItem(tabName = "main", 
                     
                     
                     # Plan Plot 
                     box(width = 8, title = "X-Y-Z Spend",
                         color = "green", ribbon = T, title_side = "top right",
                         column(width = 8,
                                plotOutput(outputId = 'plot1', height = '100%')
                         )
                     ),
                     # Solver Plot 
                     box(width = 8, title = "X-Y-Z Logarithmic Spend",
                         color = "green", ribbon = T, title_side = "top right",
                         column(width = 8,
                                plotOutput(outputId = 'plot2', height = '100%')
                         )
                     ),
                     
                     DT::dataTableOutput('results') ,
                     verbatimTextOutput('xwarning'),
                     verbatimTextOutput('ywarning'),
                     verbatimTextOutput('zwarning'),
                     
             ),
             
             # Results table 1
             tabItem(tabName = "xtb",
                     
                     DT::dataTableOutput('results2') 
             ),
             
             # Results table 2
             tabItem(tabName = "yvb",
                     
                     DT::dataTableOutput('results3') 
             ),
             
             # Results TV
             tabItem(tabName = "zbb",
                     
                     DT::dataTableOutput('results4') 
             )
             
    )
  )
)
####################################################################################################################################################

####################################################################################################################################################
server <- shinyServer(function(input, output, session) {
  
  go <- eventReactive(input$Run, {
    
    x.y.z.spend     <- as.matrix(rbind(input$x,
                                   input$y,
                                   input$z))
    
    x.y.z.log.spend <- as.matrix(rbind(log(input$x),
                                       log(input$y),
                                       log(input$z)))
    
    letters           <- as.matrix(rbind('X',
                                       'Y',
                                       'Z'))
    
    
    x.log <- log(input$x)
    y.log <- log(input$y)
    z.log <- log(input$z)
    
    values <- as.matrix(cbind(input$x, input$y, input$z, x.log, y.log, z.log))
    
    table.results <- DT::datatable(values, options = list(paging = F, searching = F, ordering = F, dom = 't',
                                                          columnDefs = list(list(className = 'dt-left', targets = "_all"))), rownames = F)
    
    
    table.x       <- DT::datatable(cbind(input$x,log(input$x)), options = list(paging = F, searching = F, ordering = F, dom = 't',
                                                           columnDefs = list(list(className = 'dt-left', targets = "_all"))), rownames = F)
    
    table.y       <- DT::datatable(cbind(input$y,log(input$y)), options = list(paging = F, searching = F, ordering = F, dom = 't',
                                                            columnDefs = list(list(className = 'dt-left', targets = "_all"))), rownames = F)
    
    table.z       <- DT::datatable(cbind(input$z,log(input$z)), options = list(paging = F, searching = F, ordering = F, dom = 't',
                                                            columnDefs = list(list(className = 'dt-left', targets = "_all"))), rownames = F)
    
    list(table = table.results,
         table2 = table.x,
         table3 = table.y,
         table4 = table.z,
         x.y.z.spend,
         x.y.z.log.spend,
         letters
         )
    
  }) 
  

  observeEvent(input$Run,{
    
    if (input$x > input$xub || input$x < input$xlb){
      
      shinyjs::hide('results')
      shinyjs::hide('results2')
      shinyjs::hide('results3')
      shinyjs::hide('results4')
      shinyjs::hide('plot1')
      shinyjs::hide('plot2')
      shinyjs::hide('ywarning')
      shinyjs::hide('zwarning')
      
      shinyjs::show('xwarning')
      output$xwarning <- renderText({paste('Please ensure that',input$x,'is less than',input$xub,'and greater than',input$xlb)})
      
      
    }
      
    else if (input$y > input$yub || input$y < input$ylb){
      
      shinyjs::hide('results')
      shinyjs::hide('results2')
      shinyjs::hide('results3')
      shinyjs::hide('results4')
      shinyjs::hide('plot1')
      shinyjs::hide('plot2')
      shinyjs::hide('xwarning')
      shinyjs::hide('zwarning')
      
      shinyjs::show('ywarning')
      
      output$ywarning <- renderText({paste('Please ensure that',input$y,'is less than',input$yub,'and greater than',input$ylb)})
      
    }
      
      else if (input$z > input$zub || input$z < input$zlb){
        
        shinyjs::hide('results')
        shinyjs::hide('results2')
        shinyjs::hide('results3')
        shinyjs::hide('results4')
        shinyjs::hide('plot1')
        shinyjs::hide('plot2')
        shinyjs::hide('xwarning')
        shinyjs::hide('ywarning')
        
        shinyjs::show('zwarning')
        
        output$zwarning <- renderText({paste('Please ensure that',input$z,'is less than',input$zub,'and greater than',input$zlb)})
        
      }
      
     else { 
       shinyjs::hide('xwarning')
       shinyjs::hide('ywarning')
       shinyjs::hide('zwarning')
       
       shinyjs::show('results')
       shinyjs::show('results2')
       shinyjs::show('results3')
       shinyjs::show('results4')
       shinyjs::show('plot1')
       shinyjs::show('plot2')
    
    output$results    = renderDataTable({go()$table})
    output$results2   = renderDataTable({go()$table2})
    output$results3  = renderDataTable({go()$table3})
    output$results4  = renderDataTable({go()$table4})
    
    output$plot1 = renderPlot({pie(go()[[5]], labels = go()[[7]],col=c("red2","white","azure"))}, 
                                   height = function(){
                                     session$clientData$output_plot1_width
                                   })
    
    output$plot2 = renderPlot({pie(go()[[6]], labels = go()[[7]],col=c("red2","white","azure"))}, 
                                   height = function(){
                                     session$clientData$output_plot2_width
                                   })
    
     }
  })
  
}) 
################################################################################################
shinyApp(ui, server)

validate 是一个非常实用的选择,因为它将为您处理输出中的警告消息,避免您尝试实现的显示隐藏逻辑:

  1. 创建验证函数
MyValidation <- function(input) {
  msg <- ""
  if (input$x > input$xub || input$x < input$xlb) {
    msg <- paste(
        'Please ensure that',
        input$x,
        'is less than',
        input$xub,
        'and greater than',
        input$xlb)
  } else if (input$y > input$yub || input$y < input$ylb) {
    msg <- paste(
        'Please ensure that',
        input$y,
        'is less than',
        input$yub,
        'and greater than',
        input$ylb)
  } else if (input$z > input$zub || input$z < input$zlb) {
    msg <- paste(
          'Please ensure that',
          input$z,
          'is less than',
          input$zub,
          'and greater than',
          input$zlb)
      }
      validate(need(msg == "", msg))
}
  1. 将此函数放在所有渲染函数的开头:
  output$results    = renderDataTable({MyValidation(input); go()$table})
  output$results2   = renderDataTable({MyValidation(input);go()$table2})
  output$results3  = renderDataTable({MyValidation(input);go()$table3})
  output$results4  = renderDataTable({MyValidation(input);go()$table4})

  output$plot1 = renderPlot({MyValidation(input)
                             pie(go()[[5]], labels = go()[[7]],col=c("red2","white","azure"))},
                            height = function(){
                              session$clientData$output_plot1_width
                            })
  output$plot2 = renderPlot({MyValidation(input)
                             pie(go()[[6]], labels = go()[[7]],col=c("red2","white","azure"))},
                            height = function(){
                              session$clientData$output_plot2_width
                            })

最明显的限制是,对于每个错误的输出,您都会收到相同的错误消息,但由于它以用户友好的方式显示,因此不会太令人不安。
如果您更喜欢只有一条消息,您可以为每个选项卡创建一个渲染函数,将许多输出组合在一起,并以相同的验证函数作为起点。