Search code examples
rggplot2plotlybar-chartggplotly

How do I keep empty levels in bar plot legend when forwarding to ggplotly?


If you inspect the ggplot output of the code below you will see that all three groups are present in the legend thanks to drop = FALSE. However, when forwarding this to ggplotly() the empty level is no longer there. How do I keep it?

library(ggplot2)
library(plotly)

# data
df <- data.frame(type = factor(c("kiwi", "banana"),
                               levels = c("kiwi", "banana", "apple")),
                 count = c(1, 3))

# ggplot
ggp <- ggplot(df, aes(y = count, fill = type, x = "a_bar")) +
  geom_bar(stat = "identity") +
  scale_fill_manual(values = c("forestgreen", "gold1", "firebrick"),
                    drop = FALSE)

# ggplotly 
ggplotly(ggp)

Solution

  • An option could be using plotly_build to have access to the layers of your plot. After that, you copy one layer (in this case kiwi or banana) and change the argument like name, legendgroup, color, and y coordinates, and append this created layer back to the object. After that, you can plot it again and you will the see apple in your legend. Here is some reproducible code:

    library(ggplot2)
    library(plotly)
    # data
    df <- data.frame(type = factor(c("kiwi", "banana"),
                                   levels = c("kiwi", "banana", "apple")),
                     count = c(1, 3))
    
    # ggplot
    ggp <- ggplot(df, aes(y = count, fill = type, x = "a_bar")) +
      geom_bar(stat = "identity") +
      scale_fill_manual(values = c("forestgreen", "gold1", "firebrick"),
                        drop = FALSE)
    # ggplotly 
    p <- ggplotly(ggp)
    x <- plotly_build(p)
    g <- list(x$x$data[[2]])
    g[[1]]$name <- 'apple'
    g[[1]]$legendgroup <- 'apple'
    g[[1]]$showlegend <- TRUE
    g[[1]]$marker$color <- 'firebrick'
    g[[1]]$y <- 0
    x$x$data <- append(x$x$data, g)
    x
    

    Created on 2023-03-24 with reprex v2.0.2