基于Base R拆分数据框并绘制多面板物种丰度曲线
Base R实现多面板物种丰度曲线(按年份拆分+分页布局)
我来帮你用Base R搞定这个多面板物种丰度曲线的需求!从数据处理到绘图,一步步给你捋清楚:
1. 先回顾你的原始数据
你提供的示例数据生成代码如下,其中rank列是各年份内lepsp对应freq的降序密集排名(丰度相同则排名重复):
set.seed(453) year= as.factor(c(rep("1998", 20), rep("1999", 16))) lepsp= c(letters[seq(from = 1, to = 20 )], c('a','b','c'),letters[seq(from =8, to = 20 )]) freq= c(sample(1:15, 20, replace=T), sample(1:18, 16,replace=T)) df<-data.frame(year, lepsp, freq) df<- df %>% group_by(year) %>% mutate(rank = dense_rank(-freq))
2. 需求梳理
你的核心需求可以总结为:
- 按年份拆分数据框
- 用Base R绘制多面板物种丰度曲线(x轴为
rank,y轴为freq) - 采用4行2列的布局,每页最多8张图(22年数据分3页展示)
- 图中添加25%、50%、75%四分位竖线
- 每个图标注对应年份,且不重复显示x、y轴标签
3. Base R完整解决方案
下面是完全符合需求的代码,我会逐部分解释:
步骤1:按年份拆分数据框
用Base R自带的split()函数就能快速按年份拆分,得到每个年份对应的子数据框列表:
# 按年份拆分数据框 df_list <- split(df, df$year) # 确认总年份数量(22年的话这里会返回22) year_count <- length(df_list)
步骤2:设置分页参数
计算需要的总页数,因为每页最多放8张图(4行2列),用ceiling()向上取整确保所有年份都能展示:
# 计算总页数:22年的话会得到3页(8+8+6) pages <- ceiling(year_count / 8)
步骤3:循环分页绘图
这部分是核心,我们用par()控制布局、轴标签显示,同时添加四分位线和年份标注:
# 循环处理每一页 for(page in 1:pages){ # 确定当前页要绘制的年份索引范围 start_idx <- (page-1)*8 + 1 end_idx <- min(page*8, year_count) current_years <- names(df_list)[start_idx:end_idx] # 设置4行2列的面板布局,同时调整内外边距避免标签重叠 par(mfrow = c(4,2), mar = c(3,3,2,1), # 内边距:下、左、上、右 oma = c(2,2,0,0)) # 外边距:用于放置统一的全局轴标签 # 循环绘制当前页的每个年份图 for(i in seq_along(current_years)){ current_df <- df_list[[current_years[i]]] # 计算rank的四分位数(针对当前年份的rank列) rank_quantiles <- quantile(current_df$rank, c(0.25, 0.5, 0.75)) # 绘制丰度曲线:用折线+点的形式,更清晰展示趋势 plot(current_df$rank, current_df$freq, type = "b", pch = 16, cex = 0.8, # 控制轴标签:先隐藏所有子图的轴标签,最后统一加全局标签 xlab = "", ylab = "", main = current_years[i], # 把年份作为子图标题,清晰标注 xaxt = ifelse(i > 6, "s", "n"), # 仅最后两行显示x轴刻度 yaxt = ifelse(i %% 2 == 1, "s", "n")) # 仅第一列显示y轴刻度 # 添加四分位竖线:蓝色虚线为25%、75%,红色实线为中位数(50%) abline(v = rank_quantiles[1], col = "blue", lty = 2) abline(v = rank_quantiles[2], col = "red", lty = 1) abline(v = rank_quantiles[3], col = "blue", lty = 2) # 可选:给四分位线添加文字标签(放在x轴下方) text(rank_quantiles, par("usr")[3] - 0.5, labels = c("25%", "50%", "75%"), col = c("blue", "red", "blue"), cex = 0.7) } # 在页面外边缘添加统一的全局x、y轴标签 mtext("Rank", side = 1, outer = TRUE, line = 0.5, cex = 1.1) mtext("Frequency", side = 2, outer = TRUE, line = 0.5, cex = 1.1) # 非最后一页时,等待用户按回车键切换下一页(避免一次性弹出所有窗口) if(page < pages){ cat("Press Enter to view next page...\n") readLines(n = 1) } }
关键细节解释
- 轴标签控制:通过
xaxt/yaxt参数确保只有边缘子图显示刻度,全局轴标签用mtext()放在页面外边缘,彻底避免重复冗余。 - 四分位线:针对每个年份的
rank列单独计算分位数,保证竖线是当前年份的真实分位位置,符合需求。 - 分页逻辑:自动适配年份数量,22年数据会自动分成3页,最后一页展示剩余的6张图,无需手动调整。
内容的提问来源于stack exchange,提问作者Danielle
相关产品推荐
相关产品推荐

