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

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)

关键修改说明

  1. 修复单项返回值:在每个单项的renderText中直接计算距离,并将结果存入reactiveValues,确保每个项的距离都被正确记录。
  2. 统一总求和逻辑:单独定义总距离的输出,根据用户选择的训练项数量(input$num)提取所有有效项的距离,求和时用na.rm=TRUE避免未选择项导致的NA干扰。
  3. 优化边界处理:增加了对未选择训练项或时长为0的情况处理,默认返回0,避免计算错误。
  4. 调整UI细节:将滑块标签改为更清晰的"Duration (minutes)",并限制numericInput的范围为1-3(因为UI中只做了3个训练项的条件面板)。

内容的提问来源于stack exchange,提问作者Sonia

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 07:00:58