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

Shiny Dashboard格式、表格显示及模拟页功能问题排查咨询

Hey Ted, let's work through each of your issues step by step—there are a few small structural mistakes causing most of your problems, and we'll fix them up with clear adjustments:


1. Fixing Cramped Sidebar Text Formatting

The main issue here is that you're nesting input controls directly inside a menuItem() call, which isn't how shinydashboard's sidebar is designed to work. menuItem is meant for navigation links and submenus, not form inputs, which causes the tight, unformatted spacing.

We'll restructure the sidebar to use sidebarMenu and menuSubItem properly, which will apply the default padding and styling automatically. We'll also remove the duplicate file input (more on that next) to clean things up:

sidebar = dashboardSidebar(
  width = 4,
  sidebarMenu(
    menuItem("Full data", tabName = "data", icon = icon("table")),  # Match tabName to body (lowercase)
    menuItem("Simulate", tabName = "simulate", icon = icon("chart-line"),
             menuSubItem("Simulation Parameters", startExpanded = TRUE,
                         radioButtons('type', "Please choose the type of analysis:", 
                                      choices = list("Gender" = 1, "US Minority Status" = 2), 
                                      selected = 1),
                         sliderInput("numSims", "Number of simulations:", 
                                     min = 1, max = 10000, step = 1000, value = 10000),
                         sliderInput("numYears", "Number of years to simulate:", 
                                     min = 1, max = 5, value = 3, step = 1),
                         numericInput('turnover', 'Total Turnover', value = 10),
                         sliderInput('promoRate', 'Set Promo rate', value = 25, min = 1, max = 100, step = 5),
                         sliderInput('growthRate', 'Set growth rate', value = 0, min = 0, max = 100, step = 1),
                         helpText('0% Growth Rate assumes a flat, constant headcount'),
                         actionButton('go', label = "Update")
             )
    )
  )
)

2. Fixing Missing Data Table After CSV Upload

You have two critical issues here:

  1. Duplicate fileInput controls: Both the sidebar and Data tab body have a fileInput with the same inputId = "file". Shiny can't tell them apart, so the reactive dataset doesn't update reliably.
  2. Case mismatch in tabNames: Your sidebar's menuItem uses tabName = "Data" (uppercase D), but the body's tabItem uses tabName = "data" (lowercase d). Shiny tab names are case-sensitive, so clicking the sidebar link wasn't even switching to the correct tab!

Fix Steps:

  • Remove the fileInput from the sidebar (we'll keep the one in the Data tab)
  • Match the sidebar's tabName to the body's (we'll use lowercase "data" for consistency)
  • Ensure the reactive dataset() only references the single, valid fileInput

Here's the corrected body section:

body <- dashboardBody(
  tabItems(
    tabItem(
      tabName = 'data',
      fluidRow(wellPanel(
        fileInput( inputId = 'file', label = "File Upload:", accept = c("csv", ".csv")))),
      wellPanel(DT::dataTableOutput('table'))
    ),
    tabItem(
      tabName = 'simulate',
      fluidRow(
        wellPanel( DT::dataTableOutput('simDataTable') )
      )
    )
  )
)

3. Ensuring simulateAvg Displays in the Simulate Tab

Right now, simulateAvg depends on simulate(), which only triggers when you click the Update button. If you haven't clicked it, simulate() is empty, so simulateAvg will return NULL and DT won't show anything. We'll add safety checks and clean up the aggregated column name for readability:

Update the server section's reactive functions:

server <- function(input, output) {
  options(shiny.maxRequestSize = 30 * 1024 ^ 2)
  
  dataset <- reactive({
    req(input$file)
    read.csv(input$file$datapath)
  })
  
  output$table = renderDataTable(dataset(), filter = 'top', options = list(scrollX = TRUE))
  
  simulate = eventReactive(input$go,{
    req(dataset(), input$numSims, input$type)  # Ensure dataset is loaded first
    dataSim(dataset(), type=input$type, numSims = input$numSims)
  })
  
  simulateAvg = reactive({
    req(simulate())  # Don't run until simulate() has data
    simulate() %>% 
      group_by(Role) %>% 
      summarise(Average_Frequency = mean(freq), .groups = "drop")  # Name the column and drop grouping
  })
  
  output$simDataTable = renderDataTable(simulateAvg())
}

Key Improvements:

  • Added req(dataset()) to simulate() so it can't run until a CSV is uploaded
  • Renamed the aggregated column to Average_Frequency (instead of the messy mean(freq) default)
  • Added .groups = "drop" to avoid leftover grouping metadata that can cause DT issues
  • Used req(simulate()) to prevent simulateAvg from running until the simulation is triggered

Full Corrected Code

Putting it all together, here's the working version:

library(needs)
needs( shiny, ggplot2, tidyverse, shinydashboard, DT )
source("~/functions.R", local = T)

# Define UI
header = dashboardHeader()

sidebar = dashboardSidebar(
  width = 4,
  sidebarMenu(
    menuItem("Full data", tabName = "data", icon = icon("table")),
    menuItem("Simulate", tabName = "simulate", icon = icon("chart-line"),
             menuSubItem("Simulation Parameters", startExpanded = TRUE,
                         radioButtons('type', "Please choose the type of analysis:", 
                                      choices = list("Gender" = 1, "US Minority Status" = 2), 
                                      selected = 1),
                         sliderInput("numSims", "Number of simulations:", 
                                     min = 1, max = 10000, step = 1000, value = 10000),
                         sliderInput("numYears", "Number of years to simulate:", 
                                     min = 1, max = 5, value = 3, step = 1),
                         numericInput('turnover', 'Total Turnover', value = 10),
                         sliderInput('promoRate', 'Set Promo rate', value = 25, min = 1, max = 100, step = 5),
                         sliderInput('growthRate', 'Set growth rate', value = 0, min = 0, max = 100, step = 1),
                         helpText('0% Growth Rate assumes a flat, constant headcount'),
                         actionButton('go', label = "Update")
             )
    )
  )
)

body <- dashboardBody(
  tabItems(
    tabItem(
      tabName = 'data',
      fluidRow(wellPanel(
        fileInput( inputId = 'file', label = "File Upload:", accept = c("csv", ".csv")))),
      wellPanel(DT::dataTableOutput('table'))
    ),
    tabItem(
      tabName = 'simulate',
      fluidRow(
        wellPanel( DT::dataTableOutput('simDataTable') )
      )
    )
  )
)

ui = shinydashboard::dashboardPage(header, sidebar, body, skin='red')

# Define Server
server <- function(input, output) {
  options(shiny.maxRequestSize = 30 * 1024 ^ 2)
  
  dataset <- reactive({
    req(input$file)
    read.csv(input$file$datapath)
  })
  
  output$table = renderDataTable(dataset(), filter = 'top', options = list(scrollX = TRUE))
  
  simulate = eventReactive(input$go,{
    req(dataset(), input$numSims, input$type)
    dataSim(dataset(), type=input$type, numSims = input$numSims)
  })
  
  simulateAvg = reactive({
    req(simulate())
    simulate() %>% 
      group_by(Role) %>% 
      summarise(Average_Frequency = mean(freq), .groups = "drop")
  })
  
  output$simDataTable = renderDataTable(simulateAvg())
}

shinyApp(ui, server)

Now when you run this:

  1. The sidebar will have proper spacing and formatting
  2. Uploading a CSV in the Data tab will show the table correctly
  3. After uploading a CSV and clicking "Update", switching to the Simulate tab will display the aggregated simulateAvg dataset as expected

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 19:37:29