Reputation: 121
My question is close to this Legends for multiple fills in ggplot and yet not the same. Let me explain.
I have a dataframe that looks like this:
df <- data.frame(
'sf'=c('a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c'),
'totalsf'=c(28, NA, NA, 32, NA, NA, 40, NA, NA),
'sl' = c('A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'C'),
'totalsl' = c(35, NA, NA, 40, NA, NA, 25, NA, NA),
'min' = c('aa', 'bb', 'cc', 'aa', 'bb','cc', 'aa', 'bb', 'cc'),
'totalmin' = c(30, 4, 0, 8, 0, 25, 8, 9, 16),
'id' = c(1,2,3,4,5,6,7,8,9))
I basically want to plot totalsf with sf as a fill, totalsl with sl as a fill and totalmin with min as a fill, all with geom_bar, as follows:
g <- ggplot(df %>% mutate(id = id), aes(group=id))
g <- g + geom_bar(aes(x=0, y=totalsf, fill=sf), width=.05, stat="identity")
g <- g + geom_bar(aes(x= 0.05, y=totalsl, fill=sl), width=.05, stat="identity")
g <- g + geom_bar(aes(x=0.1, y=totalmin, fill=min), width=.05, stat="identity")
g <- g + theme_light()
g <- g + theme(axis.title.x=element_blank(),
axis.text.x=element_blank(),
axis.ticks.x=element_blank(),
legend.position="bottom")
g <- g + labs(x = "Variable", y = "y", fill = "x")
g <- g + scale_y_continuous(breaks=seq(0, 100, by=10))
print(g)
This yields the following graph:
Mind you, this is what I want (and I also know how to change the colors but let's not overload the code). Here is the core of my problem: the legend is hideous, I would like ideally to have the three variables having their own legend and not have it in alphabetical order like it is now. Would someone know how to customize the legend so that each variable has it own legend? (basically "sf" as a title with a, b, c colors, "sl" as a title with A, B, C colors and "min" as a title with aa, bb, cc colors).
Thank you in advance for your answers!
Best,
Nathalie
Upvotes: 2
Views: 855
Reputation: 37933
I know of no easy trick, but he ggnewscale
package allows you to map multiple variables to several scales at once, which will result in the legends having multiple titles. You would have to specify a scale and then specify that you want to override the scale. An example based on your code:
library(ggnewscale)
g <- ggplot(df %>% mutate(id = id), aes(group = id)) +
# Note geom_col is shorthand for geom_bar(stat = "identity")
geom_col(aes(x = 0, y = totalsf, fill = sf), width = 0.05) +
# Scale has to be specified, not giving colour values will
# result in all scales being red blue and green.
# guide_legend(order = 1) ensures that the legends appear in your
# order instead of alphanumerically
scale_fill_manual(values = c("red", "green", "blue"),
guide = guide_legend(order = 1)) +
new_scale_fill() +
geom_col(aes(x = 0.05, y = totalsl, fill = sl), width = 0.05) +
scale_fill_manual(values = c("yellow", "magenta", "cyan"),
guide = guide_legend(order = 2)) +
new_scale_fill() +
geom_col(aes(x = 0.1, y = totalmin, fill = min), width = 0.05) +
scale_fill_manual(values = c("black", "grey50", "white"), name = "min") +
theme_light() +
theme(axis.title.x=element_blank(),
axis.text.x=element_blank(),
axis.ticks.x=element_blank(),
legend.position="bottom") +
labs(x = "Variable", y = "y", fill = "x") +
scale_y_continuous(breaks=seq(0, 100, by=10))
Upvotes: 3