0

I have the shiny app below in which I display df with ggplotly() barchart and and df2 with a datatable. The 2 dataframes have a column with same informations (dose). I would like to be able to click on a bar and automatically subset the df2 displayed in the table to the respective data. For example if I press D1 bar only the D1 data will be displayed in the table.

library(shiny)
library(ggplot2)
library(plotly)
library(DT)
ui <- fluidPage(
  plotlyOutput("plt"),
  DTOutput("dt")
)
server <- function(input, output) {
  df <- data.frame(dose=c("D0.5", "D1", "D2"),
                   len=c(4.2, 10, 29.5))
  output$plt<-renderPlotly({
    # Basic barplot
    p<-ggplot(data=df, aes(x=dose, y=len)) +
      geom_bar(stat="identity")
    ggplotly(p)
  })
  df2 <- data.frame(dose=c("D0.5", "D1", "D2"),
                   siz=c(2, 10, 2.5))
  output$dt<-renderDT(
    df2
  )
}
shinyApp(ui, server)
firmo23
  • 7,490
  • 2
  • 38
  • 114

1 Answers1

1

As long as your dataset is not to large, have a look at the crosstalk package here. It's designed for interaction between plots, maps and tables.

Automatically Subsetting

library(shiny)
library(ggplot2)
library(plotly)
library(DT)
library(crosstalk)

ui <- fluidPage(
  plotlyOutput("plt"),
  DT::dataTableOutput("dt")
)

server <- function(input, output) {
  df <- data.frame(dose=c("D0.5", "D1", "D2"),
                   len=c(4.2, 10, 29.5))
  df2 <- data.frame(dose=c("D0.5", "D1", "D2"),
                    siz=c(2, 10, 2.5))
  
  shared_df <- SharedData$new(df, key = ~dose, group = "group")
  shared_df2 <- SharedData$new(df2, key = ~dose, group = "group")
  
  output$plt<-renderPlotly({
    # Basic barplot
    p <- ggplot(data=shared_df, aes(x=dose, y=len)) +
      geom_bar(stat="identity")
    ggplotly(p)
  })
  
  output$dt<-DT::renderDataTable({
    shared_df2
    }, server = FALSE)
}
shinyApp(ui, server)

Manually Subsetting df2

library(shiny)
library(ggplot2)
library(plotly)
library(DT)
library(crosstalk)

ui <- fluidPage(
  plotlyOutput("plt"),
  DT::dataTableOutput("dt")
)

server <- function(input, output) {
  df <- data.frame(dose=c("D0.5", "D1", "D2"),
                   len=c(4.2, 10, 29.5),
                   stringsAsFactors = F) 
  df2 <- data.frame(dose=c("D0.5", "D1", "D2"),
                    siz=c(2, 10, 2.5),
                    stringsAsFactors = F)
  
  shared_df <- SharedData$new(df, key = ~dose, group = "group")

  output$plt<-renderPlotly({
    # Basic barplot
    p <- ggplot(data=shared_df, aes(x=dose, y=len)) +
      geom_bar(stat="identity")
    ggplotly(p)
  })
  
  dose_filter <- reactive({
         log <- shared_df$selection()
         if(!is.null(log)) {
           log <- shared_df$key()[log]
         } else {
           log <- shared_df$key()
         }
  })
  
   output$dt<- DT::renderDataTable({
    subset(df2, dose %in% dose_filter())
  }, server = FALSE)
  
}
shinyApp(ui, server)
tamtam
  • 3,541
  • 1
  • 7
  • 21
  • great answer indeed. could you look at this one for crosstalk? https://stackoverflow.com/questions/66508869/connect-more-than-one-charts-with-the-same-table-without-affecting-one-another-u – firmo23 Mar 06 '21 at 17:55
  • is possible to connect many charts to one table? – firmo23 Mar 08 '21 at 11:36
  • With regard to your later questions (4 datasets - 3 plots and 1 table) and your aim that only the table and not the plots should react, I think crosstalk in flexdashboard is not able to do that without shiny. You might need a reactive function to filter your table dataset like in the second example above. Than each of the 3 plot-datasets need to be converted into a sharedDataframe (each one with it's own group argument and the key might be the x-axis variable of the plot). And than you can filter your table-dataset with the three sharedDataframes in a reactive-function. – tamtam Mar 08 '21 at 14:29
  • Thanks could you check whis does not work as expected? https://stackoverflow.com/questions/66537874/subset-dataset-based-on-crosstalk-value-in-a-shiny-app – firmo23 Mar 08 '21 at 22:02