I'm trying to use the R packages crosstalk and plotly (along with tidyverse packages) to create a panels that displays multiple data sets together. There's two data frames that I want to put into one plot; here's some code that creates data sets with some of these key features:
library(tf)
library(tidyverse)
library(tidyfun) # pak::pak("tidyfun/tidyfun") to install
library(ggplot2)
library(plotly)
library(crosstalk)
df1 <- tibble(f = tf_rgp(6), fil1 = rep(c("A", "B"), each = 3),
fil2 = rep(c("C", "D", "E"), times = 2)) %>%
tf_unnest(f) %>%
rename(arg = f_arg, value = f_value)
df2 <- tibble(f = tf_rgp(2), fil3 = c("U", "V")) %>%
tf_unnest(f) %>%
rename(arg = f_arg, value = f_value)
I want the data in df1 and df2 to be put on a common plot. I also want to be able to filter the subsets of both df1 and df2 that I see. Here was an initial attempt, using ggplotly (my preferred approach; for some reason, it seems more performant than plot_ly in the actual situation I am working on).
df1_selector <- highlight_key(df1)
df1_widgets <- bscols(widths = c(12, 12),
filter_checkbox("fil1", "Filter 1", df1_selector,
~ fil1),
filter_checkbox("fil2", "Filter 2", df1_selector,
~ fil2))
df2_selector <- highlight_key(df2)
df2_widgets <- bscols(widths = 12,
filter_checkbox("fil3", "Filter 3", df2_selector,
~ fil3))
# Using ggplotly
bscols(widths = c(2, 2, 8),
df1_widgets,
df2_widgets,
(ggplot(df1_selector, aes(x = arg, y = value, color = fil1)) +
geom_line(aes(color = fil1, linetype = fil2,
group = interaction(fil1, fil2))) +
geom_line(data = df2_selector,
aes(x = arg, y = value, color = fil3, group = fil3))) %>%
ggplotly
)
Here's the resulting interface. It looks like it could work.
But it does not work correctly; filters are not choosing the correct subsets. For example, if I restrict my selection to U in the second data set, I only see that data set, when I should see that data set and everything in df1. There's other ways that it does not work that I don't need to detail exhaustively.
Using plot_ly does not give correct behavior either, but as mentioned above, I don't want to use plot_ly because for some reason it has bad performance in the application I actually care about.
# Using plot_ly
bscols(widths = c(2, 2, 8),
df1_widgets,
df2_widgets,
plot_ly(df1_selector, x = ~ arg, y = ~ value) %>%
add_lines(colors = ~ fil1, linetype = ~ fil2,
split = ~ interaction(fil1, fil2)) %>%
add_lines(data = df2_selector, colors = ~ fil3, split = ~ fil3)
)
I tried asking ChatGPT for insight and ChatGPT said that the problem is that you can't use multiple data sets with plotly and crosstalk as I am attempting to do here. It gave bad solutions, but I did attempt a solution that combines the data sets together into one data set. Here is the result. It unfortunately does not work either.
df_joined_selector <- bind_rows(mutate(df1, dat = "df1"),
mutate(df2, dat = "df2")) %>%
highlight_key
df_joined_widgets <- bscols(widths = rep(12, 3),
filter_checkbox("fil1", "Filter 1",
df_joined_selector,
~ fil1),
filter_checkbox("fil2", "Filter 2",
df_joined_selector,
~ fil2),
filter_checkbox("fil3", "Filter 3",
df_joined_selector,
~ fil3))
bscols(widths = c(4, 8),
df_joined_widgets,
(ggplot(df_joined_selector, aes(x = arg, y = value,
group = interaction(fil1, fil2, fil3, dat))) +
geom_line(aes(color = fil1, linetype = fil2))) %>%
ggplotly
)
In addition to the plot not being right, the subsetting is still incorrect; if I select U for Filter 1 I still will only see the U series, when I want to see everything.
So, how can I get a crosstalk and plotly dashboard that does the kind of subsetting I wish to do?



