【问题标题】:ggplot function to add text just below legendggplot 函数在图例下方添加文本
【发布时间】:2015-09-10 15:51:03
【问题描述】:

在 R 中,我想创建一个函数,它接受一个 ggplot 对象和一些文本,并通过在图例下方添加文本(在图的右侧,同时将图例保留在右侧)返回和 ggplot 对象。

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

我想在图例之后添加文本“Sepal.Width = 3.05 的平均值”(及其周围的框)。我查看了相关问题,但它们将图例的位置更改为底部,并且不能作为函数工作,而是打印绘图。

【问题讨论】:

  • 这篇文章可能对stackoverflow.com/questions/12409960/…有帮助
  • 谢谢。这很有帮助,但现在的问题是如何找到 xmin 和 ymin 值??
  • max() 的原始映射 x 值并添加一些小百分比
  • @zx8754 cowplot 看起来很有希望,但我的问题仍然是如何获得图例的位置,以便可以在下面添加文本!!

标签: r plot ggplot2


【解决方案1】:

几种可能性。

第一个使用annotate(),并通过反复试验来定位文本。 x 位置使用hjust 调整,y 位置选择为略低于图例。注意:文本周围没有边框。

第二个假设需要边框。使用grid 构造组合的文本和框。然后使用annotation_custom() 定位grob。 yminymax 设置为略低于图例。 xminxmax 是通过反复试验设置的,以使文本和图例对齐。

这两种方法都涉及在绘图面板之外进行绘图,因此需要关闭裁剪到绘图面板。但如果文字大小或长度发生变化,则需要调整标签的位置。

第三种方法对文本长度和大小的更改相当稳健。与方法 2 类似,使用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)

【讨论】:

  • 非常详尽,谢谢。在哪里可以了解更多关于 grobs 等低级别方面的信息?
  • 是否可以将标签文本相对于原始图例居中?当我尝试时,它会整体居中。
  • 这可能有效,但相当复杂。应该没那么难
  • 方法 #1 的更新(我更喜欢):A) 您现在可以使用 coord_cartesian(clip="off") 禁用剪辑。 B) 使用nudge_xnudge_y 微调标签位置。 C) 对于更复杂的用途(例如,多个标签),考虑将 annotate() 替换为 geom_text(data=data.frame(lab='text'), aes=aes(label=lab), inherit.aes=F, y=2.9, size=3, ...)
【解决方案2】:

另一种简单的可能性是使用标题:

myplot = ggplot(iris, aes(x=Sepal.Length, y=Sepal.Width, color=Species)) + 
           geom_line() +
           labs(caption = "Mean of Sepal.Width = 3.05")

不过,它并不真正位于图例下方:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-09
    • 2019-06-21
    • 2017-12-30
    相关资源
    最近更新 更多