如何构建R Shiny应用展示USGS流量数据的图表与表格
解决R Shiny中USGS流量数据图表与表格共用反应式数据的问题
问题核心
你的代码中,反应式函数df()每次合并站点数据时,都将流量列命名为Flow,导致最终数据框中所有站点的流量列重名。绘图时每个子图都调用~Flow,实际只会读取最后一列的流量数据;表格展示的也是一堆重复列名的混乱数据。
修复方案
1. 重构反应式数据获取逻辑
给每个站点的流量列赋予唯一的站点名称,避免列名冲突,同时让表格展示更直观。
2. 调整绘图逻辑
循环绘图时,根据站点名称匹配对应的数据列,确保每个子图展示对应站点的流量数据。
修改后的完整代码
library(shiny) library(shinythemes) library(dplyr) library(dataRetrieval) library(plotly) library(lubridate) library(DT) C_site_numbers <- c("10308200", "10309000") C_site_names <- c("Markleeville (cfs)", "Gardnerville (cfs)") ui <- fluidPage(theme = shinytheme("yeti"), titlePanel("USGS Streamflow Data"), fluidRow( column(4, wellPanel(dateInput("start_date", "Start Date:", value = Sys.Date() - 7), width = 10)), column(4, wellPanel(dateInput("end_date", "End Date:", value = Sys.Date()), width = 10)), mainPanel( tabsetPanel( tabPanel("Carson Basin", plotlyOutput("C_plot_panel", width = "100%", height = ceiling(length(C_site_numbers)) * 400)), tabPanel("Carson Tabular", dataTableOutput("Data_Tables", width = "100%")) ) ) )) server <- function(input, output) { # 重构反应式数据:给每个站点的流量列赋予唯一名称 df <- reactive({ start_date <- ymd(input$start_date) end_date <- ymd(input$end_date) # 创建时间序列框架(5分钟间隔) df <- tibble(dateTime = seq(from = start_date, to = end_date, by = "5 mins")) # 循环获取每个站点数据并合并 for (i in seq_along(C_site_numbers)) { site_num <- C_site_numbers[i] site_name <- C_site_names[i] # 根据站点名称选择参数代码(保留原逻辑) para_code <- if (site_name == 'Lahontan (acre-ft)') {'00054'} else {'00060'} # 获取USGS数据 streamflow <- readNWISuv(siteNumbers = site_num, parameterCd = para_code, startDate = start_date, endDate = end_date) attr(streamflow$dateTime, 'tzone') <- "America/Los_Angeles" # 整理数据:用站点名称作为流量列名 streamflow_df <- tibble( dateTime = as.POSIXct(streamflow$dateTime, tz = "America/Los_Angeles"), !!site_name := if (site_name == 'Lahontan (acre-ft)') {streamflow$X_00054_00000} else {streamflow$X_00060_00000} ) # 合并到主数据框 df <- df %>% left_join(streamflow_df, by = "dateTime") } df }) # 生成多站点子图面板 output$C_plot_panel <- renderPlotly({ C_plots <- list() for (i in seq_along(C_site_names)) { site_name <- C_site_names[i] plot_data <- df() # 绘制对应站点的流量图 plot <- plot_ly(data = plot_data, x = ~dateTime, y = ~.data[[site_name]], # 用站点名称匹配列 type = "scatter", mode = "lines") %>% layout(yaxis = list(title = site_name), hovermode = "x unified", plot_bgcolor = 'rgb(212,213,214)', showlegend = FALSE) C_plots[[i]] <- plot } # 组合子图 subplot(C_plots, nrows = ceiling(length(C_site_names)), titleY = TRUE, margin = 0.07) }) # 展示数据表格 output$Data_Tables <- renderDataTable({ df() %>% datatable(options = list(scrollX = TRUE, pageLength = 10), rownames = FALSE) }) } shinyApp(ui = ui, server = server)
关键修改说明
- 数据列命名:使用
!!site_name :=将流量列命名为站点名称,避免重名,表格中能直接区分各站点数据。 - 绘图列匹配:用
.data[[site_name]]动态调用对应站点的列,确保每个子图展示正确的流量数据。 - 数据结构优化:用
tibble替代data.frame,结合left_join让数据合并更简洁可靠。 - 表格美化:添加
scrollX = TRUE解决宽表格横向滚动问题,隐藏行号提升可读性。
内容的提问来源于stack exchange,提问作者Koda
相关产品推荐
相关产品推荐

