You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

R Shiny中如何随用户输入扩展动态调用函数,实现多插值场景的结果可视化

解决多场景插值结果的展示问题

我来帮你修改代码,让它能处理input2里的所有插值场景,并把所有结果都画在同一个图表里。核心思路是遍历input2的每一组两列数据(每一组对应一个场景的起始和结束Y值),对每个场景生成插值结果,然后在绘图时依次添加所有曲线。

关键修改点说明:

  1. 重构results为响应式表达式:把原来的普通函数改成reactive,这样能自动响应输入变化,同时遍历所有场景生成插值结果。
  2. 批量处理多场景:将input2的矩阵按每两列拆分,每个子矩阵对应一个场景,用lapply批量调用插值函数。
  3. 多曲线绘图与图例:在绘图时先初始化画布,再用lines添加所有场景的曲线,最后添加图例区分不同场景。

修改后的完整代码:

library(shiny)
library(shinyMatrix)

interpol <- function(a,b){ # a = periods, b = matrix inputs (1 row, 2 columns)
  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 <- reactive({
    req(input$periods)
    # 优先使用input2的多场景数据,无则使用input1的默认场景
    target_mat <- if (isTruthy(input$input2)) input$input2 else input$input1
    # 计算场景数量:每2列对应一个场景
    num_scenarios <- ncol(target_mat) %/% 2
    
    # 遍历每个场景生成插值结果
    lapply(1:num_scenarios, function(scenario_idx) {
      # 提取当前场景的起止列
      col_range <- (2*scenario_idx - 1):(2*scenario_idx)
      scenario_data <- target_mat[, col_range, drop = FALSE]
      interpol(input$periods, scenario_data)
    })
  })
  
  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)}, 
                               1, 2, 
                               dimnames = list(NULL,c("Start","End"))
                ), 
                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) <- sapply(1:(ncol(mm)/2), function(i) {
      paste("Scenario", i, "(start|end)")
    })
    isolate(updateMatrixInput(session, "input2", mm))
  })
  
  output$plot1 <-renderPlot({
    req(results())
    interpol_list <- results()
    num_scenarios <- length(interpol_list)
    
    # 设置绘图样式:不同颜色区分场景
    plot_colors <- rainbow(num_scenarios)
    plot_ltys <- 1:num_scenarios
    
    # 初始化绘图(用第一个场景的数据)
    plot(interpol_list[[1]], 
         type = "l", 
         xlab = "Periods (X)", 
         ylab = "Interpolated Y values",
         col = plot_colors[1],
         lty = plot_ltys[1],
         ylim = range(unlist(interpol_list)) # 统一Y轴范围,避免曲线被截断
    )
    
    # 添加其余场景的曲线
    if(num_scenarios > 1) {
      for(i in 2:num_scenarios) {
        lines(interpol_list[[i]], 
              col = plot_colors[i],
              lty = plot_ltys[i])
      }
    }
    
    # 添加图例,方便区分场景
    legend("topleft",
           legend = paste("Scenario", 1:num_scenarios),
           col = plot_colors,
           lty = plot_ltys,
           cex = 0.8,
           bty = "n")
  })
}

shinyApp(ui, server)

功能验证:

  • 点击"Modify/add interpolation"按钮,在模态框里点击"Add column"(每次添加2列),可以新增多个场景。
  • 每个场景的起止Y值可以独立修改,修改后图表会自动更新所有曲线。
  • 侧边栏的input1始终显示第一个场景的数值,方便快速修改默认场景。

内容的提问来源于stack exchange,提问作者Curious Jorge - user9788072

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 17:38:11