如何在 R 中使用 facet_grid 在每个单独的图中添加标题?
How to add captions in each individual plot using facet_grid in R?
我正在使用 facet_grid
绘制多个绘图,我想知道如何在每个单独的绘图中添加一些额外信息作为标题。
我设法在每个图的标题中添加信息(为了添加 Kruskal-Wallis p-value),但我想在每个图下方添加更多信息(作为标题) .
这是一个可重现的例子:
library(ggplot2)
library(dplyr)
set.seed(1234)
Gene <- floor(runif(25, min=0, max=101))
Age <- floor(runif(25, min=18, max=75))
Group <- c("Group1", "Group1", "Group3", "Group2", "Group1", "Group3", "Group2", "Group2", "Group2", "Group1", "Group1", "Group3", "Group1", "Group2", "Group1", "Group2", "Group3", "Group1", "Group3", "Group3", "Group2", "Group1", "Group3", "Group3","Group2")
df <- data.frame(Gene, Age, Group)
df$Group <- as.factor(df$Group)
mybreaks <- seq(min(df$Age)-1, to=max(df$Age)+10, by=10)
df$groups_age <- cut(df$Age, breaks = mybreaks, by=10)
bp <- ggplot(df, aes(x=groups_age, y=Gene, group=groups_age)) +
geom_boxplot(aes(fill=groups_age)) +
facet_grid(. ~ Group)
bp
pval <- df %>%
group_by(Group) %>%
summarize(Kruskal_pvalue = kruskal.test(Gene ~ groups_age)$p.value)
# This is to create new labels for the facetgrid where we can show the phenotype and the KW pvalue.
labels <- c(paste('Group 1\n KW p-val:', signif(subset(pval$Kruskal_pvalue, pval$Group=="Group1"), digits = 3)),
paste('Group 2\n KW p-val:', signif(subset(pval$Kruskal_pvalue, pval$Group=="Group2"), digits = 3)),
paste('Group 3\n KW p-val:', signif(subset(pval$Kruskal_pvalue, pval$Group=="Group3"), digits = 3)))
df$KW <- factor(df$Group, levels = levels(df$Group), labels = labels)
bp <- ggplot(df, aes(x=groups_age, y=Gene, group=groups_age)) +
geom_boxplot(aes(fill=groups_age)) +
facet_grid(. ~ KW) +
theme(legend.position="none")
bp
这是上面代码的结果:
如果我想添加有关每个图的信息作为标题,这是我能想到的唯一方法。
df_group1 <- df[df$Group == "Group1",]
df_group2 <- df[df$Group == "Group2",]
df_group3 <- df[df$Group == "Group3",]
myfunction <- function(DF){
df <- as.data.frame(table(DF$groups_age))
# This is to add ": n = " to the first column
df$Var1 <- paste(df$Var1, ": n = ", sep = "")
# We join both columns in one to have the result together.
df$X <- paste(df$Var1, df$Freq)
# We save that column into a variable
vec <- df[["X"]]
return(vec)
}
numb_group1 <- myfunction(df_group1)
numb_group1 <- paste(numb_group1, collapse = "; ")
numb_group2 <- myfunction(df_group2)
numb_group2 <- paste(numb_group2, collapse = "; ")
numb_group3 <- myfunction(df_group3)
numb_group3 <- paste(numb_group3, collapse = "; ")
numb_all <- c(numb_group1, numb_group2, numb_group3)
bp <- bp + labs(caption = paste0("Group 1: n = ", nrow(subset(df, df$Group=="Group1")),
"\n",
" Groups: ", numb_all[1],
"\n",
"\n",
"Group 2: n = ", nrow(subset(df, df$Group=="Group2")),
"\n",
" Groups: ", numb_all[2],
"\n",
"\n",
"Group 3: n = ", nrow(subset(df, df$Group=="Group3")),
"\n",
" Groups:", numb_all[3]
)) + theme(legend.position="none",
plot.caption = element_text(hjust = 0, face= "italic")) #Default is hjust=1
bp
这是它的样子:
但是,我想改进我的代码并找到另一种方法(如果存在的话)将每个信息放在每个单独的图下方。
有人知道它能做什么吗?
非常感谢
Generally-speaking multi-faceted 地块上的地块标题:
如果您想要单个标题,即低于所有情节,您应该使用theme(plot.caption = ...)
.
如果您希望相同的标题出现在每个方面下方,您可以使用[=14] =] 并关闭剪辑。
如果您想要不同的标题出现在每个方面下方,您需要一些能够映射到数据集(因此您可以为每个构面指定不同的文本)。在这种情况下,我建议使用 geom_text()
并巧妙地格式化以适合标题。
每个图都有不同标题的替代方法是创建带有标题的单独图,并通过 grid.arrange()
或 patchwork
或 [=18= 将它们 link 在一起]...
这里是使用geom_text()
和mtcars
的第三种情况的例子。我希望你能把它应用到你自己的数据集上。
基本剧情
这是我们将用于添加标题的基本情节:
library(ggplot2)
p <- ggplot(mtcars, aes(qsec, mpg)) + geom_point() +
facet_wrap(~cyl)
字幕数据框
要制作标题图,我们首先需要为每个方面定义文本。最好在与批量数据分开的 单独数据框 中执行此操作。这确保了文本 geom 没有任何过度绘制(多次在同一位置绘制),因为 数据框中的每个观察绘制一个文本 geom。这是我们的字幕数据框:
caption_df <- data.frame(
cyl = c(4,6,8),
txt = c("carb=4", "carb=6", "carb=8, OMG!")
)
带字幕绘图
为了制作情节,我们需要对情节进行一些调整。
添加标题。 添加 geom_text()
并映射到 caption_df
。我们将映射文本,但位置将在 x 和 y 中固定。 x 值设置为我们原始数据的最小值,但我们也可以手动设置。 y 值需要设置为 低于原始图 .
的值
限制绘图的范围。 由于我们将文本 geom 放置在 原始绘图区域下方,如果我们没有限制绘图区域的限制,ggplot2
只会扩展 y 限制以适应新文本。我们需要保持原来的 y 限制,以确保我们添加的 geom_text()
的 y 值保持 低于 这个区域。
关闭剪裁。为了真正看到新的字幕,您需要关闭剪裁。您可以在任何 coord_*()
函数中执行此操作,因此我们将使用 coord_cartesian()
来执行此操作并设置 y 限制。
增加下边距。为了确保我们在最终图像中看到标题,我们需要通过 theme(plot.margin=...)
增加图下方的边距.
这是所有这些的最终结果。
ggplot(mtcars, aes(qsec, mpg)) + geom_point() + facet_wrap(~cyl) +
coord_cartesian(clip="off", ylim=c(10, 40)) +
geom_text(
data=caption_df, y=5, x=min(mtcars$qsec),
mapping=aes(label=txt), hjust=0,
fontface="italic", color="red"
) +
theme(plot.margin = margin(b=25))
在使用 facet_grid
和字幕尝试了很多事情之后,我创建了一些帖子,在这些帖子中我得到了非常好的答案,可以帮助解决这个问题的人。
这是主要的解决方案:
虽然这在我尝试自动化代码时给我带来了一些问题: and 。
但是,我意识到对于这种情况,最好将观测值的数量放在每个箱线图上方。它更直观,不需要很多代码。
myFreqs <- df %>%
group_by(Group, groups_age) %>%
summarise(Freq = n())
myFreqs
bp + stat_summary(geom = 'text', label = paste("n = ", myFreqs$Freq), fun = max, vjust = -1, position = position_dodge(width=0.7))
我正在使用 facet_grid
绘制多个绘图,我想知道如何在每个单独的绘图中添加一些额外信息作为标题。
我设法在每个图的标题中添加信息(为了添加 Kruskal-Wallis p-value),但我想在每个图下方添加更多信息(作为标题) .
这是一个可重现的例子:
library(ggplot2)
library(dplyr)
set.seed(1234)
Gene <- floor(runif(25, min=0, max=101))
Age <- floor(runif(25, min=18, max=75))
Group <- c("Group1", "Group1", "Group3", "Group2", "Group1", "Group3", "Group2", "Group2", "Group2", "Group1", "Group1", "Group3", "Group1", "Group2", "Group1", "Group2", "Group3", "Group1", "Group3", "Group3", "Group2", "Group1", "Group3", "Group3","Group2")
df <- data.frame(Gene, Age, Group)
df$Group <- as.factor(df$Group)
mybreaks <- seq(min(df$Age)-1, to=max(df$Age)+10, by=10)
df$groups_age <- cut(df$Age, breaks = mybreaks, by=10)
bp <- ggplot(df, aes(x=groups_age, y=Gene, group=groups_age)) +
geom_boxplot(aes(fill=groups_age)) +
facet_grid(. ~ Group)
bp
pval <- df %>%
group_by(Group) %>%
summarize(Kruskal_pvalue = kruskal.test(Gene ~ groups_age)$p.value)
# This is to create new labels for the facetgrid where we can show the phenotype and the KW pvalue.
labels <- c(paste('Group 1\n KW p-val:', signif(subset(pval$Kruskal_pvalue, pval$Group=="Group1"), digits = 3)),
paste('Group 2\n KW p-val:', signif(subset(pval$Kruskal_pvalue, pval$Group=="Group2"), digits = 3)),
paste('Group 3\n KW p-val:', signif(subset(pval$Kruskal_pvalue, pval$Group=="Group3"), digits = 3)))
df$KW <- factor(df$Group, levels = levels(df$Group), labels = labels)
bp <- ggplot(df, aes(x=groups_age, y=Gene, group=groups_age)) +
geom_boxplot(aes(fill=groups_age)) +
facet_grid(. ~ KW) +
theme(legend.position="none")
bp
这是上面代码的结果:
如果我想添加有关每个图的信息作为标题,这是我能想到的唯一方法。
df_group1 <- df[df$Group == "Group1",]
df_group2 <- df[df$Group == "Group2",]
df_group3 <- df[df$Group == "Group3",]
myfunction <- function(DF){
df <- as.data.frame(table(DF$groups_age))
# This is to add ": n = " to the first column
df$Var1 <- paste(df$Var1, ": n = ", sep = "")
# We join both columns in one to have the result together.
df$X <- paste(df$Var1, df$Freq)
# We save that column into a variable
vec <- df[["X"]]
return(vec)
}
numb_group1 <- myfunction(df_group1)
numb_group1 <- paste(numb_group1, collapse = "; ")
numb_group2 <- myfunction(df_group2)
numb_group2 <- paste(numb_group2, collapse = "; ")
numb_group3 <- myfunction(df_group3)
numb_group3 <- paste(numb_group3, collapse = "; ")
numb_all <- c(numb_group1, numb_group2, numb_group3)
bp <- bp + labs(caption = paste0("Group 1: n = ", nrow(subset(df, df$Group=="Group1")),
"\n",
" Groups: ", numb_all[1],
"\n",
"\n",
"Group 2: n = ", nrow(subset(df, df$Group=="Group2")),
"\n",
" Groups: ", numb_all[2],
"\n",
"\n",
"Group 3: n = ", nrow(subset(df, df$Group=="Group3")),
"\n",
" Groups:", numb_all[3]
)) + theme(legend.position="none",
plot.caption = element_text(hjust = 0, face= "italic")) #Default is hjust=1
bp
这是它的样子:
但是,我想改进我的代码并找到另一种方法(如果存在的话)将每个信息放在每个单独的图下方。
有人知道它能做什么吗?
非常感谢
Generally-speaking multi-faceted 地块上的地块标题:
如果您想要单个标题,即低于所有情节,您应该使用
theme(plot.caption = ...)
.如果您希望相同的标题出现在每个方面下方,您可以使用[=14] =] 并关闭剪辑。
如果您想要不同的标题出现在每个方面下方,您需要一些能够映射到数据集(因此您可以为每个构面指定不同的文本)。在这种情况下,我建议使用
geom_text()
并巧妙地格式化以适合标题。每个图都有不同标题的替代方法是创建带有标题的单独图,并通过
grid.arrange()
或patchwork
或 [=18= 将它们 link 在一起]...
这里是使用geom_text()
和mtcars
的第三种情况的例子。我希望你能把它应用到你自己的数据集上。
基本剧情
这是我们将用于添加标题的基本情节:
library(ggplot2)
p <- ggplot(mtcars, aes(qsec, mpg)) + geom_point() +
facet_wrap(~cyl)
字幕数据框
要制作标题图,我们首先需要为每个方面定义文本。最好在与批量数据分开的 单独数据框 中执行此操作。这确保了文本 geom 没有任何过度绘制(多次在同一位置绘制),因为 数据框中的每个观察绘制一个文本 geom。这是我们的字幕数据框:
caption_df <- data.frame(
cyl = c(4,6,8),
txt = c("carb=4", "carb=6", "carb=8, OMG!")
)
带字幕绘图
为了制作情节,我们需要对情节进行一些调整。
添加标题。 添加
的值geom_text()
并映射到caption_df
。我们将映射文本,但位置将在 x 和 y 中固定。 x 值设置为我们原始数据的最小值,但我们也可以手动设置。 y 值需要设置为 低于原始图 .限制绘图的范围。 由于我们将文本 geom 放置在 原始绘图区域下方,如果我们没有限制绘图区域的限制,
ggplot2
只会扩展 y 限制以适应新文本。我们需要保持原来的 y 限制,以确保我们添加的geom_text()
的 y 值保持 低于 这个区域。关闭剪裁。为了真正看到新的字幕,您需要关闭剪裁。您可以在任何
coord_*()
函数中执行此操作,因此我们将使用coord_cartesian()
来执行此操作并设置 y 限制。增加下边距。为了确保我们在最终图像中看到标题,我们需要通过
theme(plot.margin=...)
增加图下方的边距.
这是所有这些的最终结果。
ggplot(mtcars, aes(qsec, mpg)) + geom_point() + facet_wrap(~cyl) +
coord_cartesian(clip="off", ylim=c(10, 40)) +
geom_text(
data=caption_df, y=5, x=min(mtcars$qsec),
mapping=aes(label=txt), hjust=0,
fontface="italic", color="red"
) +
theme(plot.margin = margin(b=25))
在使用 facet_grid
和字幕尝试了很多事情之后,我创建了一些帖子,在这些帖子中我得到了非常好的答案,可以帮助解决这个问题的人。
这是主要的解决方案:
虽然这在我尝试自动化代码时给我带来了一些问题:
但是,我意识到对于这种情况,最好将观测值的数量放在每个箱线图上方。它更直观,不需要很多代码。
myFreqs <- df %>%
group_by(Group, groups_age) %>%
summarise(Freq = n())
myFreqs
bp + stat_summary(geom = 'text', label = paste("n = ", myFreqs$Freq), fun = max, vjust = -1, position = position_dodge(width=0.7))