如何在R Shiny中实现各训练项目覆盖距离的求和功能?
实现Shiny训练计划总覆盖米数求和的方案
要实现所有选中训练项目的覆盖米数求和,你可以通过以下两步修改现有代码:
1. 在UI中添加总米数显示区域
在mainPanel的末尾添加专门的区块,用于展示所有训练项目的总覆盖米数:
br(), h3("Total Meters Covered"), textOutput("totalMeters")
2. 在Server中实现总和计算逻辑
创建反应式计算逻辑,动态遍历用户选中的所有训练项目,分别计算单个项目的覆盖米数后求和:
核心逻辑说明
- 获取用户设置的训练项目数量
input$num - 遍历1到
input$num的每个项目,获取对应的训练类型选择和时长滑块值 - 从
MyData中匹配对应训练的每分钟覆盖米数,计算单个项目的总米数 - 对所有有效项目的米数求和,同时处理未选择训练或时长为0的情况,避免NA干扰计算
修改后的完整代码
library(shiny) library(dplyr) MyData <- structure(list(Drill = c("GP Warm Up", "5v2 Rondo", "11v11", "10v6 Drop Behind Ball"), PlayerLoadPerMinute = c(7.72949670665213, 6.49382926701571, 9.67483408668731, 5.86770863636364), MetersPerMinute = c(69.9524820610687, 45.823744973822, 95.9405092879257, 58.185375), class = "data.frame", row.names = c(NA, -4L))) # Define UI ---- ui <- fluidPage( titlePanel("Practice Planner"), sidebarLayout( sidebarPanel( numericInput("num", h3("Number of Drills"), value = 1, min = 1, max = 10) ), mainPanel( # 第一个训练项目 selectInput("DrillName1", label = "Choose a Drill:", choices = unique(MyData$Drill), selected = NULL, multiple = FALSE), sliderInput("slider1", label = h3("Duration (minutes)"), min = 0, max = 60, value = 0), textOutput("MpM1"), br(), # 第二个训练项目(条件显示) conditionalPanel( condition = "input.num > 1", selectInput("DrillName2", label = "Choose a Drill:", choices = unique(MyData$Drill), selected = NULL, multiple = FALSE), sliderInput("slider2", label = h3("Duration (minutes)"), min = 0, max = 60, value = 0), textOutput("MpM2")), br(), # 第三个训练项目(条件显示) conditionalPanel( condition = "input.num > 2", selectInput("DrillName3", label = "Choose a Drill:", choices = unique(MyData$Drill), selected = NULL, multiple = FALSE), sliderInput("slider3", label = h3("Duration (minutes)"), min = 0, max = 60, value = 0), textOutput("MpM3")), # 总米数显示区域 br(), h3("Total Meters Covered"), textOutput("totalMeters") ) ) ) # Define server logic ---- server <- function(input, output, session) { # 计算单个训练项目的覆盖米数 lapply(1:10, function(x) { output[[paste0("MpM", x)]] <- renderText({ chosendrill <- input[[paste0("DrillName", x)]] duration <- input[[paste0("slider", x)]] if(is.null(chosendrill) || duration == 0) { return("Meters covered: 0") } meters <- MyData$MetersPerMinute[MyData$Drill == chosendrill] * duration paste0("Meters covered: ", round(meters, 2)) }) }) # 计算总覆盖米数 output$totalMeters <- renderText({ num_drills <- input$num total <- 0 for(i in 1:num_drills) { drill_name <- input[[paste0("DrillName", i)]] duration <- input[[paste0("slider", i)]] if(!is.null(drill_name) && duration > 0) { meters_per_min <- MyData$MetersPerMinute[MyData$Drill == drill_name] total <- total + (meters_per_min * duration) } } paste0("Total: ", round(total, 2)) }) } # Create Shiny app ---- shinyApp(ui = ui, server = server)
额外优化说明
- 给
numericInput添加了min=1, max=10的限制,避免超出预设的训练项目数量范围 - 修改滑块标签为"Duration (minutes)",语义更清晰
- 单个项目计算中增加空值/零时长处理,避免显示无效的NA结果
- 所有米数结果保留两位小数,显示更美观规范
内容的提问来源于stack exchange,提问作者Sonia
相关产品推荐
相关产品推荐

