Noskario
Noskario

Reputation: 674

How do I hide the spinner of shinycssloaders::withSpinner after I have used shinyjs::hide on the element?

I have a website with a non-constant amount of plots that I show/hide using shinyjs. I also want to have a spinner on the (visible) plots.

Here is what I have created:

library(shiny)
library(ggplot2)

ui <- fluidPage(
  shinyjs::useShinyjs(),
  numericInput("numberOfPlotsToShow", label = "number of plots to show", value = 1),
  plotOutput("p1", height = "150px") |> shinycssloaders::withSpinner(id = "spinner1"),
  plotOutput("p2", height = "150px") |> shinycssloaders::withSpinner(id = "spinner2"),
  plotOutput("p3", height = "150px") |> shinycssloaders::withSpinner(id = "spinner3"),

)

server <- function(input, output, session) {
  plot <- ggplot(iris) + geom_point(aes(x=Sepal.Width, y=Sepal.Length))
  output$p1 <- renderPlot(plot + ggtitle(input$numberOfPlotsToShow))
  output$p2 <- renderPlot(plot + ggtitle(input$numberOfPlotsToShow))
  output$p3 <- renderPlot(plot + ggtitle(input$numberOfPlotsToShow))
  observeEvent(input$numberOfPlotsToShow, {
    N <- input$numberOfPlotsToShow
    for (ii in 1:3) {
      if (ii <= N) {
        shinyjs::show(paste0("p",ii))
      } else {
        shinyjs::hide(paste0("p",ii))
        # shinycssloaders::hideSpinner(paste0("spinner", ii))
      }
    }
  })
}

shinyApp(ui, server, options = list(launch.browser = TRUE))

Unfortunately, when you set the number of visible plots from 1 to 2 by clicking on the triangle in the numeric input, you see the spinner for plot 3 appearing and staying there. Is there a way to make it better? Uncommenting the line with hideSpinner seems to do nothing.

enter image description here

Upvotes: 1

Views: 33

Answers (1)

dog
dog

Reputation: 2496

One could put plotOutputs and Spinners in containers and conditionally show them based on the numeric input by placing both inside a container with containerId and hiding/showing the div shinyjs::show(containerId) or shinyjs::hide(containerId). I also added a dynamic title using ggtitle(paste("Plot", i, "- Showing", numPlots, "plots")) - before you just used the input number as title. Also added min/max to the numeric input.

Result

out

Code

library(shiny)
library(shinyjs)
library(shinycssloaders)
library(ggplot2)

ui <- fluidPage(
  useShinyjs(),
  numericInput("numberOfPlotsToShow", label = "Number of plots to show", value = 1, min = 1, max = 3),
  uiOutput("plotContainer") # Dynamically generate plot container
)

server <- function(input, output, session) {
  # Predefine the base ggplot
  basePlot <- ggplot(iris, aes(x = Sepal.Width, y = Sepal.Length)) +
    geom_point() +
    theme_minimal()
  
  # Dynamically generate plot containers and initially hide them
  output$plotContainer <- renderUI({
    lapply(1:3, function(i) {
      div(
        id = paste0("plot", i),
        style = if_else(i>input$numberOfPlotsToShow, "display: none;", "display: block;"), # Initially hide the plot container
        plotOutput(paste0("p", i), height = "150px") %>% withSpinner(id = paste0("spinner", i))
      )
    })
  })
  
  # Dynamically render plots
  observe({
    numPlots <- input$numberOfPlotsToShow
    lapply(1:3, function(i) {
      plotId <- paste0("p", i)
      containerId <- paste0("plot", i)
      
      if (i <= numPlots) {
        # Render the plot dynamically
        output[[plotId]] <- renderPlot({
          basePlot + ggtitle(paste("Plot", i, "- Showing", numPlots, "plots"))
        })
        # Show the plot container
        shinyjs::show(containerId)
      } else {
        # Hide the plot container
        shinyjs::hide(containerId)
      }
    })
  })
}

shinyApp(ui, server, options = list(launch.browser = TRUE))

Upvotes: 2

Related Questions