Ggplot function to add text just below the legend

In RI, you need to make a function that takes a ggplot object and some text and returns a ggplot object, adds text just below the legend (on the right side of the graph, keeping the legend on the right side).

myplot = ggplot(iris, aes(x=Sepal.Length, y=Sepal.Width, color=Species)) + 
           geom_line()

I want to add the text "average Sepal.Width = 3.05" (and the box around it) right after the legend. I looked at related issues, but they change the position of the legend to the bottom and do not work as a function, but prints the plot.

+4
source share
1 answer

A few possibilities.

annotate() . x hjust, y . : .

, . grid. grob annotation_custom(). ymin ymax . xmin xmax , .

, . , .

. 2, -grob grid. , gtable, grob ( ).

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

enter image description here

+1

Source: https://habr.com/ru/post/1606820/


All Articles