Reputation: 674
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.
Upvotes: 1
Views: 33
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.
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