Legends for multiple fillings in ggplot

I am new to ggplot2 . So, I apologize if this question sounds too thorough. I would be grateful for any recommendations. I spent 4 hours on this and looked at SO SO R: Custom Legend for layered ggplot for guidance, but nothing worked .

Purpose: I want to be able to apply the legend to different fill colors used for different layers. I am doing this example only to test my understanding of ggplot2 concept concepts.

In addition, I do not want to change the type of figure; Changing the fill color is normal - by โ€œfillโ€ I do not mean that we can change the โ€œcolorโ€. Therefore, I would appreciate if you could correct my mistakes in my work.

Try 1: Here is the code for bare bones without any manually set colors.

 ggplot(mtcars, aes(disp,mpg)) + geom_point(aes(fill = factor(vs)),shape = 23, size = 8, alpha = 0.4) + geom_point (aes(fill = factor(cyl)),shape = 21, size = 2) + geom_rect(aes(xmin = min(disp)-5, ymax = max(mpg) + 2,fill = "cyan"), xmax = mean(range(mtcars$disp)),ymin = 25, alpha = 0.02) ##region for high mpg 

The output looks like this: enter image description here

Now there are several problems with this image:

Problem 1) A blue rectangle that shows โ€œhigh mpg areasโ€ has lost its legend.

Problem 2) ggplot tries to combine the legend of two geom_point() and as a result, the legend for two geom_point() also mixes.

Problem 3) The default color palette used by ggplot2 makes the colors indistinguishable to my eyes.

So, I tried to manually set the iestart colors with fix number 3 above.

 ggplot(mtcars, aes(disp,mpg)) + geom_point(aes(fill = factor(vs)),shape = 23, size = 8, alpha = 0.4)+ geom_point(aes(fill = factor(cyl)),shape = 21, size = 2) + geom_rect(aes(xmin = min(disp)-5, ymax = max(mpg) + 2,fill = "cyan"), xmax = mean(range(mtcars$disp)),ymin = 25, alpha = 0.02) + scale_fill_manual(values = c("green","blue", "black", "cyan", "red", "orange"), labels=c("4 gears","6 gears","8 gears","High mpg","0","1")) 

Here is the conclusion: enter image description here Unfortunately, some of the problems highlighted above persist. There is a new question about the order.

Problem # 4: It seems to me that ggplot2 expects me to provide colors in the order in which the layers were set. those. first set the color for mtcars$vs fill, then mtcars$cyl fill and finally a rectangle with blue color. I was able to fix this by changing the code like this:

 ggplot(mtcars, aes(disp,mpg)) + geom_point(aes(fill = factor(vs)),shape = 23, size = 8, alpha = 0.4) + geom_point(aes(fill = factor(cyl)),shape = 21, size = 2) + geom_rect(aes(xmin = min(disp)-5, ymax = max(mpg) + 2,fill = "cyan"), xmax = mean(range(mtcars$disp)),ymin = 25, alpha = 0.02) + scale_fill_manual(values = c("red", "orange", "green", "blue", "black", "cyan"), labels=c("0","1","4 gears","6 gears","8 gears","High mpg")) #changed the order 

So, I have two questions:

Question 1: How can I fix legends - I want three different legends - one to fill a rectangle (which I call a rectangle with high mpg), another to fill for geom_point() represented by mtcars$vs and the last to fill for geom_point() provided by mtcars$cyl

Question 2: Is my hypothesis about the ordering of colors in layers correct (i.e. problem No. 4, discussed above)? I doubt it, because if there are many factors, we need to remember them, then arrange them according to the drawn layers, and finally, do not forget to apply the color palette manually in the order in which each geom_*() layer is created?

As a beginner, I spent many hours on it, googling everywhere. So, I would appreciate your kind guidance.

+8
source share
3 answers

(Note, I edited this to clear it after a few rewinds - look at the change history for most of what I tried.)

Scales are really intended for displaying data of one type. One approach is to use both col and fill to get at least 2 legends. Then you can add linetype and hack it a bit using override.aes . It should be noted that I think that this (in the general case) will lead you to more problems than it solves. If you desperately need to do this, you can (example below). However, if I can convince you: I beg you not to use this approach, if at all possible. Mapping to different things (e.g. shape and linetype ) is likely to result in less clutter. I will give an example of this below.

In addition, when setting the color or fill manually, it is always recommended to use named vectors for palette which ensure that the colors match what you want. If not, then matches occur in order of factor levels.

 ggplot(mtcars, aes(x = disp , y = mpg)) + ##region for high mpg geom_rect(aes(linetype = "High MPG") , xmin = min(mtcars$disp)-5 , ymax = max(mtcars$mpg) + 2 , fill = "cyan" , xmax = mean(range(mtcars$disp)) , ymin = 25 , alpha = 0.02 , col = "black") + ## test diff region geom_rect(aes(linetype = "Other Region") , xmin = 300 , xmax = 400 , ymax = 30 , ymin = 25 , fill = "yellow" , alpha = 0.02 , col = "black") + geom_point(aes(fill = factor(vs)),shape = 23, size = 8, alpha = 0.4) + geom_point (aes(col = factor(cyl)),shape = 19, size = 2) + scale_color_manual(values = c("4" = "red" , "6" = "orange" , "8" = "green") , name = "Cylinders") + scale_fill_manual(values = c("0" = "blue" , "1" = "black" , "cyan" = "cyan") , name = "V/S" , labels = c("0?", "1?", "High MPG")) + scale_linetype_manual(values = c("High MPG" = 0 , "Other Region" = 0) , name = "Region" , guide = guide_legend(override.aes = list(fill = c("cyan", "yellow") , alpha = .4))) 

enter image description here

Here is a plot that I think will work better in almost all use cases:

 ggplot(mtcars, aes(x = disp , y = mpg)) + ##region for high mpg geom_rect(aes(linetype = "High MPG") , xmin = min(mtcars$disp)-5 , ymax = max(mtcars$mpg) + 2 , fill = NA , xmax = mean(range(mtcars$disp)) , ymin = 25 , col = "black") + ## test diff region geom_rect(aes(linetype = "Other Region") , xmin = 300 , xmax = 400 , ymax = 30 , ymin = 25 , fill = NA , col = "black") + geom_point(aes(col = factor(cyl) , shape = factor(vs)) , size = 3) + scale_color_brewer(name = "Cylinders" , palette = "Set1") + scale_shape(name = "V/S") + scale_linetype_manual(values = c("High MPG" = "dotted" , "Other Region" = "dashed") , name = "Region") 

enter image description here

For some reason, you insist on using fill . Here's an approach that builds exactly the same plot as the first in this answer, but uses fill as the aesthetics for each of the layers. If this is not what you are insisting on, then I still do not know what you are looking for.

 ggplot(mtcars, aes(x = disp , y = mpg)) + ##region for high mpg geom_rect(aes(linetype = "High MPG") , xmin = min(mtcars$disp)-5 , ymax = max(mtcars$mpg) + 2 , fill = "cyan" , xmax = mean(range(mtcars$disp)) , ymin = 25 , alpha = 0.02 , col = "black") + ## test diff region geom_rect(aes(linetype = "Other Region") , xmin = 300 , xmax = 400 , ymax = 30 , ymin = 25 , fill = "yellow" , alpha = 0.02 , col = "black") + geom_point(aes(fill = factor(vs)),shape = 23, size = 8, alpha = 0.4) + geom_point (aes(col = "4") , data = mtcars[mtcars$cyl == 4, ] , shape = 21 , size = 2 , fill = "red") + geom_point (aes(col = "6") , data = mtcars[mtcars$cyl == 6, ] , shape = 21 , size = 2 , fill = "orange") + geom_point (aes(col = "8") , data = mtcars[mtcars$cyl == 8, ] , shape = 21 , size = 2 , fill = "green") + scale_color_manual(values = c("4" = NA , "6" = NA , "8" = NA) , name = "Cylinders" , guide = guide_legend(override.aes = list(fill = c("red","orange","green")))) + scale_fill_manual(values = c("0" = "blue" , "1" = "black" , "cyan" = "cyan") , name = "V/S" , labels = c("0?", "1?", "High MPG")) + scale_linetype_manual(values = c("High MPG" = 0 , "Other Region" = 0) , name = "Region" , guide = guide_legend(override.aes = list(fill = c("cyan", "yellow") , alpha = .4))) 

Because I apparently can not leave it alone - here is another approach that uses only fill for aesthetics, and then make separate legends for separate layers and pricking it all together, using cowplot freely after this lesson .

 library(cowplot) library(dplyr) theme_set(theme_minimal()) allScales <- c("4" = "red" , "6" = "orange" , "8" = "green" , "0" = "blue" , "1" = "black" , "High MPG" = "cyan" , "Other Region" = "yellow") mainPlot <- ggplot(mtcars, aes(x = disp , y = mpg)) + ##region for high mpg geom_rect(aes(fill = "High MPG") , xmin = min(mtcars$disp)-5 , ymax = max(mtcars$mpg) + 2 , xmax = mean(range(mtcars$disp)) , ymin = 25 , alpha = 0.02) + ## test diff region geom_rect(aes(fill = "Other Region") , xmin = 300 , xmax = 400 , ymax = 30 , ymin = 25 , alpha = 0.02) + geom_point(aes(fill = factor(vs)),shape = 23, size = 8, alpha = 0.4) + geom_point (aes(fill = factor(cyl)),shape = 21, size = 2) + scale_fill_manual(values = allScales) vsLeg <- (ggplot(mtcars, aes(x = disp , y = mpg)) + geom_point(aes(fill = factor(vs)),shape = 23, size = 8, alpha = 0.4) + scale_fill_manual(values = allScales , name = "VS") ) %>% ggplotGrob %>% {.$grobs[[which(sapply(.$grobs, function(x) {x$name}) == "guide-box")]]} cylLeg <- (ggplot(mtcars, aes(x = disp , y = mpg)) + geom_point (aes(fill = factor(cyl)),shape = 21, size = 2) + scale_fill_manual(values = allScales , name = "Cylinders") ) %>% ggplotGrob %>% {.$grobs[[which(sapply(.$grobs, function(x) {x$name}) == "guide-box")]]} regionLeg <- (ggplot(mtcars, aes(x = disp , y = mpg)) + geom_rect(aes(fill = "High MPG") , xmin = min(mtcars$disp)-5 , ymax = max(mtcars$mpg) + 2 , xmax = mean(range(mtcars$disp)) , ymin = 25 , alpha = 0.02) + ## test diff region geom_rect(aes(fill = "Other Region") , xmin = 300 , xmax = 400 , ymax = 30 , ymin = 25 , alpha = 0.02) + scale_fill_manual(values = allScales , name = "Region" , guide = guide_legend(override.aes = list(alpha = 0.4))) ) %>% ggplotGrob %>% {.$grobs[[which(sapply(.$grobs, function(x) {x$name}) == "guide-box")]]} legendColumn <- plot_grid( # To make space at the top vsLeg + theme(legend.position = "none") # Plot the legends , vsLeg, regionLeg, cylLeg # To make space at the bottom , vsLeg + theme(legend.position = "none") , ncol = 1 , align = "v") plot_grid(mainPlot + theme(legend.position = "none") , legendColumn , rel_widths = c(1,.25)) 

enter image description here

As you can see, the result is almost identical to the first method, which I demonstrated how to do it, but now does not use any other aesthetics. I still do not understand why you think this difference is important, but at least now there is another way to skin the cat. I can use this approach for generality (for example, when several graphs have a common aesthetics of color / symbol / line type, and you want to use one legend), but I do not see the point in using it here.

+11
source

There is currently an excellent ggnewscale package that allows you to do this in a simple way.

0
source

You can also achieve this by align_plots multiple plots using the align_plots and ggdraw in cowplot . This is the solution I used to place the diffuser (discrete color scale) on the raster (continuous color scale). See the vignette at the following link.

https://www.rdocumentation.org/packages/cowplot/versions/0.9.2/topics/align_plots

-one
source

All Articles