Reputation: 321
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
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)
Upvotes: 6
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)
Upvotes: 1