在ggplot2中的单个方面注释文本

Posted

技术标签:

【中文标题】在ggplot2中的单个方面注释文本【英文标题】:Annotating text on individual facet in ggplot2 【发布时间】:2012-08-07 01:04:55 【问题描述】:

我想使用以下代码在绘图的最后一个方面注释一些文本:

library(ggplot2)
p <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
p <- p + facet_grid(. ~ cyl)
p <- p + annotate("text", label = "Test", size = 4, x = 15, y = 5)
print(p)

但是这段代码在每个方面都对文本进行了注释。如何仅在一个方面获取带注释的文本?

【问题讨论】:

我相信这是not yet implemented,所以我怀疑您将不得不求助于使用文本构建数据框的久经考验的方法,并为构面变量提供一列。跨度> 【参考方案1】:

如果有人正在寻找一种简单的方法来标记报告或出版物的方面,egg (CRAN) 包具有非常漂亮的 tag_facet()tag_facet_outside() 功能。

library(ggplot2)

p <- ggplot(mtcars, aes(qsec, mpg)) + 
  geom_point() + 
  facet_grid(. ~ am) +
  theme_bw(base_size = 12)

# install.packages('egg', dependencies = TRUE)
library(egg)

标签内

默认

tag_facet(p)

注意:如果您想保留条形文字和背景,请尝试在theme 中添加strip.text and strip.background 或从原始tag_facet() 函数中删除theme(strip.text = element_blank(), strip.background = element_blank())

tag_facet <- function(p, open = "(", close = ")", tag_pool = letters, x = -Inf, y = Inf, 
                      hjust = -0.5, vjust = 1.5, fontface = 2, family = "", ...) 

  gb <- ggplot_build(p)
  lay <- gb$layout$layout
  tags <- cbind(lay, label = paste0(open, tag_pool[lay$PANEL], close), x = x, y = y)
  p + geom_text(data = tags, aes_string(x = "x", y = "y", label = "label"), ..., hjust = hjust, 
                vjust = vjust, fontface = fontface, family = family, inherit.aes = FALSE) 

右上方对齐并使用罗马数字

tag_facet(p, x = Inf, y = Inf, 
          hjust = 1.5,
          tag_pool = as.roman(1:nlevels(factor(mtcars$am))))

左下对齐并使用大写字母

tag_facet(p, 
          x = -Inf, y = -Inf, 
          vjust = -1,
          open = "", close = ")",
          tag_pool = LETTERS)

定义你自己的标签

my_tag <- c("i) 4 cylinders", "ii) 6 cyls")
tag_facet(p, 
          x = -Inf, y = -Inf, 
          vjust = -1, hjust = -0.25,
          open = "", close = "",
          fontface = 4,
          size = 5,
          family = "serif",
          tag_pool = my_tag)

在外面标记

p2 <- ggplot(mtcars, aes(qsec, mpg)) + 
  geom_point() + 
  facet_grid(cyl ~ am, switch = 'y') +
  theme_bw(base_size = 12) +
  theme(strip.placement = 'outside')

tag_facet_outside(p2)

编辑:使用stickylabeller 包添加另一个替代方案

- `.n` numbers the facets numerically: `"1"`, `"2"`, `"3"`...
- `.l` numbers the facets using lowercase letters: `"a"`, `"b"`, `"c"`...
- `.L` numbers the facets using uppercase letters: `"A"`, `"B"`, `"C"`...
- `.r` numbers the facets using lowercase Roman numerals: `"i"`, `"ii"`, `"iii"`...
- `.R` numbers the facets using uppercase Roman numerals: `"I"`, `"II"`, `"III"`...

# devtools::install_github("rensa/stickylabeller")
library(stickylabeller)

ggplot(mtcars, aes(qsec, mpg)) + 
  geom_point() + 
  facet_wrap(. ~ am, 
             labeller = label_glue('(.l) am = am')) +
  theme_bw(base_size = 12)

由reprex package (v0.2.1) 创建

【讨论】:

来源说“将虚拟文本层添加到 ggplot 以标记构面并将构面条设置为空白。”因此,如果您有不想丢失的自定义构面标签条,请编辑脚本对于tag_facet 由nixing strip.text = element_blank() @CrunchyTopping 这实际上是我正在寻找的帽子,但它似乎不适合我:Warning: Ignoring unknown parameters: strip.text 回答我上面的问题...这篇文章很好地解释了如何保留条带:***.com/a/56064130/3609450 这是一个了不起的答案@Tung!超级有用! 非常感谢@Ecg :)【参考方案2】:

我不知道egg 包, 所以这里是一个普通的ggplot2 包解决方案

library(tidyverse)
library(magrittr)
Data1=data.frame(A=runif(20, min = 0, max = 100), B=runif(20, min = 0, max = 250), C=runif(20, min = 0, max = 300))
Data2=data.frame(A=runif(20, min = -10, max = 50), B=runif(20, min = -5, max = 150), C=runif(20, min = 5, max = 200))
bind_cols(
Data1 %>% gather("Vars","Data_1"),
Data2 %>% gather("Vars","Data_2")
) %>% select(-Vars1) -> Data_combined
Data_combined %>%
  group_by(Vars) %>%
  summarise(r=cor(Data_1,Data_2),
            r2=r^2,
            p=(pt(abs(r),nrow(.)-2)-pt(-abs(r),nrow(.)-2))) %>%
  mutate(rlabel=paste("r:",format(r,digits=3)),
         plabel=paste("p:",format(p,digits=3))) ->
  label_df 
label_df %<>% mutate(x=60,y=190)
Data_combined %>%
  ggplot(aes(x=Data_1,y=Data_2,color=Vars)) +
  geom_point() + 
  geom_smooth(method="lm",se=FALSE) +
  geom_text(data=label_df,aes(x=x,y=y,label=rlabel),inherit.aes = FALSE) + 
  geom_text(data=label_df,aes(x=x,y=y-10,label=plabel),inherit.aes = FALSE) + 
    facet_wrap(~ Vars)

【讨论】:

【参考方案3】:

稍微扩展 joran 的出色答案,以阐明标签数据框的工作原理。

您可以将“mpg”和“wt”分别视为 x 和 y 坐标(我发现跟踪原始变量名称比重命名它们更容易,就像在 Kamil 的同样出色的答案中一样)。每个标签需要一行,“cyl”列显示每行与哪个方面相关联。

ann_text<-data.frame(mpg=c(25,15),wt=c(3,5),cyl=c(6,8),label=c("Label 1","Label 2"))

ann_text
>  mpg wt cyl  label
>  25  3   6   Label 1
>  15  5   8   Label 2

p <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
p <- p + facet_grid(. ~ factor(cyl))
p + geom_text(data = ann_text,label=ann_text$label)

【讨论】:

【参考方案4】:

这是没有文字注释的情节:

library(ggplot2)

p <- ggplot(mtcars, aes(mpg, wt)) +
  geom_point() +
  facet_grid(. ~ cyl) +
  theme(panel.spacing = unit(1, "lines"))
p

让我们创建一个额外的数据框来保存文本注释:

dat_text <- data.frame(
  label = c("4 cylinders", "6 cylinders", "8 cylinders"),
  cyl   = c(4, 6, 8)
)
p + geom_text(
  data    = dat_text,
  mapping = aes(x = -Inf, y = -Inf, label = label),
  hjust   = -0.1,
  vjust   = -1
)

或者,我们可以手动指定每个标签的位置:

dat_text <- data.frame(
  label = c("4 cylinders", "6 cylinders", "8 cylinders"),
  cyl   = c(4, 6, 8),
  x     = c(20, 27.5, 25),
  y     = c(4, 4, 4.5)
)

p + geom_text(
  data    = dat_text,
  mapping = aes(x = x, y = y, label = label)
)

我们还可以跨两个方面标记图:

dat_text <- data.frame(
  cyl   = c(4, 6, 8, 4, 6, 8),
  am    = c(0, 0, 0, 1, 1, 1)
)
dat_text$label <- sprintf(
  "%s, %s cylinders",
  ifelse(dat_text$am == 0, "automatic", "manual"),
  dat_text$cyl
)
p +
  facet_grid(am ~ cyl) +
  geom_text(
    size    = 5,
    data    = dat_text,
    mapping = aes(x = Inf, y = Inf, label = label),
    hjust   = 1.05,
    vjust   = 1.5
  )

注意事项:

您可以使用-InfInf 将文本定位在面板的边缘。 您可以使用hjustvjust 调整文本对齐方式。 文本标签数据框dat_text 应该有一个与您的facet_grid()facet_wrap() 一起使用的列。

【讨论】:

这个答案优于公认的答案(显然两者之间有 5 年的差异),因为它通过每一步的清晰程度。也更加清晰和解释。 如果要将文本添加到多行,请确保文本 data.frame 中的 colnames() 与您要绘制的数据匹配。 当我尝试对我的一个方面执行此操作时,注释会显示,但实际点已消失(或模糊?)。 Ben G,你可以考虑发一个新帖子来分享你的代码和图。【参考方案5】:

我认为lab="Text"上面的答案没用,下面的代码也可以。

ann_text <- data.frame(mpg = 15,wt = 5,
                       cyl = factor(8,levels = c("4","6","8")))
p + geom_text(data = ann_text,label = "Text" )

但是如果你想在不同的子图中进行不同的标注,这样就可以了:

ann_text <- data.frame(mpg = c(14,15),wt = c(4,5),lab=c("text1","text2"),
                       cyl = factor(c(6,8),levels = c("4","6","8")))
p + geom_text(data = ann_text,aes(label =lab) )

【讨论】:

您应该深入解释与已经给出和接受的答案相比,您的解决方案提供了什么。 谢谢,这对于标记不同的子图很有用。 出于某种原因,当我这样做时,它会为因子 cyl=2 和 cyl=3 添加(空)方面。【参考方案6】:

通常你会这样做:

ann_text <- data.frame(mpg = 15,wt = 5,lab = "Text",
                       cyl = factor(8,levels = c("4","6","8")))
p + geom_text(data = ann_text,label = "Text")

它应该可以在不完全指定因子变量的情况下工作,但可能会引发一些警告:

【讨论】:

当我尝试在多面图上使用 geom_text() 时,我似乎遇到了一些模糊的标签。这与此处讨论的问题相同 (groups.google.com/forum/?fromgroups=#!topic/ggplot2/evsbeBT48M4),并已通过使用 annotate("text",...) 解决。有没有其他人使用 geom_text() 得到模糊的标签? @Margaret 通常,这是因为您错误地告诉 ggplot 为原始数据框中的每一行(带有点、线等的行)绘制每个标签的副本。请注意,我将一个单独的数据框传递给geom_text,只有一行。 好的,我知道了-谢谢。如果您想在多面图上放置 3 个不同的标签怎么办?我尝试了一个数据框,它的行数与我的构面一样多,并且每行都有唯一的标签。也许我应该从一个单独的问题开始。 感谢您的解决方案。我想知道我是否也可以使用annotate()...? @user3420448 同样,你只需要为每个分面变量指定值。

以上是关于在ggplot2中的单个方面注释文本的主要内容,如果未能解决你的问题,请参考以下文章

如何在ggplot2的注释中左对齐文本

ggplot2:面内几个线图的单个平滑线

ggplot2,更改标题大小

使用 purrr 时如何自定义 ggplot2 facet_grid 标签中的文本?

用 ggplot2 注释 R 中的矩形以获得对数刻度的图形

R语言与医学统计图形-16ggplot2几何对象之标签与文本