Search code examples
rshinyr-leaflet

Remove unwanted white space when rendering leaflet or plot


I want the user of my Shiny app to be able to choose between two types of plots by clicking on radiobuttons in the Events panel. The code I have written works, but the page leaves a huge white space when going from "Map" to "Plot". Is there any way to get rid of the white space and position the plot at the very top?

# Load R packages
library(shiny)
library(shinythemes)
library(tidyverse)
library(leaflet)

set.seed(123)

year <- 2001:2020
event <- sample(1:100, size = 20, replace = TRUE)

dat <- as.data.frame(cbind(year, event))


# Define UI
ui <- fluidPage(
  shinyjs::useShinyjs(),
  theme = shinytheme("journal"),
                navbarPage(
                  "Title",
                  tabPanel("About",
                  ),
                  tabPanel("Events", 
                           fluidPage(
                             titlePanel("Title"),
                             sliderInput("range", label = "Move slider to select time period", min(2001), max(2020),
                                         value = range(2001:2002), step = 1,  sep = "", width = "65%"),
                             sidebarLayout(
                               sidebarPanel(
                                 radioButtons("plotType", "Plot type", choices = c("Map" = "m", "Chart" = "l"))),
                               mainPanel(
                                 leafletOutput("map"),
                                 plotOutput("plot"))
                             )
                    )
            )
      )
)


# Define server function  
server <- function(input, output, session) {
  
  observeEvent(input$plotType, {
    if(input$plotType == "l"){
      shinyjs::disable("range")
    }else{
      shinyjs::enable("range")
    }
  })
  
  
  output$plot <- renderPlot({
    if (input$plotType == "l") {
  
        ggplot(dat, aes(year, event)) +
        geom_line() +
        labs(x = "Year", y = "Events") +
        theme_bw()
    }
  })  
  
  output$map <- renderLeaflet({
    if ( input$plotType == "m") {
      
      leaflet(dat) %>% addTiles() %>%
        fitBounds(~min(11), ~min(54), ~max(67), ~max(24))
    }
  })

  
} # server


# Create Shiny object
shinyApp(ui = ui, server = server)

Solution

  • There is a big space because the map html object still exists, but is empty. To avoid this, I created and observeEvent that hides or show the map output depending on input value. I did the same thing with the plot, in cas you need to add others elements below it.

    Please note that there are others solutions (conditionalPanel for example), I am just giving you the one I think is the simpliest here.

    # Load R packages
    library(shiny)
    library(shinythemes)
    library(tidyverse)
    library(leaflet)
    
    set.seed(123)
    
    year <- 2001:2020
    event <- sample(1:100, size = 20, replace = TRUE)
    
    dat <- as.data.frame(cbind(year, event))
    
    
    # Define UI
    ui <- fluidPage(
      shinyjs::useShinyjs(),
      theme = shinytheme("journal"),
      navbarPage(
        "Title",
        tabPanel("About",
        ),
        tabPanel("Events", 
                 fluidPage(
                   titlePanel("Title"),
                   sliderInput("range", label = "Move slider to select time period", min(2001), max(2020),
                               value = range(2001:2002), step = 1,  sep = "", width = "65%"),
                   sidebarLayout(
                     sidebarPanel(
                       radioButtons("plotType", "Plot type", choices = c("Map" = "m", "Chart" = "l"))),
                     mainPanel(
                       leafletOutput("map"),
                       plotOutput("plot"))
                   )
                 )
        )
      )
    )
    
    
    # Define server function  
    server <- function(input, output, session) {
            
      # hide or show map and plot
      observeEvent(input$plotType, {
        if(input$plotType == "l"){
          shinyjs::disable("range")
          shinyjs::hide("map") 
          shinyjs::show("plot")
        } 
        if(input$plotType == "m"){
          shinyjs::enable("range")
          shinyjs::show("map")
          shinyjs::hide("plot")
        } 
      })
      
      output$plot <- renderPlot({
        req(input$plotType == "l") # good practice to use req instead of if
        ggplot(dat, aes(year, event)) +
          geom_line() +
          labs(x = "Year", y = "Events") +
          theme_bw()
      })  
      
      output$map <- renderLeaflet({
        req(input$plotType == "m")
        leaflet(dat) %>% addTiles() %>%
          fitBounds(~min(11), ~min(54), ~max(67), ~max(24))
      })
      
      
    } # server
    
    
    # Create Shiny object
    shinyApp(ui = ui, server = server)