R Shiny中子图无对应数据时用主图数据填充并显示‘Other’类别
解决方案
核心思路是在子图的数据源中,为Jewel门店补充指定的"Other"分类数据,确保筛选Vegetable/Fruit时能显示数值800的柱状条。只需修改server部分的store_reactive_2反应式对象即可实现需求:
store_reactive_2 <- reactive({ # 先获取原始筛选数据 filtered_data <- store_data %>% filter(Grocery_Store %in% input$store) %>% filter(Food_Filter %in% input$food_subcategory) # 检查是否需要添加Jewel的Other数据 if ("Jewel" %in% input$store && input$food_subcategory %in% c("Vegetable", "Fruit")) { # 构造Jewel的补充行 jewel_other <- tibble( Grocery_Store = "Jewel", Sales = 800, Food_Main = "Other", Food_Filter = input$food_subcategory ) # 合并原始数据和补充数据 filtered_data <- bind_rows(filtered_data, jewel_other) } filtered_data })
完整修改后的代码
library(tidyverse) library(plotly) library(shiny) library(shinydashboard) library(shinyWidgets) store_data <- tibble( Whole_Foods = c(1000, 500, 500, 1000, 500, 500), Kroger = c(700, 300, 400, 700, 300, 400), Jewel = c(800, 0, 0, 800, 0, 0), Food_Main = c("Vegetable", "Lettuce", "Potato", "Fruit", "Lemon", "Watermelon"), Food_Filter = c("None", "Vegetable", "Vegetable", "None", "Fruit", "Fruit") ) store_data <- store_data %>% reshape2::melt(measure.vars = c("Whole_Foods", "Kroger", "Jewel"), variable.name = "Grocery_Store") %>% mutate(value = value %>% as.numeric()) %>% rename(Sales = value) ui <- fluidPage( selectInput(inputId = "store", label = "Grocery Store", multiple = TRUE, choices = unique(store_data$Grocery_Store), selected = unique(store_data$Grocery_Store)), selectInput(inputId = "food_subcategory", label = "Food Type", choices = c("Vegetable", "Fruit")), plotlyOutput("food_level", height = 200), plotlyOutput("filter_level", height = 200), uiOutput('back'), uiOutput("back1") ) server <- function(input, output, session) { food_filter <- reactiveVal() type_filter <- reactiveVal() observeEvent(event_data("plotly_click", source = "food_level"), { food_filter(event_data("plotly_click", source = "food_level")$x) type_filter(NULL) }) observeEvent(event_data("plotly_click", source = "filter_level"), { type_filter( event_data("plotly_click", source = "filter_level")$x ) }) store_reactive <- reactive({ store_data %>% filter(Food_Filter == "None") %>% filter(Grocery_Store %in% input$store) }) output$food_level <- renderPlotly({ store_reactive() %>% plot_ly( x = ~Grocery_Store, y = ~Sales, color = ~Food_Main, source = "food_level", type = "bar" ) %>% layout(barmode = "stack", showlegend = T) }) store_reactive_2 <- reactive({ # 先获取原始筛选数据 filtered_data <- store_data %>% filter(Grocery_Store %in% input$store) %>% filter(Food_Filter %in% input$food_subcategory) # 检查是否需要添加Jewel的Other数据 if ("Jewel" %in% input$store && input$food_subcategory %in% c("Vegetable", "Fruit")) { # 构造Jewel的补充行 jewel_other <- tibble( Grocery_Store = "Jewel", Sales = 800, Food_Main = "Other", Food_Filter = input$food_subcategory ) # 合并原始数据和补充数据 filtered_data <- bind_rows(filtered_data, jewel_other) } filtered_data }) output$filter_level <- renderPlotly({ if (is.null(food_filter())) return(NULL) store_reactive_2() %>% plot_ly( x = ~Grocery_Store, y = ~Sales, color = ~Food_Main, source = "food_level", type = "bar" ) %>% layout(barmode = "stack", showlegend = T) }) output$back <- renderUI({ if (!is.null(food_filter()) && is.null(type_filter())) { actionButton("clear", "Back", icon("chevron-left")) } }) output$back1 <- renderUI({ if (!is.null(type_filter())) { actionButton("clear1", "Back", icon("chevron-left")) } }) observeEvent(input$clear, food_filter(NULL)) observeEvent(input$clear1, type_filter(NULL)) } shinyApp(ui, server)
关键说明
- 当用户选择的门店包含Jewel,且Food Type为Vegetable或Fruit时,自动添加一条Jewel的记录,Sales设为800,Food_Main标注为"Other"
- 使用
bind_rows将补充数据与原始筛选数据合并,保证子图能正确渲染Jewel的柱状条 - 逻辑判断确保只有在符合条件时才添加数据,不影响其他场景的正常展示
内容的提问来源于stack exchange,提问作者Harry Kalsted
相关产品推荐
相关产品推荐

