【问题标题】:In R Shiny, how to invoke download handler from radio buttons?在 R Shiny 中,如何从单选按钮调用下载处理程序?
【发布时间】:2021-11-08 13:07:03
【问题描述】:

在运行下面的 MWE 代码时,我希望能够单击出现在主面板中标有“下载”的单选按钮,并调用已经内置的模式对话框进行下载,如第一张图片所示底部。我能够让它工作的唯一方法是使用出现在主面板中单选按钮正下方的中间操作按钮(标记为“下载”),该按钮在单击“下载”单选按钮后出现,如图所示在下面的第二张图片中。如何消除此中间操作按钮并直接从单击相应的单选按钮进入下载模式对话框?

请注意,为了便于理解,下面的 MWE 被严重删减。运行时它可能会在某些地方出现“不稳定”,但这不应该影响这篇文章的重点,即使用单选按钮调用模态对话。顺便说一句,如果不失去我的一些解决方案测试能力,我认为不能进一步削减它!

MWE 代码:

library(shiny)
library(shinyMatrix)
library(shinyjs)
library(DT)

matrix1Input <- function(x){
  matrixInput(x, 
              value = matrix(c(0.2), 1, 1, dimnames = list(c("Yield"),NULL)),
              rows = list(extend = FALSE,  names = TRUE),
              cols = list(extend = FALSE, names = FALSE, editableNames = FALSE),
              class = "numeric")}

vectorBase <- function(x,y){
  a <- rep(y,x)                         
  b <- seq(1:x)                         
  c <- data.frame(x = b, y = a)         
  return(c)}

vectorPlot <- function(w,x,y,z){plot(w,main=x,xlab=y,ylab=z)}

ui <- pageWithSidebar(
  
  headerPanel("Model"),
  
  sidebarPanel(
    fluidRow(helpText(h5("Base Input Panel"))),
    uiOutput("Panels") 
  ), # close sidebar panel
    
  mainPanel(
    tabsetPanel(
      tabPanel("Balances", value=2,
         fluidRow(
           radioButtons(
             inputId = 'mainPanelBtnTab2',
             label = h5(strong(helpText("Asset outputs:"))),
             choices = 
               c('Vector plots','Vector values','Downloads'),
             selected = 'Vector plots',
             inline = TRUE
           ) # close radio buttons
         ), # close fluid row
                 
         conditionalPanel(condition = "input.mainPanelBtnTab2 == 'Vector plots'",plotOutput("graph1")),
         conditionalPanel(condition = "input.mainPanelBtnTab2 == 'Vector values'",DTOutput("table1")),
         fluidRow(actionButton("showDownload", "Download")),
                 
      ),  # close tab panel
      id = "tabselected"
  ) # close tabset panel
 ) # close main panel
) # close page with sidebar

server <- function(input,output,session)({
  periods                <- reactive(input$periods)
  base_input             <- reactive(input$base_input)
  yield_vector_input     <- reactive(input$yield_vector_input)

  vectorVariable <- function(x,y){
    if(input$showVectorBtn == 0) vectorBase(input$periods,x)
    else vectorMultiFinal(input$periods,matrixValidate(input$periods,y))}
  
  yield  <- function(){vectorVariable(input$base_input[1,1],yield_vector_input())}

  output$Panels <- renderUI({
    tagList( 
      conditionalPanel(
          condition="input.tabselected==2",
          sliderInput('periods','',min=1,max=120,value=60),
          matrix1Input("base_input"),
          useShinyjs(),
          actionButton('showVectorBtn','Show'), 
          actionButton('hideVectorBtn','Hide'),
          actionButton('resetVectorBtn','Reset'),
          hidden(uiOutput("Vectors"))
      ) # close conditional panel
    ) # close tagList
  }) # close renderUI
  
  renderUI({matrixLink("yield_vector_input",input$base_input[1,1])})
  
  output$Vectors <- renderUI({
    input$resetVectorBtn
    tagList(matrix2Input("yield_vector_input",input$periods,input$base_input[1,1]))
  }) # close render UI
  
  observeEvent(input$showVectorBtn,{shinyjs::show("Vectors")})
  observeEvent(input$hideVectorBtn,{shinyjs::hide("Vectors")})
  
  output$graph1 <-renderPlot(vectorPlot(yield(),"A","Period","Rate"))

  vectorsAll <- reactive({cbind(Period  = 1:periods(),Yld_Rate = yield()[,2])})
  
  output$table1 <- renderDT({vectorsAll()},
                            options=list(columnDefs=list(list(className='dt-center',targets=0:1)))
  ) # close renderDT

  output$download <- downloadHandler(
    filename = function() {paste("Yield","png",sep=".")},
    content = function(file){
      {png(file)
        vectorPlot(yield(),"Annual yield","Period","Rate")
        dev.off()}
    } # close content function
  ) # close download handler
  
  observeEvent(input$showDownload,
               {showModal(modalDialog(
                 selectInput("downloadItem","Selection:",c("Yield plot")),
                 downloadButton("download", "Download")
               ))} 
  ) # close observeEvent

}) # close server

shinyApp(ui, server)

【问题讨论】:

    标签: r shiny download shiny-reactivity


    【解决方案1】:

    你也可以坚持observeEvent:

      observeEvent(input$mainPanelBtnTab2,{
        req(input$mainPanelBtnTab2 == "Downloads")
        showModal(modalDialog(
          selectInput("downloadItem","Selection:",c("Yield plot")),
          downloadButton("download", "Download")
        ))}
      ) # close observeEvent
    

    或者像@RonakShah 那样使用if 而不是req

    【讨论】:

      【解决方案2】:

      您可以将下载按钮上的observeEvent 更改为observe,然后在您选择“下载”单选按钮时运行对话框。

      observe({
          if(input$mainPanelBtnTab2 == "Downloads") {
            showModal(modalDialog(
                       selectInput("downloadItem","Selection:",c("Yield plot")),
                       downloadButton("download", "Download")
            ))
        } 
        }) 
      

      【讨论】:

      • Arrggghh 谢谢你,效果很好。但是我需要解决一些新问题:observe vs. observeEvent。有什么区别?
      • 顾名思义,observeEvent 寻找要触发的“事件”,observe 不需要那个。不过,此代码也适用于 observeEvent。这些链接可能对stackoverflow.com/questions/53016404/…stackoverflow.com/questions/60413024/…有帮助
      • 那么由于后面使用了if语句,observe就不需要触发事件了吗?实际上,满足“如果”成为事件?
      • 不,if 与此无关。触发事件是指来自用户的任何输入。点击是一个事件,移动光标是这样的事件。
      • observe 默认情况下对响应式依赖项的所有更改(在传递给它的表达式中)做出反应,而 observeEvent 仅由 eventExpr 中明确列出的依赖项触发。在这种情况下,我更喜欢observeEvent,因为您确保仅在单击按钮后才触发模式。如果您稍后更改代码,向此 observe 添加响应式,您可能会对触发模式的原因感到困惑。
      猜你喜欢
      • 1970-01-01
      • 2019-04-27
      • 2019-08-21
      • 1970-01-01
      • 2017-08-09
      • 1970-01-01
      • 2023-03-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多