Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

keep two legends from ggplot plot using plotly::ggplotly

When I convert a ggplot with two separate legends to plotly (using ggplotly), the two legends merge. Does anyone know how to prevent this?

library(tidyverse)
library(plotly)
df <- data.frame(date = 
                   as.Date(c("01/01/1998", "10/01/1998", "15/01/1998", 
                             "25/01/1998", "01/02/1998", "12/02/1998", "20/02/1998"), "%d/%m/%Y"),
                 date2 = as.Date(c(NA, "10/01/1998", NA, 
                                   NA, NA, NA, NA), "%d/%m/%Y"),
                 counts = c(12, 10, 2, 24, 15, 1, 14),
                 yes_no = c("yes", "yes", "yes", "no", "no", "no", "no"))
gg <- ggplot(df, aes(x = date, y = counts)) +
  geom_line() +
  geom_ribbon(aes(ymin = 0, ymax = counts, fill = yes_no), color = NA, alpha = 0.5) +
  ggplot2::scale_fill_brewer(name = "status 1", palette = "Accent") +
  geom_vline(mapping = aes(xintercept = as.numeric(date2), col = "mystatistic")) +
  scale_color_manual(name = "statistics", values = c("mystatistic" = "red")) 
gg

which produces two legends:

enter image description here

but when I convert to plotly:

ggplotly(gg)

it returns one legend with second legend title missing:

enter image description here

This link is useful to remove the parenthesis and comma from the current plot but that's not the fix I am looking for.

thanks

like image 355
user63230 Avatar asked Jul 03 '26 20:07

user63230


1 Answers

In general the concept of legends is different in ggplot2 and plotly.

In ggplot2 legends reflect aesthetics, i.e. for your example you get a legend for the fill aes and one for the color aes. Additionally for each legend the legend entries reflect the categories of the variable mapped on the aesthetic.

In contrast, in plotly versions < 5.15 there is only one legend (while plotly >= 5.15 supports multiple legends, this feature is at present not supported by the plotly for R package) and each legend entry reflects a trace.

But one option to achieve your desired result would be to use legendgroups which allows to collect traces in groups and requires to manipulate the plotly object, e.g. in the code below I group the traces into two groups which I call fill and color (Note: There is also a fourth trace with index 1 reflecting the black geom_line, which however is not displayed in the legend). Second, we can assign a title to each legend group and finally get rid of the overall legend title.

library(ggplot2)
library(plotly)

gg <- ggplot(df, aes(x = date, y = counts)) +
  geom_line() +
  geom_ribbon(aes(ymin = 0, ymax = counts, fill = yes_no), color = NA, alpha = 0.5) +
  ggplot2::scale_fill_brewer(name = "status 1", palette = "Accent") +
  geom_vline(mapping = aes(xintercept = as.numeric(date2), col = "mystatistic")) +
  scale_color_manual(name = "statistics", values = c("mystatistic" = "red"))

ggp <- ggplotly(gg)

# Assign the traces to legendgroups
ggp$x$data[[2]]$legendgroup <- "fill"
ggp$x$data[[3]]$legendgroup <- "fill"
ggp$x$data[[4]]$legendgroup <- "color"

# Add titles for the legendgroups
ggp$x$data[[2]]$legendgrouptitle <- list(text = "status 1")
ggp$x$data[[3]]$legendgrouptitle <- list(text = "status 1")
ggp$x$data[[4]]$legendgrouptitle <- list(text = "statistics")

# Remove overall legend title
ggp$x$layout$legend$title <- NULL

ggp

enter image description here

like image 164
stefan Avatar answered Jul 06 '26 12:07

stefan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!