Shiny keeps empty blanc space when plots are not rendered

Viewed 876

Context: a shiny app allows user to choose to display or not tables and graphs.

Problem: UI keeps a big white "placeholder" space for plots if they are not displayed (this behaviour is not wanted). But, when it comes to tables, UI doesn't display this empty white space (expected behaviour).

Question: How to prevent Shiny from keeping empty placeholder for plots?

Previous researches: This question has already been asked here but the answer by @the-mad-statter doesn't fits my needs. I would like to understand why Shiny has this behaviour and if possible correct it without changing the UI.

Many thanks for yout help! Please find below a reproductible example and some screenshots.

Reproductible example

library(shiny)
library(tidyverse)

# basic user interface
ui <- fluidPage(
    checkboxGroupInput(inputId = "checkboxes", label = NULL ,choices = list("Plot"="plot", "Table"="table")),
    plotOutput(outputId = "plotdf1"),
    tableOutput(outputId = "tabledf"),
    plotOutput(outputId = "plotdf2")
)

# server side calculations
server <- function(input, output, session) {
    df = mtcars
    output$plotdf1 = renderPlot({
      if("plot"%in%input$checkboxes){
      ggplot(data = df, aes(x = disp, y = qsec)) +
        geom_line()
      }
    })

    output$tabledf = renderTable({
      if("table"%in%input$checkboxes){
      df[1:5,]
      }
    })
    output$plotdf2 = renderPlot({
      if("plot"%in%input$checkboxes){
        ggplot(data = df, aes(x = gear)) +
          geom_bar()
      }
    })

}
shinyApp(ui,server)

Screenshots: All objects displayed:

all objects

When the table is removed the UI "fill"/removes the space left empty

table ok

But when plots are removed, empty placeholder remains

plot not ok

1 Answers

1. Using conditionalPanel

You can use a conditionalPanel to hide the plot area when Plot is not selected:

ui <- fluidPage(
  checkboxGroupInput(inputId = "checkboxes", label = NULL, 
                     choices = list("Plot"="plot", "Table"="table")),
  conditionalPanel(
    "input.checkboxes.indexOf('plot') > -1",
    plotOutput(outputId = "plotdf1")
  ),
  tableOutput(outputId = "tabledf"),
  conditionalPanel(
    "input.checkboxes.indexOf('plot') > -1",
    plotOutput(outputId = "plotdf2")
  )
)

2. Using renderUI()

As suggested in comments section, another approach with renderUI():

Modifications are much more important than in the 1st idea but if it fails this one might be a good alternative.

library(shiny)
library(tidyverse)

# basic user interface
ui <- fluidPage(
  checkboxGroupInput(
    inputId = "checkboxes",
    label = NULL ,
    choices = list("Plot" = "plot", "Table" = "table")
  ),
  uiOutput(outputId = "uiplotdf1"),
  uiOutput(outputId = "uitabledf"),
  uiOutput(outputId = "uiplotdf2")
)

# server side calculations
server <- function(input, output, session) {
  df = mtcars
  # create the object to render and the conditional UI display anlong with it
  # 1st plot------------------
  # object
  output$plotdf1 = renderPlot({
    ggplot(data = df, aes(x = disp, y = qsec)) +
      geom_line()
  })
  # conditional UI
  output$uiplotdf1 = renderUI({
    if ("plot" %in% input$checkboxes) {
      plotOutput(outputId = "plotdf1")
    }
  })
  # table----------------------
  output$tabledf = renderTable({
    df[1:5, ]
  })
  output$uitabledf = renderUI({
    if ("table" %in% input$checkboxes) {
      tableOutput(outputId = "tabledf")
    }
  })
  #2nd plot---------------------
  output$plotdf2 = renderPlot({
    ggplot(data = df, aes(x = gear)) +
      geom_bar()
  })
  output$uiplotdf2 = renderUI({
    # this render is not pulled with the 1st one bcse otherwise we have to put plots in a "bigger" element (such as fluidrow)
    if ("plot" %in% input$checkboxes) {
      plotOutput(outputId = "plotdf2")
    }
  })

}
shinyApp(ui, server)
Related