2

In a chart I have columns and points. I'm trying to unify the legend; I've already put the same name on the scales, but they still appear separate. Could someone please help me solve this issue?

library(ggplot2)

X <- factor(c("a", "b"))
Y1 <- c(10, 15)
Y2 <- c(22, 23)

df <- data.frame(X, Y1, Y2)

ggplot(data = df, aes(x = X,
                      group = 1)) +
  geom_col(aes(y = Y1,
               fill = "Y1")) +
  geom_line(aes(y = Y2,
                color = "Y2")) +
  geom_point(aes(y = Y2,
                 color = "Y2")) +
  scale_fill_manual(name = "Legend",
                    values = "blue") +
  scale_color_manual(name = "Legend",
                     values = "red")

enter image description here

Daniel Valencia C.
  • 2,159
  • 2
  • 19
  • 38

2 Answers2

2

To merge the legends you also have to use the same values in both the fill and color scale. Additionally you have to tweak the legend a bit by removing the fill color for the "Y2" legend key using the override.aes argument of guide_legend:

EDIT Thanks to the comment by @aosmith. To make this approach work for ggplot2 version <=3.3.3 we have to explicitly set the limits of both scales.

library(ggplot2)

X <- factor(c("a", "b"))
Y1 <- c(10, 15)
Y2 <- c(22, 23)

df <- data.frame(X, Y1, Y2)

ggplot(data = df, aes(x = X,
                      group = 1)) +
  geom_col(aes(y = Y1,
               fill = "Y1")) +
  geom_line(aes(y = Y2,
                color = "Y2")) +
  geom_point(aes(y = Y2,
                 color = "Y2")) +
  scale_fill_manual(name = "Legend",
                    values = c(Y1 = "blue", Y2 = "red"), limits = c("Y1", "Y2")) +
  scale_color_manual(name = "Legend",
                     values = c(Y1 = "blue", Y2 = "red"), limits = c("Y1", "Y2")) +
  guides(color = guide_legend(override.aes = list(fill = c("blue", NA))))

stefan
  • 90,330
  • 6
  • 25
  • 51
  • I am unable to reproduce this code. The following error message appears: Error in [[<-.data.frame`(`*tmp*`, i, value = c("blue", NA)) : replacement has 2 rows, data has 1 – Daniel Valencia C. Jun 29 '21 at 14:41
  • Hm. Weird. I just ran the code again via the reprex package. And it works fine. Maybe an issue with the ggplot2 versions? I'm using ggplot2 3.3.5. – stefan Jun 29 '21 at 14:53
  • my version is 4.0.5. Is there a way to do this in version 4.0.5? – Daniel Valencia C. Jun 29 '21 at 14:57
  • Just FYI, based on [this issue that has been marked as a bug](https://github.com/tidyverse/ggplot2/issues/4511) I'm not positive this approach will always work in the future without explicitly setting the `limits` in each scale. – aosmith Jun 29 '21 at 15:07
  • 1
    @DanielValenciaC. Check your ggplot2 version, i.e. `packageVersion("ggplot")`. 4.0.5 is the R-Version. – stefan Jun 29 '21 at 15:18
  • @stefan sorry. My ggplot2 version is 3.3.3. I'm gonna update – Daniel Valencia C. Jun 29 '21 at 15:34
  • @aosmith. Thanks for sharing. Quite interesting. Could swear that this (or something similar) worked in ggplot2 <3.3.4 too. Will keep an eye on this issue. – stefan Jun 29 '21 at 15:53
  • @stefan Yeah, I only bring it up because your solution didn't work for me in 3.3.3 and seems potentially related to that issue. I upgraded before I could test more, but, I *think* this is because the default `drop = TRUE` came into play if you didn't set the `limits`. – aosmith Jun 29 '21 at 16:05
2

Another option would to make only one of the legends and then manually change that legend to have it represent all the layers.

In this case, I make a fill legend but set color to constants outside of aes(). I force the inclusion of the line/point layers by adding show.legend = TRUE.

Then I add the extra value to fill, setting both values and limits in scale_fill_manual(). Note I set the Y2 to have a transparent fill.

Finally I make manual changes to the legend to keep the lines and points only for the second legend key with override.aes in guide_legend().

ggplot(data = df, aes(x = X,
                      group = 1)) +
    geom_col(aes(y = Y1,
                 fill = "Y1")) +
    geom_line(aes(y = Y2), color = "red", show.legend = TRUE) +
    geom_point(aes(y = Y2), color = "red", show.legend = TRUE) +
    scale_fill_manual(name = "Legend",
                      values = c(Y1 = "blue", Y2 = "transparent"),
                      limits = c("Y1", "Y2")) +
    guides(fill = guide_legend(override.aes = list(shape = c(NA, 19),
                                                   linetype = c(0, 1))))

Created on 2021-06-29 by the reprex package (v2.0.0)

aosmith
  • 34,856
  • 9
  • 84
  • 118