【问题标题】:In R Shiny, how to move user inputs from sidebar panel into a modal dialogue box?在 R Shiny 中,如何将用户输入从侧边栏面板移动到模式对话框中?
【发布时间】:2021-10-23 21:38:39
【问题描述】:

在下面的 MWE 代码中,用户将值输入到“负债模块”选项卡侧边栏面板中的矩阵中。工作正常。但我想将矩阵输入网格 侧边栏面板和 移动到 模态对话框。那要怎么做呢?

该矩阵输入网格将不再出现在侧边栏面板中。相反,它只会出现在模态对话框中。

主面板中的模型输出(链接到标有“A”的第一个矩阵行)将继续链接到重新定位的矩阵输入网格。

您将在 MWE 底部看到我尝试创建模态对话框的骨架,observeEvent(input$showLiabilityGrid...

在最底部,我还附上了一张图片,解释了我正在尝试做的事情。

MWE 代码:

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

button2 <- function(x,y){actionButton(x,y,style="width:90px;margin-bottom:5px;font-size:80%")}

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

pct <- function(x){paste(format(round(x*100,digits=1),nsmall=1),"%",sep="")} # convert to percentage

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,type="b",col="blue",pch=19,cex=1.25)}

ui <- 
  pageWithSidebar(
    headerPanel("Model..."),
    sidebarPanel(
      fluidRow(helpText(h5(strong("Base Input Panel")),align="center",
                        style="margin-top:-15px;margin-bottom:5px")),
    # Panels rendered with uiOuput & renderUI in server to stop flashing at invocation
      uiOutput("Panels") 
    ), # close sidebar panel
    mainPanel(
      tabsetPanel(
        tabPanel("By balances", value=2),
        tabPanel("By accounts", value=3), 
        tabPanel("Liabilities module", value=4,
                 fluidRow(h5(strong(helpText("Select model output to view:")))),
                 fluidRow(
                   button2('showVectorValueBtn','Vector values'),
                   button2('showVectorPlotBtn','Vector plots'),
                 ), # close fluid row
                 
                 div(style = "margin-top: 5px"),
                 
                 # Shows outputs on each page of main panel   
                 uiOutput('showResults')), 
        id = "tabselected"
      ) # close tabset panel
    ) # close main panel
  ) # close page with sidebar

server <- function(input,output,session)({
  
  base_input  <- reactive(input$base_input)
  showResults <- reactiveValues()

  yield   <- function(){vectorBase(60,input$base_input[1,1])} # Must remain in server section
  
  # --- Conditional panels rendered here rather than in UI to eliminate invocation flashing ------------>
  output$Panels <- renderUI({
    tagList( 
      conditionalPanel(
        condition="input.tabselected==4",
        
        actionButton('showLiabilityGrid','Input Liabilities',style='width:100%;background-color:LightGrey'),
        setShadow(id='showLiabilityGrid'),
        div(style = "margin-bottom: 10px"),
        
        matrix1Input("base_input"),
        div(style = "margin-top: 0px"), 
        useShinyjs(),
      ), # close conditional panel
      conditionalPanel(condition="input.tabselected==3"),
      conditionalPanel(condition="input.tabselected==4")
    ) # close tagList
  }) # close renderUI
  
  # --- Below produces vector values as default view when first invoking App --------------------------->
  vectorsAll <- reactive({cbind(Period = 1:60,Yld_Rate = pct(yield()[,2]))}) # Produces vector values
  output$table1 <- renderTable({vectorsAll()})
  
  # --- Below produces vector values after clicking "Vector Values" button; see above for pre-click ---->
  observeEvent(input$showVectorValueBtn,
               {showResults$showme <-
                 tagList(tableOutput("table1"))
               },ignoreNULL = FALSE)

  # --- Below produces vector plots -------------------------------------------------------------------->   
  output$graph1 <-renderPlot(vectorPlot(yield(),"A Variable","Period","Rate"))
  observeEvent(input$showVectorPlotBtn,{showResults$showme <- plotOutput("graph1")})
  
  # --- Below sends both vector plots and vector values to UI section above ---------------------------->
  output$showResults <- renderUI({showResults$showme})

  # --- Below for modal dialog inputs ------------------------------------------------------------------>
  
  observeEvent(input$showLiabilityGrid,
               {showModal(modalDialog(
                 # ???
               ) # close modalDialog
               ) # close showModal
               } # close showModal function
  ) # close observeEvent
  
}) # close server

shinyApp(ui, server)

【问题讨论】:

  • 我认为您可能只需要在 UI 中进行移动,您的服务器可能不需要更改。只是一个想法......

标签: r shiny modal-dialog


【解决方案1】:

我不知道您希望输入模块处于什么位置。但是,这确实可以移动它并且可以正常工作。

我必须添加一个库,除了我已经注释掉了我会从您的原始代码中删除的代码。

因为侧边栏现在是空白的,所以它是 navbarPage()

您将在您的tabPanel('Liabilities module'... 中看到一个新的fluidrow()

library(shiny)
library(shinyMatrix)
library(shinyjs)
library(shinyWidgets)  # added for the function setShadow

button2 <- function(x,y){actionButton(x,y,style="width:90px;margin-bottom:5px;font-size:80%")}

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

pct <- function(x){paste(format(round(x*100,digits=1),nsmall=1),"%",sep="")} # convert to percentage

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,type="b",col="blue",pch=19,cex=1.25)}

ui <- 
 # pageWithSidebar(
  navbarPage(
    headerPanel("Model..."),
    # sidebarPanel(
    #   fluidRow(helpText(h5(strong("Base Input Panel")),align="center",
    #                     style="margin-top:-15px;margin-bottom:5px")),
    #   # Panels rendered with uiOuput & renderUI in server to stop flashing at invocation
    #   uiOutput("Panels") 
    # ), # close sidebar panel
    mainPanel(
      tabsetPanel(
        tabPanel("By balances", value=2),
        tabPanel("By accounts", value=3), 
        tabPanel("Liabilities module", value = 4,
  # added - taken from sidebar coding
                 fluidRow(helpText(h5(strong("Base Input Panel")),align="center",
                                   style="margin-top:-15px;margin-bottom:5px")),
                 # Panels rendered with uiOuput & renderUI in server to stop flashing at invocation
                 uiOutput("Panels"),
  # end add
                 fluidRow(h5(strong(helpText("Select model output to view:")))),
                 fluidRow(
                   button2('showVectorValueBtn','Vector values'),
                   button2('showVectorPlotBtn','Vector plots'),
                 ), # close fluid row

                 div(style = "margin-top: 5px"),

                 # Shows outputs on each page of main panel
                 uiOutput('showResults')),
        id = "tabselected"
      ) # close tabset panel
    ) # close main panel
 ) # close page with sidebar

server <- function(input,output,session)({
  
  base_input  <- reactive(input$base_input)
  showResults <- reactiveValues()
  
  yield   <- function(){vectorBase(60,input$base_input[1,1])} # Must remain in server section
  
  # --- Conditional panels rendered here rather than in UI to eliminate invocation flashing ------------>
  output$Panels <- renderUI({
    tagList( 
      conditionalPanel(
        condition="input.tabselected==4",
        
        actionButton('showLiabilityGrid','Input Liabilities',
                     style='width:100%;background-color:LightGrey'),
        setShadow(id='showLiabilityGrid'),
        div(style = "margin-bottom: 10px"),
        
        matrix1Input("base_input"),
        div(style = "margin-top: 0px"), 
        useShinyjs(),
      ), # close conditional panel
      conditionalPanel(condition="input.tabselected==3"),
      conditionalPanel(condition="input.tabselected==4")
    ) # close tagList
  }) # close renderUI
  
  # --- Below produces vector values as default view when first invoking App --------------------------->
  vectorsAll <- reactive({cbind(Period = 1:60,Yld_Rate = pct(yield()[,2]))}) # Produces vector values
  output$table1 <- renderTable({vectorsAll()})
  
  # --- Below produces vector values after clicking "Vector Values" button; see above for pre-click ---->
  observeEvent(input$showVectorValueBtn,
               {showResults$showme <-
                 tagList(tableOutput("table1"))
               },ignoreNULL = FALSE)
  
  # --- Below produces vector plots -------------------------------------------------------------------->   
  output$graph1 <-renderPlot(vectorPlot(yield(),"A Variable","Period","Rate"))
  observeEvent(input$showVectorPlotBtn,{showResults$showme <- plotOutput("graph1")})
  
  # --- Below sends both vector plots and vector values to UI section above ---------------------------->
  output$showResults <- renderUI({showResults$showme})
  
  # --- Below for modal dialog inputs ------------------------------------------------------------------>
  
  observeEvent(input$showLiabilityGrid,
               {showModal(modalDialog(
                 # ???
               ) # close modalDialog
               ) # close showModal
               } # close showModal function
  ) # close observeEvent
  
}) # close server

shinyApp(ui, server)

它是这样的:

【讨论】:

    【解决方案2】:

    在 YBS 在另一篇 Stack Overflow 帖子中的进一步挖掘和帮助下,下面完整的 MWE 现在可以正常工作并解决原始查询。用户输入模式对话框,结果显示在主面板中。以这种方式使用模态对话框,用户界面更加简洁。

    library(shiny)
    library(shinyMatrix)
    library(shinyjs)
    
    button2 <- function(x,y){actionButton(x,y,style="width:90px;margin-bottom:5px;font-size:80%")}
    
    matrix1Input <- function(x){
      matrixInput(x, 
                  value = matrix(c(0.2), 4, 1,dimnames=list(c("A","B","C","D"),NULL)),
                  rows = list(extend=FALSE,names=TRUE),
                  cols = list(extend=FALSE,names=FALSE,editableNames=FALSE),
                  class = "numeric")}
    
    pct <- function(x){paste(format(round(x*100,digits=1),nsmall=1),"%",sep="")} # convert to percentage
    
    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,type="b",col="blue",pch=19,cex=1.25)}
    
    ui <- 
      pageWithSidebar(
        headerPanel("Model..."),
        sidebarPanel(
          fluidRow(helpText(h5(strong("Base Input Panel")),align="center",
                            style="margin-top:-15px;margin-bottom:5px")),
          # Panels rendered with uiOuput & renderUI in server to stop flashing at invocation
          uiOutput("Panels") 
        ), # close sidebar panel
        mainPanel(
          tabsetPanel(
            tabPanel("By balances", value=2),
            tabPanel("By accounts", value=3), 
            tabPanel("Liabilities module", value=4,
                     fluidRow(h5(strong(helpText("Select model output to view:")))),
                     fluidRow(
                       button2('showVectorValueBtn','Vector values'),
                       button2('showVectorPlotBtn','Vector plots'),
                     ), # close fluid row
                     
                     div(style = "margin-top: 5px"),
                     
                     # Shows outputs on each page of main panel   
                     uiOutput('showResults')), 
            id = "tabselected"
          ) # close tabset panel
        ) # close main panel
      ) # close page with sidebar
    
    server <- function(input,output,session)({
      
      base_input  <- reactive(input$base_input)
      showResults <- reactiveValues()
      
      yield   <- function(){vectorBase(60,input$base_input[1,1])} # Must remain in server section
      
      # --- Conditional panels rendered here rather than in UI to eliminate invocation flashing ------------>
      output$Panels <- renderUI({
        tagList( 
          conditionalPanel(
            condition="input.tabselected==4",
            actionButton('showLiabilityGrid','Input Liabilities',style='width:100%;background-color:LightGrey'),
            setShadow(id='showLiabilityGrid'),
            div(style = "margin-bottom: 10px"),
          ), # close conditional panel
          conditionalPanel(condition="input.tabselected==3"),
          conditionalPanel(condition="input.tabselected==4")
        ) # close tagList
      }) # close renderUI
      
      # --- Below produces vector values ---------------------------------------------------------------------->
      
      # Below now defines the vectorsAll object before user clicks on actionButton "Input Liabilities".
      vectorsAll <- reactive({
        if (is.null(input$showLiabilityGrid)){df <- NULL}
        else {
          if(input$showLiabilityGrid < 1){df <- cbind(Period = 1:60,Yld_Rate = pct(0.2))}  # define what you want to display by default
          else {
            req(input$base_input)
            df <- cbind(Period = 1:60,Yld_Rate = pct(yield()[,2]))
          } # close 2nd else
        } # close 1st else
        df
      }) # close reactive
      
      output$table1 <- renderTable({vectorsAll()})
      
      # --- Below produces vector values after clicking "Vector Values" button; see above for pre-click ---->
      observeEvent(input$showVectorValueBtn,
                   {showResults$showme <-
                     tagList(tableOutput("table1"))
                   },ignoreNULL = FALSE)
      
      # --- Below produces vector plots -------------------------------------------------------------------->   
      output$graph1 <-renderPlot(vectorPlot(yield(),"A Variable","Period","Rate"))
      observeEvent(input$showVectorPlotBtn,{showResults$showme <- plotOutput("graph1")})
      
      # --- Below sends both vector plots and vector values to UI section above ---------------------------->
      output$showResults <- renderUI({showResults$showme})
      
      # --- Below for modal dialog inputs ------------------------------------------------------------------>
      observeEvent(input$showLiabilityGrid,
                   {showModal(modalDialog(
                     matrix1Input("base_input"),
                     div(style = "margin-top: 0px"),
                     useShinyjs(),
                   ) # close modalDialog
                   ) # close showModal
                   } # close showModal function
      ) # close observeEvent
      
    }) # close server
    
    shinyApp(ui, server)
    

    【讨论】:

      猜你喜欢
      • 2021-01-03
      • 2021-10-30
      • 1970-01-01
      • 2013-11-03
      • 2018-04-19
      • 2021-10-01
      • 1970-01-01
      • 2021-12-03
      相关资源
      最近更新 更多