Pete
Pete

Reputation: 321

In an Shiny App, I want a plot to update, based on the search results in a datatable.

Say I have a Shiny app with a datatable and a plot. I want to be able to search/filter the datatable, and have a plot reflect the results.

How do I do this? Is this even possible? Is there any way to output the filtered datatable to an object I can use?

Here is a basic shiny application which does not work.

library(DT)

ui <- basicPage(
  h2("The mtcars data"),
  DT::dataTableOutput("mytable"),
  plotOutput('plot1')

)

server <- function(input, output) {

  output$mytable = DT::renderDataTable({
    datatable(mtcars,filter = 'top')
  })

  output$plot1 <- renderPlot({
    plot(input$mytable$wt, input$mytable$mpg)
  })

}

shinyApp(ui, server)

Upvotes: 0

Views: 1487

Answers (2)

Shree
Shree

Reputation: 11150

I have edited your code a bit since your way has some mistakes as pointed out by @r2evans.

Anyways, you can get the filtered rows of a datatable using input$tableId_rows_all. It gives the indices of rows on all pages (after the table is filtered by the search strings).

In my code filtered_table() gives you a dataframe object after all search filters are applied. output$test shows this table in real-time.

library(shiny)
library(DT)

ui <- basicPage(
  h2("The mtcars data"),
  DT::dataTableOutput("mytable"),
  verbatimTextOutput("test"),
  plotOutput('plot1')

)

server <- function(input, output) {

  mc <- head(mtcars) # could be reactive in real world case

  output$mytable = DT::renderDataTable({
    datatable(mc, filter = 'top')
  })

  filtered_table <- reactive({
    req(input$mytable_rows_all)
    mc[input$mytable_rows_all, ]  
  })

  output$plot1 <- renderPlot({
    plot(filtered_table()$wt, filtered_table()$mpg, col = "red", lwd = 10)
  })

  output$test <- renderPrint({
    filtered_table()
  })

}

shinyApp(ui, server)

enter image description here

Upvotes: 6

r2evans
r2evans

Reputation: 160952

Suggestions:

  • Tour input$mytable reference in output$plot1 is just a string, not a frame like you'd hope, so this needs to be replaced. You can hard-code mtcars, but hard-coding data doesn't really lend to an extensible and interactive experience.

  • Additionally, since you are going to be showing the same data in two different blocks ($mytable and $plot1), I suggest breaking the data into its own reactive block and referencing that block in the others.

  • Lastly, I think it's good defensive practice to use req(...) in blocks so that they do not try to execute before the data is available (common when reactive pathways are unclear or the inputs are not set yet).

Try this:

library(DT)
library(shiny)

ui <- basicPage(
  h2("The mtcars data"),
  DT::dataTableOutput("mytable"),
  plotOutput('plot1')
)

server <- function(input, output) {
  mydat <- reactive({
    # eventually you'll support filtering here
    mtcars
  })    

  output$mytable = DT::renderDataTable({
    req(mydat())
    datatable(mydat(), filter = 'top')
  })

  output$plot1 <- renderPlot({
    req(mydat())
    plot(mydat()$wt, mydat()$mpg)
  })

}

shinyApp(ui, server)

working shiny example

Upvotes: 1

Related Questions