R Shiny仪表板图表不显示问题排查求助
问题排查与修复方案
核心问题与解决步骤
重复的Input ID导致组件冲突
Shiny要求所有输入组件的inputId必须唯一,你的代码中多个radioButtons和downloadButton使用了相同的ID(filetype、dwd),这会导致组件交互失效,甚至阻断图表渲染。需要给每个组件分配唯一ID,比如filetype_line、dwd_line等。时间序列分解的错误处理
你将包含两列的数据框整体转为时间序列,decompose处理多列时间序列会生成多列的趋势/季节/残差项,后续无法在Shiny中正常渲染。应仅对demand列创建时间序列:tsdata <- ts(BODFrame$demand, frequency = 2, start = min(BODFrame$Time))条件判断的类型不匹配
selectInput的选项值是字符型("1"/"2"/"3"),但服务器端用数值型判断(input$Models == 1),导致条件永远不成立,分解图无法渲染。建议直接用语义化的字符值匹配,更直观:# UI中修改selectInput选项 selectInput(inputId = "Models", label = "Select Model:", choices = c("Trend"="trend", "Seasonality"="seasonal", "Noise"="random"), selected = "trend") # 服务器端用switch简化判断 output$plot2 <- renderPlot({ switch(input$Models, "trend" = plot(trend, main = "Decomposed Trend - BOD"), "seasonal" = plot(seasonal, main = "Decomposed Seasonality - BOD"), "random" = plot(random, main = "Decomposed Noise - BOD") ) })直方图的ggplot语法错误
直方图中y = ..Demand..是错误用法,..xxx..仅用于ggplot内置统计量(如..count..),这里无需手动指定y轴,直接映射x即可:output$hist <- renderPlot({ ggplot(data = BODFrame) + geom_histogram(bins = 6, breaks = c(1:7), mapping = aes(x = Time), col = "cadetblue4", fill = "cadetblue4", alpha = 0.5) + theme_ipsum() + ggtitle("BOD (mg/1) vs Time Histogram") })
修复后的完整代码
library(shiny) library(shinythemes) library(tidyverse) library(ggplot2) library(DT) library(forecast) library(fpp) library(tsbox) library(hrbrthemes) # 数据预处理</think_never_used_51bce0c785ca2f68081bfa7d91973934> data(BOD) BODFrame <- data.frame(BOD) # 仅对demand列创建时间序列 tsdata <- ts(BODFrame$demand, frequency = 2, start = min(BODFrame$Time)) ddata <- decompose(tsdata, "multiplicative") seasonal <- ddata$seasonal trend <- ddata$trend random <- ddata$random # 修正预测对象:基于demand列构建ARIMA模型 forecastframe <- auto.arima(BODFrame$demand) myforecastframe <- forecast(forecastframe, level=c(60), h = 12) # UI部分 ui <- fluidPage( titlePanel("Effect of Time on BOD (mg/1) Levels"), navbarPage("Select Tab", tabPanel("Explore The Data", mainPanel( tabsetPanel( tabPanel("Line Graph", plotOutput("line"), br(), radioButtons("filetype_line", "Select file type", c("png", "jpeg")), downloadButton("dwd_line", "Download Graph")), tabPanel("Histogram", plotOutput("hist"), br(), radioButtons("filetype_hist", "Select file type", c("png", "jpeg")), downloadButton("dwd_hist", "Download Graph")) ) ) ), tabPanel("Statistical Decomposition of the Data", sidebarLayout( sidebarPanel(width = 3, selectInput(inputId = "Models", label = "Select Model:", choices = c("Trend"="trend", "Seasonality"="seasonal", "Noise"="random"), selected = "trend"), textOutput("text1") ), mainPanel( plotOutput("plot2"), br(), radioButtons("filetype_decomp", "Select file type", c("png", "jpeg")), downloadButton("dwd_decomp", "Download Graph") ) ) ), tabPanel("Forecasting BOD", mainPanel( plotOutput("Forecast"), br(), radioButtons("filetype_forecast", "Select file type", c("png", "jpeg")), downloadButton("dwd_forecast", "Download Graph") ) ) ) ) # 服务器逻辑 server <- function(input, output){ output$line <- renderPlot({ ggplot(BODFrame, aes(x = Time, y = demand)) + geom_line(col = "cadetblue4", size = 2) + theme_ipsum() + ggtitle("BOD (mg/1) vs Time") + geom_point(col = "red", size = 3) }) output$hist <- renderPlot({ ggplot(data = BODFrame) + geom_histogram(bins = 6, breaks = c(1:7), mapping = aes(x = Time), col = "cadetblue4", fill = "cadetblue4", alpha = 0.5) + theme_ipsum() + ggtitle("BOD (mg/1) vs Time Histogram") }) output$plot2 <- renderPlot({ switch(input$Models, "trend" = plot(trend, main = "Decomposed Trend - BOD"), "seasonal" = plot(seasonal, main = "Decomposed Seasonality - BOD"), "random" = plot(random, main = "Decomposed Noise - BOD") ) }) output$Forecast <- renderPlot({ plot(myforecastframe, main = "Forecasted Level of BOD (mg/1)") }) output$text1 <- renderText({ switch(input$Models, "trend" = "The increasing or decreasing value of BOD in the series", "seasonal" = "The repeating short term cycle of the BOD series.", "random" = "The random variation in the BOD series." ) }) # 折线图下载示例(其余下载逻辑可参照扩展) output$dwd_line <- downloadHandler( filename = function() { paste("line_plot.", input$filetype_line, sep = "") }, content = function(file) { ggsave(file, plot = ggplot(BODFrame, aes(x = Time, y = demand)) + geom_line(col = "cadetblue4", size = 2) + theme_ipsum() + ggtitle("BOD (mg/1) vs Time") + geom_point(col = "red", size = 3), device = input$filetype_line) } ) } shinyApp(ui = ui, server = server)
内容的提问来源于stack exchange,提问作者NoobDataAnalyst
相关产品推荐
相关产品推荐

