You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

R Shiny基于选中分类筛选后添加饼图展示剩余记录占比方案

实现思路
  • 先把过滤逻辑抽成响应式变量,避免DT表格和百分比组件重复写过滤规则,也方便后续统一修改逻辑
  • 总记录数固定为150,直接用过滤后数据集的行数除以150计算占比,保留1位小数即可
  • 百分比展示提供两种可选方案:一种是进度条,可读性更强;另一种是极简环形饼图,符合饼图需求
  • 原有"all"排除选项的逻辑同步适配,选all时占比直接显示0%
完整修改后代码

先安装依赖包:install.packages(c("shinyWidgets", "DT"))

irismut <- data.frame(
    stringsAsFactors = FALSE,
    Sepal.Length = c(5.1,4.9,4.7,4.6,5,5.4,4.6,
                        5,4.4,4.9,5.4,4.8,4.8,4.3,5.8,5.7,5.4,5.1,
                        5.7,5.1,5.4,5.1,4.6,5.1,4.8,5,5,5.2,5.2,4.7,4.8,
                        5.4,5.2,5.5,4.9,5,5.5,4.9,4.4,5.1,5,4.5,4.4,
                        5,5.1,4.8,5.1,4.6,5.3,5,7,6.4,6.9,5.5,6.5,
                        5.7,6.3,4.9,6.6,5.2,5,5.9,6,6.1,5.6,6.7,5.6,5.8,
                        6.2,5.6,5.9,6.1,6.3,6.1,6.4,6.6,6.8,6.7,6,
                        5.7,5.5,5.5,5.8,6,5.4,6,6.7,6.3,5.6,5.5,5.5,6.1,
                        5.8,5,5.6,5.7,5.7,6.2,5.1,5.7,6.3,5.8,7.1,
                        6.3,6.5,7.6,4.9,7.3,6.7,7.2,6.5,6.4,6.8,5.7,5.8,
                        6.4,6.5,7.7,7.7,6,6.9,5.6,7.7,6.3,6.7,7.2,6.2,
                        6.1,6.4,7.2,7.4,7.9,6.4,6.3,6.1,7.7,6.3,6.4,
                        6,6.9,6.7,6.9,5.8,6.8,6.7,6.7,6.3,6.5,6.2,5.9),
    Sepal.Width = c(3.5,3,3.2,3.1,3.6,3.9,3.4,
                    3.4,2.9,3.1,3.7,3.4,3,3,4,4.4,3.9,3.5,3.8,
                    3.8,3.4,3.7,3.6,3.3,3.4,3,3.4,3.5,3.4,3.2,3.1,
                    3.4,4.1,4.2,3.1,3.2,3.5,3.6,3,3.4,3.5,2.3,3.2,
                    3.5,3.8,3,3.8,3.2,3.7,3.3,3.2,3.2,3.1,2.3,2.8,
                    2.8,3.3,2.4,2.9,2.7,2,3,2.2,2.9,2.9,3.1,3,
                    2.7,2.2,2.5,3.2,2.8,2.5,2.8,2.9,3,2.8,3,2.9,
                    2.6,2.4,2.4,2.7,2.7,3,3.4,3.1,2.3,3,2.5,2.6,3,
                    2.6,2.3,2.7,3,2.9,2.9,2.5,2.8,3.3,2.7,3,2.9,3,
                    3,2.5,2.9,2.5,3.6,3.2,2.7,3,2.5,2.8,3.2,3,
                    3.8,2.6,2.2,3.2,2.8,2.8,2.7,3.3,3.2,2.8,3,2.8,
                    3,2.8,3.8,2.8,2.8,2.6,3,3.4,3.1,3,3.1,3.1,3.1,
                    2.7,3.2,3.3,3,2.5,3,3.4,3),
    Petal.Length = c(1.4,1.4,1.3,1.5,1.4,1.7,
                     1.4,1.5,1.4,1.5,1.5,1.6,1.4,1.1,1.2,1.5,1.3,1.4,
                     1.7,1.5,1.7,1.5,1,1.7,1.9,1.6,1.6,1.5,1.4,
                     1.6,1.6,1.5,1.5,1.4,1.5,1.2,1.3,1.4,1.3,1.5,1.3,
                     1.3,1.3,1.6,1.9,1.4,1.6,1.4,1.5,1.4,4.7,4.5,
                     4.9,4,4.6,4.5,4.7,3.3,4.6,3.9,3.5,4.2,4,4.7,
                     3.6,4.4,4.5,4.1,4.5,3.9,4.8,4,4.9,4.7,4.3,4.4,
                     4.8,5,4.5,3.5,3.8,3.7,3.9,5.1,4.5,4.5,4.7,4.4,
                     4.1,4,4.4,4.6,4,3.3,4.2,4.2,4.2,4.3,3,4.1,6,
                     5.1,5.9,5.6,5.8,6.6,4.5,6.3,5.8,6.1,5.1,5.3,
                     5.5,5,5.1,5.3,5.5,6.7,6.9,5,5.7,4.9,6.7,4.9,5.7,
                     6,4.8,4.9,5.6,5.8,6.1,6.4,5.6,5.1,5.6,6.1,
                     5.6,5.5,4.8,5.4,5.6,5.1,5.1,5.9,5.7,5.2,5,5.2,
                     5.4,5.1),
    Petal.Width = c(0.2,0.2,0.2,0.2,0.2,0.4,
                    0.3,0.2,0.2,0.1,0.2,0.2,0.1,0.1,0.2,0.4,0.4,0.3,
                    0.3,0.3,0.2,0.4,0.2,0.5,0.2,0.2,0.4,0.2,0.2,
                    0.2,0.2,0.4,0.1,0.2,0.2,0.2,0.2,0.1,0.2,0.2,
                    0.3,0.3,0.2,0.6,0.4,0.3,0.2,0.2,0.2,0.2,1.4,1.5,
                    1.5,1.3,1.5,1.3,1.6,1,1.3,1.4,1,1.5,1,1.4,
                    1.3,1.4,1.5,1,1.5,1.1,1.8,1.3,1.5,1.2,1.3,1.4,
                    1.4,1.7,1.5,1,1.1,1,1.2,1.6,1.5,1.6,1.5,1.3,
                    1.3,1.3,1.2,1.4,1.2,1,1.3,1.2,1.3,1.3,1.1,1.3,
                    2.5,1.9,2.1,1.8,2.2,2.1,1.7,1.8,1.8,2.5,2,1.9,
                    2.1,2,2.4,2.3,1.8,2.2,2.3,1.5,2.3,2,2,1.8,2.1,
                    1.8,1.8,1.8,2.1,1.6,1.9,2,2.2,1.5,1.4,2.3,
                    2.4,1.8,1.8,2.1,2.4,2.3,1.9,2.3,2.5,2.3,1.9,2,
                    2.3,1.8),
    Species = c("setosa, versicolor",
                "setosa, versicolor","setosa, versicolor","setosa, versicolor",
                "setosa, versicolor","setosa, versicolor",
                "setosa, versicolor","setosa, versicolor","setosa, versicolor",
                "setosa, versicolor","setosa, versicolor",
                "setosa, versicolor","setosa, versicolor","setosa, versicolor",
                "setosa, versicolor","setosa, versicolor","setosa, versicolor",
                "setosa, versicolor","setosa, versicolor",
                "setosa, virginica","setosa, virginica","setosa, virginica",
                "setosa, virginica","setosa, virginica","setosa, virginica",
                "setosa, virginica","setosa, virginica",
                "setosa, virginica","setosa, virginica","setosa, virginica","setosa",
                "setosa","setosa","setosa","setosa","setosa",
                "setosa","setosa","setosa","setosa","setosa","setosa",
                "setosa","setosa","setosa","setosa","setosa","setosa",
                "setosa","setosa","versicolor","versicolor",
                "versicolor","versicolor","versicolor","versicolor",
                "versicolor","versicolor","versicolor","versicolor",
                "versicolor","versicolor","versicolor","versicolor","versicolor",
                "versicolor","versicolor","versicolor","versicolor",
                "versicolor","versicolor","versicolor","versicolor",
                "versicolor","versicolor","versicolor","versicolor",
                "versicolor","versicolor","versicolor","versicolor",
                "versicolor","versicolor","versicolor","versicolor",
                "versicolor","versicolor","versicolor","versicolor",
                "versicolor","versicolor","versicolor","versicolor",
                "versicolor","versicolor","versicolor","versicolor",
                "versicolor","versicolor","versicolor","virginica",
                "virginica","virginica","virginica","virginica","virginica",
                "virginica","virginica","virginica","virginica",
                "virginica","virginica","virginica","virginica",
                "virginica","virginica","virginica","virginica","virginica",
                "virginica","virginica","virginica","virginica",
                "virginica","virginica","virginica","virginica","virginica",
                "virginica","virginica","virginica","virginica",
                "virginica","virginica","virginica","virginica",
                "virginica","virginica","virginica","virginica","virginica",
                "virginica","virginica","virginica","virginica",
                "virginica","virginica","virginica","virginica","virginica")
)
library(shiny)
library(ggplot2)
library(tidyverse)
library(shinyWidgets)
library(DT)

# 总记录数固定值
TOTAL_RECORD <- 150

# UI
ui <- fluidPage(
    titlePanel("Iris dataset but mutated for this purpose"),
    fluidRow(
        column(
            4,
            checkboxGroupInput("names",
                               "select the species you want to exclude:",
                               choices = NULL, inline = TRUE
            ),
            br(),
            # 新增百分比进度条
            progressBar(
                id = "ratio_bar",
                value = 100,
                total = 100,
                title = "剩余记录占比:",
                display_pct = TRUE,
                status = "primary"
            )
        ),
        column(8, DT::dataTableOutput("table"))
    )
)

# 服务端逻辑
server <- function(input, output, session) {
    updateCheckboxGroupInput(session, "names", choices = unique(irismut$Species) %>% discard(~ .x %>% str_detect(",")) %>% c("all"))
    
    # 抽离过滤后的数据集为响应式变量,表格和占比计算复用
    filtered_data <- reactive({
        if(is.null(input$names)) {
            return(irismut)
        }
        if("all" %in% input$names) {
            return(irismut[0,])
        }
        irismut %>%
            filter(!Species %>% str_detect(input$names %>% paste0(collapse = "|")))
    })
    
    # 监听过滤结果更新进度条
    observe({
        current_cnt <- nrow(filtered_data())
        ratio <- round(current_cnt / TOTAL_RECORD * 100, 1)
        updateProgressBar(session, "ratio_bar", value = ratio)
    })
    
    output$table <- DT::renderDataTable(DT::datatable(filtered_data()))
}

# 运行应用
shinyApp(ui = ui, server = server)

如果要换用环形饼图的话,把UI里的progressBar部分替换成plotOutput("pie_chart", height = "200px"),然后在server里新增以下代码即可:

output$pie_chart <- renderPlot({
    current_cnt <- nrow(filtered_data())
    ratio <- round(current_cnt / TOTAL_RECORD * 100, 1)
    # 构造环形图数据
    pie_data <- data.frame(
        category = c("剩余", "排除"),
        value = c(ratio, 100 - ratio)
    )
    ggplot(pie_data, aes(x = 2, y = value, fill = category)) +
        geom_col(color = "white") +
        coord_polar(theta = "y") +
        xlim(0.5, 2.5) + # 实现环形效果
        scale_fill_manual(values = c("剩余" = "#2c7fb8", "排除" = "#f0f0f0")) +
        geom_text(aes(x = 0.5, label = paste0(ratio, "%")), size = 10) +
        theme_void() +
        theme(legend.position = "none")
})

内容的提问来源于stack exchange,提问作者Robbie Vo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 23:42:01