用串扰过滤两个表
Filter two tables with crosstalk
我正在 R 中创建一个 Flexdashboard。我希望仪表板包含 table 和一系列可视化效果,这些可视化效果将通过输入进行过滤。
因为我需要在本地提供仪表板(后台没有服务器 运行),所以我无法使用 Shiny,因此我依赖串扰。
我知道 crosstalk 包在前端提供的功能有限。例如,文档说您不能聚合 SharedData 对象。
不过,我不清楚是否可以使用相同的输入来过滤两个不同的数据帧。
例如,假设我有:
数据框一:包含原始数据
df1 <-结构(列表(所有者=结构(c(1L,2L,2L,2L,2L),.Label = c("John",
"Mark"), class = "factor"), 马力 = c(250, 120, 250, 100, 110),
汽车 = 结构 (c(2L, 2L, 2L, 1L, 1L), .Label = c("benz",
"bmw"), class = "factor"), id = 结构(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")
Datafrane 二:包含聚合数据
df2 <-结构(列表(汽车=结构(c(1L,2L,1L,2L),.Label = c("benz",
- "bmw"), class = "factor"), 所有者=结构(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")
这两个数据帧包含 具有相同值的列 - car 和 owner。此外,还有其他列。
我可以创建两个不同的对象:
library(crosstalk)
shared_df1 <- SharedData$new(df1)
shared_df2 <- SharedData$new(df2)
比:
filter_select("owner", "Car owner:", shared_df1, ~ owner)
filter_select("owner", "Car owner:", shared_df2, ~ owner)
但是,这意味着用户将需要填写两次基本相同的输入。此外,如果 table 很大,这将使使用仪表板所需的内存大小加倍。
是否可以解决这个串扰问题?
啊我最近运行也入这个了,还有一个说法要SharedData$new(..., group = )
!小组论证似乎可以解决问题。当我有两个数据帧并使用 group =
.
时,我偶然发现了
如果你创建一个sharedData对象,它将包含
- 一个数据框
- select 行的键 - 最好是唯一的,但不一定。
- 群名
我认为发生的情况是串扰通过键过滤 sharedData - 对于同一组中的所有 sharedData 对象!因此,只要两个数据帧使用相同的键,您就应该能够在一组中将它们一起过滤。
这应该适用于您的示例。
---
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)
```
我花了一些时间尝试使用 plotly_data()
从 plot_ly()
中提取数据,但没有成功,直到我找到答案。这就是为什么 plotly 有一些非常简单的情节。
最近也想用一个过滤器过滤2个可视化。
简单描述一下我的情况
我想使用一个过滤器来过滤箱线图和 table。
源数据是一个数据框。我想为箱线图使用一些变量,并计算一些统计数据(如均值、标准差、众数、记录数)。
我需要用来显示结果的函数:plotly::plot_ly()、DT::datatable()、crosstalk::bscols()。
我发现有3个关键信息可以解决这个问题
关键1)正确创建共享数据很有必要。
就我而言,我不得不使用 crosstalk::SharedData$new() 两次。
如果首先满足键 2 和 3,则可以使用要用作可视化源的正确共享数据。
关键 2) 创建共享数据时,使用与“Lodewic Van Twillert”在 2018 年 3 月 16 日解释的相同组参数。
键 3) 确保所有 SharedData 实例在概念上都引用相同的数据点,并共享相同的键。
从确保数据框具有行名称开始,即使行名称是带有数字的字符向量(如“1”、“2”、...)。
此键 3 的使用文献:https://rstudio.github.io/crosstalk/using.html。 (我建议主要看副标题“分组”。)
步骤总结我已经习惯了上面的关键信息
关键3) 为了满足上面关键3的相关条件,这个可能有点棘手。
我选择的方法创建一个 table 包含所有数据,这个 table (数据框)将用于创建两个共享数据。
我对原始数据框 (risk_scores_df) 应用了数据操作,因此现在该数据有一个新列。
我创建了一个带有统计数据的新数据框。
我已经加入了两个数据框
risk_scores_df <- dplyr::left_join...
所以现在原始数据框包含所有准备好的数据。
我 运行 print(rownames(risk_scores_df))
以确保我更新的数据框有行名称。
现在,我已经有了一个数据框,其中包含满足上述关键 3 信息条件的所有数据(两种可视化都需要)。
键 2) 我只是在 crosstalk::SharedData$new()
中添加了 group = "sd1"
关键 1) 如果选择了错误的方法,这个也可能很棘手。
在这里,创建 正确 共享数据实例的关键是将那个 table 与所有数据一起使用,并仅选择相关共享数据所需的行和列。
示例 - 在我的例子中,我在选项 1 中有 运行 代码来创建两个共享数据实例,但选项 2 也是可能的。
选项 1(只选择需要的行和列在 crosstalk::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
的更多信息,例如https://plotly.com/r/reference/table/) but because method data()
is used (see more e.g. at https://rdrr.io/cran/crosstalk/man/SharedData.html#method-data) 那么它将不适用于 crosstalk::bscols.
我正在 R 中创建一个 Flexdashboard。我希望仪表板包含 table 和一系列可视化效果,这些可视化效果将通过输入进行过滤。
因为我需要在本地提供仪表板(后台没有服务器 运行),所以我无法使用 Shiny,因此我依赖串扰。
我知道 crosstalk 包在前端提供的功能有限。例如,文档说您不能聚合 SharedData 对象。
不过,我不清楚是否可以使用相同的输入来过滤两个不同的数据帧。
例如,假设我有:
数据框一:包含原始数据
df1 <-结构(列表(所有者=结构(c(1L,2L,2L,2L,2L),.Label = c("John", "Mark"), class = "factor"), 马力 = c(250, 120, 250, 100, 110), 汽车 = 结构 (c(2L, 2L, 2L, 1L, 1L), .Label = c("benz", "bmw"), class = "factor"), id = 结构(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")
Datafrane 二:包含聚合数据
df2 <-结构(列表(汽车=结构(c(1L,2L,1L,2L),.Label = c("benz",
- "bmw"), class = "factor"), 所有者=结构(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")
这两个数据帧包含 具有相同值的列 - car 和 owner。此外,还有其他列。
我可以创建两个不同的对象:
library(crosstalk)
shared_df1 <- SharedData$new(df1)
shared_df2 <- SharedData$new(df2)
比:
filter_select("owner", "Car owner:", shared_df1, ~ owner)
filter_select("owner", "Car owner:", shared_df2, ~ owner)
但是,这意味着用户将需要填写两次基本相同的输入。此外,如果 table 很大,这将使使用仪表板所需的内存大小加倍。
是否可以解决这个串扰问题?
啊我最近运行也入这个了,还有一个说法要SharedData$new(..., group = )
!小组论证似乎可以解决问题。当我有两个数据帧并使用 group =
.
如果你创建一个sharedData对象,它将包含
- 一个数据框
- select 行的键 - 最好是唯一的,但不一定。
- 群名
我认为发生的情况是串扰通过键过滤 sharedData - 对于同一组中的所有 sharedData 对象!因此,只要两个数据帧使用相同的键,您就应该能够在一组中将它们一起过滤。
这应该适用于您的示例。
---
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)
```
我花了一些时间尝试使用 plotly_data()
从 plot_ly()
中提取数据,但没有成功,直到我找到答案。这就是为什么 plotly 有一些非常简单的情节。
最近也想用一个过滤器过滤2个可视化。
简单描述一下我的情况
我想使用一个过滤器来过滤箱线图和 table。
源数据是一个数据框。我想为箱线图使用一些变量,并计算一些统计数据(如均值、标准差、众数、记录数)。
我需要用来显示结果的函数:plotly::plot_ly()、DT::datatable()、crosstalk::bscols()。
我发现有3个关键信息可以解决这个问题
关键1)正确创建共享数据很有必要。
就我而言,我不得不使用 crosstalk::SharedData$new() 两次。
如果首先满足键 2 和 3,则可以使用要用作可视化源的正确共享数据。
关键 2) 创建共享数据时,使用与“Lodewic Van Twillert”在 2018 年 3 月 16 日解释的相同组参数。
键 3) 确保所有 SharedData 实例在概念上都引用相同的数据点,并共享相同的键。
从确保数据框具有行名称开始,即使行名称是带有数字的字符向量(如“1”、“2”、...)。
此键 3 的使用文献:https://rstudio.github.io/crosstalk/using.html。 (我建议主要看副标题“分组”。)
步骤总结我已经习惯了上面的关键信息
关键3) 为了满足上面关键3的相关条件,这个可能有点棘手。
我选择的方法创建一个 table 包含所有数据,这个 table (数据框)将用于创建两个共享数据。
我对原始数据框 (risk_scores_df) 应用了数据操作,因此现在该数据有一个新列。
我创建了一个带有统计数据的新数据框。
我已经加入了两个数据框
risk_scores_df <- dplyr::left_join...
所以现在原始数据框包含所有准备好的数据。
我 运行 print(rownames(risk_scores_df))
以确保我更新的数据框有行名称。
现在,我已经有了一个数据框,其中包含满足上述关键 3 信息条件的所有数据(两种可视化都需要)。
键 2) 我只是在 crosstalk::SharedData$new()
中添加了 group = "sd1"
关键 1) 如果选择了错误的方法,这个也可能很棘手。
在这里,创建 正确 共享数据实例的关键是将那个 table 与所有数据一起使用,并仅选择相关共享数据所需的行和列。
示例 - 在我的例子中,我在选项 1 中有 运行 代码来创建两个共享数据实例,但选项 2 也是可能的。
选项 1(只选择需要的行和列在 crosstalk::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
的更多信息,例如https://plotly.com/r/reference/table/) but because method data()
is used (see more e.g. at https://rdrr.io/cran/crosstalk/man/SharedData.html#method-data) 那么它将不适用于 crosstalk::bscols.