I have a Shiny application that plots large treemaps. I create the treemap objects ahead of time and serialize them:
library(readr)
library(magrittr)
library(highcharter)
library(treemap)
tm_file_name <- function(num_leaves) {
paste0(as.character(num_leaves), "_leaves.rds")
}
create_rand_treemap <- function(num_leaves) {
random.hierarchical.data(n = num_leaves) %>%
treemap(index = c("index1", "index2", "index3"),
vSize = "x",
draw = FALSE) %>%
hctreemap(allowDrillDown = TRUE) %>%
write_rds(tm_file_name(num_leaves))
}
for (leaves in c(50, 500, 5000)) {
create_rand_treemap(leaves)
}
Then I load them like this:
library(shiny)
library(shinydashboard)
library(shinycssloaders)
library(readr)
library(highcharter)
tm_file_name <- function(num_leaves) paste0(as.character(num_leaves), "_leaves.rds")
load_treemap <- function(num_leaves) tm_file_name(num_leaves) %>% read_rds()
ui <- dashboardPage(
dashboardHeader(
title = "Reproducible Shiny Example",
titleWidth = "100%"
),
dashboardSidebar(
radioButtons(
"num_leaves", "Number of Leaves in Treemap:",
c("50" = 50, "500" = 500, "5000" = 5000)
),
actionButton("createTreemap", "Create Treemap")
),
dashboardBody(
# CSS spinner
withSpinner(highchartOutput("treemap", width = "100%", height = "500px"),
type = 7))
)
server <- function(input, output) {
output$treemap <- renderHighchart({
# load and render only on button press
if (length(input$createTreemap) != 0) {
if (input$createTreemap > 0) {
# notification attempt
progress <- shiny::Progress$new()
on.exit(progress$close())
progress$set(message = 'Generating treemap...')
isolate({load_treemap(input$num_leaves)})
}
}
})
}
shinyApp(ui = ui, server = server)
I would like to display a loading notification or spinner until the treemap has fully rendered.
The above example, live here, contains two attempts at this.
The first attempt uses Shiny progress objects to create a notification. However, the notification only displays for a very short time before disappearing. I believe this is because Shiny only has to read a serialized file and then it thinks the task is complete, but it takes the browser a long time to render the plot.
I've also tried a shinycssloaders
approach, but
- The CSS spinner displays briefly when the application first loads, which I don't want.
- The spinner freezes after several seconds when rendering large treemaps (i.e 5000 leaves).
Lastly, I tried some blind copy-pasting from this SO question, but either couldn't get the solutions there to work with shinydashboard
or to persist until the rendering was complete.
How can I display Shiny notifications until both Shiny and the browser are no longer busy?