如何在Shiny中创建可定时更新数据的交互式Donut Chart
实现Shiny动态甜甜圈图(定时更新)
核心方案
要实现每隔1-2秒从tibble数据框取对应行更新甜甜圈图,关键是用reactiveTimer()创建定时触发器,配合响应式变量跟踪当前行索引,每次触发时切换数据并重新渲染图表。
完整可运行代码
假设你的示例数据框结构如下(每行对应一组甜甜圈切片数据):
library(tibble) df <- tibble( group = list(c("A", "B", "C")), value = list(c(30, 50, 20), c(40, 40, 20), c(20, 60, 20), c(50, 30, 20)) )
修改后的Shiny代码:
library(shiny) library(ggplot2) library(tibble) # 示例数据框 df <- tibble( group = list(c("A", "B", "C")), value = list(c(30, 50, 20), c(40, 40, 20), c(20, 60, 20), c(50, 30, 20)) ) ui <- fluidPage( plotOutput("donut_plot") ) server <- function(input, output, session) { # 创建1-2秒的随机定时触发器(避免机械重复感) auto_refresh <- reactiveTimer(sample(1000:2000, 1)) # 跟踪当前数据行的索引 current_row <- reactiveVal(1) # 响应式获取当前行数据 current_donut_data <- reactive({ auto_refresh() # 触发定时更新 row_num <- current_row() # 循环切换行:到最后一行后回到第一行 if (row_num >= nrow(df)) { current_row(1) } else { current_row(row_num + 1) } # 提取当前行数据并转为ggplot可用格式 tibble( group = df$group[[current_row()]], value = df$value[[current_row()]] ) }) # 渲染动态甜甜圈图 output$donut_plot <- renderPlot({ plot_data <- current_donut_data() # 可选:添加百分比标签 plot_data$percent <- paste0(round(plot_data$value / sum(plot_data$value) * 100), "%") ggplot(plot_data, aes(x = 2, y = value, fill = group)) + geom_col(color = "white") + coord_polar(theta = "y") + xlim(0.5, 2.5) # 挖空中间形成甜甜圈效果 geom_text(aes(label = percent), position = position_stack(vjust = 0.5)) + theme_void() + theme(legend.position = "bottom") }) } shinyApp(ui, server)
关键修改说明
- 定时触发:
reactiveTimer()生成1-2秒的随机间隔,每次触发会强制current_donut_data()重新计算。 - 行索引管理:用
reactiveVal()保存当前行号,每次更新时自动切换到下一行,循环遍历整个数据框。 - 响应式数据处理:
current_donut_data()作为响应式数据源,每次定时触发都会提取最新行的数据,确保图表用的是最新切片长度。 - 甜甜圈实现:通过
coord_polar(theta = "y")和xlim()的组合,把柱状图转为甜甜圈样式。
适配调整提示
- 如果你的
df结构不同(比如group是独立列而非列表),只需修改current_donut_data()中提取数据的逻辑即可。 - 若需要固定间隔更新,把
sample(1000:2000, 1)改成固定数值(比如1500代表1.5秒)。
内容的提问来源于stack exchange,提问作者Golem
相关产品推荐
相关产品推荐

