Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ggarrange(common.legend = TRUE) returns a misleading legend #347

Open
GegznaV opened this issue Oct 13, 2020 · 10 comments
Open

ggarrange(common.legend = TRUE) returns a misleading legend #347

GegznaV opened this issue Oct 13, 2020 · 10 comments

Comments

@GegznaV
Copy link

GegznaV commented Oct 13, 2020

Function ggarrange(common.legend = TRUE) returns a misleading legend. Note the reversed order of factor levels in iris_1 and iris_3 and continuous legend in iris_2.

library(tidyverse)

iris_1 <-
  ggplot(iris, aes(x = Sepal.Length, fill = Species, color = Species)) +
  geom_density(alpha = 0.3, adjust = 1.5)

iris_2 <-
  ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width, color = Sepal.Width)) +
  geom_point()

iris_3 <-
  ggplot(iris, aes(x = Species, y = Sepal.Width, fill = fct_rev(Species))) +
  geom_boxplot()

ggpubr::ggarrange(iris_1, iris_2, iris_3, nrow = 1, common.legend = FALSE)

ggpubr::ggarrange(iris_1, iris_2, iris_3, nrow = 1, common.legend = TRUE)

Created on 2020-10-14 by the reprex package (v0.3.0)

@kassambara
Copy link
Owner

Do you want to merge the legends like below?

library(tidyverse)
suppressPackageStartupMessages(library(ggpubr))

iris_1 <-
  ggplot(iris, aes(x = Sepal.Length, fill = Species, color = Species)) +
  geom_density(alpha = 0.3, adjust = 1.5)

iris_2 <-
  ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width, color = Sepal.Width)) +
  geom_point()

iris_3 <-
  ggplot(iris, aes(x = Species, y = Sepal.Width, fill = fct_rev(Species))) +
  geom_boxplot()


# Merging legends
legend_1 <- get_legend(iris_1)
legend_2 <- get_legend(iris_2)
legend_3 <- get_legend(iris_3)
legends <- ggarrange(legend_1, legend_2, legend_3, nrow=3)

# Combining plots
rm_legend <- function(p){p + theme(legend.position = "none")}
plots <- ggarrange(rm_legend(iris_1), rm_legend(iris_2), rm_legend(iris_3), nrow = 1)

# plots + merged legends
ggarrange(plots, legends, widths = c(0.75, 0.25))

Created on 2020-10-14 by the reprex package (v0.3.0.9001)

@GegznaV
Copy link
Author

GegznaV commented Oct 14, 2020

In this particular case, where a new legend misrepresents data, separate legends would be a more correct solution.

But in case, when the legends can be merged, a single legend should be preferred. E.g., I like this output:

library(tidyverse)

iris_1 <-
  ggplot(iris, aes(x = Sepal.Length, fill = Species, color = Species)) +
  geom_density(alpha = 0.3, adjust = 1.5)

iris_2 <-
  ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width, color = Species)) +
  geom_point()

iris_3 <-
  ggplot(iris, aes(x = Species, y = Sepal.Width, fill = Species)) +
  geom_boxplot()

ggpubr::ggarrange(iris_1, iris_2, iris_3, nrow = 1, common.legend = TRUE)

Created on 2020-10-14 by the reprex package (v0.3.0)

Even more challenging is the situation, where I expect some legends to be merged and some – not. E.g., here I expect 2 legends (one for discrete colors and the other one for continuous colors) but now the legend for continuous colors is missing:

library(tidyverse)

iris_1 <-
  ggplot(iris, aes(x = Sepal.Length, fill = Species, color = Species)) +
  geom_density(alpha = 0.3, adjust = 1.5)

iris_2 <-
  ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width, color = Sepal.Width)) +
  geom_point()

iris_3 <-
  ggplot(iris, aes(x = Species, y = Sepal.Width, fill = Species)) +
  geom_boxplot()

ggpubr::ggarrange(iris_1, iris_2, iris_3, nrow = 1, common.legend = TRUE)

Created on 2020-10-14 by the reprex package (v0.3.0)

@kassambara
Copy link
Owner

OK, I can see the issue know; you want to keep the first and the second legends in the arranged plots.

The current behavior of the option common.legend is to keep only the legend of the first plot. A possible improvement would be to be able to specify something like common.legend = c(1, 2), so that the legends of the first and the second plots are kept.

@GegznaV
Copy link
Author

GegznaV commented Oct 14, 2020

I thought that the function should check and merge the values in several legends to create a single common legend. But now I see that the user decides if all plots can be represented by a legend of the first plot and common.legend = TRUE actually means discard all the legends but the first one.

In no checking is performed and the legends are not actually merged, then common.legend = c(1, 2) would be a nice alternative that enables to keep the legends of interest.

@stragu
Copy link

stragu commented Feb 16, 2022

I believe that a first quick step to resolve this issue would be to properly document the current behaviour.
In version 0.4.0, the argument's description is as follows:

common.legend: logical value. Default is FALSE. If TRUE, a common unique legend will be created for arranged plots.

It really does make it sound like a common legend is created to accurately describe all plots included.

This issue is particularly problematic for combined plots that share the same geometry and colour scale, for example:

library(ggplot2)
library(palmerpenguins)
peng_simple <- ggplot(penguins,
                      aes(x = bill_length_mm,
                          y = bill_depth_mm,
                          colour = bill_depth_mm)) +
  geom_point()
# same, but bill depth is multiplied by 3
peng_triple <-ggplot(penguins,
                     aes(x = bill_length_mm,
                         y = bill_depth_mm * 3,
                         colour = bill_depth_mm * 3)) +
  geom_point()

ggpubr::ggarrange(peng_simple, peng_triple,
                  nrow = 1, common.legend = TRUE)

Created on 2022-02-16 by the reprex package (v2.0.1)

@fthielen
Copy link

I believe that a first quick step to resolve this issue would be to properly document the current behaviour. In version 0.4.0, the argument's description is as follows:

common.legend: logical value. Default is FALSE. If TRUE, a common unique legend will be created for arranged plots.

It really does make it sound like a common legend is created to accurately describe all plots included.

Even more so, it is not true that a "common unique legend" is created because only the first legend is chosen. In my case, I have missing data (NA) for one group in the first plot, but this group is present in all subsequent plots. With common.legend and the current description I expected that all unique groups would be represented instead of only those of the first plot.

@nikbpetrov
Copy link

Following.

@dariotommasini
Copy link

Any updates on this? Is "common.legend" still using the legend of the first plot rather than a merged legend?

@mariofiorini
Copy link

Any updates on this? Is "common.legend" still using the legend of the first plot rather than a merged legend?

I think you can use "legend.grob" to specify which plot to use for the legend.

@megardn
Copy link

megardn commented Nov 13, 2023

anyone found a good workaround for this? I have two plots that have the same continuous color scale, and the legend i get using ggarrange is just totally inaccurate for one of them

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants