Search code examples
rggplot2shinyplotlyggplotly

Issue with ggplotly legend being cropped in R Shiny application


In my Shiny application, depending on the size of the screen, some of the legend information for my ggplotly interactive plots is cropped. Is there a way to fix this?

Here's a small example:

library(shiny)
library(ggplot2)
library(plotly)
library(tidyverse)


df <- tibble(
  year = rep(c(2015:2023), 8),
  number = c(10:18, 20:12, 13:21, 14:22, 19:11,5:13, 18:10, 8:16),
  region = c(rep("Region 1", 9), rep("Region 2", 9),
             rep("Region 3", 9), rep("Region 4", 9), 
             rep("Region 5", 9), rep("Region 6", 9),
             rep("Region 7", 9), rep("Region 8", 9))
)

# Define UI for application that draws a histogram
ui <- fluidPage(

    # Application title
    titlePanel("Example for StackOverflow"),

    # Sidebar with a slider input for number of bins 
    sidebarLayout(
        sidebarPanel(
            sliderInput("bins",
                        "Number of bins:",
                        min = 1,
                        max = 50,
                        value = 30)
        ),

        # Show a plot of the generated distribution
        mainPanel(
           uiOutput("plotpanel")
        )
    )
)

# Define server logic required to draw a histogram
server <- function(input, output) {
  
  output$plotlyObject <- renderPlotly({
    p <- ggplot(df, aes(x = year, y = number, group = region, color = region)) + 
      geom_line(stat= "identity") 
    ggplotly(p) %>% 
      plotly::layout(
        xaxis = list(
          title = list(text = "Year", font = list(size = 14, family = "Arial black")),
          tickfont = list(family = "Arial black"),
          tickangle = -45
        ),
        yaxis = list(
          title = list(text = 
                         "Number of Patients", font = list(size = 14, family = "Arial black")),
          tickfont = list(family = "Arial black")
        ),
        legend = list(
          orientation = "h",
          y = -.25,
          x = -.1
        ) ) %>% 
      plotly::config(displaylogo = FALSE,
                     modeBarButtonsToRemove = list('hoverClosestCartesian',
                                                   'hoverCompareCartesian',
                                                   'autoScale2d',
                                                   'lasso2d',
                                                   'select2d',
                                                   'zoom2d'
                     ))
  })
  
  output$plotpanel <- renderUI({
    wellPanel(
      plotlyOutput("plotlyObject", height = "400px"),
      style = "padding: 5px; border-color: darkgray"
    )
  })

}

# Run the application 
shinyApp(ui = ui, server = server)

Depending on the size of the browser window, sometimes the legend displays correctly but often it does not: plot with cropped legend plot with cropped legend

Are there settings in plotly::layout that will fix this? I haven't found a solution.


Solution

  • you must adjust the margins of the plot using the margin argument in the layout() function.

    library(shiny)
    library(ggplot2)
    library(plotly)
    library(tidyverse)
    
    
    df <- tibble(
      year = rep(c(2015:2023), 8),
      number = c(10:18, 20:12, 13:21, 14:22, 19:11,5:13, 18:10, 8:16),
      region = c(rep("Region 1", 9), rep("Region 2", 9),
                 rep("Region 3", 9), rep("Region 4", 9), 
                 rep("Region 5", 9), rep("Region 6", 9),
                 rep("Region 7", 9), rep("Region 8", 9))
    )
    
    # Define UI for application that draws a histogram
    ui <- fluidPage(
      
      # Application title
      titlePanel("Example for StackOverflow"),
      
      # Sidebar with a slider input for number of bins 
      sidebarLayout(
        sidebarPanel(
          sliderInput("bins",
                      "Number of bins:",
                      min = 1,
                      max = 50,
                      value = 30)
        ),
        
        # Show a plot of the generated distribution
        mainPanel(
          uiOutput("plotpanel")
        )
      )
    )
    
    # Define server logic required to draw a histogram
    server <- function(input, output) {
      
      output$plotlyObject <- renderPlotly({
        p <- ggplot(df, aes(x = year, y = number, group = region, color = region)) + 
          geom_line(stat= "identity") 
        ggplotly(p) %>% 
          plotly::layout(
            xaxis = list(
              title = list(text = "Year", font = list(size = 14, family = "Arial black")),
              tickfont = list(family = "Arial black"),
              tickangle = -45
            ),
            yaxis = list(
              title = list(text = 
                             "Number of Patients", font = list(size = 14, family = "Arial black")),
              tickfont = list(family = "Arial black")
            ),
            legend = list(
              orientation = "h",
              y = -.25,
              x = -.1
            ),
            margin = list(
              l = 100, # adjust the left margin
              r = 100, # adjust the right margin
              t = 50,  # adjust the top margin
              b = 50   # adjust the bottom margin
            )) %>% 
          plotly::config(displaylogo = FALSE,
                         modeBarButtonsToRemove = list('hoverClosestCartesian',
                                                       'hoverCompareCartesian',
                                                       'autoScale2d',
                                                       'lasso2d',
                                                       'select2d',
                                                       'zoom2d'
                         ))
      })
      
      output$plotpanel <- renderUI({
        wellPanel(
          plotlyOutput("plotlyObject", height = "400px"),
          style = "padding: 5px; border-color: darkgray"
        )
      })
      
    }
    
    # Run the application 
    shinyApp(ui = ui, server = server)