首页 > 解决方案 > 在 Shiny App 中为多个反应式 DF 创建通用过滤器

问题描述

我正在构建一个仪表板,它需要显示多个表,每个表都有一个选项卡。数据都是相关的,我希望有通用过滤器,应用时将过滤所有表。作为一个简化的示例,假设我有以下汽车经销商的表格,其中包含有关客户、他们的车辆以及在车辆上执行的服务的信息:

顾客 邮政编码 年龄
石匠 14350 44
都乐 14352 25
罗杰斯 14358 60
车辆识别码 模型 顾客
355 翼豹 2015 石匠
1324 森林人 2020 都乐
121 凯美瑞 2018 罗杰斯
服务编号 服务 车辆识别码
1 换油 355
2 刹车 355
3 传感器更换 355
4 换油 1324
5 刹车 121

我的目标是将这些表中的每一个都作为数据表呈现在 Shiny App 的自己的选项卡中。然后,我想要基于关系过滤所有表的通用过滤器。例如,如果我将服务表过滤为换油,我希望服务表只过滤换油,但也希望车辆和客户表根据车主/车辆是否符合换油标准进行过滤。

实现这一目标的最佳方法是什么?我试图动态循环遍历这些数据集,并为每个数据集创建一个响应式数据框以及一个输出表,但我正在努力研究如何同时将过滤器应用于所有数据框。在通过为每个视图/框架选择特定列来创建视图的情况下,创建一个大型数据框会是一个更好的选择吗?

标签: rshinyshinydashboard

解决方案


我们可以将三个表连接在一起,使用 selectizeGroup-module过滤它们,然后再次拆分它们。执行连接然后拆分可能会导致一些重复的行,但使用dplyr::distinct可以解决它。

应用程序:

library(tidyverse)
library(shiny)
library(shinyWidgets)
library(gt)

customer <-
  tribble(
    ~Customer, ~Zip_Code, ~Age,
    "Mason", 14350, 44,
    "Dole", 14352, 25,
    "Rogers", 14358, 60
  )

vehicle <-
  tribble(
    ~Vehicle_ID, ~Model, ~Year, ~Customer,
    355, "Impreza", 2015, "Mason",
    1324, "Forester", 2020, "Dole",
    121, "Camry", 2018, "Rogers"
  )
service <-
  tribble(
    ~Service_ID, ~Service, ~Vehicle_ID,
    1, "Oil Change", 355,
    2, "Brakes", 355,
    3, "sensor replacement", 355,
    4, "Oil Change", 1324,
    5, "Brakes", 121
  )

df_joined <- inner_join(customer, vehicle, by = "Customer")
df_joined <- left_join(df_joined, service, by = ("Vehicle_ID"))

nms <- names(df_joined)

params <- nms %>%
  map(~ list(inputId = ., title = str_to_title(.))) %>%
  set_names(nms)

ui <- fluidPage(
  fluidRow(selectizeGroupUI(id = "my_filters", params = params)),
  tabsetPanel(
    tabPanel("Service", gt_output({
      "service_table"
    })),
    tabPanel("Vehicle", gt_output({
      "vehicle_table"
    })),
    tabPanel("Customer", gt_output({
      "customer_table"
    }))
  )
)

server <- function(input, output, session) {
  res_mod <- callModule(
    module = selectizeGroupServer,
    id = "my_filters",
    data = df_joined,
    vars = nms
  )



  df_splitted <- reactive({
    map(
      map(list(customer, vehicle, service), names),
      ~ select(res_mod(), all_of(.x))
    ) %>%
      map(distinct) %>%
      set_names(c("customer", "vehicle", "service"))
  })

  observeEvent(df_splitted(), { # the order of the table names matter
    walk2(c("customer_table", "vehicle_table", "service_table"), df_splitted(), ~ {
      output[[.x]] <<- render_gt({
        .y
      })
    })
  })
}

shinyApp(ui, server)

在此处输入图像描述


推荐阅读