Reputation: 1
I have a moderatly large data.frame (5000 - 10000) in my Shiny app that should be rendered dynamically as a datatable
, together with dynamically created action buttons.
I used the pattern from this stackoverflow post to create the buttons: R Shiny: Handle Action Buttons in Data Table
This works perfectly, however, with larger data.frames i ran into performance issues. Converting the shiny.tags
to character (either with as.character()
or with htmltools::renderTags()
) makes things very slow. I ran a small microbenchmark on this:
library(microbenchmark)
library(shiny)
library(ggplot2)
library(dplyr)
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, union
create_info_btns_mapChr <- function(FUN, len, id, ...) {
args <- rlang::list2(...)
list <-
seq_len(len) %>% purrr::map(.f = FUN, inputId = paste0(id), ...)
chr <- list %>% purrr::map( ~ as.character(.x))
}
create_info_btns_map <- function(FUN, len, id, ...) {
args <- rlang::list2(...)
list <-
seq_len(len) %>% purrr::map(.f = FUN, inputId = paste0(id), ...)
}
df <- diamonds[1:10000, ]
mbm <- microbenchmark::microbenchmark(tags = {
create_info_btns_map(
actionButton,
nrow(df),
id = "test_",
label = icon("info-circle"),
icon = NULL)
},
html = {
out <- create_info_btns_mapChr(
actionButton,
nrow(df),
id = "test_",
label = icon("info-circle"),
icon = NULL)
},
times = 2)
mbm
#> Unit: seconds
#> expr min lq mean median uq max neval cld
#> tags 1.411491 1.411491 1.424619 1.424619 1.437746 1.437746 2 a
#> html 15.852125 15.852125 15.951569 15.951569 16.051013 16.051013 2 b
autoplot(mbm)
#> Coordinate system already present. Adding new coordinate system, which will replace the existing one.
Created on 2022-10-07 by the reprex package (v2.0.1)
Output image can be found here (cant include it directly yet) "https://i.imgur.com/eHhwbEo.png"
I have not found good entry points for optimization here. Maybe not adding all the buttons at once, but only for the visible records - but I would not know how to tackle that.. Any suggestions?
Best
Upvotes: 0
Views: 135
Reputation: 24845
Use a helper function to generate the character tag directly. In addition, in the example below, I convert the frame (df
) to data.table
, using setDT()
, and then I add the btn
column inplace using :=
library(data.table)
df <- diamonds[1:10000, ]
setDT(df)
make_button <- function(id) {
paste0('<button id="',id,
'" type="button" class="btn btn-default action-button">',
id,'_btn</button>')
}
# This takes about 1 millisecond on my machine
df[,id:=.I][, btn:=make_button(id)]
Output (head(df)
):
carat cut color clarity depth table price x y z id
<num> <ord> <ord> <ord> <num> <num> <int> <num> <num> <num> <int>
1: 0.23 Ideal E SI2 61.5 55 326 3.95 3.98 2.43 1
2: 0.21 Premium E SI1 59.8 61 326 3.89 3.84 2.31 2
3: 0.23 Good E VS1 56.9 65 327 4.05 4.07 2.31 3
4: 0.29 Premium I VS2 62.4 58 334 4.20 4.23 2.63 4
5: 0.31 Good J SI2 63.3 58 335 4.34 4.35 2.75 5
6: 0.24 Very Good J VVS2 62.8 57 336 3.94 3.96 2.48 6
btn
<char>
1: <button id="1" type="button" class="btn btn-default action-button">1_btn</button>
2: <button id="2" type="button" class="btn btn-default action-button">2_btn</button>
3: <button id="3" type="button" class="btn btn-default action-button">3_btn</button>
4: <button id="4" type="button" class="btn btn-default action-button">4_btn</button>
5: <button id="5" type="button" class="btn btn-default action-button">5_btn</button>
6: <button id="6" type="button" class="btn btn-default action-button">6_btn</button>
Adjust your make_btn
function above to fit your needs.
Upvotes: 1