如何在ggplot2图例下方(图表外)添加汇总统计信息?
将ggplot2直方图的统计信息移至图例下方(外部)
问题背景
现有模拟数据及直方图生成代码,当前代码将均值、最大值、最小值标注在图表右上角,但添加标准差等更多统计指标时会导致图表拥挤,需要将汇总统计信息(均值、最大值、最小值、标准差等)放置在图例下方的图表外部区域。
模拟数据
library(fitdistrplus) values <- sample(20:50, 100, replace = TRUE) df <- data.frame(values)
原直方图代码
create_histogram <- function(data_set, column_name, bins_number) { colname <- as_label(enquo(column_name)) # Calculate summary statistics summary_stats <- data.frame( mean = mean(data_set[[colname]]), max = max(data_set[[colname]]), min = min(data_set[[colname]]) ) ggplot(data_set, aes(x = {{ column_name }})) + geom_histogram(aes(y = after_stat(density)), bins = bins_number, fill = "lightblue", colour = "black") + stat_function(fun = dnorm , args = list(mean = mean(data_set[[colname]]), sd = sd(data_set[[colname]])), mapping = aes(colour = "Normal")) + scale_colour_manual("Distribution", values = c("red")) + annotate("text", x = Inf, y = Inf, hjust = 1.1, vjust = 1.1, label = paste("Mean:", round(summary_stats$mean, 2), "\nMax:", round(summary_stats$max, 2), "\nMin:", round(summary_stats$min, 2))) } create_histogram(df, values, 15)
解决方案
以下提供三种可行的实现方式,均能将统计信息放置在图例下方的外部区域:
方法一:调整边距+直接标注文本
通过扩大图表右侧边距,将统计文本标注在图例下方的外部位置,无需额外包:
library(ggplot2) library(rlang) create_histogram <- function(data_set, column_name, bins_number) { colname <- as_label(enquo(column_name)) # 计算包含标准差的统计量 summary_stats <- data.frame( mean = mean(data_set[[colname]]), max = max(data_set[[colname]]), min = min(data_set[[colname]]), sd = sd(data_set[[colname]]) ) # 拼接统计文本 stats_text <- paste0( "Mean: ", round(summary_stats$mean, 2), "\n", "Max: ", round(summary_stats$max, 2), "\n", "Min: ", round(summary_stats$min, 2), "\n", "SD: ", round(summary_stats$sd, 2) ) ggplot(data_set, aes(x = {{ column_name }})) + geom_histogram(aes(y = after_stat(density)), bins = bins_number, fill = "lightblue", colour = "black") + stat_function(fun = dnorm, args = list(mean = summary_stats$mean, sd = summary_stats$sd), mapping = aes(colour = "Normal")) + scale_colour_manual("Distribution", values = c("red")) + # 扩大右侧边距,为统计文本预留空间 theme(plot.margin = margin(5.5, 80, 5.5, 5.5)) + # 将文本标注在图例下方(x=Inf对应最右侧,y=-0.01对应图表底部偏上位置,可根据需求调整) annotate("text", x = Inf, y = -0.01, hjust = 1, vjust = 1, label = stats_text, size = 3.5) } # 调用函数 create_histogram(df, values, 15)
方法二:使用grid包的文本框精准控制位置
利用grid包的textGrob结合annotation_custom,不受数据坐标轴范围影响,更精准控制文本位置:
library(ggplot2) library(rlang) library(grid) create_histogram <- function(data_set, column_name, bins_number) { colname <- as_label(enquo(column_name)) # 计算包含标准差的统计量 summary_stats <- data.frame( mean = mean(data_set[[colname]]), max = max(data_set[[colname]]), min = min(data_set[[colname]]), sd = sd(data_set[[colname]]) ) # 拼接统计文本 stats_text <- paste0( "Mean: ", round(summary_stats$mean, 2), "\n", "Max: ", round(summary_stats$max, 2), "\n", "Min: ", round(summary_stats$min, 2), "\n", "SD: ", round(summary_stats$sd, 2) ) # 创建文本框对象 stats_grob <- textGrob( label = stats_text, x = unit(1, "npc"), y = unit(0, "npc"), # 锚定在右上角底部 hjust = 1, vjust = 0, gp = gpar(fontsize = 10) ) ggplot(data_set, aes(x = {{ column_name }})) + geom_histogram(aes(y = after_stat(density)), bins = bins_number, fill = "lightblue", colour = "black") + stat_function(fun = dnorm, args = list(mean = summary_stats$mean, sd = summary_stats$sd), mapping = aes(colour = "Normal")) + scale_colour_manual("Distribution", values = c("red")) + # 扩大右侧边距 theme(plot.margin = margin(5.5, 100, 5.5, 5.5)) + # 添加文本框到图表外部 annotation_custom(stats_grob, xmin = Inf, xmax = Inf, ymin = -Inf, ymax = Inf) } # 调用函数 create_histogram(df, values, 15)
方法三:使用patchwork拼接图表与文本
通过patchwork包将主直方图和统计文本区域拼接,布局更灵活:
library(ggplot2) library(rlang) library(patchwork) create_histogram <- function(data_set, column_name, bins_number) { colname <- as_label(enquo(column_name)) # 计算包含标准差的统计量 summary_stats <- data.frame( mean = mean(data_set[[colname]]), max = max(data_set[[colname]]), min = min(data_set[[colname]]), sd = sd(data_set[[colname]]) ) # 拼接统计文本 stats_text <- paste0( "Mean: ", round(summary_stats$mean, 2), "\n", "Max: ", round(summary_stats$max, 2), "\n", "Min: ", round(summary_stats$min, 2), "\n", "SD: ", round(summary_stats$sd, 2) ) # 生成主直方图 main_plot <- ggplot(data_set, aes(x = {{ column_name }})) + geom_histogram(aes(y = after_stat(density)), bins = bins_number, fill = "lightblue", colour = "black") + stat_function(fun = dnorm, args = list(mean = summary_stats$mean, sd = summary_stats$sd), mapping = aes(colour = "Normal")) + scale_colour_manual("Distribution", values = c("red")) # 生成统计文本的空白图表 stats_plot <- ggplot() + annotate("text", x = 0, y = 0, label = stats_text, size = 3.5, hjust = 1) + theme_void() + theme(plot.margin = margin(0, 0, 0, 20)) # 调整左侧边距对齐图例 # 拼接两个图表,主图占4份宽度,文本区域占1份 main_plot + stats_plot + plot_layout(widths = c(4, 1)) } # 调用函数 create_histogram(df, values, 15)
内容的提问来源于stack exchange,提问作者Joe the Second
相关产品推荐
相关产品推荐

