使用串扰过滤两个表

时间:2018-02-02 11:19:48

标签: r datatables shiny flexdashboard

我在R中创建一个Flexdashboard。我希望仪表板包含一个表和一系列可视化,这些可视化将通过输入进行过滤。

由于我需要在本地提供仪表板(没有服务器在后台运行),我无法使用Shiny,因此我依赖于串扰。

我知道串扰包在前端提供有限的功能。例如,文档说您无法聚合SharedData对象。

尽管如此,我不清楚我是否可以使用相同的输入来过滤两个不同的数据帧

例如,假设我有:

  1. Dataframe One:包含原始数据

    df1< - structure(list(owner = structure(c(1L,2L,2L,2L,2L),. Label = c(" John", " Mark"),class =" factor"),hp = c(250,120,250,100,110), car =结构(c(2L,2L,2L,1L,1L),. Label = c(" benz", " bmw"),class =" factor"),id = structure(1:5,.Label = c(" car1", " car2"," car3"," car4"," car5"),class =" factor")), .Names = c("所有者", " hp"," car"," id"),row.names = c(NA,-5L),class =" data.frame&# 34)

  2. Datafrane Two:包含汇总数据

    df2< - 结构(列表(car =结构(c(1L,2L,1L,2L),。Label = c(" benz",

    • " bmw"),class =" factor"),owner = structure(c(1L,1L,2L,2L
    • ),。Label = c(" John"," Mark"),class =" factor"),freq = c(0L,
    • 1L,2L,2L)),. Name = c(" car"," owner"," freq"),row.names = c(不,
    • -4L),class =" data.frame")
  3. 这两个数据框包含具有相同值的列 - 汽车和所有者。以及其他列也是如此。

    我可以创建两个不同的对象:

    meteor shell

    而不是:

    library(crosstalk)
    shared_df1 <- SharedData$new(df1)
    shared_df2 <- SharedData$new(df2)
    

    但是,这意味着用户需要填写两次基本相同的输入。此外,如果表很大,这将使使用仪表板所需的内存大小加倍。

    是否可以在串扰中解决此问题?

2 个答案:

答案 0 :(得分:6)

啊我最近遇到过这个问题,<odoo> <data> <record model="ir.ui.view" id="invoice_form_test"> <field name="name">invoice.form.test</field> <field name="model">account.invoice</field> <field name="inherit_id" ref="account.invoice_form"/> <field name="arch" type="xml"> <header position="inside"> <button type="action" string="Print Test" icon="fa-print" custom="print" /> </header> </field> </record> </data> </odoo> 还有另一个论点!小组争论似乎可以解决问题。当我有两个数据帧并使用SharedData$new(..., group = )时,我偶然发现了。

如果您创建一个sharedData对象,它将包含

  • 数据框
  • 选择行的键 - 最好是唯一的,但不一定。
  • 组名

我认为发生的是串扰通过密钥过滤sharedData - 对于同一组中的所有sharedData对象!因此,只要两个数据帧使用相同的密钥,您就应该能够在一个组中一起过滤它们。

这应该适用于你的例子。

group =

我花了一些时间来尝试使用--- title: "blabla" output: flexdashboard::flex_dashboard: orientation: rows social: menu source_code: embed theme: cerulean --- ```{r} library(plotly) library(crosstalk) library(tidyverse) ``` ```{r Make dataset} df1 <- structure(list(owner = structure(c(1L, 2L, 2L, 2L, 2L), .Label = c("John", "Mark"), class = "factor"), hp = c(250, 120, 250, 100, 110), car = structure(c(2L, 2L, 2L, 1L, 1L), .Label = c("benz", "bmw"), class = "factor"), id = structure(1:5, .Label = c("car1", "car2", "car3", "car4", "car5"), class = "factor")), .Names = c("owner", "hp", "car", "id"), row.names = c(NA, -5L), class = "data.frame") df2 <- structure(list(car = structure(c(1L, 2L, 1L, 2L), .Label = c("benz", "bmw"), class = "factor"), owner = structure(c(1L, 1L, 2L, 2L ), .Label = c("John", "Mark"), class = "factor"), freq = c(0L, 1L, 2L, 2L)), .Names = c("car", "owner", "freq"), row.names = c(NA, -4L), class = "data.frame") ``` # ## ### Filters ```{r} library(crosstalk) # Notice the 'group = ' argument - this does the trick! shared_df1 <- SharedData$new(df1, ~owner, group = "Choose owner") shared_df2 <- SharedData$new(df2, ~owner, group = "Choose owner") filter_select("owner", "Car owner:", shared_df1, ~owner) # You don't need this second filter now # filter_select("owner", "Car owner:", shared_df2, ~ owner) ``` ### Plot1 with plotly ```{r} plot_ly(shared_df1, x = ~id, y = ~hp, color = ~owner) %>% add_markers() %>% highlight("plotly_click") ``` ### Plots with plotly ```{r} plot_ly(shared_df2, x = ~owner, y = ~freq, color = ~car) %>% group_by(owner) %>% add_bars() ``` ## ### Dataframe 1 ```{r} DT::datatable(shared_df1) ``` ### Dataframe 2 ```{r} DT::datatable(shared_df2) ``` plot_ly()中提取数据而没有运气,直到我找到答案。这就是为什么有一些非常简单的情节剧情的原因。

答案 1 :(得分:1)

最近,我还想使用一个过滤器来过滤 2 个可视化效果。

简要说明我的情况
我想使用一个过滤器来过滤箱线图和表格。
源数据一直是一个数据框。我想为箱线图使用一些变量,并计算一些统计数据(如均值、标准差、众数、记录数)。
我需要用来显示结果的函数:plotly::plot_ly()、DT::datatable()、crosstalk::bscols()。

我发现有3个关键信息可以解决这种情况
关键 1)正确创建共享数据是必要的。
就我而言,我不得不使用 crosstalk::SharedData$new() 两次。
如果首先满足键 2 和键 3,则可以使用正确的共享数据,用作可视化的来源。
关键 2) 创建共享数据时,使用与 2018 年 3 月 16 日解释的“Lodewic Van Twillert”相同的组参数。
键 3) 确保所有 SharedData 实例在概念上引用相同的数据点,并共享相同的键。
首先确保数据框具有行名称,即使行名称是带有数字的字符向量(如“1”、“2”...)。
用于此键 3 的文献:https://rstudio.github.io/crosstalk/using.html。 (建议主要看副标题“分组”。)

步骤总结我已经用来完成上面的关键信息
Key 3) 为了满足上述 Key 3 的相关条件,这可能很棘手。
我选择的方法创建一个包含所有数据的表,这个表(数据框)将用于创建两个共享数据。
我已经对原始数据框 (risk_scores_df) 应用了数据操作,所以现在这个数据有了一个新列。
我创建了一个带有统计信息的新数据框。
我已经加入了两个数据框使用 risk_scores_df <- dplyr::left_join... 所以现在原始数据框包含所有准备好的数据。
我已运行 print(rownames(risk_scores_df)) 以确保我更新的数据框具有行名称。
现在,我有一个数据框,其中包含满足上述关键 3 信息条件的所有数据(两种可视化都需要)。
关键 2) 我只是在两个串扰中添加了 group = "sd1"::SharedData$new()
关键 1) 如果选择了错误的方法,这个方法也会很棘手。
在这里,创建正确共享数据实例的关键是使用包含所有数据的同一个表,并仅选择相关共享数据所需的行和列。
示例 - 就我而言,我已经在选项 1 中运行代码来创建两个共享数据实例,但选项 2 也是可能的。

选项 1(在串扰中只选择需要的行和列:::SharedData$new())

  rs_df_sd1 <- crosstalk::SharedData$new(
    risk_scores_df[, c(1, 2, 5)],
    group = "sd1"
  )
  rs_df_sd1a <- crosstalk::SharedData$new(
    risk_scores_df[risk_scores_df$NumRecords > 0 &
                   is.na(risk_scores_df$NumRecords) == F,
                   c(1, 6:11)],
    group = "sd1"
  )

选项 2(在附加变量中只选择需要的行和列)

  sd1 <- risk_scores_df[, c(1, 2, 5)]
  sd1a <- risk_scores_df[risk_scores_df$NumRecords > 0 &
                         is.na(risk_scores_df$NumRecords) == F,
                         c(1, 6:11)]

  rs_df_sd1 <- crosstalk::SharedData$new(sd1, group = "sd1")
  rs_df_sd1a <- crosstalk::SharedData$new(sd1a, group = "sd1")

完成解决方案
在这一点上,我创建了共享数据实例 rs_df_sd1 和 rs_df_sd1a,它们可以用作可视化的主要来源,这些可视化将使用 crosstalk::bscols() 进行过滤。
简单例子:

  box_n_jitter_chart1 <- plotly::plot_ly(rs_df_sd1) %>% add_trace(...
  DT_table1 <- DT::datatable(rs_df_sd1a)
  crosstalk::bscols(
    widths = c(6, 12, NA),
    crosstalk::filter_select(
      id = "idAvgRisk",
      label = "Account",
      sharedData = rs_df_sd1,
      group = ~Account,
      multiple = F
    ),
    box_n_jitter_chart1,
    DT_table1
  )

注意:DT::datatable() 也可以使用 rs_df_sd1a$data()cells = list(values = base::rbind(...(参见使用了 cells = ...;查看更多关于使用 cells 的信息,例如在 {{3 }}) 但因为使用了 method data()(更多信息,例如在 https://plotly.com/r/reference/table/ 处),那么它不会与串扰::bscols 一起使用。