2

I would like to reverse the order of the legend for a horizontal bar chart. When adding guides(fill = guide_legend(reverse = TRUE)) to the ggplot it works fine (see second plot). However, after applying ggplotly() the legend is again in the default order.

How to reverse the order of the plotly legend without changing the order of the bars?

library(ggplot2)
library(dplyr)
data(mtcars)

p1 <- mtcars %>%
  count(cyl, am) %>%
  mutate(cyl = factor(cyl), am = factor(am)) %>%
  ggplot(aes(cyl, n, fill = am)) +
  geom_col(position = "dodge") +
  coord_flip()
p1


p2 <- p1 + guides(fill = guide_legend(reverse = TRUE))
p2

plotly::ggplotly(p2)

enter image description here

Thomas Neitmann
  • 2,552
  • 1
  • 16
  • 31

3 Answers3

6

Adding to the great answer of @Zac Garland here is a solution that works with legends of arbitrary length:

library(ggplot2)
library(dplyr)

reverse_legend_labels <- function(plotly_plot) {
  n_labels <- length(plotly_plot$x$data)
  plotly_plot$x$data[1:n_labels] <- plotly_plot$x$data[n_labels:1]
  plotly_plot
}

p1 <- mtcars %>%
  count(cyl, am) %>%
  mutate(cyl = factor(cyl), am = factor(am)) %>%
  ggplot(aes(cyl, n, fill = am)) +
  geom_col(position = "dodge") +
  coord_flip()

p2 <- mtcars %>%
  count(am, cyl) %>%
  mutate(cyl = factor(cyl), am = factor(am)) %>%
  ggplot(aes(am, n, fill = cyl)) +
  geom_col(position = "dodge") +
  coord_flip()
p1 %>%
  plotly::ggplotly() %>%
  reverse_legend_labels()

enter image description here

p2 %>%
  plotly::ggplotly() %>%
  reverse_legend_labels()

enter image description here

Thomas Neitmann
  • 2,552
  • 1
  • 16
  • 31
3

When you call ggplotly, it's really just creating a list and a function call on that list.

So if you save that intermediate step, you can modify the list directly. and as such, modify the plot output.

library(ggplot2)
library(dplyr)
data(mtcars)

p1 <- mtcars %>%
  count(cyl, am) %>%
  mutate(cyl = factor(cyl), am = factor(am)) %>%
  ggplot(aes(cyl, n, fill = am)) +
  geom_col(position = "dodge") +
  coord_flip()

html_plot <- ggplotly(p1)

replace_1 <- html_plot[["x"]][["data"]][[2]]
replace_2 <- html_plot[["x"]][["data"]][[1]]
html_plot[["x"]][["data"]][[1]] <- replace_1
html_plot[["x"]][["data"]][[2]] <- replace_2

html_plot

plot output

Zac Garland
  • 153
  • 7
1

A simple solution is to define the order of the levels of the factor variable am:

library(ggplot2)
library(dplyr)
data(mtcars)


df <-  mtcars %>%
  count(cyl, am) %>%
  mutate(cyl = factor(cyl), am = factor(as.character(am), levels = c("1", "0"))) 

head(df)


p1 <- df %>%
  ggplot(aes(cyl, n, fill = am)) +
  geom_col(position = "dodge") +
  coord_flip()
p1

enter image description here

plotly::ggplotly(p1)

enter image description here

Rami Krispin
  • 79
  • 1
  • 6
  • Thanks @Rami Krispin! What I am trying to achieve though is that the color of the upper bar matches the color of the upper legend. Here this issue remains. The upper bar is green but the upper legend is orange. – Thomas Neitmann Jan 06 '20 at 13:05