Shiny训练计划应用:总距离计算始终为0的问题求助
问题排查与修复
你的总距离始终显示为0,核心有两个问题:
1. 单项距离计算的Reactive未返回值
在原代码的MetersPerMin reactive函数中,你计算了MpM_text但没有将其作为返回值。Shiny的reactive函数需要明确返回计算结果,否则默认返回NULL,对NULL求和自然得到0。
2. 总距离求和逻辑错误
你在lapply循环中每次都重新定义MpM_Sum和output$MpM_Total,这会导致最终只有最后一次循环的单项距离被纳入求和,完全忽略了前面的项。正确的做法是收集所有有效项的距离后再统一求和。
修正后的完整代码
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=3), textOutput("MpM_Total") ), 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")) ) ) ) # Define server logic ---- server <- function(input, output, session) { # 存储每个单项的距离计算结果 drill_distances <- reactiveValues() # 循环生成每个单项的计算逻辑 lapply(1:3, function(x) { output[[paste0("MpM", x)]] <- renderText({ chosendrill <- input[[paste0("DrillName",x)]] duration <- input[[paste0("slider",x)]] if(is.null(chosendrill) || duration == 0){ dist <- 0 } else { mpd <- MyData$MetersPerMinute[MyData$Drill == chosendrill] dist <- mpd * duration } # 把结果存入reactiveValues,方便后续求和 drill_distances[[paste0("dist",x)]] <- dist paste0("Meters covered: ", round(dist, 2)) }) }) # 计算总距离 output$MpM_Total <- renderText({ # 根据用户选择的训练项数量,提取对应的距离值 total <- sum(unlist(drill_distances[paste0("dist",1:input$num)]), na.rm = TRUE) paste("Total Meters Covered: ", round(total, 2)) }) } # Create Shiny app ---- shinyApp(ui = ui, server = server)
关键修改说明
- 修复单项返回值:在每个单项的
renderText中直接计算距离,并将结果存入reactiveValues,确保每个项的距离都被正确记录。 - 统一总求和逻辑:单独定义总距离的输出,根据用户选择的训练项数量(
input$num)提取所有有效项的距离,求和时用na.rm=TRUE避免未选择项导致的NA干扰。 - 优化边界处理:增加了对未选择训练项或时长为0的情况处理,默认返回0,避免计算错误。
- 调整UI细节:将滑块标签改为更清晰的"Duration (minutes)",并限制
numericInput的范围为1-3(因为UI中只做了3个训练项的条件面板)。
内容的提问来源于stack exchange,提问作者Sonia
相关产品推荐
相关产品推荐

