如何基于行数调整ggplot2中facet_wrap的子图大小
调整ggplot2 facet_wrap子图尺寸:按类别行数分配高度
我用R语言的ggplot2包绘图时,通过facet_wrap()按Category做单列分面,希望实现:行数较多的子图(示例中的MF、CC)高度更大,行数较少的子图(示例中的BP)高度更小,同时保持整体图表的总大小不变。
示例数据与代码如下:
df <- data.frame( 'Seq ratio' = runif(15, min = 0, max = 0.5), 'feature' = stringi::stri_rand_strings(15, 1, pattern = "[A-F]"), 'Seq count' = c(8, 10, 8, 8, 8, 4, 4, 4, 5, 4, 4, 7, 15, 15, 15), 'adj. P value' = c(0.012609566, 0.012609566, 0.033278332, 0.021875357, 0.021875357,0.003216359, 0.003216359, 0.003216359, 0.030076544, 0.017188404, 0.003216359, 0.047018661, 0.002584020, 0.002584020, 0.002584020), 'cluster' = c('Cluster 1', 'Cluster 1', 'Cluster 1', 'Cluster 1', 'Cluster 1', 'Cluster 2', 'Cluster 2', 'Cluster 2', 'Cluster 2', 'Cluster 3', 'Cluster 3', 'Cluster 4', 'Cluster 4', 'Cluster 4', 'Cluster 4'), 'Category' = c('MF', 'MF', 'CC', 'MF', 'CC', 'BP', 'BP', 'BP', 'BP', 'MF', 'MF', 'BP', 'CC', 'CC', 'CC'))
ggplot(df, aes(`Seq ratio`, feature, size = `Seq count`, colour = `adj. P value`)) + facet_wrap(~Category, ncol = 1, scales = "free_y") + geom_point() + ylab(NULL) + scale_x_continuous(n.breaks = 5) + scale_size(name = "Seq count", limits = c(0, 15))
当前效果:三个子图高度完全一致,BP类别因feature数量少存在明显空间浪费;而MF、CC类别下的feature排列拥挤,可读性较差。
解决方案
方法1:用ggh4x包的facet_wrap2(简单高效)
ggh4x是ggplot2的扩展包,它的facet_wrap2()支持按子图内容自动分配高度,只需添加一个参数就能实现需求:
- 安装并加载包:
install.packages("ggh4x") library(ggh4x)
- 修改绘图代码:
ggplot(df, aes(`Seq ratio`, feature, size = `Seq count`, colour = `adj. P value`)) + facet_wrap2(~Category, ncol = 1, scales = "free_y", heights = "free") + geom_point() + ylab(NULL) + scale_x_continuous(n.breaks = 5) + scale_size(name = "Seq count", limits = c(0, 15))
这个方法会自动根据每个Category下的feature数量调整子图高度,数量多的子图占比更大,整体图表大小保持稳定,无需手动计算比例。
方法2:用patchwork手动拼接子图(灵活自定义)
如果不想依赖额外包,可以手动拆分数据绘制单个子图,再用patchwork按比例拼接:
- 安装并加载包:
install.packages("patchwork") library(patchwork)
- 计算每个类别的行数比例:
# 统计每个Category的feature数量 cat_row_counts <- table(df$Category) # 按数量占比计算高度比例 height_proportions <- as.numeric(cat_row_counts) / sum(cat_row_counts)
- 绘制单个子图并拼接:
# MF子图 p_mf <- ggplot(subset(df, Category == "MF"), aes(`Seq ratio`, feature, size = `Seq count`, colour = `adj. P value`)) + geom_point() + ylab(NULL) + scale_x_continuous(n.breaks = 5) + scale_size(name = "Seq count", limits = c(0, 15)) + ggtitle("MF") + theme(plot.title = element_text(hjust = 0.5)) # CC子图 p_cc <- ggplot(subset(df, Category == "CC"), aes(`Seq ratio`, feature, size = `Seq count`, colour = `adj. P value`)) + geom_point() + ylab(NULL) + scale_x_continuous(n.breaks = 5) + scale_size(name = "Seq count", limits = c(0, 15)) + ggtitle("CC") + theme(plot.title = element_text(hjust = 0.5)) # BP子图 p_bp <- ggplot(subset(df, Category == "BP"), aes(`Seq ratio`, feature, size = `Seq count`, colour = `adj. P value`)) + geom_point() + ylab(NULL) + scale_x_continuous(n.breaks = 5) + scale_size(name = "Seq count", limits = c(0, 15)) + ggtitle("BP") + theme(plot.title = element_text(hjust = 0.5)) # 按比例垂直拼接 p_mf / p_cc / p_bp + plot_layout(heights = height_proportions)
这种方法可以自定义高度比例,比如给行数多的子图额外增加权重,灵活性更高。
内容的提问来源于stack exchange,提问作者Marta López
相关产品推荐
相关产品推荐

