In R I want to make a function which takes an ggplot object and some text and returns and ggplot object by adds text just below the legend (in the right side of the plot, while keeping legend on the right side).
myplot = ggplot(iris, aes(x=Sepal.Length, y=Sepal.Width, color=Species)) +
geom_line()
I want to add text "mean of Sepal.Width = 3.05" (and a box around it) just after the legend. I looked at related questions but they change the position of legend to bottom and do not work as a function rather prints the plot.
You can use the annotate() function to add text to plots in ggplot2. where: x, y: The (x, y) coordinates where the text should be placed. label: The text to display.
By specifying legend. position=”none” you're telling ggplot2 to remove all legends from the plot.
You can use the following syntax to change the legend labels in ggplot2: p + scale_fill_discrete(labels=c('label1', 'label2', 'label3', ...))
A couple of possibilities.
The first uses annotate()
, and involves positioning the text by trial and error. The x position is adjusted using hjust
, the y position is selected to be a little below the legend. Note: no border around the text.
The second assumes a border is required. The combined text and box is constructed using grid
. Then the grob is positioned using annotation_custom()
. ymin
and ymax
are set to be a little below the legend. xmin
and xmax
are set by trial and error to get the text and the legend to align.
Both methods involve plotting outside the plot panel, so clipping to the plot panel needs to be turned off. But if the text size or length changes, the position of the label needs to be adjusted.
The third method is reasonably robust to changes to text length and size. Similar to method 2, the combined text and box grob is constructed using grid
. Then, using gtable
functions, the grob is attached to the legend (to the middle column of the legend).
# 1.
library(ggplot2)
library(grid)
library(gtable)
# The label
label = "Mean of Sepal.Width = 3.05"
# The plot - Note the extra margin space for the label
myplot = ggplot(iris, aes(x=Sepal.Length, y=Sepal.Width, color=Species)) +
geom_line() +
annotate("text", x = Inf, y = 2.9, label = label, hjust = -0.08, size = 3) +
theme(plot.margin = unit(c(.5,6,.5,.5),"lines"),
legend.background = element_rect(colour = "black"))
# Turn off clipping to the plot panel
g = ggplotGrob(myplot)
g$layout$clip[g$layout$name == "panel"] = "off"
grid.draw(g)
# 2.
# Construct the label grob - a combination of text and box
textgrob = textGrob(label, gp = gpar(cex = .75), )
width = unit(1, "grobwidth",textgrob) + unit(10, "points")
height = unit(1, "grobheight", textgrob)+ unit(10, "points")
rectgrob = rectGrob(gp=gpar(colour = "black", fill = NA), height = height, width = width)
labelGrob = gTree("labelGrob", children = gList(rectgrob, textgrob))
# The plot - Note the extra margin space for the label
myplot = ggplot(iris, aes(x=Sepal.Length, y=Sepal.Width, color=Species)) +
geom_line() +
annotation_custom(labelGrob,
xmin = 1.137*max(iris$Sepal.Length), xmax = 1.137*max(iris$Sepal.Length),
ymin = 2.9, ymax = 2.9) +
theme(plot.margin = unit(c(0.5, 6, 0.5, 0.5), "lines"),
legend.background = element_rect(colour = "black"))
# Turn off clipping to the plot panel
g = ggplotGrob(myplot)
g$layout$clip[g$layout$name == "panel"] = "off"
grid.draw(g)
#3.
# The label
label = "Mean of\nSepal.Width = 3.05"
# Try a different label
# label = "a"
# The plot
myplot = ggplot(iris, aes(x=Sepal.Length, y=Sepal.Width, color=Species)) +
geom_line() +
theme(legend.background = element_rect(colour = "black"))
# Get the legend
g = ggplotGrob(myplot)
leg = g$grobs[[which(g$layout$name == "guide-box")]]
# Construct the label grob
xpos = 5
textgrob = textGrob(x = unit(xpos, "points"), label, gp = gpar(cex = .75), just = "left")
width = unit(1, "grobwidth",textgrob) + unit(2*xpos, "points") # twice the x position
height = unit(1, "grobheight", textgrob)+ unit(2*xpos, "points")
rectgrob = rectGrob(x = unit(0, "points"), just = "left",
gp = gpar(colour = "black", fill = NA), height = height, width = width)
labelGrob = gTree("labelGrob", children = gList(rectgrob, textgrob))
# Add the label grob to a new row added to the legend
pos = subset(leg$layout, grepl("guides", name), t:r)
leg = gtable_add_rows(leg, height, pos = pos$t+1)
leg = gtable_add_grob(leg, labelGrob, t = pos$t+2, l = pos$l)
# Adjust the middle width of the legend to be the maximum of the original width
# or the width of the grob
leg$widths[pos$l] = max(width, leg$widths[pos$l])
# Add some space between the two parts of the legend
leg$heights[pos$t+1] = unit(5, "pt")
# Return the modified legend to the origial plot
g$grobs[[which(g$layout$name == "guide-box")]] = leg
# Adjust the width of the column containing the legend to be the maximum
# of the original width or the width of the label
g$widths[g$layout[grepl("guide-box", g$layout$name), "l"]] = max(width, sum(leg$widths))
# Draw the plot
grid.newpage()
grid.draw(g)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With