R Shiny and DataTable (DT) Proxy Demonstration For Reactive Data Tables
October 12, 2020 By Pascal Schmidt R R Shiny
In this R Shiny demonstration, we will be looking at an example where the user can manually add and remove data from a data table without rendering the entire DataTable
again and again. Instead, we will be using the DataTable
proxy (DT::dataTableProxy
function) to replace and add data according to the user.
Let’s do it!
Shiny Application Set-Up
First, we will be loading the libraries.
library(shiny) library(tidyverse) library(DT)
And then we will be creating a data frame that shiny displays when the app first loads.
The data frame we will be using looks like that:
df <- dplyr::tibble(Height = "185", Weight = "95")
We are starting out with one row and two columns. The user should be able to add their height and weight to the table and then also removing rows without the need to render the data table every time.
R Shiny Data Table UI Components
For the UI components, we need 2 textinputs
shiny::textInput(inputId = "height", label = "height")
shiny::textInput(inputId = "weight", label = "weight")
For the first text input, the user can specify the height and in the second one their height. Next, we want to have an action button that initializes the appending to the data frame.
shiny::actionButton(inputId = "add", label = "Add")
Also, we need a drop-down menu that tells us what row number we want to remove plus one action button that initializes the removal of that particular row.
shiny::selectInput(inputId = "remove_row", label = "Remove Row", choices = 1:nrow(df))
shiny::actionButton(inputId = "remove", label = "Remove")
We are almost done with the UI! We only need the DataTable
now.
DT::DTOutput(outputId = “table”)
That’s it for the UI. All in all, the UI looks like this:
ui <- fluidPage( # App title ---- titlePanel("DT + Proxy + Replace Data"), # Sidebar layout with input and output definitions ---- sidebarLayout( # Sidebar panel for inputs ---- sidebarPanel( # Input: Slider for the number of bins ---- shiny::textInput(inputId = "height", label = "height"), shiny::textInput(inputId = "weight", label = "weight"), shiny::actionButton(inputId = "add", label = "Add"), shiny::selectInput(inputId = "remove_row", label = "Remove Row", choices = 1:nrow(df)), shiny::actionButton(inputId = "remove", label = "Remove") ), # Main panel for displaying outputs ---- mainPanel( # Output: Histogram ---- DT::DTOutput(outputId = "table") ) ) )
R Shiny DataTable Server Components – Proxy + ReplaceData
The server logic is a bit more complicated because we are using reactivity. The user has the chance to update the DataTable
reactively/manually.
First, we will be creating reactive values and then rendering the DataTable
consisting of one row and two columns.
mod_df <- shiny::reactiveValues(x = df) output$table <- DT::renderDT({ isolate(mod_df$x) }, options = list(paging = FALSE, processing = FALSE))
We use isolate
in the code above because we do not want to have a dependency between the data and the DataTable
render function. At the start, the entire table should be loaded, however, beyond that theDataTable
should only get updated, instead of rendered every time the user adds or removes a row.
Next, we have to update the drop-down menu. Whenever the user adds a row, we have to add one more row to the drop-down menu, and when the user removes a row, we have to remove a row from the drop-down menu. We do that with updateSelectInput
.
shiny::observe({ shiny::updateSelectInput(session, inputId = "remove_row", choices = 1:nrow(mod_df$x)) })
Next, we use observeEvent
to make use of the action buttons.
shiny::observeEvent(input$add, { mod_df$x <- mod_df$x %>% dplyr::bind_rows( dplyr::tibble(Height = input$height, Weight = input$weight) ) }) shiny::observeEvent(input$remove, { mod_df$x <- mod_df$x[-as.integer(input$remove_row), ] })
After that, the magic with data table proxy happens, and with the replaceData
function in the DT
package.
proxy <- DT::dataTableProxy('table') shiny::observe({ DT::replaceData(proxy, mod_df$x) })
And we are done. Now, every time the user adds or removes a row, the proxy is used to update the data instead of using the data table render function to render the entire data. This is especially critical when we have large amounts of data. Using the proxy is way more efficient and increases the speed of your R Shiny application by a lot!
Full R Shiny Application Code
library(shiny) library(tidyverse) library(DT) df <- dplyr::tibble(Height = "185", Weight = "95") ui <- fluidPage( # App title ---- titlePanel("DT + Proxy + Replace Data"), # Sidebar layout with input and output definitions ---- sidebarLayout( # Sidebar panel for inputs ---- sidebarPanel( # Input: Slider for the number of bins ---- shiny::textInput(inputId = "height", label = "height"), shiny::textInput(inputId = "weight", label = "weight"), shiny::actionButton(inputId = "add", label = "Add"), shiny::selectInput(inputId = "remove_row", label = "Remove Row", choices = 1:nrow(df)), shiny::actionButton(inputId = "remove", label = "Remove") ), # Main panel for displaying outputs ---- mainPanel( # Output: Histogram ---- DT::DTOutput(outputId = "table") ) ) ) # Define server logic required to draw a histogram ---- server <- function(input, output, session) { mod_df <- shiny::reactiveValues(x = df) output$table <- DT::renderDT({ isolate(mod_df$x) }) shiny::observe({ shiny::updateSelectInput(session, inputId = "remove_row", choices = 1:nrow(mod_df$x)) }) shiny::observeEvent(input$add, { mod_df$x <- mod_df$x %>% dplyr::bind_rows( dplyr::tibble(Height = input$height, Weight = input$weight) ) }) shiny::observeEvent(input$remove, { mod_df$x <- mod_df$x[-as.integer(input$remove_row), ] }) proxy <- DT::dataTableProxy('table') shiny::observe({ DT::replaceData(proxy, mod_df$x) }) } shinyApp(ui, server)
The R Shiny application can be found here.
Additional Resources
- A great blog post about
DataTable
proxy and editing tables after rendering can be found here. - Another post, that talks about the same
DataTable
andreplaceData
can be found here. - Here is another interesting read that is more theoretical.
- This blog post uses the
DTedit
library for updatingDataTables
. - Another great article, that provides the source code, some explanation, and a shiny application for demonstration purposes on how to reactively edit
DataTables
in an R Shiny application.
If you have any questions or suggestions, let me know in the comments below.
Recent Posts
Recent Comments
- Kardiana on The Lasso – R Tutorial (Part 3)
- Pascal Schmidt on RSelenium Tutorial: A Tutorial to Basic Web Scraping With RSelenium
- Pascal Schmidt on Dynamic Tabs, insertTab, and removeTab For More efficient R Shiny Applications
- Gisa on Persistent Data Storage With a MySQL Database in R Shiny – An Example App
- Nicholas on Dynamic Tabs, insertTab, and removeTab For More efficient R Shiny Applications