Thomas Neitmann
Thomas Neitmann

Reputation: 2722

Reverse the legend order when using ggplotly()

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

Upvotes: 3

Views: 1865

Answers (3)

Thomas Neitmann
Thomas Neitmann

Reputation: 2722

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

Upvotes: 6

Zac Garland
Zac Garland

Reputation: 163

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

Upvotes: 3

Rami Krispin
Rami Krispin

Reputation: 99

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

Upvotes: 1

Related Questions