【问题标题】:In R Shiny, how to dynamically expand the use of a function as user inputs expand?在 R Shiny 中,如何在用户输入扩展时动态扩展函数的使用?
【发布时间】:2021-11-28 21:41:05
【问题描述】:

以下 MWE 代码将用户输入(侧边栏面板中的 2 列矩阵输入网格中的 Y 值,id = input1)插入 X 个周期(侧边栏中的每个滑块输入,id = periods)。自定义插值函数interpol() 在服务器部分由results <- function(){interpol(...)} 触发。用户可以选择通过单击单个操作按钮来添加或修改场景,这会触发包含第二个可扩展矩阵输入 (id = input2) 的模式。插值结果显示在主面板的图中。到目前为止一切顺利,按预期工作。

按照草案,results 函数仅处理第一个矩阵输入,包括在第二个矩阵输入中对其执行的任何修改。

我的问题:如何扩展 results 函数以包含在第二个可扩展矩阵输入中添加的场景 > 1,并自动将它们包含在输出图中?我一直在努力使用 for 循环来做到这一点,但不太清楚如何做到这一点。我已经避免了 for 循环,而是依赖 lapply 和相关的。但在实践中,用户最多不会输入超过 20-30 个场景,也许 for 循环是一个无害的选择。但我对任何解决方案都持开放态度,当然不会拘泥于 for 循环!

MWE 代码:

library(shiny)
library(shinyMatrix)

interpol <- function(a,b){ # a = periods, b = matrix inputs
  c <- rep(NA,a)
  c[1] <- b[1]
  c[a] <- b[2]
  c <- approx(seq_along(c)[!is.na(c)],c[!is.na(c)],seq_along(c))$y # this interpolates
  return(c)
}

ui <- fluidPage(
    sidebarLayout(
      sidebarPanel(uiOutput("panel"),actionButton("showInput2","Modify/add interpolation")),
      mainPanel(plotOutput("plot1"))
    )
  )

server <- function(input, output, session){
 
  results <- function(){interpol(req(input$periods),req(input$input1))}
  
  output$panel <- renderUI({
    tagList(
      sliderInput('periods','Interpolate over periods (X):',min=2,max=12,value=6),
      uiOutput("input1"))
  })

  output$input1 <- renderUI({
    matrixInput("input1", 
                label = "Interpolation 1 (Y values):",
                value =  matrix(if(isTruthy(input$input2)){c(input$input2[1],input$input2[2])} 
                                  else {c(1,5)},                        # matrix values
                                1, 2,                                   # matrix row/column count
                                dimnames = list(NULL,c("Start","End"))  # matrix column header
                                ),
                rows =  list(names = FALSE),
                class = "numeric")
  })
  
  observeEvent(input$showInput2,{
    showModal(
      modalDialog(
        matrixInput("input2",
          label = "Automatically numbered scenarios (input into blank cells to add):",
          value = if(isTruthy(input$input2)){input$input2}
                  else if(isTruthy(input$input1)){input$input1},
          rows =  list(names = FALSE),
          cols =  list(extend = TRUE,
                       delta = 2,
                       delete = TRUE,
                       multiheader=TRUE),
          class = "numeric"),
    footer = modalButton("Close")
    ))
  })

  observe({
    req(input$input2)
    mm <- input$input2
    colnames(mm) <- paste(trunc(1:ncol(mm)/2)+1, " (start|end)")
    isolate(updateMatrixInput(session, "input2", mm))
  })
  
  output$plot1 <-renderPlot({
    req(results())
    plot(results(),type="l", xlab = "Periods (X)", ylab = "Interpolated Y values")
  })
  
}

shinyApp(ui, server)

【问题讨论】:

    标签: r function for-loop shiny


    【解决方案1】:

    由于用户一次只能(大概)添加一个场景,我认为for 循环不会有帮助。我处理这种情况的方法是将附加数据绑定到observeEvent 中的适当反应式。然后,这将自动触发必要输出中的更新。这是一个 MWE 来说明这项技术。

    library(shiny)
    library(tidyverse)
    
    ui <- fluidPage(
      actionButton("add", "Add scenario"),
      plotOutput("plot"),
    )
    
    server <- function(input, output, session) {
      v <- reactiveValues(results=tibble(Scenario=1, X=1:10, Y=runif(10)))
      
      observeEvent(input$add, {
        newData <- tibble(Scenario=max(v$results$Scenario) + 1, X=1:10, Y=runif(10))
        v$results <- v$results %>% bind_rows(newData)
      })
      
      output$plot <- renderPlot({
        v$results %>% ggplot() + geom_point(aes(x=X, y=Y, colour=as.factor(Scenario)))
      })
    }
    
    shinyApp(ui, server)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-12-20
      • 2016-01-14
      • 1970-01-01
      • 2013-04-18
      • 2021-12-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多