在R中我想创建一个函数,它接受一个ggplot对象和一些文本并返回和ggplot对象通过在图例下方添加文本(在图的右侧,同时保持图例在右侧).
myplot = ggplot(iris, aes(x=Sepal.Length, y=Sepal.Width, color=Species)) +
geom_line()
我想在传奇之后添加文字“Sepal.Width = 3.05的平均值”(及其周围的方框).我查看了相关问题,但是他们将图例的位置更改为底部,并且不作为函数工作而是打印图.
最佳答案 几种可能性.
第一个使用annotate(),并涉及通过反复试验来定位文本.使用hjust调整x位置,选择y位置略低于图例.注意:文本周围没有边框.
第二个假设需要边框.组合的文本和框使用网格构造.然后使用annotation_custom()定位grob. ymin和ymax设置为略低于图例.通过反复试验设置xmin和xmax,以使文本和图例对齐.
两种方法都涉及在绘图面板外绘图,因此需要关闭对绘图面板的裁剪.但是,如果文本大小或长度发生变化,则需要调整标签的位置.
第三种方法对文本长度和大小的更改非常稳健.与方法2类似,组合的文本和框grob使用网格构造.然后,使用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)