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)
Related
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"))
I have a ggplot2 plot as follows:
library(ggplot2)
ggplot(mtcars, aes(factor(cyl), fill=factor(cyl))) +
geom_bar() +
coord_flip() +
theme(legend.position = 'top') +
guides(fill = guide_legend(title=NULL))
I'd like add spacing between the fill elements as follows:
The issue mentioned by alistaire and Tyler Rinker was solved. Now we can adjust the margins of the element_text`.
ggplot(mtcars, aes(factor(cyl), fill = factor(cyl))) +
geom_bar() +
coord_flip() +
theme(
legend.position = 'top',
legend.title = element_blank(),
legend.text = element_text(margin = margin(r = 2, unit = 'cm'))
)
It really seems something like theme(legend.text = element_text(margin = margin(r = 2, unit = 'in'))) would be the right way to accomplish the task, but that doesn't do anything at all.
Instead, (and not for the first time) I fall back on the Microsoft Word style of alignment-hacking, i.e. just add spaces:
ggplot(mtcars, aes(factor(cyl), fill=factor(paste(cyl, ' ')))) +
geom_bar() +
coord_flip() +
theme(legend.position = 'top') +
guides(fill = guide_legend(title=NULL))
Because there's spaces on the 8 as well, it's a little off-center, but if you just paste them onto the previous labels you can nudge them around as you like.
Apologies for any nightmares caused to graphic designers.
This is another hack but one that I prefer, as it adds additional white space at the end of each label according to its number of characters. Replace fill = factor(cyl) with
fill = sprintf("%-20s", factor(cyl)).
This pads all strings in the vector with white characters on the right to reach 20 characters total. This is perfect if you have text labels of different lengths. You can change 20 to whatever number you want, or remove the negative sign to add spaces to the left instead of the right. In general sprintf() is a good function to explore and use for formatting text and numbers as desired.
This is a hack, but...
Let's add some empty factor levels in cyl between the real levels. Then we'll make sure they're included in the plot (using drop=FALSE) for spacing in the legend, but will set their colors and labels to empty values so that you can't see them in the legend. I found that I also needed to include override.aes=list(color="white") in order to avoid the blank legend key boxes still being ever-so-slightly visible in the legend.
mtcars$cyl = factor(mtcars$cyl, levels=c(4, 11:15, 6, 16:20, 8))
cols = hcl(seq(15,375,length.out=4)[1:3], 100, 65)
ggplot(mtcars, aes(cyl, fill=cyl)) +
geom_bar() +
coord_flip() +
scale_fill_manual(values=c(cols[1], rep("white",5), cols[2], rep("white",5), cols[3]),
labels=c(4, rep("",5), 6, rep("",5), 8), drop=FALSE) +
theme(legend.position = 'top') +
guides(fill = guide_legend(title=NULL, nrow=1, override.aes=list(color="white")))
With ggplot2 v3.0.0, we can use legend.spacing.x to manipulate the space between legend keys.
library(ggplot2)
ggplot(mtcars, aes(factor(cyl), fill = factor(cyl))) +
geom_bar() +
coord_flip() +
theme(legend.position = 'top') +
guides(fill = guide_legend(title = "Cyl")) +
theme(legend.spacing.x = unit(0.5, 'cm'))
Created on 2018-05-30 by the reprex package (v0.2.0).
Not a hack here, this is the way to do it:
Use theme(legend.text = element_text(margin = margin(r = 2, unit = 'cm')))
ggplot(mtcars, aes(factor(cyl), fill = factor(cyl))) +
geom_bar() +
coord_flip() +
theme(
legend.position = 'top',
legend.title = element_blank(),
legend.text = element_text(margin = margin(r = 2, unit = 'cm'))
)
Will do it.
when we use the facet option in ggplot, we get a beautiful grey box around the headings (3,4,5).
library(ggplot2)
data(mtcars)
ggplot(mtcars, aes(cyl)) + geom_bar() + facet_wrap(~gear) + theme_bw()
How can we place a similiar grey box around the chart title when we do no use the facet option?
ggplot(mtcars, aes(cyl)) + geom_bar() + theme_bw() +
ggtitle("How do you put a grey box around me??")
Since you are asking how to do it without facets, this is strictly speaking not an answer, but just to point it out, one quick and dirty way would be to "cheat" and to use a facet after all. For instance,
mtcars$title <- "How do you put a grey box around me??"
ggplot(mtcars, aes(cyl)) + geom_bar() + theme_bw() +
facet_grid(. ~ title)
does the trick.
you can use annotate and change plot title margin, then from annotate you can use "rect" geom for annotation:
ggplot(mtcars, aes(x = factor(cyl))) +
geom_bar() +
theme_bw() +
ggtitle(" How do you put a grey box around me??") +
theme(panel.grid = element_blank(),
panel.border = element_blank(),
axis.line.x = element_line(color = "black"),
axis.line.y = element_line(color = "black"),
plot.title = element_text(size = 12, color = "black", face = "bold", margin = margin(t = 10, b = -30)))+
annotate("rect",xmin=0,xmax=3,ymin=14,ymax=15,alpha=.2,color="black", linetype = 'dotted', fill = "grey1")
Title with borders from annotate
The other best and easy solution to save image as SVG then open it from inkscape 'free software' and then easily add rectangle to the title:
Title grey box using inkscape
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"
)
I have a plot in ggplot with 4 separate lines that I have added with a separate geom_line() argument. I would like to add legend but scale_colour_manual doesn't work in this case. What is the proper way to add legends when I added the variables separately?
Here's my code:
ggplot(proba[108:140,], aes(c,four)) +
geom_line(linetype=1, size=0.3) +
scale_x_continuous(breaks=seq(110,140,5)) +
theme_bw() +
theme(axis.line = element_line(colour = "black", size=0.25),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.border = element_blank(),
panel.background = element_blank()) +
theme(axis.text.x = element_text(angle = 0, hjust = +0.5, size=6,color="black")) +
theme(axis.text.y = element_text(angle = 0, hjust = -100, size=6, color="black")) +
theme(axis.ticks=element_line(colour="black",size=0.25)) +
xlab("\nTime-steps") +
ylab("Proportion correct\n") +
theme(axis.text=element_text(size=8),axis.title=element_text(size=8)) +
geom_line(aes(c,three), size=0.2, linetype=2) +
geom_line(aes(c,one),linetype=3, size=0.8, colour="darkgrey") +
geom_line(aes(c,two), linetype=1, size=0.8, colour="darkgrey")
Just set the color name in aes to whatever the line's name on the legend should be.
I don't have your data, but here's an example using iris a line with random y values:
library(ggplot2)
line.data <- data.frame(x=seq(0, 10, length.out=10), y=runif(10, 0, 10))
qplot(Sepal.Length, Petal.Length, color=Species, data=iris) +
geom_line(aes(x, y, color="My Line"), data=line.data)
The key thing to note is that you're creating an aesthetic mapping, but instead of mapping color to a column in a data frame, you're mapping it to a string you specify. ggplot will assign a color to that value, just as with values that come from a data frame. You could have produced the same plot as above by adding a Species column to the data frame:
line.data$Species <- "My Line"
qplot(Sepal.Length, Petal.Length, color=Species, data=iris) +
geom_line(aes(x, y), data=line.data)
Either way, if you don't like the color ggplot2 assigns, then you can specify your own using scale_color_manual:
qplot(Sepal.Length, Petal.Length, color=Species, data=iris) +
geom_line(aes(x, y, color="My Line"), data=line.data) +
scale_color_manual(values=c("setosa"="blue4", "versicolor"="red4",
"virginica"="purple4", "My Line"="gray"))
Another alternative is to just directly label the lines, or to make the purpose of the lines obvious from the context. Really, the best option depends on your specific circumstances.