R ggplot 2 legend border issue - r

I know this is minor, but it's for a publication and will drive me crazy. The bottom of the P0688 box is like 1-2 pixels thinner than the rest. I don't want to make the borders thicker because then it doesn't match the rest of the bar chart.
plot<- ggplot(tukey_letters, aes(x = variable, y = value.x,
fill = L1)) +
theme(panel.background=element_rect(fill="#ffffff", color
="#000000"), panel.grid.major=element_blank(),
panel.grid.minor=element_blank()) +
geom_bar(stat = "identity", position=position_dodge(),color="black")+ scale_fill_manual(values=c("#FFFFFF", "#999999"))+ guides(fill=guide_legend(title="Genotype", title.position = "left")) +
geom_errorbar(aes(ymin=value.x-se, ymax=value.x+se), width=.1,size=.5,position=position_dodge(0.9), color="black")+
theme(
axis.title = element_text(size =12, face="bold"),
axis.text = element_text(angle=30, vjust=0.5,hjust=0.6,size=8,face="bold", color="#000000"),
axis.ticks = element_line(size = rel(1)),
axis.ticks.length = unit(0.3, "cm"),
legend.position = c(0.2, 0.9)
)+
labs(
x="Treatment",
y="ARI1"
)+
#facet_wrap(~L1)+ ## You can use face_wrap function only if you need it+
geom_text(data =tukey_letters,
aes(x=xpos, y=ymax+offset_asterisk,label=groups),
size = 4,position=position_dodge(0.9) , vjust=-0.5
)
Thanks in advance. Let me know if there is anything else needed to help solve this.

This is due to the filling behaviour of the legend keys. It's a known issue, see this GitHub thread https://github.com/tidyverse/ggplot2/issues/2844. There is also a fix suggested on this site, let me show this here.
library(tidyverse)
ggplot(mtcars) +
aes(fill=factor(cyl), x=cyl) +
geom_bar(color = 'black') +
guides(fill=guide_legend(title.position = "left")) +
theme(legend.key = element_rect(color="white") +
legend.position = c(0.2, 0.7))
Enlarged, the legend will look now like this:
Now let's do the fix.
draw_key_polygon3 <- function(data, params, size) {
lwd <- min(data$size, min(size) / 4)
grid::rectGrob(
width = grid::unit(0.7, "npc"),
height = grid::unit(0.7, "npc"),
gp = grid::gpar(
col = data$colour,
fill = alpha(data$fill, data$alpha),
lty = data$linetype,
lwd = lwd * .pt,
linejoin = "mitre"
))
}
GeomBar$draw_key = draw_key_polygon3
ggplot(mtcars) +
aes(fill=factor(cyl), x=cyl) +
geom_bar(color = 'black') +
guides(fill=guide_legend(title.position = "left")) +
theme(legend.key = element_rect(color="white", fill = 'white'),
legend.position = c(0.2, 0.7))
But what is actually going on here? Let's see!
ggplot(mtcars) +
aes(fill=factor(cyl), x=cyl) +
geom_bar(color = 'black') +
guides(fill=guide_legend(title.position = "left")) +
theme(legend.position = c(0.2, 0.7),
legend.key = element_rect(color="black", fill = 'white'))
The legend has two borders! One for the legend glyph, the other for the key. You draw the border for the key with the call to theme, and the border around the glyph is created with your color argument in geom_bar
Created on 2020-04-04 by the reprex package (v0.3.0)

Related

Increase Vertical Spacing between Legend Key in ggplot2

How can I increase vertical spacing between legend keys:
p1 <- ggplot(data = HSS, mapping = aes(x = EVENT, y = HSS, fill = TIME)) +
geom_bar(stat = "identity",width=0.7, colour = "black", position = position_dodge(0.7)) +
scale_fill_manual("HSS", values = c("deepskyblue3", "indianred2"),
labels = c("1200 UTC (0.049)", "0000 UTC (0.031)")) + theme_bw()
p1 <- p1 + scale_y_continuous(expand = expansion(mult = c(0.0085, -0.085)),
limits = c(-0.03,0.5), breaks = c(-0.03,-0.01, 0.01, 0.03, 0.05, 0.07,0.09,0.11,0.13,0.15,0.17,
0.19, 0.21,0.23,0.25,0.27,0.29,0.31,0.33,0.45),
labels = c("-0.03","-0.01","0.01","0.03","0.05","0.07","0.09","0.11","0.13","0.15","0.17",
"0.19","0.21","0.23","0.25","0.27","0.29","0.31","0.33","0.45")) +
theme(axis.text.x=element_text(color = "black", size=12, face = "bold", angle=90, vjust=.5,
hjust=0.8)) +
theme(axis.text.y = element_text(color = "black", size=12, face = "bold"))
p1 <- p1 + theme( axis.line = element_line(colour = "black", size = 0.5, linetype = "solid")) +
labs( y = "HSS")
p1 <- p1 + theme(axis.title=element_text(colour = "blue2" ,size=14,face="bold", vjust = 0.1))
p1 <- p1 + theme(legend.position=c(0.98,0.98)) + theme(legend.title=element_blank(),
legend.text = element_text(face = "bold", size = "12"),
legend.box.background = element_rect(size=0.7, linetype="solid"),
legend.justification = c("right", "top"),
legend.box.margin = margin(1, 1, 1, 1)
)
p1
I tried using legend.key.height legend.spacing.y guide but it only stretched legend keys without adding space between them. Also how can I remove alternate lables (encircled) of Y-axis keeping tickmark with plot.
After browsing ggplot2's source code for a bit, I come to the conclusion that the legend.spacing.y is only applied when the byrow = TRUE as argument to the legend.
Simplied example below.
library(ggplot2)
ggplot(iris, aes(Sepal.Width)) +
geom_density(aes(fill = Species)) +
guides(fill = guide_legend(byrow = TRUE)) +
theme(legend.spacing.y = unit(1, "cm"))
With regards to the labels, just remove the values from the breaks argument in scale_y_continuous() that you don't want to show, you're already specifying them manually.

Plot legend to move left ggplot

I like to move the legend a bit further on the left But I am not getting how to do it.
Secondly, I also want to reduce the space between axis label and legend too
Can you please suggest something
the code is given below that I am using
The image of the graph is in the link below
"tooltip"
ggplot(Q6_m, aes( choice,temp,fill=Answer ))+
geom_bar(position = position_stack(reverse = TRUE), stat="identity") +
coord_flip() +
xlab("") +
ylab("Number of responses") +
scale_fill_brewer(type = "div") +
theme(axis.text=element_text(size=8),
axis.title=element_text(size=8,face="bold"), legend.title = element_blank(),
legend.text=element_text(size=7)) +
ggtitle("Q6:Rate your ability to perform the following procedures WITHOUT attending assistance?")+
theme(plot.title = element_text(color = "black", size = 7.5, face = "bold", hjust = 1))+
facet_wrap(~gender,scales = "free_x")+
theme(legend.position="bottom", legend.direction = "horizontal",legend.key.size = unit(0.5,"line")
)
You should use legend.justification to get the legend on the left side of the plot and legend.margin to reduce the space between axis labels and the legend:
ggplot(iris, aes(x = Species, y = Sepal.Length, fill = Species))+
geom_boxplot()+
theme(legend.position = "bottom",
legend.justification = c(0,1),
legend.margin = margin(t = -15, r = 0, b = 0, l = 0, unit = "pt"))
Does it answer your question ?

Change line type of border

I would like to change the line type of the panel border from solid line to dashed line in my graph. I tried to use panel.border and panel_border in theme, but R keep telling me it cannot find these two functions in theme.
I think this will be very difficult to do with theme options. Even when the panel spacing is 0, I'm pretty sure it's using element_rect to draw the panel borders. Getting the plot you want with theme modifications would require modifying 1 or 2 lines of each panel border with awareness of whether the facet is a left, right, or central facet.
To get around this we can use hline and vline instead. Hacky, but it works:
hline_df = expand.grid(visit = unique(df$visit), yint = c(-Inf, Inf))
vline_df = expand.grid(visit = unique(df$visit), xint = c(-Inf, Inf)) %>%
mutate(no_dash = !(
(xint == Inf & visit == tail(levels(visit), 1)) |
(xint == -Inf & visit == head(levels(visit), 1))
))
ggplot(df, aes(x=avisit, y=mean, group=Type, color=Type, shape=Type)) +
scale_y_continuous(breaks=seq(0,18,2), limits=c(0, 18)) +
geom_point(position=pd, cex=2) +
xlab("") +
ylab("Mean") +
scale_colour_manual(values=c("blue", "red")) +
scale_shape_manual(values=c("triangle", "circle")) +
coord_cartesian(ylim = c(0, 18)) +
facet_grid(.~factor(visit), scales = "free_x", space ="free_x",switch = "both") +
geom_hline(data = hline_df, aes(yintercept = yint)) +
geom_vline(data = vline_df, aes(xintercept = xint, linetype = no_dash), show.legend = FALSE) +
theme_bw() +
theme(axis.text.y = element_text(margin = margin(r = 0)),
panel.spacing = unit(0, "mm"),
strip.background = element_blank(),
legend.title=element_blank(),
strip.placement = "outside",
legend.background = element_rect(color="black", fill="white", size=0.5, linetype="solid"),
legend.direction = "horizontal",
panel.grid.minor = element_line(colour="white", linetype="dashed"),
panel.grid.major = element_line(colour = "white",linetype="dashed"),
panel.border = element_blank())
element_rect takes a linetype argument. It might draw the axis line on top of the border or vice versa, so you can modify axis.line too. This theme should give you what you want and will be a little more elegant:
ggplot() + theme(axis.line = element_line(linetype = 3), panel.border = element_rect(linetype =3)

Draw a box around a legend ggplot2

I created a plot with a custom legend in ggplot2. I tried to draw a box around all the items in the legend, however I could only draw a box around each individual item. How can I create only one box around all the items?
library(ggplot2)
ggplot(mpg, aes(displ, cty)) +
geom_point(aes(shape = "Data")) +
stat_smooth(aes(linetype = "Regression"), method = "lm",
formula = y ~ x, se = FALSE, colour = 1, size = 0.5) +
scale_shape_manual(values = 1) +
labs(shape = "", linetype = "") +
theme_classic() +
theme(panel.border = element_rect(colour = "black", fill=NA),
aspect.ratio = 1, axis.text = element_text(colour = 1, size = 12),
legend.background = element_rect(linetype = 2, size = 0.5, colour = 1))
It seems that the legend.background rectangle overlaps the legend.box.background rectangle. An easy fix is to set legend.background = element_blank().
But then, in my opinion, the spacing in the legend is ugly. The legend titles take up too much space even with no title set. Fix this be setting legend.title = element_blank(). Also the spacing between the two legends is too large. Fix this by setting the space to zero legend.spacing.y = unit(0, "mm")
library(ggplot2)
ggplot(mpg, aes(displ, cty)) +
geom_point(aes(shape = "Data")) +
stat_smooth(aes(linetype = "Regression"), method = "lm",
formula = y ~ x, se = FALSE, colour = 1, size = 0.5) +
scale_shape_manual(values = 1) +
labs(shape = "", linetype = "") +
theme_classic() +
theme(legend.title = element_blank(),
legend.spacing.y = unit(0, "mm"),
panel.border = element_rect(colour = "black", fill=NA),
aspect.ratio = 1, axis.text = element_text(colour = 1, size = 12),
legend.background = element_blank(),
legend.box.background = element_rect(colour = "black"))

Is there a way to change the spacing between legend items in ggplot2?

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")

Resources