I would like to get my ggplot legends to appear side by side, underneath the plot with the variable names above the symbols, as they are in this blog post (the second plot). The opts function is now defunct, and theme does not appear to replicate its behaviour...
library("ggplot2")
ggplot(diamonds, aes(x = carat, y=price, shape = cut, group=interaction(cut, color), color=color)) +
geom_point() +
#opts(legend.direction = "horizontal", legend.position = "bottom")
#potential options, not all seem have an effect...
theme(legend.direction = "horizontal") +
theme(legend.position = "bottom") +
theme(legend.box = "vertical") +
theme(legend.title.align = 0)
...using my MS paint skills to illustrate the desired plot.
You need to specify theme(legend.box = "horizontal")
Try this:
library("ggplot2")
ggplot(diamonds, aes(x = carat, y=price, shape = cut, group=interaction(cut, color), color=color)) +
geom_point() +
theme(legend.direction = "horizontal",
legend.position = "bottom",
legend.box = "horizontal"
)
Adapting from the previous suggestions with legend.box = "horizontal", I have found that you can get the legend titles on top using title.position = "top" in the guides for the scale_ functions. These have to be defined for each variable that makes up the legend else the title will be to the left.
ggplot(data = diamonds,
mapping = aes(x = carat, y = price, shape = cut,
group=interaction(cut, color), color=color)) +
geom_point() +
theme(legend.box = "horizontal",
legend.position="bottom") +
scale_shape(guide = guide_legend(title.position = "top")) +
scale_colour_discrete(guide = guide_legend(title.position = "top", nrow = 1))
You could shift the titles to the center, as I suggested in the question, using title.hjust = 0.5. However, upon inspection, doing so might confuse the reader as to which colours/points refers to which variable.
#gjbel - I think to make the legend title above the symbols you either need to change legend direction from horizontal to vertical or remove legend direction entirely as the default is vertical:
library("ggplot2")
ggplot(diamonds, aes(x = carat, y=price, shape = cut, group=interaction(cut, color), color=color)) +
geom_point() +
theme(legend.direction = "vertical",
legend.position = "bottom",
legend.box = "horizontal"
)
OR
library("ggplot2")
ggplot(diamonds, aes(x = carat, y=price, shape = cut, group=interaction(cut, color), color=color)) +
geom_point() +
theme(legend.position = "bottom",
legend.box = "horizontal"
)
Related
So I have a ggplot that doesn't require a legend because it actually has a title and thus doesn't need a legend that would simply repeat the title.
Imagine something like this:
ggplot(iris)+
geom_point(aes(x=Sepal.Length, y=Sepal.Width, color=Species))+
theme(legend.box.background=element_rect(fill="white", color="black"))+
labs(color="")+
ggtitle("Sepals ~ Species")+
xlab("Length")+
ylab("Width")
(ignore the fact that the legend in my reprex only has two lines drawn for the box)
Do you notice the graphical problem? Apparently ggplot "thinks" there is a legend title and leaves some space, so I though using element_blank for the legend title might work.
ggplot(iris)+
geom_point(aes(x=Sepal.Length, y=Sepal.Width, color=Species))+
labs(color=element_blank())+
theme(legend.box.background=element_rect(fill=NA, color="black"),
legend.margin=margin(t=0,r=0,b=0,l=0))+
ggtitle("Sepals ~ Species")+
xlab("Length")+
ylab("Width")
While this improves the situation by making the box smaller at the top, it does not fix the problem because the top space is still smaller. As I have manually set the legend margins to 0 this can't be the issue.
any ideas?
You can set theme(legend.title = element_blank()) . This also means you don't need to set an empty string for the label.
To show this, let's make that box outline a little thicker, and use the "empty string" method:
ggplot(iris) +
geom_point(aes(Sepal.Length, Sepal.Width, color = Species)) +
ggtitle("Sepals ~ Species") +
labs(x = "Length", y = "Width", color = "") +
theme(legend.box.background = element_rect(color ="black", size = 2))
We can see that there is an obvious space where the title should be.
But now let's try it with the element_blank() method:
ggplot(iris) +
geom_point(aes(Sepal.Length, Sepal.Width, color = Species)) +
ggtitle("Sepals ~ Species") +
labs(x = "Length", y = "Width") +
theme(legend.box.background = element_rect(color ="black", size = 2),
legend.title = element_blank())
As Tjebo points out, the other option is to use NULL instead of an empty string, which does the same thing as theme(legend.title = element_blank())
ggplot(iris) +
geom_point(aes(Sepal.Length, Sepal.Width, color = Species)) +
ggtitle("Sepals ~ Species") +
labs(x = "Length", y = "Width", color = NULL) +
theme(legend.box.background = element_rect(color ="black", size = 2))
You additionally need to change legend.spacing. Very related: Reduce padding in ggplot2 legend
By the way, margin() has as defaults all = 0, so you don't need to type them out... ;)
library(ggplot2)
ggplot(iris)+
geom_point(aes(x=Sepal.Length, y=Sepal.Width, color=Species))+
labs(color=NULL) +
theme(legend.box.background=element_rect(fill="white", color="black"),
legend.margin=margin(),
legend.spacing.y = unit(0, "mm"))
Created on 2022-05-31 by the reprex package (v2.0.1)
I have a stacked bar graph with 2 numerical values and the bars are stacked on top of eachother. I would like to display a Legend that indicates the description of the 2 colors. Here it is my code but its not displaying. Any help from anyone I would be greatful for.
ggplot(data=my_data, aes(x = Xaxis)) +
ggtitle("My Title")+
theme(plot.title = element_text(hjust = 0.5, face="bold"))+
geom_col(aes(y = v1), fill ="red")+
geom_col(aes(y = v2), fill="blue")+
labs(y= "Amount", color ="Legend")+
theme(legend.title = element_text(color='black',face='bold'),
legend.text = element_text(color='black',face='bold'))+
scale_y_continuous(labels = comma)
From the above code the legend does not display
Update:
As I already mentioned in the comments you may consider another strategy with long format, but with your format you are in conflict with showing the legend of fill argument and getting the correct colors.
If you put the fill argument outside of aes no legend will be shown but you get the correct colors.
If you put fill argument inside the aes then the legend will be shown but the colors will be not as desired -> this is because you're basically generating a new factor variable and a legend.
https://github.com/tidyverse/ggplot2/issues/1675
With the mtcars dataset:
ggplot(data=mtcars, aes(x = cyl)) +
ggtitle("My Title")+
theme(plot.title = element_text(hjust = 0.5, face="bold"))+
geom_col(aes(x = cyl, y = disp, fill ="red"))+
geom_col(aes(x= cyl, y = mpg, fill="blue"))+
labs(y= "Amount", color ="Legend")+
theme(legend.title = element_text(color='black',face='bold'),
legend.text = element_text(color='black',face='bold'))+
scale_fill_manual(values = c('red','blue'), labels=c('disp', 'mpg'))
First answer:
try this:
ggplot(data=my_data, aes(x = Xaxis)) +
ggtitle("My Title")+
theme(plot.title = element_text(hjust = 0.5, face="bold"))+
geom_col(aes(y = v1, fill ="red"))+
geom_col(aes(y = v2, fill="blue")))+
labs(y= "Amount", color ="Legend")+
theme(legend.title = element_text(color='black',face='bold'),
legend.text = element_text(color='black',face='bold'))+
scale_y_continuous(labels = comma)
your code with the mtcars data set:
ggplot(data=mtcars, aes(x = cyl)) +
ggtitle("My Title")+
theme(plot.title = element_text(hjust = 0.5, face="bold"))+
geom_col(aes(y = disp, fill ="red"))+
geom_col(aes(y = mpg, fill="blue"))+
labs(y= "Amount", color ="Legend")+
theme(legend.title = element_text(color='black',face='bold'),
legend.text = element_text(color='black',face='bold'))
gives:
I'm plotting two sets of data in ggplot2 with code like the following, which leads to me having two legends (ignore the ugly plot, this is just an example)
x <- ggplot(mtcars)+
theme_bw() +
theme(legend.position=c(0.8, 0.8), legend.direction="horizontal",
legend.key.size=unit(0.008, "cm"), legend.title=element_blank(),
legend.margin=margin(), legend.spacing = unit(0.04, "cm")) +
guides(colour = guide_legend(override.aes = list(size=6)), shape= guide_legend(override.aes = list(size=5))) +
geom_point(aes(x=mpg, y=cyl, colour=cyl))+
geom_point(aes(x=mpg, y = hp, shape=as.factor(carb)))
print(x)
The issue is that for me, the black shapes in the bottom are vertically too close together, I would like the two rows of black shapes to have more vertical space between them. I tried to use legend.spacing.y but it did not help at all, it only changed the space between the two individual legends (for cyl and carb). I would like to know if there's some theme command that would let me do something like legend.spacing(legend=carb, unit(0.1, "cm")) so it specifically acts on the carb legend.
Thanks!
You can use the keyheight argument in guide_legend
ggplot(mtcars) +
theme_bw() +
theme(
legend.position = c(0.8, 0.8),
legend.direction = "horizontal",
legend.key.size = unit(0.008, "cm"),
legend.title = element_blank(),
legend.margin = margin(),
legend.spacing = unit(0.04, "cm")
) +
guides(colour = guide_legend(override.aes = list(size = 6)),
shape = guide_legend(override.aes = list(size = 5), keyheight = 2)) +
geom_point(aes(x = mpg, y = cyl, colour = cyl)) +
geom_point(aes(x = mpg, y = hp, shape = as.factor(carb)))
I have made a plot with a legend.
Using an image editing program I made the legend invisible (but otherwise the figure has the same dimensions)
Is it possible to do this in ggplot2? I want to have a 2x2 panel of diagrams in a document but only one legend.
Using this as an example,
library(ggplot2)
p <- ggplot(mtcars, aes(x = disp, y = hp, color = factor(cyl))) +
geom_point() +
geom_line()
The following seems to work:
p + theme(
legend.text = element_text(color = "white"),
legend.title = element_text(color = "white"),
legend.key = element_rect(fill = "white")
) +
scale_color_discrete(
guide = guide_legend(override.aes = list(color = "white"))
)
Notice that the dimension of the gray plot area did not change.
Making the elements just white could cause problems, i.e. in cases of continuous scales or so. One may makes the scales and text elements just invisible.
p <- ggplot(mtcars, aes(x = disp, y = hp, lty = factor(gear))) +
geom_point(aes(color = cyl)) +
geom_line()
Gives a normal plot with legend:
Now make it really "invisible" by setting alpha = 0 in override.aes = list() within the guide = guide_legend() argument for each of the scales and color = "transparent" for the text elements of the legend:
p + scale_color_continuous(guide = guide_legend(override.aes = list(alpha = 0) ) )+
scale_linetype(guide = guide_legend(override.aes = list(alpha = 0) ) )+
theme(legend.title = element_text(color = "transparent"),
legend.text = element_text(color = "transparent"))
Is there a way to change the spacing between legend items in ggplot2? I currently have
legend.position ="top"
which automatically produces a horizontal legend. However, the spacing of the items is very close together and I am wondering how to space them farther apart.
ggplot2 v3.0.0 released in July 2018 has working options to modify legend.spacing.x, legend.spacing.y and legend.text.
Update Dec 2021 - to make legend.spacing.y work, you will need to set byrow = TRUE in the corresponding guide_legend. See also this thread. Example below.
Example: Increase horizontal spacing between legend keys
library(ggplot2)
ggplot(mtcars, aes(factor(cyl), fill = factor(cyl))) +
geom_bar() +
coord_flip() +
scale_fill_brewer("Cyl", palette = "Dark2") +
theme_minimal(base_size = 14) +
theme(legend.position = 'top',
legend.spacing.x = unit(1.0, 'cm'))
Note: If you only want to expand the spacing to the right of the legend text, use stringr::str_pad()
Example: Increase vertical spacing (mind byrow = TRUE)
library(ggplot2)
ggplot(mtcars, aes(y = factor(cyl), fill = factor(cyl))) +
geom_bar() +
theme(legend.spacing.y = unit(1.0, 'cm')) +
## important additional element
guides(fill = guide_legend(byrow = TRUE))
Example: Move the legend key labels to the bottom and increase vertical spacing
ggplot(mtcars, aes(factor(cyl), fill = factor(cyl))) +
geom_bar() +
coord_flip() +
scale_fill_brewer("Cyl", palette = "Dark2") +
theme_minimal(base_size = 14) +
theme(legend.position = 'top',
legend.spacing.x = unit(1.0, 'cm'),
legend.text = element_text(margin = margin(t = 10))) +
guides(fill = guide_legend(title = "Cyl",
label.position = "bottom",
title.position = "left", title.vjust = 1))
Example: for scale_fill_xxx & guide_colorbar
ggplot(mtcars, aes(mpg, wt)) +
geom_point(aes(fill = hp), pch = I(21), size = 5)+
scale_fill_viridis_c(guide = FALSE) +
theme_classic(base_size = 14) +
theme(legend.position = 'top',
legend.spacing.x = unit(0.5, 'cm'),
legend.text = element_text(margin = margin(t = 10))) +
guides(fill = guide_colorbar(title = "HP",
label.position = "bottom",
title.position = "left", title.vjust = 1,
# draw border around the legend
frame.colour = "black",
barwidth = 15,
barheight = 1.5))
The below is obsolete, but is left for curious people.
For vertical legends, settinglegend.key.size only increases the size of the legend keys, not the vertical space between them
ggplot(mtcars) +
aes(x = cyl, fill = factor(cyl)) +
geom_bar() +
scale_fill_brewer("Cyl", palette = "Dark2") +
theme_minimal(base_size = 14) +
theme(legend.key.size = unit(1, "cm"))
In order to increase the distance between legend keys, modification of the legend-draw.r function is needed. See this issue for more info
# function to increase vertical spacing between legend keys
# #clauswilke
draw_key_polygon3 <- function(data, params, size) {
lwd <- min(data$size, min(size) / 4)
grid::rectGrob(
width = grid::unit(0.6, "npc"),
height = grid::unit(0.6, "npc"),
gp = grid::gpar(
col = data$colour,
fill = alpha(data$fill, data$alpha),
lty = data$linetype,
lwd = lwd * .pt,
linejoin = "mitre"
))
}
### this step is not needed anymore per tjebo's comment below
### see also: https://ggplot2.tidyverse.org/reference/draw_key.html
# register new key drawing function,
# the effect is global & persistent throughout the R session
# GeomBar$draw_key = draw_key_polygon3
ggplot(mtcars) +
aes(x = cyl, fill = factor(cyl)) +
geom_bar(key_glyph = "polygon3") +
scale_fill_brewer("Cyl", palette = "Dark2") +
theme_minimal(base_size = 14) +
theme(legend.key = element_rect(color = NA, fill = NA),
legend.key.size = unit(1.5, "cm")) +
theme(legend.title.align = 0.5)
I think the best option is to use guide_legend within guides:
p + guides(fill=guide_legend(
keywidth=0.1,
keyheight=0.1,
default.unit="inch")
)
Note the use of default.unit , no need to load grid package.
A simple fix that I use to add space in horizontal legends, simply add spaces in the labels (see extract below):
scale_fill_manual(values=c("red","blue","white"),
labels=c("Label of category 1 ",
"Label of category 2 ",
"Label of category 3"))
To add spacing between entries in a legend, adjust the margins of the theme element legend.text.
To add 30pt of space to the right of each legend label (may be useful for a horizontal legend):
p + theme(legend.text = element_text(
margin = margin(r = 30, unit = "pt")))
To add 30pt of space to the left of each legend label (may be useful for a vertical legend):
p + theme(legend.text = element_text(
margin = margin(l = 30, unit = "pt")))
for a ggplot2 object p. The keywords are legend.text and margin.
[Note about edit: When this answer was first posted, there was a bug. The bug has now been fixed]
Now that opts is deprecated in ggplot2 package, function theme should be used instead:
library(grid) # for unit()
... + theme(legend.key.height=unit(3,"line"))
... + theme(legend.key.width=unit(3,"line"))
Looks like the best approach (in 2018) is to use legend.key.size under the theme object. (e.g., see here).
#Set-up:
library(ggplot2)
library(gridExtra)
gp <- ggplot(data = mtcars, aes(mpg, cyl, colour = factor(cyl))) +
geom_point()
This is real easy if you are using theme_bw():
gpbw <- gp + theme_bw()
#Change spacing size:
g1bw <- gpbw + theme(legend.key.size = unit(0, 'lines'))
g2bw <- gpbw + theme(legend.key.size = unit(1.5, 'lines'))
g3bw <- gpbw + theme(legend.key.size = unit(3, 'lines'))
grid.arrange(g1bw,g2bw,g3bw,nrow=3)
However, this doesn't work quite so well otherwise (e.g., if you need the grey background on your legend symbol):
g1 <- gp + theme(legend.key.size = unit(0, 'lines'))
g2 <- gp + theme(legend.key.size = unit(1.5, 'lines'))
g3 <- gp + theme(legend.key.size = unit(3, 'lines'))
grid.arrange(g1,g2,g3,nrow=3)
#Notice that the legend symbol squares get bigger (that's what legend.key.size does).
#Let's [indirectly] "control" that, too:
gp2 <- g3
g4 <- gp2 + theme(legend.key = element_rect(size = 1))
g5 <- gp2 + theme(legend.key = element_rect(size = 3))
g6 <- gp2 + theme(legend.key = element_rect(size = 10))
grid.arrange(g4,g5,g6,nrow=3) #see picture below, left
Notice that white squares begin blocking legend title (and eventually the graph itself if we kept increasing the value).
#This shows you why:
gt <- gp2 + theme(legend.key = element_rect(size = 10,color = 'yellow' ))
I haven't quite found a work-around for fixing the above problem...
Let me know in the comments if you have an idea, and I'll update accordingly!
I wonder if there is some way to re-layer things using $layers...
From Koshke's work on ggplot2 and his blog (Koshke's blog)
... + theme(legend.key.height=unit(3,"line")) # Change 3 to X
... + theme(legend.key.width=unit(3,"line")) # Change 3 to X
Type theme_get() in the console to see other editable legend attributes.
Use any of these
legend.spacing = unit(1,"cm")
legend.spacing.x = unit(1,"cm")
legend.spacing.y = unit(1,"cm")