2

this question builds off of this solution provided at enter link description here

as follows.

library(ggplot2)
library(gtable)
library(grid)

diamonds$cut = factor(diamonds$cut, levels=c("Fair","Good"," ","Very Good",
                                             "Premium","Ideal"))

p = ggplot(diamonds, aes(color, fill = cut)) + 
       geom_bar() + 
       scale_fill_manual(values = 
              c(hcl(seq(15, 325, length.out = 5), 100, 65)[1:2], 
              "white",
              hcl(seq(15, 325, length.out = 5), 100, 65)[3:5]),
              drop = FALSE) +
  guides(fill = guide_legend(ncol = 2, title.position = "top")) +
  theme(legend.position = "bottom", 
        legend.key = element_rect(fill = "white"))

# Get the ggplot grob
g = ggplotGrob(p)

# Get the legend
leg = g$grobs[[which(g$layout$name == "guide-box")]]$grobs[[1]]

# Set up the two sub-titles as text grobs
st = lapply(c("First group", "Second group"), function(x) {
   textGrob(x, x = 0, just = "left", gp = gpar(cex = 0.8)) } )

# Add a row to the legend gtable to take the legend sub-titles
leg = gtable_add_rows(leg, unit(1, "grobheight", st[[1]]) + unit(0.2, "cm"), pos =  3)

# Add the sub-titles to the new row
leg = gtable_add_grob(leg, st, 
            t = 4, l = c(2, 6), r = c(4, 8), clip = "off")

# Add a little more space between the two columns
leg$widths[[5]] = unit(.6, "cm")

# Move the legend to the right
 leg$vp = viewport(x = unit(.95, "npc"), width = sum(leg$widths), just = "right")

# Put the legend back into the plot
g$grobs[[which(g$layout$name == "guide-box")]] = leg

# Draw the plot
grid.newpage()
grid.draw(g)

This provides the figure (from there).

enter image description here

However, I want to do two things.

  1. First group: I want to relabel "Fair" and "Good" to "Very Good" and "Premium" respectively. So they are Very Good and Premium of each group (first and second).

  2. The second thing I would like to do is to put them in one line (in two columns of First group and second group side by side, everything in one line, to save vertical space.

How do I do this? Please let me know if my questions are not clear. I feel like I am quite close here, but this solution does not quite answer my question. Many thanks!

user3236841
  • 1,088
  • 1
  • 15
  • 39
  • Your question seems unclear.(And multipart part questions are discouraged.) Why not modify the data argument before the ggplot call? And put into "one line"? What does that mean? – IRTFM Aug 01 '21 at 06:32

1 Answers1

2

First, you could simply change the labels appearing in the legend via the labels argument of scale_fill_manual. Second, instead of fiddling around with the gtable which probably is even more demanding if you want the groups in one line you could make use of the ggnewscale package as already proposed by this answer in the same post you added as link. While that answer additionally makes use of the relayer package my approach is a bit different in that I rearrange the order of the layers such that the relayer package is not necessary:

library(ggplot2)
library(ggnewscale)

diamonds$cut = factor(diamonds$cut, levels=c("Fair","Good", "Very Good",
                                             "Premium","Ideal"))

labels <- levels(diamonds$cut)
labels <- setNames(labels, labels)
labels["Fair"] <- "Very Good"
labels["Good"] <- "Premium"

colors <- hcl(seq(15, 325, length.out = 5), 100, 65)
colors <- setNames(colors, levels(diamonds$cut))

ggplot() + 
  geom_bar(data = diamonds, aes(color, fill = cut)) + 
  scale_fill_manual(aesthetics = "fill", values = colors, labels = labels[1:2],
                    breaks = names(colors)[1:2], name = "First Group:",
                    guide = guide_legend(title.position = "left", order = 1)) +
  new_scale_fill() +
  geom_bar(data = diamonds, aes(color, fill = cut)) + 
  scale_fill_manual(aesthetics = "fill", values = colors, labels = labels[3:5],
                    breaks = names(colors)[3:5], name = "Second Group:",
                    guide = guide_legend(title.position = "left", order = 0)) +
  theme(legend.position = "bottom", 
        legend.direction = "horizontal",
        legend.key = element_rect(fill = "white"))

stefan
  • 90,330
  • 6
  • 25
  • 51
  • Thank you. My issue is that I am really using boxplots, so it is one call to a function. I don't know if I can make your suggestion work with boxplots, one for each group. I thought that the legend issue would be the same. However, this answers this specific question so I will mark it as such. Thanks very much again! – user3236841 Aug 01 '21 at 13:41
  • I decided to post my more complicated question with an example here because I can not figure this out from here. The new question is here: https://stackoverflow.com/questions/68611542/changing-legend-of-faceted-boxplot-in-ggplot2-to-have-groups-with-similar-names – user3236841 Aug 01 '21 at 14:50