Shiny应用中Plotly点击事件双向筛选图表失效问题
问题原因与修复方案
核心问题
反向筛选失效的本质是第二个活动频率图未配置customdata,导致点击时无法捕获对应的活动名称,无法传递给第一个图表完成筛选;同时重置按钮未绑定功能,无法恢复初始状态。
修复后的完整代码
library(shiny) library(shinydashboard) library(plotly) library(dplyr) library(ggplot2) library(bupaR) library(edeaR) pr59<-structure(list(case_id = c("WC4120721", "WC4120667", "WC4120689", "WC4121068", "WC4120667", "WC4120666", "WC4120667", "WC4121068", "WC4120667", "WC4121068"), lifecycle = c(110, 110, 110, 110, 120, 110, 130, 120, 10, 130), action = c("WC4120721-CN354877", "WC4120667-CN354878", "WC4120689-CN356752", "WC4121068-CN301950", "WC4120667-CSW310", "WC4120666-CN354878", "WC4120667-CSW308", "WC4121068-CSW303", "WC4120667-CSW309", "WC4121068-CSW308"), activity = c("Forged Wire, Medium (Sport)", "Forged Wire, Medium (Sport)", "Forged Wire, Medium (Sport)", "Forged Wire, Medium (Sport)", "BBH-1&2", "Forged Wire, Medium (Sport)", "TCE Cleaning", "SOLO Oil", "Tempering", "TCE Cleaning"), resource = c("3419", "3216", "3409", "3201", "C3-100", "3216", "C3-080", "C3-030", "C3-090", "C3-080"), timestamp = structure(c(1606964400, 1607115480, 1607435760, 1607568120, 1607630220, 1607670780, 1607685420, 1607710800, 1607729520, 1607744100), tzone = "", class = c("POSIXct", "POSIXt")), .order = 1:10), row.names = c(NA, -10L), class = c("eventlog", "log", "tbl_df", "tbl", "data.frame"), spec = structure(list( cols = list(case_id = structure(list(), class = c("collector_character", "collector")), lifecycle = structure(list(), class = c("collector_double", "collector")), action = structure(list(), class = c("collector_character", "collector")), activity = structure(list(), class = c("collector_character", "collector")), resource = structure(list(), class = c("collector_character", "collector")), timestamp = structure(list(), class = c("collector_character", "collector"))), default = structure(list(), class = c("collector_guess", "collector")), delim = ";"), class = "col_spec"), case_id = "case_id", activity_id = "activity", activity_instance_id = "action", lifecycle_id = "lifecycle", resource_id = "resource", timestamp = "timestamp") ui <- tags$body( dashboardPage( header = dashboardHeader(), sidebar = dashboardSidebar( actionButton("res","RESET") ), body = dashboardBody( plotlyOutput("plot1"), plotlyOutput("plot2") ) ) ) server <- function(input, output, session) { # 用反应式值统一管理筛选数据,支持重置与双向联动 filtered_data <- reactiveVal(pr59) # 重置按钮逻辑:恢复原始数据并清除点击缓存 observeEvent(input$res, { filtered_data(pr59) event_data("plotly_click", source = "myPlotSource1", session = session, priority = "event") event_data("plotly_click", source = "myPlotSource2", session = session, priority = "event") }) # 处理第一个图表的点击事件,按日期筛选 observeEvent(event_data("plotly_click", source = "myPlotSource1"), { click_data <- event_data("plotly_click", source = "myPlotSource1") if (!is.null(click_data)) { selected_date <- as.Date(click_data$customdata) filtered_data(subset(pr59, as.Date(timestamp) == selected_date)) } }) # 处理第二个图表的点击事件,按活动筛选 observeEvent(event_data("plotly_click", source = "myPlotSource2"), { click_data <- event_data("plotly_click", source = "myPlotSource2") if (!is.null(click_data)) { selected_activity <- click_data$customdata filtered_data(subset(pr59, activity == selected_activity)) } }) # 渲染第一个图表(每日案例数) output$plot1<-renderPlotly({ dat <- filtered_data() %>% group_by(date = as.Date(timestamp)) %>% bupaR::n_cases() p <- ggplot(data = dat, aes(x = date, y = n_cases, customdata = date)) + geom_area(fill = "#69b3a2", alpha = 0.4) + geom_line(color = "#69b3a2", size = 0.5) + geom_point(size = 1, color = "#69b3a2") + scale_color_grey() + theme_classic() + labs(title = "每日案例数", x = "时间", y = "案例数") ggplotly(p, source = "myPlotSource1") }) # 渲染第二个图表(活动频率):手动构建ggplot以添加customdata output$plot2<-renderPlotly({ actfr <- filtered_data() %>% activity_frequency("activity") %>% arrange(desc(absolute_frequency)) plt <- ggplot(actfr, aes(x = absolute_frequency, y = reorder(activity, absolute_frequency), customdata = activity)) + geom_bar(stat = "identity", fill = "#404080") + theme_classic() + theme(axis.text.y = element_text(size = 8)) + labs(title = "活动频率", x = "频率", y = "活动") ggplotly(plt, source = "myPlotSource2") }) } shinyApp(ui, server)
关键修改说明
- 统一数据源管理:新增
filtered_data反应式值,让两个图表基于同一数据源渲染,避免各自处理数据的逻辑冲突。 - 配置第二个图表的customdata:放弃默认的
activity_frequency %>% plot,手动构建ggplot并添加customdata = activity,确保点击时能捕获活动名称。 - 绑定重置功能:点击重置按钮时恢复原始数据集,同时清除plotly的点击事件缓存,避免残留数据干扰后续筛选。
- 分离点击事件处理:用
observeEvent分别处理两个图表的点击动作,更新统一数据源,实现双向联动筛选。
内容的提问来源于stack exchange,提问作者firmo23
相关产品推荐
相关产品推荐

